@nanobpm/nano-workforce 0.142.0 → 0.144.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.
@@ -118,7 +118,7 @@
118
118
  "data": {
119
119
  "kind": "datasource",
120
120
  "source": "app",
121
- "table": "delivery_graph_runs",
121
+ "table": "delivery_graph_read_model",
122
122
  "orderBy": { "field": "updated_at", "dir": "desc" },
123
123
  "filter": [{ "field": "status", "in": ["awaiting-approval", "running"] }]
124
124
  },
@@ -128,15 +128,32 @@
128
128
  { "label": "All", "filter": [] }
129
129
  ],
130
130
  "columns": [
131
- { "field": "title", "template": "{{title}}", "header": "Graph", "subtitleField": "run_key", "truncate": true, "width": "20%", "link": { "kind": "page", "page": "delivery-graph-detail", "keyField": "run_key" } },
132
- { "field": "status", "header": "Status", "truncate": true, "width": "12%", "link": { "kind": "processExplorer", "keyField": "process_key" } },
133
- { "field": "process_key", "header": "Instance", "width": "9%", "truncate": true, "link": { "kind": "processExplorer", "keyField": "process_key" } },
134
- { "field": "phase", "header": "Phase", "truncate": true, "width": "15%" },
131
+ { "field": "title", "template": "{{title}}", "header": "Graph", "subtitleField": "run_key", "truncate": true, "width": "18%", "link": { "kind": "page", "page": "delivery-graph-detail", "keyField": "run_key" } },
132
+ { "field": "status", "header": "Status", "truncate": true, "width": "10%", "link": { "kind": "processExplorer", "keyField": "process_key" } },
133
+ { "field": "process_key", "header": "Instance", "width": "8%", "truncate": true, "link": { "kind": "processExplorer", "keyField": "process_key" } },
134
+ {
135
+ "field": "stage",
136
+ "header": "Pipeline",
137
+ "kind": "pipeline",
138
+ "width": "18%",
139
+ "stages": [
140
+ { "key": "Requested", "label": "Requested" },
141
+ { "key": "Implementing", "label": "Implementing" },
142
+ { "key": "PR open", "label": "PR open" },
143
+ { "key": "Converging", "label": "Converging" },
144
+ { "key": "Merging", "label": "Merging" },
145
+ { "key": "Done", "label": "Done" }
146
+ ],
147
+ "activeField": "stage",
148
+ "stateField": "stage_state",
149
+ "locus": { "field": "process_key", "link": { "kind": "processExplorer", "keyField": "process_key" } }
150
+ },
151
+ { "field": "park_label", "header": "Parked", "truncate": true, "width": "12%" },
135
152
  { "field": "node_count", "header": "Nodes", "width": "5%" },
136
153
  { "field": "human_node_count", "header": "Human", "width": "5%" },
137
- { "field": "side_effect_count", "header": "Effects", "width": "7%" },
138
- { "field": "created_at", "header": "Dispatched", "width": "11%", "truncate": true, "format": "datetime" },
139
- { "field": "updated_at", "header": "Updated", "width": "11%", "truncate": true, "format": "datetime" }
154
+ { "field": "side_effect_count", "header": "Effects", "width": "6%" },
155
+ { "field": "created_at", "header": "Dispatched", "width": "7%", "truncate": true, "format": "datetime" },
156
+ { "field": "updated_at", "header": "Updated", "width": "6%", "truncate": true, "format": "datetime" }
140
157
  ],
