@nanobpm/nano-workforce 0.126.0 → 0.128.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.github/workflows/invariants.yml +8 -0
  2. package/.github/workflows/pr-title-lint.yml +9 -1
  3. package/.github/workflows/release.yml +37 -8
  4. package/AGENTS.md +37 -0
  5. package/CHANGELOG.md +14 -0
  6. package/app/agentCompletion.ts +11 -0
  7. package/app/agentic/cockpit/cockpit-route.test.ts +21 -0
  8. package/app/agentic/cockpit/cockpit-route.ts +17 -0
  9. package/app/agentic/cockpit/index.ts +16 -0
  10. package/app/agentic/cockpit/supply-boot-past.test.ts +44 -0
  11. package/app/agentic/cockpit/supply-boot.test.ts +2 -2
  12. package/app/agentic/cockpit/supply-boot.ts +76 -10
  13. package/app/agentic/cockpit/supply-render.test.ts +13 -4
  14. package/app/agentic/cockpit/supply-render.ts +14 -2
  15. package/app/agentic/cockpit/transcript-render.ts +6 -2
  16. package/app/agentic/cockpit/transcript-view.ts +9 -0
  17. package/app/agentic/cockpit/worker-detail-render.test.ts +86 -0
  18. package/app/agentic/cockpit/worker-detail-render.ts +88 -0
  19. package/app/agentic/cockpit/worker-detail-view.ts +43 -0
  20. package/app/agentic/correlation-store.test.ts +99 -0
  21. package/app/agentic/correlation-store.ts +162 -0
  22. package/app/agentic/families/presence.family.test.ts +12 -0
  23. package/app/agentic/families/presence.family.ts +14 -0
  24. package/app/agentic/families/relay.family.test.ts +72 -0
  25. package/app/agentic/families/relay.family.ts +130 -1
  26. package/app/agentic/transcript-read.test.ts +55 -3
  27. package/app/agentic/transcript-read.ts +49 -9
  28. package/app/agentic/vocab/demand-report.test.ts +23 -10
  29. package/app/pollUserTasks.test.ts +66 -2
  30. package/app/service.ts +21 -8
  31. package/app/tasksPage.test.ts +44 -0
  32. package/app/userTasks.test.ts +19 -0
  33. package/app/userTasks.ts +13 -1
  34. package/db/migrations/077_user_tasks_form_key.sql +25 -0
  35. package/db/migrations/078_agentic_correlation.sql +32 -0
  36. package/docs/adr/0006-delivery-units-one-representation.md +59 -20
  37. package/e2e/delivery-graph.e2e.ts +7 -0
  38. package/e2e/feature-preflight.e2e.ts +7 -0
  39. package/e2e/inter-epic-dependency.e2e.ts +8 -0
  40. package/e2e/plan-fanout-preflight.e2e.ts +7 -0
  41. package/e2e/plan-fanout-sla.e2e.ts +4 -3
  42. package/e2e/plan-fanout.e2e.ts +2 -2
  43. package/e2e/readiness-gate.e2e.ts +8 -37
  44. package/e2e/support/probe-exec.test.ts +78 -0
  45. package/e2e/support/probe-exec.ts +69 -0
  46. package/e2e/support/time.test.ts +42 -0
  47. package/e2e/support/time.ts +33 -0
  48. package/openapi.yaml +26 -0
  49. package/operations/getAgenticTranscript.ts +3 -2
  50. package/operations/listAgenticTranscripts.ts +2 -1
  51. package/package.json +3 -3
  52. package/pages/cockpit/cockpit.css +65 -2
  53. package/pages/cockpit/mount.js +187 -16
  54. package/pages/tasks.page.json +24 -554
@@ -9,30 +9,12 @@
9
9
  "variant": "bar",
10
10
  "title": "Nano Workforce",
11
11
  "items": [
12
- {
13
- "label": "Overview",
14
- "page": "overview"
15
- },
16
- {
17
- "label": "Lineage",
18
- "page": "lineage"
19
- },
20
- {
21
- "label": "Convergence",
22
- "page": "home"
23
- },
24
- {
25
- "label": "Epics",
26
- "page": "epic"
27
- },
28
- {
29
- "label": "Feature",
30
- "page": "feature"
31
- },
32
- {
33
- "label": "Delivery Graphs",
34
- "page": "delivery-graphs"
35
- },
12
+ { "label": "Overview", "page": "overview" },
13
+ { "label": "Lineage", "page": "lineage" },
14
+ { "label": "Convergence", "page": "home" },
15
+ { "label": "Epics", "page": "epic" },
16
+ { "label": "Feature", "page": "feature" },
17
+ { "label": "Delivery Graphs", "page": "delivery-graphs" },
36
18
  {
37
19
  "label": "Tasks",
38
20
  "page": "tasks",
@@ -45,18 +27,9 @@
45
27
  "hideWhenZero": true
46
28
  }
47
29
  },