141
158
  "detail": {
142
159
  "fields": [
@@ -207,14 +207,30 @@
207
207
  "data": {
208
208
  "kind": "datasource",
209
209
  "source": "app",
210
- "table": "delivery_graph_runs",
210
+ "table": "delivery_graph_read_model",
211
211
  "orderBy": { "field": "updated_at", "dir": "desc" },
212
212
  "filter": [{ "field": "status", "in": ["awaiting-approval", "running"] }]
213
213
  },
214
214
  "columns": [
215
215
  { "field": "title", "template": "{{title}}", "header": "Item", "subtitleField": "run_key", "truncate": true, "width": "30%", "link": { "kind": "page", "page": "delivery-graph-detail", "keyField": "run_key" } },
216
216
  { "field": "status", "header": "Status", "link": { "kind": "processExplorer", "keyField": "process_key" } },
217
- { "field": "phase", "header": "Phase", "truncate": true, "width": "28%" },
217
+ {
218
+ "field": "stage",
219
+ "header": "Pipeline",
220
+ "kind": "pipeline",
221
+ "stages": [
222
+ { "key": "Requested", "label": "Requested" },
223
+ { "key": "Implementing", "label": "Implementing" },
224
+ { "key": "PR open", "label": "PR open" },
225
+ { "key": "Converging", "label": "Converging" },
226
+ { "key": "Merging", "label": "Merging" },
227
+ { "key": "Done", "label": "Done" }
228
+ ],
229
+ "activeField": "stage",
230
+ "stateField": "stage_state",
231
+ "locus": { "field": "process_key", "link": { "kind": "processExplorer", "keyField": "process_key" } }
232
+ },
233
+ { "field": "park_label", "header": "Parked", "truncate": true, "width": "28%" },
218
234
  { "field": "updated_at", "header": "Updated", "width": "9rem", "format": "datetime" }
219
235
  ],
220
236
  "detail": {
@@ -333,8 +333,10 @@ test("issue #205: overview is the landing page and first nav item", async () =>
333
333
  plan_read_model: { field: "list_bucket", in: ["active"] },
334
334
  feature_runs: { field: "status", in: ["running", "escalated", "awaiting_operator"] },
335
335
  // The 4th dispatch surface (issue #386) — active delivery graphs. Both in-flight statuses
336
- // (`awaiting-approval` parked at the gate, `running` dispatched) show here.
337
- delivery_graph_runs: { field: "status", in: ["awaiting-approval", "running"] },
336
+ // (`awaiting-approval` parked at the gate, `running` dispatched) show here. Binds the derived
337
+ // `delivery_graph_read_model` VIEW (S7 / #541 — the single source of truth for the pipeline
338
+ // projection it also renders), which re-exports every run column plus the effective `status`.
339
+ delivery_graph_read_model: { field: "status", in: ["awaiting-approval", "running"] },
338
340
  };
339
341
  const grids = (overview.nodes ?? []).filter((n: Json) => n.type === "dataGrid");
340
342
  for (const [table, { field, in: values }] of Object.entries(expected)) {
@@ -361,19 +363,21 @@ test("issue #386: the human-facing Delivery Graphs surface is wired (nav tab, pa
361
363
  assert(tab, "pages/_nav.json must carry a `Delivery Graphs` nav tab → the delivery-graphs page");
362
364
 
363
365
  // 2) The page carries the compose → preview → dispatch App View (issue #441 — the rendered preview
364
- // that consumes the compile output), plus an in-flight grid over the delivery_graph_runs aggregate
365
- // that links to the per-graph detail page. The rich preview (mermaid diagram + humanNodes[] +
366
- // sideEffects[] + inline errors) can't render in a bare `actionForm` (its response is discarded),
367
- // so the surface is an `appView` embed over the SAME compile/dispatch doors.
366
+ // that consumes the compile output), plus an in-flight grid over the delivery-graph run data (the
367
+ // derived `delivery_graph_read_model` VIEW, S7 / #541 — which re-exports every `delivery_graph_runs`
368
+ // column plus the pipeline projection) that links to the per-graph detail page. The rich preview
369
+ // (mermaid diagram + humanNodes[] + sideEffects[] + inline errors) can't render in a bare
370
+ // `actionForm` (its response is discarded), so the surface is an `appView` embed over the SAME
371
+ // compile/dispatch doors.
368
372
  const page = JSON.parse(readFileSync(`${ROOT}pages/delivery-graphs.page.json`, "utf8"));
369
373
  const compose = (page.nodes ?? []).find(
370
374
  (n: Json) => n.type === "appView" && typeof n.props?.embed === "string" && n.props.embed.includes("delivery-graphs/embed.html"),
371
375
  );
372
376
  assert(compose, "delivery-graphs page must have an appView embedding ./delivery-graphs/embed.html (the compose → preview → dispatch view, #441)");
373
377
  const grid = (page.nodes ?? []).find(
374
- (n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_runs",
378
+ (n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_read_model",
375
379
  );
376
- assert(grid, "delivery-graphs page must have an in-flight grid over delivery_graph_runs");
380
+ assert(grid, "delivery-graphs page must have an in-flight grid over the derived delivery_graph_read_model VIEW");
377
381
  const linkCol = (grid.props?.columns ?? []).find((c: Json) => c.link?.page === "delivery-graph-detail");
378
382
  assert(
379
383
  linkCol && linkCol.link?.keyField === "run_key",
@@ -383,9 +387,9 @@ test("issue #386: the human-facing Delivery Graphs surface is wired (nav tab, pa
383
387
  // 3) The per-graph detail page reads the run aggregate scoped to the route param (run_key).
384
388
  const detail = JSON.parse(readFileSync(`${ROOT}pages/delivery-graph-detail.page.json`, "utf8"));
385
389
  const runGrid = (detail.nodes ?? []).find(
386
- (n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_runs",
390
+ (n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_read_model",
387
391
  );
388
- assert(runGrid, "delivery-graph-detail must bind a grid to delivery_graph_runs");
392
+ assert(runGrid, "delivery-graph-detail must bind a grid to the derived delivery_graph_read_model VIEW");
389
393
  assert(
390
394
  (runGrid.props?.data?.filter ?? []).some((fl: Json) => fl.field === "run_key" && fl.eqParam === true),
391
395
  "delivery-graph-detail must scope its run grid to the route param (run_key eqParam)",
@@ -399,7 +403,7 @@ test("issue #386: the human-facing Delivery Graphs surface is wired (nav tab, pa
399
403
  "overview subtitle must no longer say 'three dispatch surfaces' (a delivery graph is a 4th)",
400
404
  );
401
405
  const ovGrid = (overview.nodes ?? []).find(
402
- (n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_runs",
406
+ (n: Json) => n.type === "dataGrid" && n.props?.data?.table === "delivery_graph_read_model",
403
407
  );
404
408
  const ovLink = (ovGrid?.props?.columns ?? []).find((c: Json) => c.link?.page === "delivery-graph-detail");
405
409
  assert(