48
- {
49
- "label": "Cockpit",
50
- "page": "cockpit"
51
- },
52
- {
53
- "label": "Board",
54
- "page": "board"
55
- },
56
- {
57
- "label": "Velocity",
58
- "page": "velocity"
59
- }
30
+ { "label": "Cockpit", "page": "cockpit" },
31
+ { "label": "Board", "page": "board" },
32
+ { "label": "Velocity", "page": "velocity" }
60
33
  ],
61
34
  "sticky": true
62
35
  }
@@ -64,42 +37,30 @@
64
37
  {
65
38
  "type": "text",
66
39
  "id": "title",
67
- "props": {
68
- "text": "Tasks",
69
- "variant": "heading"
70
- }
40
+ "props": { "text": "Tasks", "variant": "heading" }
71
41
  },
72
42
  {
73
43
  "type": "text",
74
44
  "id": "subtitle",
75
45
  "props": {
76
- "text": "Open native user-task escalations awaiting a human decision — across feature runs, epics, and PR review loops. Each row parks a process on your decision; submit one and the process resumes on the same canonical path Urban's task inbox uses. Rows disappear once completed (here, via the inbox, or out-of-band).",
46
+ "text": "Every open native user-task escalation awaiting a human decision — feature runs, epics, PR review/merge loops, conformance reviews, and delivery-graph human/escalation gates in one list. The \"Type\" column tells them apart; open a row to complete it via the process's own deployed form, on the same canonical path Urban's task inbox uses. This list is exactly the set the nav badge counts, so a badge always maps to a visible, completable row. Rows disappear once completed (here, via the inbox, or out-of-band).",
77
47
  "variant": "sub"
78
48
  }
79
49
  },
80
50
  {
81
51
  "type": "dataGrid",
82
- "id": "feature-escalations",
52
+ "id": "user-tasks",
83
53
  "props": {
84
- "title": "Feature escalations",
54
+ "title": "Open tasks",
85
55
  "data": {
86
56
  "kind": "datasource",
87
57
  "source": "app",
88
58
  "table": "user_tasks",
89
- "filter": [
90
- {
91
- "field": "element_id",
92
- "in": [
93
- "feature-escalation"
94
- ]
95
- }
96
- ],
97
- "orderBy": {
98
- "field": "updated_at",
99
- "dir": "desc"
100
- }
59
+ "filter": [],
60
+ "orderBy": { "field": "updated_at", "dir": "desc" }
101
61
  },
102
62
  "columns": [
63
+ { "field": "kind_label", "header": "Type" },
103
64
  {
104
65
  "field": "subject_title",
105
66
  "template": "{{subject_title}}",
@@ -108,518 +69,27 @@
108
69
  "truncate": true,
109
70
  "linkField": "subject_url"
110
71
  },
111
- {
112
- "field": "subject_url",
113
- "header": "Issue"
114
- },
72
+ { "field": "subject_url", "header": "Link" },
115
73
  {
116
74
  "field": "process_key",
117
75
  "header": "Process",
118
- "link": {
119
- "kind": "processExplorer",
120
- "keyField": "process_key"
121
- }
76
+ "link": { "kind": "processExplorer", "keyField": "process_key" }
122
77
  },
123
- {
124
- "field": "updated_at",
125
- "header": "Updated",
126
- "format": "datetime"
127
- }
78
+ { "field": "updated_at", "header": "Updated", "format": "datetime" }
128
79
  ],
129
80
  "rowKey": "user_task_key",
130
81
  "detail": {
131
82
  "linkField": "subject_url",
132
83
  "fields": [
133
- {
134
- "field": "question",
135
- "label": "Escalation question"
136
- }
84
+ { "field": "question", "label": "Decision context" }
137
85
  ],
138
- "form": {
139
- "showWhenField": "user_task_key",
140
- "title": "Answer escalation",
141
- "promptField": "question",
142
- "submitLabel": "Submit decision",
143
- "fields": [
144
- {
145
- "inputKey": "resolution",
146
- "type": "select",
147
- "inputLabel": "Resolution",
148
- "options": [
149
- { "value": "answer", "label": "Answer — re-dispatch the task with this guidance" },
150
- { "value": "abandon", "label": "Abandon — give up on this task" }
151
- ]
152
- },
153
- {
154
- "inputKey": "answer",
155
- "type": "textarea",
156
- "inputLabel": "Answer / guidance for the implementation agent",
157
- "conditional": {
158
- "hide": "=resolution != \"answer\""
159
- }
160
- }
161
- ],
162
- "action": {
163
- "path": "/app/api/actions/complete-user-task",
164
- "successLabel": "Decision submitted — the process will continue",
165
- "body": {
166
- "userTaskKey": "{{row.user_task_key}}",
167
- "variables": "{{form}}"
168
- }
169
- }
170
- }
171
- },
172
- "refreshMs": 5000
173
- }
174
- },
175
- {
176
- "type": "dataGrid",
177
- "id": "plan-reviews",
178
- "props": {
179
- "title": "Plan-review decisions",
180
- "data": {
181
- "kind": "datasource",
182
- "source": "app",
183
- "table": "user_tasks",
184
- "filter": [
185
- {
186
- "field": "element_id",
187
- "in": [
188
- "plan-review-decision"
189
- ]
190
- }
191
- ],
192
- "orderBy": {
193
- "field": "updated_at",
194
- "dir": "desc"
195
- }
196
- },
197
- "columns": [
198
- {
199
- "field": "subject_title",
200
- "template": "{{subject_title}}",
201
- "header": "Item",
202
- "subtitleField": "subject_key",
203
- "truncate": true,
204
- "linkField": "subject_url"
205
- },
206
- {
207
- "field": "question",
208
- "header": "Findings"
209
- },
210
- {
211
- "field": "subject_url",
212
- "header": "Issue"
213
- },
214
- {
215
- "field": "process_key",
216
- "header": "Process",
217
- "link": {
218
- "kind": "processExplorer",
219
- "keyField": "process_key"
220
- }
221
- },
222
- {
223
- "field": "updated_at",
224
- "header": "Updated",
225
- "format": "datetime"
226
- }
227
- ],
228
- "rowKey": "user_task_key",
229
- "detail": {
230
- "linkField": "subject_url",
231
- "fields": [
232
- {
233
- "field": "question",
234
- "label": "Review findings"
235
- }
236
- ],
237
- "form": {
238
- "showWhenField": "user_task_key",
239
- "title": "Review the plan",
240
- "promptField": "question",
241
- "submitLabel": "Submit decision",
242
- "fields": [
243
- {
244
- "inputKey": "directive",
245
- "type": "select",
246
- "inputLabel": "Directive",
247
- "options": [
248
- { "value": "proceed", "label": "Proceed — dispatch the current plan as-is" },
249
- { "value": "revise", "label": "Revise — send the plan back to the planner" }
250
- ]
251
- },
252
- {
253
- "inputKey": "notes",
254
- "type": "textarea",
255
- "inputLabel": "Revision guidance for the planner",
256
- "conditional": {
257
- "hide": "=directive != \"revise\""
258
- }
259
- }
260
- ],
261
- "action": {
262
- "path": "/app/api/actions/complete-user-task",
263
- "successLabel": "Decision recorded",
264
- "body": {
265
- "userTaskKey": "{{row.user_task_key}}",
266
- "variables": "{{form}}"
267
- }
268
- }
269
- }
270
- },
271
- "refreshMs": 5000
272
- }
273
- },
274
- {
275
- "type": "dataGrid",
276
- "id": "trial-merges",
277
- "props": {
278
- "title": "Trial-merge decisions",
279
- "data": {
280
- "kind": "datasource",
281
- "source": "app",
282
- "table": "user_tasks",
283
- "filter": [
284
- {
285
- "field": "element_id",
286
- "in": [
287
- "trial-merge-decision"
288
- ]
289
- }
290
- ],
291
- "orderBy": {
292
- "field": "updated_at",
293
- "dir": "desc"
294
- }
295
- },
296
- "columns": [
297
- {
298
- "field": "subject_title",
299
- "template": "{{subject_title}}",
300
- "header": "Item",
301
- "subtitleField": "subject_key",
302
- "truncate": true,
303
- "linkField": "subject_url"
304
- },
305
- {
306
- "field": "question",
307
- "header": "Trial merge"
308
- },
309
- {
310
- "field": "subject_url",
311
- "header": "Issue"
312
- },
313
- {
314
- "field": "process_key",
315
- "header": "Process",
316
- "link": {
317
- "kind": "processExplorer",
318
- "keyField": "process_key"
319
- }
320
- },
321
- {
322
- "field": "updated_at",
323
- "header": "Updated",
324
- "format": "datetime"
325
- }
326
- ],
327
- "rowKey": "user_task_key",
328
- "detail": {
329
- "linkField": "subject_url",
330
- "fields": [
331
- {
332
- "field": "question",
333
- "label": "Trial merge"
334
- }
335
- ],
336
- "form": {
337
- "showWhenField": "user_task_key",
338
- "title": "Trial-merge decision",
339
- "promptField": "question",
340
- "submitLabel": "Submit decision",
341
- "fields": [
342
- {
343
- "inputKey": "action",
344
- "type": "select",
345
- "inputLabel": "Action",
346
- "options": [
347
- { "value": "proceed", "label": "Proceed — accept the red trial merge and continue" },
348
- { "value": "rebase", "label": "Rebase — re-run the trial merge" },
349
- { "value": "abandon", "label": "Abandon — stop and finalize the plan" }
350
- ]
351
- },
352
- {
353
- "inputKey": "notes",
354
- "type": "textarea",
355
- "inputLabel": "Notes"
356
- }
357
- ],
358
- "action": {
359
- "path": "/app/api/actions/complete-user-task",
360
- "successLabel": "Decision recorded",
361
- "body": {
362
- "userTaskKey": "{{row.user_task_key}}",
363
- "variables": "{{form}}"
364
- }
365
- }
366
- }
367
- },
368
- "refreshMs": 5000
369
- }
370
- },
371
- {
372
- "type": "dataGrid",
373
- "id": "pr-reviews",
374
- "props": {
375
- "title": "PR escalations",
376
- "data": {
377
- "kind": "datasource",
378
- "source": "app",
379
- "table": "user_tasks",
380
- "filter": [
381
- {
382
- "field": "element_id",
383
- "in": [
384
- "wait-answer",
385
- "wait-merge-answer"
386
- ]
387
- }
388
- ],
389
- "orderBy": {
390
- "field": "updated_at",
391
- "dir": "desc"
392
- }
393
- },
394
- "columns": [
395
- {
396
- "field": "subject_title",
397
- "template": "{{subject_title}}",
398
- "header": "Item",
399
- "subtitleField": "subject_key",
400
- "truncate": true,
401
- "linkField": "subject_url"
402
- },
403
- {
404
- "field": "kind_label",
405
- "header": "Stage"
406
- },
407
- {
408
- "field": "subject_url",
409
- "header": "PR link"
410
- },
411
- {
412
- "field": "process_key",
413
- "header": "Process",
414
- "link": {
415
- "kind": "processExplorer",
416
- "keyField": "process_key"
417
- }
418
- },
419
- {
420
- "field": "updated_at",
421
- "header": "Updated",
422
- "format": "datetime"
423
- }
424
- ],
425
- "rowKey": "user_task_key",
426
- "detail": {
427
- "linkField": "subject_url",
428
- "fields": [
429
- {
430
- "field": "question",
431
- "label": "Escalation question"
432
- }
433
- ],
434
- "form": {
435
- "showWhenField": "user_task_key",
436
- "title": "Answer escalation",
437
- "promptField": "question",
438
- "inputKey": "answer",
439
- "inputLabel": "Your answer",
440
- "submitLabel": "Answer & resume",
441
- "action": {
442
- "path": "/app/api/actions/complete-user-task",
443
- "successLabel": "Answered — the loop will resume",
444
- "body": {
445
- "userTaskKey": "{{row.user_task_key}}",
446
- "variables": {
447
- "answer": "{{form.answer}}"
448
- }
449
- }
450
- }
451
- }
452
- },
453
- "refreshMs": 5000
454
- }
455
- },
456
- {
457
- "type": "dataGrid",
458
- "id": "blocked-runs",
459
- "props": {
460
- "title": "Blocked feature runs",
461
- "data": {
462
- "kind": "datasource",
463
- "source": "app",
464
- "table": "user_tasks",
465
- "filter": [
466
- {
467
- "field": "element_id",
468
- "in": [
469
- "feature-blocked"
470
- ]
471
- }
472
- ],
473
- "orderBy": {
474
- "field": "updated_at",
475
- "dir": "desc"
476
- }
477
- },
478
- "columns": [
479
- {
480
- "field": "subject_title",
481
- "template": "{{subject_title}}",
482
- "header": "Item",
483
- "subtitleField": "subject_key",
484
- "truncate": true,
485
- "linkField": "subject_url"
486
- },
487
- {
488
- "field": "question",
489
- "header": "Disposition"
490
- },
491
- {
492
- "field": "subject_url",
493
- "header": "Issue"
494
- },
495
- {
496
- "field": "process_key",
497
- "header": "Process",
498
- "link": {
499
- "kind": "processExplorer",
500
- "keyField": "process_key"
501
- }
502
- },
503
- {
504
- "field": "updated_at",
505
- "header": "Updated",
506
- "format": "datetime"
507
- }
508
- ],
509
- "rowKey": "user_task_key",
510
- "detail": {
511
- "linkField": "subject_url",
512
- "fields": [
513
- {
514
- "field": "question",
515
- "label": "Disposition"
516
- }
517
- ],
518
- "form": {
519
- "showWhenField": "user_task_key",
520
- "title": "Acknowledge blocked run",
521
- "promptField": "question",
522
- "inputKey": "note",
523
- "inputLabel": "Disposition note (what you did / why)",
524
- "submitLabel": "Acknowledge & close",
525
- "action": {
526
- "path": "/app/api/actions/complete-user-task",
527
- "successLabel": "Acknowledged — the run will close",
528
- "body": {
529
- "userTaskKey": "{{row.user_task_key}}",
530
- "variables": {
531
- "note": "{{form.note}}"
532
- }
533
- }
534
- }
535
- }
536
- },
537
- "refreshMs": 5000
538
- }
539
- },
540
- {
541
- "type": "dataGrid",
542
- "id": "conformance-reviews",
543
- "props": {
544
- "title": "Conformance reviews",
545
- "data": {
546
- "kind": "datasource",
547
- "source": "app",
548
- "table": "user_tasks",
549
- "filter": [
550
- {
551
- "field": "element_id",
552
- "in": [
553
- "conformance-escalation"
554
- ]
555
- }
556
- ],
557
- "orderBy": {
558
- "field": "updated_at",
559
- "dir": "desc"
560
- }
561
- },
562
- "columns": [
563
- {
564
- "field": "subject_title",
565
- "template": "{{subject_title}}",
566
- "header": "Epic",
567
- "subtitleField": "subject_key",
568
- "truncate": true,
569
- "linkField": "subject_url"
570
- },
571
- {
572
- "field": "question",
573
- "header": "Findings"
574
- },
575
- {
576
- "field": "subject_url",
577
- "header": "Issue"
578
- },
579
- {
580
- "field": "process_key",
581
- "header": "Process",
582
- "link": {
583
- "kind": "processExplorer",
584
- "keyField": "process_key"
585
- }
586
- },
587
- {
588
- "field": "updated_at",
589
- "header": "Updated",
590
- "format": "datetime"
591
- }
592
- ],
593
- "rowKey": "user_task_key",
594
- "detail": {
595
- "linkField": "subject_url",
596
- "fields": [
597
- {
598
- "field": "question",
599
- "label": "Findings"
600
- }
601
- ],
602
- "form": {
603
- "showWhenField": "user_task_key",
604
- "title": "Acknowledge conformance review",
605
- "promptField": "question",
606
- "inputKey": "note",
607
- "inputLabel": "Disposition note (what you decided / follow-up)",
608
- "submitLabel": "Acknowledge & close",
609
- "action": {
610
- "path": "/app/api/actions/complete-user-task",
611
- "successLabel": "Acknowledged — the review will close",
612
- "body": {
613
- "userTaskKey": "{{row.user_task_key}}",
614
- "variables": {
615
- "note": "{{form.note}}"
616
- }
617
- }
618
- }
86
+ "engineForm": {
87
+ "formKeyField": "form_key",
88
+ "userTaskKeyField": "user_task_key"
619
89
  }
620
90
  },
621
91
  "refreshMs": 5000
622
92
  }
623
93
  }
624
94
  ]
625
- }
95
+ }