@nanobpm/nano-workforce 0.158.0 → 0.159.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.
package/openapi.yaml CHANGED
@@ -1295,6 +1295,30 @@ components:
1295
1295
  no compiler, dispatch, or execution (those land in later slices).
1296
1296
  type: object
1297
1297
  additionalProperties: false
1298
+ # Canonical worked example — the §9.5 `wait[epic]`-gated graph from the operator guide
1299
+ # (docs/agent-guide.md). `compileDeliveryGraph` takes THIS structured object directly. The
1300
+ # generator (scripts/inline-mcp-bodies.ts) carries this example into the projected MCP tool
1301
+ # schema so an agent can call the tool from the surface alone.
1302
+ example:
1303
+ name: start #567 once epic #488 has fully merged
1304
+ nodes:
1305
+ - id: gate-epic
1306
+ kind: wait
1307
+ wait:
1308
+ kind: epic
1309
+ target: nanobpm/nano-ide#488
1310
+ match: { epicState: merged }
1311
+ poll: { everyMs: 300000, timeoutMs: 259200000 }
1312
+ onTimeout: escalate
1313
+ emits:
1314
+ - { name: prCount, type: number }
1315
+ - id: start-b
1316
+ kind: agent
1317
+ agent:
1318
+ jobType: senior:feature
1319
+ prompt: Implement nanobpm/nano-workforce#567 and open a PR.
1320
+ edges:
1321
+ - { from: gate-epic, to: start-b }
1298
1322
  required:
1299
1323
  - nodes
1300
1324
  properties:
@@ -1643,6 +1667,12 @@ components:
1643
1667
  evolvable.
1644
1668
  type: object
1645
1669
  additionalProperties: false
1670
+ # Worked example — the SAME canonical §9.5 `wait[epic]`-gated graph as `DeliveryGraph.example`,
1671
+ # but serialised to a JSON STRING (the text-door convention this operation shares with the
1672
+ # cockpit paste). `previewDeliveryGraph` takes `{ "graphJson": "<serialized DeliveryGraph>" }`.
1673
+ example:
1674
+ graphJson: >-
1675
+ {"name":"start #567 once epic #488 has fully merged","nodes":[{"id":"gate-epic","kind":"wait","wait":{"kind":"epic","target":"nanobpm/nano-ide#488","match":{"epicState":"merged"},"poll":{"everyMs":300000,"timeoutMs":259200000},"onTimeout":"escalate"},"emits":[{"name":"prCount","type":"number"}]},{"id":"start-b","kind":"agent","agent":{"jobType":"senior:feature","prompt":"Implement nanobpm/nano-workforce#567 and open a PR."}}],"edges":[{"from":"gate-epic","to":"start-b"}]}
1646
1676
  required:
1647
1677
  - graphJson
1648
1678
  properties:
@@ -2669,6 +2699,26 @@ components:
2669
2699
  abandoned:
2670
2700
  type: boolean
2671
2701
  description: Derived from pull_requests.status; true ⇒ the run was cancelled and the agent must stop.
2702
+ # ─────────────────────────────────────────────────────────────────────────────────────────────
2703
+ # MCP tool-schema convention (epic nano-workforce#605, S0 — the shared invariant every later slice
2704
+ # inherits). The Urban runtime projects THIS document into MCP tools (ADR 0067 — zero MCP server
2705
+ # code in nwf). The projector copies each operation's request-body schema VERBATIM into the tool's
2706
+ # `inputSchema.properties.body`; it does NOT resolve `$ref`s. So EVERY projected (non-`x-mcp`)
2707
+ # request-body operation MUST present a self-contained tool schema:
2708
+ # • `type: object` with inline `properties` (never a bare `$ref` — it is unresolvable in an MCP
2709
+ # client, and the object gets stringified and rejected at the door: nano-ide#501/#502/#503);
2710
+ # • NO `$ref` anywhere in the projected body schema;
2711
+ # • the graph doors (`compileDeliveryGraph`/`previewDeliveryGraph`) carry a worked `example` — the
2712
+ # only example the invariant enforces (`test/mcp-tool-schemas.test.ts`); other doors MAY add one;
2713
+ # • a `description` that carries the contract (input shape, side effects, idempotency, next call).
2714
+ # You do NOT hand-write the inline body. Author the shape ONCE as a `components.schemas` entry and
2715
+ # reference it here as usual (`schema: { $ref: … }` OR keep the generated block); the generator
2716
+ # scripts/inline-mcp-bodies.ts DERIVES the `$ref`-free inline body from that component (single source
2717
+ # of truth) into a `# BEGIN/END generated:mcp-body` region. Run `npm run gen:mcp-bodies` after
2718
+ # changing a source component; `npm run check:mcp-bodies` (CI) + test/mcp-tool-schemas.test.ts (the
2719
+ # real projector) fail the build on any drift or re-leaked `$ref`. Operator-only doors opt OUT with
2720
+ # `x-mcp: { exclude: true }` (stage/dispatch/dismiss) and are not projected.
2721
+ # ─────────────────────────────────────────────────────────────────────────────────────────────
2672
2722
  paths:
2673
2723
  /status:
2674
2724
  get:
@@ -2774,7 +2824,38 @@ paths:
2774
2824
  content:
2775
2825
  application/json:
2776
2826
  schema:
2777
- $ref: "#/components/schemas/EnrolRequest"
2827
+ # BEGIN generated:mcp-body source=#/components/schemas/EnrolRequest (scripts/inline-mcp-bodies.ts — do not hand-edit)
2828
+ type: object
2829
+ description: A worker's enrol request — its declared capability (ADR 0059 revised, per-worker).
2830
+ required:
2831
+ - capability
2832
+ properties:
2833
+ capability:
2834
+ type: object
2835
+ description: A worker's declared enrolment capability. NEVER a routing token — it gates enrolment.
2836
+ properties:
2837
+ cognition:
2838
+ type: string
2839
+ description: The worker's cognition class (e.g. planning / implementation / qa / ci / decide).
2840
+ weight:
2841
+ type: number
2842
+ description: The cognition weight (the one numeric capability field).
2843
+ family:
2844
+ type: string
2845
+ description: The model family (the diversity-SLO seat filler, e.g. frontier / kimi / qwen).
2846
+ host:
2847
+ type: string
2848
+ description: Where the worker runs.
2849
+ host:
2850
+ type: string
2851
+ description: Where the worker runs. Folded into `capability.host` when the latter is absent.
2852
+ instance:
2853
+ type: string
2854
+ description: The worker instance id, echoed back for provenance (optional).
2855
+ durableResume:
2856
+ type: boolean
2857
+ description: "Whether this worker's harness advertises durable-resume (issue #325, ADR 0062 Slice 5/5) — an ENROLMENT attribute, never a routing token. Recorded per instance so the app emits the world-restore marker only to a fleet with a participant; a harness that omits it (or sets false) redrives a re-leased round from scratch. Recorded only when `instance` is a non-blank string — a missing, empty, or whitespace-only `instance` is echoed back for provenance but the flag is not persisted."
2858
+ # END generated:mcp-body
2778
2859
  responses:
2779
2860
  "200":
2780
2861
  description: The resolved SERVE set for the declared capability.
@@ -3008,7 +3089,49 @@ paths:
3008
3089
  content:
3009
3090
  application/json:
3010
3091
  schema:
3011
- $ref: "#/components/schemas/ConvergenceStart"
3092
+ # BEGIN generated:mcp-body source=#/components/schemas/ConvergenceStart (scripts/inline-mcp-bodies.ts — do not hand-edit)
3093
+ description: The start-convergence request body. Names the target PR by EXACTLY ONE of `pr` (an `owner/repo#123` reference) or `url` (a bare PR URL) — never both, never neither — with the optional convergence knobs. Modeled as `oneOf` named variants (ADR — Camunda REST v2 pattern) so the runtime rejects an ambiguous or empty target at the edge with a 400 that names the allowed shapes, rather than the delegate silently coalescing `pr ?? url`.
3094
+ oneOf:
3095
+ - type: object
3096
+ additionalProperties: false
3097
+ required:
3098
+ - pr
3099
+ properties:
3100
+ pr:
3101
+ type: string
3102
+ description: 'PR reference: owner/repo#123.'
3103
+ dependsOn:
3104
+ type: array
3105
+ items:
3106
+ type: string
3107
+ maxRounds:
3108
+ type: integer
3109
+ minimum: 1
3110
+ description: Values above 100 are accepted and clamped to 100 by the delegate.
3111
+ convergeOnly:
3112
+ type: boolean
3113
+ description: When true, run convergence only and stop at `converged` — the PR is never handed to the merge-loop even if auto-merge is on globally (`NANO_PR_AUTO_MERGE`). A per-request review-only override; defaults to false (the global auto-merge default applies).
3114
+ - type: object
3115
+ additionalProperties: false
3116
+ required:
3117
+ - url
3118
+ properties:
3119
+ url:
3120
+ type: string
3121
+ description: A bare PR URL, when no `owner/repo#123` reference is supplied.
3122
+ dependsOn:
3123
+ type: array
3124
+ items:
3125
+ type: string
3126
+ maxRounds:
3127
+ type: integer
3128
+ minimum: 1
3129
+ description: Values above 100 are accepted and clamped to 100 by the delegate.
3130
+ convergeOnly:
3131
+ type: boolean
3132
+ description: When true, run convergence only and stop at `converged` — the PR is never handed to the merge-loop even if auto-merge is on globally (`NANO_PR_AUTO_MERGE`). A per-request review-only override; defaults to false (the global auto-merge default applies).
3133
+ type: object
3134
+ # END generated:mcp-body
3012
3135
  responses:
3013
3136
  "202":
3014
3137
  description: The loop was started (or refreshed).
@@ -3031,7 +3154,53 @@ paths:
3031
3154
  content:
3032
3155
  application/json:
3033
3156
  schema:
3034
- $ref: "#/components/schemas/PlanStart"
3157
+ # BEGIN generated:mcp-body source=#/components/schemas/PlanStart (scripts/inline-mcp-bodies.ts — do not hand-edit)
3158
+ description: The start-plan-fanout request body. Names the target issue by EXACTLY ONE of `issue` (an `owner/repo#123` reference) or `url` (a bare issue URL), plus a REQUIRED `baseBranch` (ADR 0003) the fleet branches off — a blank/absent base is a 400. Modeled as `oneOf` named variants (Camunda REST v2 pattern) so an ambiguous or empty target is a 400 at the edge, not a silent `issue ?? url` coalesce in the delegate.
3159
+ oneOf:
3160
+ - type: object
3161
+ additionalProperties: false
3162
+ required:
3163
+ - issue
3164
+ - baseBranch
3165
+ properties:
3166
+ issue:
3167
+ type: string
3168
+ description: 'Issue reference: owner/repo#123.'
3169
+ baseBranch:
3170
+ type: string
3171
+ minLength: 1
3172
+ maxLength: 255
3173
+ pattern: \S
3174
+ description: 'REQUIRED target branch the fleet branches off and opens every PR against. Every epic launch must name its base explicitly (ADR 0003): a blank/absent value is rejected with a 400, not silently coalesced to the repository default branch. Use it to land an entire epic on a long-lived integration branch (e.g. `epic/agent-protocol`) so nothing reaches the default branch — and any merge-to-default side effect, such as auto-publishing a package — until you deliberately merge the integration branch. NOTE: this slice (B0) only enforces that `baseBranch` is present and a plausible branch name; branch-existence admission (auto-creating a missing `epic/*` base off the default branch HEAD, and rejecting a missing non-`epic/*` base with a 400) is specified by ADR 0003 but NOT yet enforced here — it lands in a later admission slice.'
3175
+ allowSharedBase:
3176
+ type: boolean
3177
+ description: 'Reserved for a later ADR 0003 admission slice — NOT yet enforced in this slice (B0). When implemented it will opt in to sharing a custom integration base branch with another already-active plan: admission will otherwise reject (409) when another active plan already targets the same repo + same custom base branch, to stop two epics interleaving commits on one integration branch (the repository default branch is exempt from that guard). Accepted by the schema today but currently has no runtime effect.'
3178
+ confirmDefaultBase:
3179
+ type: boolean
3180
+ description: 'Reserved for a later ADR 0003 admission slice — NOT yet enforced in this slice (B0). When implemented it will be the required acknowledgement when `baseBranch` names the repository default branch: targeting the default lands every task directly on it with no integration buffer — and fires any merge-to-default side effect per task — so admission will reject (400) unless confirmed with true (no effect for a non-default base). Accepted by the schema today but currently has no runtime effect.'
3181
+ - type: object
3182
+ additionalProperties: false
3183
+ required:
3184
+ - url
3185
+ - baseBranch
3186
+ properties:
3187
+ url:
3188
+ type: string
3189
+ description: A bare issue URL, when no `owner/repo#123` reference is supplied.
3190
+ baseBranch:
3191
+ type: string
3192
+ minLength: 1
3193
+ maxLength: 255
3194
+ pattern: \S
3195
+ description: REQUIRED target branch the fleet branches off and opens every PR against. See `PlanStartByIssue.baseBranch`.
3196
+ allowSharedBase:
3197
+ type: boolean
3198
+ description: Reserved for a later ADR 0003 admission slice — NOT yet enforced in this slice (B0). Accepted by the schema today but currently has no runtime effect. When implemented it will opt in to sharing a custom integration base branch with another already-active plan. See `PlanStartByIssue.allowSharedBase`.
3199
+ confirmDefaultBase:
3200
+ type: boolean
3201
+ description: Reserved for a later ADR 0003 admission slice — NOT yet enforced in this slice (B0). Accepted by the schema today but currently has no runtime effect. When implemented it will be the required acknowledgement when `baseBranch` names the repository default branch. See `PlanStartByIssue.confirmDefaultBase`.
3202
+ type: object
3203
+ # END generated:mcp-body
3035
3204
  responses:
3036
3205
  "202":
3037
3206
  description: The plan fan-out was started (or was already running).
@@ -3064,7 +3233,90 @@ paths:
3064
3233
  content:
3065
3234
  application/json:
3066
3235
  schema:
3067
- $ref: "#/components/schemas/EpicSetStart"
3236
+ # BEGIN generated:mcp-body source=#/components/schemas/EpicSetStart (scripts/inline-mcp-bodies.ts — do not hand-edit)
3237
+ description: "The set/batch admission request body (issue #292, slice S2). Submits a SET of epics plus the inter-epic dependency edges between them. `epics` is admitted all-or-nothing through the same `admitPlan` gate as the single-issue door; `deps` declares that a `consumer` epic waits for a `producer` epic's published `{ package, capabilityRef }` capability. Every edge must connect two epics named in `epics`, and the edge set must be an acyclic DAG — otherwise the whole set is rejected with a 4xx and nothing is persisted."
3238
+ type: object
3239
+ additionalProperties: false
3240
+ required:
3241
+ - epics
3242
+ properties:
3243
+ epics:
3244
+ type: array
3245
+ minItems: 1
3246
+ description: The epics to admit as one set. Each is admitted through the `admitPlan` gate.
3247
+ items:
3248
+ description: One epic in a submitted set. Names the target issue by EXACTLY ONE of `issue` (`owner/repo#123`) or `url` (a bare issue URL), plus a REQUIRED `baseBranch` and the optional admission acknowledgements — the same per-epic admission inputs as `PlanStart`.
3249
+ oneOf:
3250
+ - type: object
3251
+ additionalProperties: false
3252
+ required:
3253
+ - issue
3254
+ - baseBranch
3255
+ properties:
3256
+ issue:
3257
+ type: string
3258
+ description: 'Issue reference: owner/repo#123.'
3259
+ baseBranch:
3260
+ type: string
3261
+ minLength: 1
3262
+ maxLength: 255
3263
+ pattern: \S
3264
+ description: REQUIRED integration branch this epic branches off and opens its PRs against, admitted through the same ADR 0003 policy as the single-issue door. See `PlanStartByIssue.baseBranch`.
3265
+ allowSharedBase:
3266
+ type: boolean
3267
+ description: Opt in to sharing a custom integration base with another active epic. See `PlanStartByIssue.allowSharedBase`.
3268
+ confirmDefaultBase:
3269
+ type: boolean
3270
+ description: Acknowledge that `baseBranch` names the repository default branch. See `PlanStartByIssue.confirmDefaultBase`.
3271
+ - type: object
3272
+ additionalProperties: false
3273
+ required:
3274
+ - url
3275
+ - baseBranch
3276
+ properties:
3277
+ url:
3278
+ type: string
3279
+ description: A bare issue URL, when no `owner/repo#123` reference is supplied.
3280
+ baseBranch:
3281
+ type: string
3282
+ minLength: 1
3283
+ maxLength: 255
3284
+ pattern: \S
3285
+ description: REQUIRED integration branch this epic branches off. See `EpicSetMemberByIssue.baseBranch`.
3286
+ allowSharedBase:
3287
+ type: boolean
3288
+ description: Share a custom integration base with another active epic. See `PlanStartByIssue.allowSharedBase`.
3289
+ confirmDefaultBase:
3290
+ type: boolean
3291
+ description: Acknowledge landing on the default branch. See `PlanStartByIssue.confirmDefaultBase`.
3292
+ deps:
3293
+ type: array
3294
+ description: The inter-epic dependency edges. Each declares `consumer` waits for `producer` to publish the `{ package, capabilityRef }` capability. Both endpoints must name epics in `epics`. Omit or pass `[]` for a set of independent (root) epics.
3295
+ items:
3296
+ description: "One inter-epic dependency edge: the `consumer` epic waits for the `producer` epic to publish the `{ package, capabilityRef }` capability. `consumer`/`producer` are epic references (`owner/repo#123` or an issue URL) that MUST both appear in the set's `epics`."
3297
+ type: object
3298
+ additionalProperties: false
3299
+ required:
3300
+ - consumer
3301
+ - producer
3302
+ - package
3303
+ - capabilityRef
3304
+ properties:
3305
+ consumer:
3306
+ type: string
3307
+ description: The dependent epic (waits). An `owner/repo#123` reference or issue URL in the set.
3308
+ producer:
3309
+ type: string
3310
+ description: The producer epic it waits for. An `owner/repo#123` reference or issue URL in the set.
3311
+ package:
3312
+ type: string
3313
+ minLength: 1
3314
+ description: The producer epic's published package name — the capability probe's target (S3).
3315
+ capabilityRef:
3316
+ type: string
3317
+ minLength: 1
3318
+ description: The producer epic's issue handle, used to resolve which published pkg@version first carries the capability (S3).
3319
+ # END generated:mcp-body
3068
3320
  responses:
3069
3321
  "202":
3070
3322
  description: The whole set validated; every epic was admitted and every edge staged FK-free (in `admitted_plan_deps`) for S3 to materialize.
@@ -3102,12 +3354,442 @@ paths:
3102
3354
  receives a dispatch handle, there is nothing to replay (closing the self-approval hole the old
3103
3355
  replayable `approvalToken` left open). A malformed graph is a 400 carrying path-qualified errors;
3104
3356
  nothing is staged.
3357
+
3358
+
3359
+ INPUT — the structured `DeliveryGraph` OBJECT directly (`{ nodes[], edges[] }`), NOT a string:
3360
+ this is the object-body door. Its sibling `previewDeliveryGraph` instead takes the
3361
+ text-door shape `{ "graphJson": "<serialized DeliveryGraph>" }` (the same paste the cockpit
3362
+ uses). SIDE EFFECTS — impure: a valid graph is STAGED (persisted as a `staged` proposal),
3363
+ unlike the pure `previewDeliveryGraph` which never persists. IDEMPOTENCY — content-addressed
3364
+ by `digest`: re-compiling an identical graph re-stages the same digest, not a duplicate.
3365
+ VALIDATION — a failure returns `400` with `errors: [{ path, message }]`. NEXT — surface the
3366
+ returned `reviewUrl` to the operator (only a human's cockpit Dispatch runs it); poll
3367
+ `listStagedProposals` to see the staged digest.
3105
3368
  requestBody:
3106
3369
  required: true
3107
3370
  content:
3108
3371
  application/json:
3109
3372
  schema:
3110
- $ref: "#/components/schemas/DeliveryGraph"
3373
+ # BEGIN generated:mcp-body source=#/components/schemas/DeliveryGraph (scripts/inline-mcp-bodies.ts — do not hand-edit)
3374
+ description: 'An agent-authored delivery graph (ADR 0005) — the SINGLE agent-facing artifact for a heterogeneous, partly-human, cross-repo delivery runbook. It is DATA, never an executable artifact: a JSON DAG whose nodes each name a `kind` from a CLOSED allowlist (`agent`/`wait`/`human`/`connector` — Decision 1/2, the trust boundary) and whose `edges` name DISCOVERED facts (Decision 3). Ingest validates the SHAPE here and the SEMANTICS (acyclicity, edge integrity, fact resolution) in the pure `validateDeliveryGraph` (`app/deliveryGraph.ts`). This slice (S0) defines the vocabulary + validation surface ONLY — no compiler, dispatch, or execution (those land in later slices).'
3375
+ type: object
3376
+ additionalProperties: false
3377
+ example:
3378
+ name: start
3379
+ nodes:
3380
+ - id: gate-epic
3381
+ kind: wait
3382
+ wait:
3383
+ kind: epic
3384
+ target: nanobpm/nano-ide#488
3385
+ match:
3386
+ epicState: merged
3387
+ poll:
3388
+ everyMs: 300000
3389
+ timeoutMs: 259200000
3390
+ onTimeout: escalate
3391
+ emits:
3392
+ - name: prCount
3393
+ type: number
3394
+ - id: start-b
3395
+ kind: agent
3396
+ agent:
3397
+ jobType: senior:feature
3398
+ prompt: Implement nanobpm/nano-workforce#567 and open a PR.
3399
+ edges:
3400
+ - from: gate-epic
3401
+ to: start-b
3402
+ required:
3403
+ - nodes
3404
+ properties:
3405
+ name:
3406
+ type: string
3407
+ maxLength: 255
3408
+ description: OPTIONAL human-readable label for the graph (shown in the rendered preview).
3409
+ nodes:
3410
+ type: array
3411
+ minItems: 1
3412
+ maxItems: 256
3413
+ items:
3414
+ description: One node in a delivery graph. A discriminated union on `kind` over the CLOSED allowlist; the matching per-kind config object (`agent`/`wait`/`connector`) is REQUIRED and names the engine-native body the node delegates to (Decision 2 — the graph schedules, it does not re-implement execution). The `human` config is the sole exception — it is OPTIONAL (a bare `human` node resolves to a generic emit-capturing form fallback in S3).
3415
+ oneOf:
3416
+ - type: object
3417
+ properties:
3418
+ id:
3419
+ type: string
3420
+ emits:
3421
+ type: array
3422
+ items:
3423
+ description: 'A typed output a node declares it will EMIT (ADR 0005 Decision 3/4 — emitted-fact typing). A downstream edge references it as `from: "<nodeId>.<fact>"`, so a bind is validated against this declaration, not stringly. A "click done" human node or a pass-through node declares no facts (`emits` absent/empty) — the degenerate no-emit case.'
3424
+ type: object
3425
+ additionalProperties: false
3426
+ required:
3427
+ - name
3428
+ - type
3429
+ properties:
3430
+ name:
3431
+ type: string
3432
+ minLength: 1
3433
+ maxLength: 128
3434
+ pattern: ^[A-Za-z_][A-Za-z0-9_]*$
3435
+ description: The fact's identifier, referenced downstream as `<nodeId>.<name>`. Must be unique within the node.
3436
+ type:
3437
+ type: string
3438
+ enum:
3439
+ - string
3440
+ - number
3441
+ - boolean
3442
+ - artifact
3443
+ - version
3444
+ - url
3445
+ - pr
3446
+ description: "The fact's declared type. `artifact` is a `pkg@version` handle, `version` a bare version string, `url` a location — mirrors the values `capability`/`pr` probes late-bind. `pr` (issue #548) is a PR reference (`owner/repo#N`) an `agent` node emits for the PR it opened, so a downstream `connector[converge*]`/`wait[pr]` node LATE-BINDS its target PR from the fact instead of a hardcoded literal."
3447
+ description:
3448
+ type: string
3449
+ maxLength: 512
3450
+ description: OPTIONAL human note describing what the fact carries.
3451
+ description: 'The typed facts this agent node hands forward (issue #506 — the classifier-emit contract). Each declared fact is appended to the node''s dispatch prompt as an instruction the servicing `senior:*` agent MUST honour: return the fact as an extra TOP-LEVEL field of its result JSON (the same `AGENT_RESULT_FILE` envelope that carries `status`/`summary`/`pr`). The delivery output-mapping publishes that completion variable (named exactly after the fact) so a downstream guarded edge (`when: "<node>.<fact>"` + `equals`) routes on it; an omitted fact takes the split''s `default` branch.'
3452
+ kind:
3453
+ type: string
3454
+ enum:
3455
+ - agent
3456
+ agent:
3457
+ type: object
3458
+ additionalProperties: false
3459
+ required:
3460
+ - jobType
3461
+ properties:
3462
+ jobType:
3463
+ type: string
3464
+ minLength: 1
3465
+ description: The agent job type a worker executes for this node (e.g. `senior:feature`).
3466
+ prompt:
3467
+ type: string
3468
+ maxLength: 20000
3469
+ description: OPTIONAL steering prompt appended to the node's job brief.
3470
+ converge:
3471
+ type: boolean
3472
+ description: 'OPTIONAL first-class CONVERGE policy (ADR 0006 §3 / S5) — a DECLARED, compiler- validated completion-policy flag on this cell node. It declares that the node''s opened PR is to be driven through the review-convergence loop to green as an edge-gated completion policy; this slice adds and validates the flag, with the delivery-graph execution wiring that consumes it landing in a follow-up slice. It supersedes (in intent) the emergent `feature.bpmn` `gw-converge` gateway and the "un-draft + merge #B" prompt prose a delivery-graph `agent` node used to smuggle. Converge and merge are SEPARABLE phases; a node may converge without merging (stop at green and gate the landing behind a downstream node).'
3473
+ merge:
3474
+ type: boolean
3475
+ description: "OPTIONAL first-class MERGE (land) policy (ADR 0006 §3 / S5) — a DECLARED, compiler-validated flag. When set it declares that the cell lands its PR. REQUIRES `converge: true` — you cannot land a PR you have not driven to green (the validator rejects `merge` without `converge`). This slice adds and validates the flag; the execution wiring that consumes it lands in a follow-up slice. TWO-LEVEL (ADR 0003 base-branch admission): a UNIT node lands onto its epic/graph base branch, never `main` directly; the graph's final merge-to-`main` is a separate top-level step."
3476
+ timeout:
3477
+ type: string
3478
+ pattern: ^[Pp](?!$)(\d+[Yy])?(\d+[Mm])?(\d+[Ww])?(\d+[Dd])?([Tt](?=\d)(\d+[Hh])?(\d+[Mm])?(\d+[Ss])?)?$
3479
+ maxLength: 64
3480
+ description: OPTIONAL per-node ISO-8601 SLA timeout (#505). Overrides the run-level `nodeTimeout` (and the `PT1H` default) for THIS node's bounded-timeout → escalate boundary timer, so a legitimately-long node (e.g. a full `senior:feature` implementation) can outlast a quick gate without a spurious escalation. Absent → the run/default value.
3481
+ required:
3482
+ - id
3483
+ - kind
3484
+ - agent
3485
+ description: An `agent` node — a worker executes an agent job type (the existing fan-out body). Bounded (timeout → escalate) and resumable like every node.
3486
+ additionalProperties: false
3487
+ - type: object
3488
+ properties:
3489
+ id:
3490
+ type: string
3491
+ emits:
3492
+ type: array
3493
+ items:
3494
+ description: 'A typed output a node declares it will EMIT (ADR 0005 Decision 3/4 — emitted-fact typing). A downstream edge references it as `from: "<nodeId>.<fact>"`, so a bind is validated against this declaration, not stringly. A "click done" human node or a pass-through node declares no facts (`emits` absent/empty) — the degenerate no-emit case.'
3495
+ type: object
3496
+ additionalProperties: false
3497
+ required:
3498
+ - name
3499
+ - type
3500
+ properties:
3501
+ name:
3502
+ type: string
3503
+ minLength: 1
3504
+ maxLength: 128
3505
+ pattern: ^[A-Za-z_][A-Za-z0-9_]*$
3506
+ description: The fact's identifier, referenced downstream as `<nodeId>.<name>`. Must be unique within the node.
3507
+ type:
3508
+ type: string
3509
+ enum:
3510
+ - string
3511
+ - number
3512
+ - boolean
3513
+ - artifact
3514
+ - version
3515
+ - url
3516
+ - pr
3517
+ description: "The fact's declared type. `artifact` is a `pkg@version` handle, `version` a bare version string, `url` a location — mirrors the values `capability`/`pr` probes late-bind. `pr` (issue #548) is a PR reference (`owner/repo#N`) an `agent` node emits for the PR it opened, so a downstream `connector[converge*]`/`wait[pr]` node LATE-BINDS its target PR from the fact instead of a hardcoded literal."
3518
+ description:
3519
+ type: string
3520
+ maxLength: 512
3521
+ description: OPTIONAL human note describing what the fact carries.
3522
+ kind:
3523
+ type: string
3524
+ enum:
3525
+ - wait
3526
+ wait:
3527
+ description: 'A single durable readiness probe (issue #258, #295) the feature run must satisfy before its implementation agent is dispatched. `kind` selects the source; `target` + `match` are the per-kind predicate. The `capability` kind resolves "which published `pkg@version` first carries capability C?" from publish provenance and late-binds it into the run. See `app/readiness.ts` for the full per-kind semantics.'
3528
+ type: object
3529
+ additionalProperties: false
3530
+ required:
3531
+ - kind
3532
+ - target
3533
+ properties:
3534
+ kind:
3535
+ type: string
3536
+ enum:
3537
+ - http
3538
+ - command
3539
+ - npm
3540
+ - github-check
3541
+ - capability
3542
+ - pr
3543
+ - epic
3544
+ description: The readiness source. `command` is the escape hatch; `capability` resolves a cross-repo published-artifact edge; `pr` watches an in-flight PR's merge state (ADR 0005 §2); `epic` gates on an nwf plan-fanout epic reaching "fully merged", keyed by its `planKey` (issue
3545
+ target:
3546
+ type: string
3547
+ minLength: 1
3548
+ description: The kind-specific target (a URL, a shell command, a `pkg@version`, an `owner/repo@ref`, `github-releases:owner/repo`, an `owner/repo#123` PR reference for the `pr` kind, or an `owner/repo#NN` planKey — the epic issue — for the `epic` kind). For a `pr`/`epic` target used in a **delivery-graph `wait` node** it may instead be a `<nodeId>.<fact>` late-binding reference the delivery-graph compiler resolves at dispatch (issue
3549
+ onTimeout:
3550
+ type: string
3551
+ enum:
3552
+ - escalate
3553
+ - fail
3554
+ - continue
3555
+ description: What the gate does when the bounded wait elapses (default `escalate`).
3556
+ credentialEnv:
3557
+ type: string
3558
+ description: A declared env-contract key supplying a credential (http kind only). Names a key, never a secret value.
3559
+ match:
3560
+ type: object
3561
+ additionalProperties: false
3562
+ description: The per-kind readiness predicate; every field is optional and read only by the kinds that understand it.
3563
+ properties:
3564
+ status:
3565
+ type: integer
3566
+ description: 'http: the exact status that means ready (default any 2xx).'
3567
+ bodyIncludes:
3568
+ type: string
3569
+ description: 'http: a substring the response body must contain.'
3570
+ exitCode:
3571
+ type: integer
3572
+ description: 'command: the exit code that means ready (default 0).'
3573
+ stdoutIncludes:
3574
+ type: string
3575
+ description: 'command/npm: a substring stdout must contain.'
3576
+ version:
3577
+ type: string
3578
+ description: 'npm: the version that must be published.'
3579
+ conclusion:
3580
+ type: string
3581
+ description: 'github-check: the conclusion that means ready (default success).'
3582
+ checkName:
3583
+ type: string
3584
+ description: 'github-check: restrict to the named check run.'
3585
+ capabilityRef:
3586
+ type: string
3587
+ description: 'capability: the upstream issue/PR handle the resolved version must carry.'
3588
+ package:
3589
+ type: string
3590
+ description: 'capability: the package whose releases are scanned for provenance.'
3591
+ verifyCommand:
3592
+ type: string
3593
+ description: 'capability: optional empirical verifier run once at the gate boundary.'
3594
+ prState:
3595
+ type: string
3596
+ enum:
3597
+ - ready
3598
+ - merged
3599
+ - mergeable
3600
+ - checks-green
3601
+ description: 'pr: the declared PR state to wait for (default merged).'
3602
+ epicState:
3603
+ type: string
3604
+ enum:
3605
+ - merged
3606
+ - done
3607
+ description: "epic: the declared plan-fanout aggregate state to wait for (default merged) — both mean 'fully merged' (issue #568)."
3608
+ poll:
3609
+ type: object
3610
+ additionalProperties: false
3611
+ description: The poll cadence (how often to re-probe, how long to keep trying, and the backoff shape).
3612
+ properties:
3613
+ everyMs:
3614
+ type: integer
3615
+ description: Interval between poll attempts (ms).
3616
+ timeoutMs:
3617
+ type: integer
3618
+ description: Bounded budget (ms) before the gate escalates.
3619
+ backoff:
3620
+ type: string
3621
+ enum:
3622
+ - fixed
3623
+ - exponential
3624
+ description: Backoff shape between attempts.
3625
+ required:
3626
+ - id
3627
+ - kind
3628
+ - wait
3629
+ description: A `wait` node — a durable `ReadinessProbe` (ADR 0001 §2) watching an external fact. Reuses the existing `ReadinessProbe` shape verbatim (Decision 3 — never a second wait loop); the `pr` merge-state kind is added to that shape by slice S2 and flows in here automatically. The probe's `poll.timeoutMs` sets THIS node's escalation boundary (how long the gate waits before it acts on `onTimeout`), falling back to the run/default when absent (#462). `onTimeout` `escalate` (default) parks the elapsed gate on a human-completable task; `continue` proceeds past the gate as not-ready with NO human stop (a sharp edge — the downstream side-effecting node then runs without the awaited fact); `fail` is NOT yet supported on a delivery `wait` node (blocked on engine terminate-end execution, Magikcraft/nano-bpm#978) and is rejected at compile with a path-qualified error rather than silently degrading.
3630
+ additionalProperties: false
3631
+ - type: object
3632
+ properties:
3633
+ id:
3634
+ type: string
3635
+ emits:
3636
+ type: array
3637
+ items:
3638
+ description: 'A typed output a node declares it will EMIT (ADR 0005 Decision 3/4 — emitted-fact typing). A downstream edge references it as `from: "<nodeId>.<fact>"`, so a bind is validated against this declaration, not stringly. A "click done" human node or a pass-through node declares no facts (`emits` absent/empty) — the degenerate no-emit case.'
3639
+ type: object
3640
+ additionalProperties: false
3641
+ required:
3642
+ - name
3643
+ - type
3644
+ properties:
3645
+ name:
3646
+ type: string
3647
+ minLength: 1
3648
+ maxLength: 128
3649
+ pattern: ^[A-Za-z_][A-Za-z0-9_]*$
3650
+ description: The fact's identifier, referenced downstream as `<nodeId>.<name>`. Must be unique within the node.
3651
+ type:
3652
+ type: string
3653
+ enum:
3654
+ - string
3655
+ - number
3656
+ - boolean
3657
+ - artifact
3658
+ - version
3659
+ - url
3660
+ - pr
3661
+ description: "The fact's declared type. `artifact` is a `pkg@version` handle, `version` a bare version string, `url` a location — mirrors the values `capability`/`pr` probes late-bind. `pr` (issue #548) is a PR reference (`owner/repo#N`) an `agent` node emits for the PR it opened, so a downstream `connector[converge*]`/`wait[pr]` node LATE-BINDS its target PR from the fact instead of a hardcoded literal."
3662
+ description:
3663
+ type: string
3664
+ maxLength: 512
3665
+ description: OPTIONAL human note describing what the fact carries.
3666
+ kind:
3667
+ type: string
3668
+ enum:
3669
+ - human
3670
+ human:
3671
+ type: object
3672
+ additionalProperties: false
3673
+ description: OPTIONAL human-node config. `formKey` explicitly attaches a form (else a form is selected by node category, else a generic emit-capturing fallback — resolved in S3). The node's typed output is declared via the node-level `emits[]`.
3674
+ properties:
3675
+ formKey:
3676
+ type: string
3677
+ minLength: 1
3678
+ description: OPTIONAL explicit form to attach at authoring time (specific-else-generic resolution, S3).
3679
+ prompt:
3680
+ type: string
3681
+ maxLength: 20000
3682
+ description: OPTIONAL instruction shown to the human/agent completing the task ("now do X").
3683
+ required:
3684
+ - id
3685
+ - kind
3686
+ description: A `human` node — a scheduled user task + form (ADR 0002 machinery promoted from exception to node, Decision 4). Surfaces "now do X" on the Tasks inbox, blocks dependents, is answerable by a human OR an agent, is SLA-bounded, and can EMIT a typed fact its form captures.
3687
+ additionalProperties: false
3688
+ - type: object
3689
+ properties:
3690
+ id:
3691
+ type: string
3692
+ emits:
3693
+ type: array
3694
+ items:
3695
+ description: 'A typed output a node declares it will EMIT (ADR 0005 Decision 3/4 — emitted-fact typing). A downstream edge references it as `from: "<nodeId>.<fact>"`, so a bind is validated against this declaration, not stringly. A "click done" human node or a pass-through node declares no facts (`emits` absent/empty) — the degenerate no-emit case.'
3696
+ type: object
3697
+ additionalProperties: false
3698
+ required:
3699
+ - name
3700
+ - type
3701
+ properties:
3702
+ name:
3703
+ type: string
3704
+ minLength: 1
3705
+ maxLength: 128
3706
+ pattern: ^[A-Za-z_][A-Za-z0-9_]*$
3707
+ description: The fact's identifier, referenced downstream as `<nodeId>.<name>`. Must be unique within the node.
3708
+ type:
3709
+ type: string
3710
+ enum:
3711
+ - string
3712
+ - number
3713
+ - boolean
3714
+ - artifact
3715
+ - version
3716
+ - url
3717
+ - pr
3718
+ description: "The fact's declared type. `artifact` is a `pkg@version` handle, `version` a bare version string, `url` a location — mirrors the values `capability`/`pr` probes late-bind. `pr` (issue #548) is a PR reference (`owner/repo#N`) an `agent` node emits for the PR it opened, so a downstream `connector[converge*]`/`wait[pr]` node LATE-BINDS its target PR from the fact instead of a hardcoded literal."
3719
+ description:
3720
+ type: string
3721
+ maxLength: 512
3722
+ description: OPTIONAL human note describing what the fact carries.
3723
+ kind:
3724
+ type: string
3725
+ enum:
3726
+ - connector
3727
+ connector:
3728
+ type: object
3729
+ additionalProperties: false
3730
+ required:
3731
+ - target
3732
+ properties:
3733
+ target:
3734
+ type: string
3735
+ minLength: 1
3736
+ description: The connector action target (forward-declared — the concrete scheme lands in a later slice).
3737
+ dedupeKey:
3738
+ type: string
3739
+ minLength: 1
3740
+ description: OPTIONAL idempotency key so an at-least-once resume cannot double-fire this side-effecting node (ADR 0005 Decision 7). Author-supplied or graph-derived.
3741
+ payload:
3742
+ type: object
3743
+ additionalProperties: true
3744
+ description: Minimal forward-declared payload stub — the concrete connector payload schema is deferred (ADR non-goal).
3745
+ timeout:
3746
+ type: string
3747
+ pattern: ^[Pp](?!$)(\d+[Yy])?(\d+[Mm])?(\d+[Ww])?(\d+[Dd])?([Tt](?=\d)(\d+[Hh])?(\d+[Mm])?(\d+[Ss])?)?$
3748
+ maxLength: 64
3749
+ description: OPTIONAL per-node ISO-8601 SLA timeout (#505). Overrides the run-level `nodeTimeout` (and the `PT1H` default) for THIS connector node's bounded-timeout → escalate boundary timer. Absent → the run/default value.
3750
+ required:
3751
+ - id
3752
+ - kind
3753
+ - connector
3754
+ description: A `connector` node — an automated, side-effecting outbound action (the connector I/O surface). Side-effecting, so it carries a `dedupeKey` and tolerates at-least-once execution. The `payload` schema is a minimal forward-declared stub in this slice (ADR 0005 non-goal — the concrete connector I/O lands later).
3755
+ additionalProperties: false
3756
+ description: The graph's nodes. Each carries a unique `id` and a `kind` from the closed allowlist, plus its per-kind config and its typed `emits[]` declaration. Node ids must be unique across the graph (enforced by `validateDeliveryGraph`).
3757
+ edges:
3758
+ type: array
3759
+ maxItems: 1024
3760
+ items:
3761
+ description: A dependency edge — "`to` proceeds once fact `from` is observable" (ADR 0005 Decision 3). `from` is either a bare `<nodeId>` (wait for the upstream node's completion fact) or a qualified `<nodeId>.<fact>` referencing a declared `emits` fact of that node. Both endpoints must resolve to a node in the graph, the referenced fact must be declared, and the whole edge set must be a DAG — all enforced by `validateDeliveryGraph`. An OPTIONAL `when`/`equals` guard (or a `default` else-branch) makes the edge CONDITIONAL, turning its producer into an exclusive split (ADR 0005 S7) — a node's out-edges are then ALL guarded or ALL unconditional.
3762
+ type: object
3763
+ additionalProperties: false
3764
+ required:
3765
+ - from
3766
+ - to
3767
+ properties:
3768
+ from:
3769
+ type: string
3770
+ minLength: 1
3771
+ description: The upstream endpoint — `<nodeId>` (completion) or `<nodeId>.<fact>` (a declared emitted fact).
3772
+ to:
3773
+ type: string
3774
+ minLength: 1
3775
+ description: The dependent node's id — proceeds once `from` is observed.
3776
+ when:
3777
+ type: string
3778
+ minLength: 1
3779
+ description: 'OPTIONAL guard reference `<nodeId>.<fact>` naming a SCALAR emitted fact (`string`, `number`, or `boolean`) of the `from`-adjacent producer (ADR 0005 S7). Its presence makes this a GUARDED edge and turns the producer into an exclusive-split point: the edge is taken only when that runtime fact `equals` the literal below. Equality-only — no arbitrary expressions (the trust boundary). Mutually exclusive with `default`.'
3780
+ equals:
3781
+ description: The literal value `when`'s fact must equal for this guarded edge to be taken (ADR 0005 S7). REQUIRED iff `when` is present, and its JSON type must match the referenced fact's declared type (`string`/`number`/`boolean`).
3782
+ oneOf:
3783
+ - type: string
3784
+ - type: number
3785
+ - type: boolean
3786
+ default:
3787
+ type: boolean
3788
+ enum:
3789
+ - true
3790
+ description: 'OPTIONAL — marks this edge as the ELSE branch of the exclusive split (taken when no guarded edge matches at runtime). A FLAG: only `true` is meaningful, so it is constrained to `true` (omit the field entirely for a non-default edge — `default: false` is not a valid wire value). At most one `default` edge per split node. Mutually exclusive with `when`/`equals` (ADR 0005 S7).'
3791
+ description: The dependency edges — the graph's discovered-fact topology (Decision 3). Each edge means "`to` proceeds once fact `from` about the upstream node is observable". `from` is either a bare `<nodeId>` (the degenerate "wait for the upstream node's completion" fact) or a qualified `<nodeId>.<fact>` referencing one of that node's declared `emits`. Omit/`[]` for a set of independent (root) nodes. The edge set must be a DAG.
3792
+ # END generated:mcp-body
3111
3793
  responses:
3112
3794
  "200":
3113
3795
  description: The graph validated and compiled — it is STAGED for operator review; the response carries a preview and a navigational reviewUrl (no dispatch handle).
@@ -3135,12 +3817,33 @@ paths:
3135
3817
  interchange) so the page can render the laid-out BPMN in the host explorer without staging. It
3136
3818
  never deploys, stages or dispatches. A blank/invalid JSON string, or a graph that fails
3137
3819
  validation, is a 400 carrying a human `error` (and path-qualified `errors` for a compile failure).
3820
+
3821
+
3822
+ INPUT — the text-door shape `{ "graphJson": "<serialized DeliveryGraph>" }` (a STRING, the
3823
+ same paste the cockpit uses), NOT the structured object; its sibling `compileDeliveryGraph`
3824
+ takes the `DeliveryGraph` OBJECT directly. SIDE EFFECTS — none: PURE preview, nothing is
3825
+ persisted or dispatched (`staged: false`). IDEMPOTENCY — total (a pure function of the input).
3826
+ VALIDATION — a bad string or invalid graph returns `400` with a human `error` and
3827
+ `errors: [{ path, message }]`. NEXT — to actually stage, send the SAME graph as an object to
3828
+ `compileDeliveryGraph`, then have an operator dispatch it from the `reviewUrl`.
3138
3829
  requestBody:
3139
3830
  required: true
3140
3831
  content:
3141
3832
  application/json:
3142
3833
  schema:
3143
- $ref: "#/components/schemas/DeliveryGraphPreviewSubmit"
3834
+ # BEGIN generated:mcp-body source=#/components/schemas/DeliveryGraphPreviewSubmit (scripts/inline-mcp-bodies.ts — do not hand-edit)
3835
+ description: 'The human-facing UI JSON-paste PREVIEW request (issues #386 + #516). The Delivery Graphs page''s "Preview" action cannot submit a structured object, so the operator''s pasted delivery-graph is carried as a raw JSON STRING (`graphJson`), parsed server-side and handed to the SAME pure `compileDeliveryGraph` compiler the agent-facing door uses. Preview compiles WITHOUT persisting. Per-operation schema (not shared with the stage door) so each door''s request stays independently evolvable.'
3836
+ type: object
3837
+ additionalProperties: false
3838
+ example:
3839
+ graphJson: '{"name":"start #567 once epic #488 has fully merged","nodes":[{"id":"gate-epic","kind":"wait","wait":{"kind":"epic","target":"nanobpm/nano-ide#488","match":{"epicState":"merged"},"poll":{"everyMs":300000,"timeoutMs":259200000},"onTimeout":"escalate"},"emits":[{"name":"prCount","type":"number"}]},{"id":"start-b","kind":"agent","agent":{"jobType":"senior:feature","prompt":"Implement nanobpm/nano-workforce#567 and open a PR."}}],"edges":[{"from":"gate-epic","to":"start-b"}]}'
3840
+ required:
3841
+ - graphJson
3842
+ properties:
3843
+ graphJson:
3844
+ type: string
3845
+ description: The pasted delivery-graph JSON (a serialised `DeliveryGraph`), parsed server-side.
3846
+ # END generated:mcp-body
3144
3847
  responses:
3145
3848
  "200":
3146
3849
  description: The pasted graph parsed, validated and compiled — the preview summary and compiled BPMN are returned; nothing is staged.
@@ -3297,7 +4000,17 @@ paths:
3297
4000
  content:
3298
4001
  application/json:
3299
4002
  schema:
3300
- $ref: "#/components/schemas/DeliveryGraphProposalBpmnRequest"
4003
+ # BEGIN generated:mcp-body source=#/components/schemas/DeliveryGraphProposalBpmnRequest (scripts/inline-mcp-bodies.ts — do not hand-edit)
4004
+ description: Request the compiled BPMN of a staged delivery-graph proposal for read-only DI PREVIEW. Carries only the proposal's content `digest`; the door recompiles the staged graph deterministically. No deploy, no dispatch — this reads, it does not launch anything.
4005
+ type: object
4006
+ additionalProperties: false
4007
+ required:
4008
+ - digest
4009
+ properties:
4010
+ digest:
4011
+ type: string
4012
+ description: The staged proposal's content digest — the proposal whose compiled BPMN (with DI) to render.
4013
+ # END generated:mcp-body
3301
4014
  responses:
3302
4015
  "200":
3303
4016
  description: The staged proposal recompiled; the body carries its BPMN (with DI).
@@ -3359,7 +4072,26 @@ paths:
3359
4072
  content:
3360
4073
  application/json:
3361
4074
  schema:
3362
- $ref: "#/components/schemas/SaveToLibrarySubmit"
4075
+ # BEGIN generated:mcp-body source=#/components/schemas/SaveToLibrarySubmit (scripts/inline-mcp-bodies.ts — do not hand-edit)
4076
+ description: 'Save a delivery graph to the reusable library (issue #522). Carries the entry `name` (its slug/hash derive the id) and an optional `description`, PLUS exactly one graph source: either a raw `graphJson` STRING (validated + compiled before persisting, `source: composed`), or the `digest` of an existing staged/dispatched proposal whose already-stored graph is reused (`source: from-staged` / `from-dispatched`). A graph that fails to compile is a clean 400 and nothing is persisted.'
4077
+ type: object
4078
+ additionalProperties: false
4079
+ required:
4080
+ - name
4081
+ properties:
4082
+ name:
4083
+ type: string
4084
+ description: The entry's human name — its slug + short-hash derive the stable library id (re-saving the same name upserts).
4085
+ description:
4086
+ type: string
4087
+ description: An optional human note stored alongside the entry.
4088
+ graphJson:
4089
+ type: string
4090
+ description: 'A raw `DeliveryGraph` JSON string to validate, compile and save (`source: composed`). Mutually exclusive with `digest`.'
4091
+ digest:
4092
+ type: string
4093
+ description: The content digest of an existing staged/dispatched proposal whose stored graph is reused. Mutually exclusive with `graphJson`.
4094
+ # END generated:mcp-body
3363
4095
  responses:
3364
4096
  "200":
3365
4097
  description: The graph validated and the entry was saved (upserted on its name-derived id).
@@ -3396,7 +4128,23 @@ paths:
3396
4128
  content:
3397
4129
  application/json:
3398
4130
  schema:
3399
- $ref: "#/components/schemas/ImportToLibrarySubmit"
4131
+ # BEGIN generated:mcp-body source=#/components/schemas/ImportToLibrarySubmit (scripts/inline-mcp-bodies.ts — do not hand-edit)
4132
+ description: "Import a delivery graph into the reusable library FROM A FILE (issue #524, epic #519 S5). The compose App-View's `<input type=file accept=.json>` reads the selected file's text client-side and POSTs it here as the raw `graphJson` string. The door validates + compiles it via the SAME `parseAndCompileText` pipeline the preview/stage/save doors use, then persists it with `source: imported`. A file that is not valid JSON, or a graph that fails to compile, is a clean 400 with path-qualified errors and NOTHING is persisted. The entry `name` defaults to the imported graph's own `name`; an explicit `name` overrides it (an unnamed graph with no override is a clean 400)."
4133
+ type: object
4134
+ additionalProperties: false
4135
+ required:
4136
+ - graphJson
4137
+ properties:
4138
+ graphJson:
4139
+ type: string
4140
+ description: The raw `DeliveryGraph` JSON text read from the imported file (validated + compiled before persisting).
4141
+ name:
4142
+ type: string
4143
+ description: Optional override for the entry name — its slug + short-hash derive the library id. Defaults to the imported graph's own `name`.
4144
+ description:
4145
+ type: string
4146
+ description: An optional human note stored alongside the imported entry.
4147
+ # END generated:mcp-body
3400
4148
  responses:
3401
4149
  "200":
3402
4150
  description: The imported graph validated and the entry was saved (source=imported).
@@ -3517,7 +4265,301 @@ paths:
3517
4265
  content:
3518
4266
  application/json:
3519
4267
  schema:
3520
- $ref: "#/components/schemas/FeatureStart"
4268
+ # BEGIN generated:mcp-body source=#/components/schemas/FeatureStart (scripts/inline-mcp-bodies.ts — do not hand-edit)
4269
+ description: The start-feature request body — a SINGLE-issue feature run. Names the target issue by EXACTLY ONE of `issue` (an `owner/repo#123` reference) or `url` (a bare issue URL), plus a REQUIRED `baseBranch` (ADR 0003, same admission as the epic path), and the two optional follow-on knobs `converge` / `autoMerge`. May also carry an intake-time readiness gate (`readiness` and/or `blockedOn` + `consumerPackage`, per issue 295) that parks the run until the declared upstreams land. Modeled as `oneOf` named variants (Camunda REST v2 pattern) so an ambiguous or empty target is a 400 at the edge.
4270
+ oneOf:
4271
+ - type: object
4272
+ additionalProperties: false
4273
+ required:
4274
+ - issue
4275
+ - baseBranch
4276
+ properties:
4277
+ issue:
4278
+ type: string
4279
+ description: 'Issue reference: owner/repo#123.'
4280
+ baseBranch:
4281
+ type: string
4282
+ minLength: 1
4283
+ maxLength: 255
4284
+ pattern: \S
4285
+ description: 'REQUIRED target branch the agent branches off and opens its PR against. Admitted through the same ADR 0003 policy as the epic path (`admitPlan`): a missing `epic/*` base is auto-created off default HEAD; a non-`epic/*` base must already exist; naming the default branch requires `confirmDefaultBase`.'
4286
+ converge:
4287
+ type: boolean
4288
+ description: When true, hand the opened PR to the convergence loop (review rounds) as a follow-on step. When false (default) the run ends at "PR raised, not reviewed".
4289
+ autoMerge:
4290
+ type: boolean
4291
+ description: When true (and `converge` is true), drive the merge-loop after convergence — mirrors `convergeOnly`/`NANO_PR_AUTO_MERGE` inverted. When false the run stops at `converged`. Moot when `converge` is false.
4292
+ confirmDefaultBase:
4293
+ type: boolean
4294
+ description: Acknowledge that `baseBranch` is the repository default branch (the PR would target it directly). See `PlanStartByIssue.confirmDefaultBase`.
4295
+ allowSharedBase:
4296
+ type: boolean
4297
+ description: Opt in to sharing a custom integration base branch with another already-active epic. See `PlanStartByIssue.allowSharedBase`.
4298
+ customInstructions:
4299
+ type: string
4300
+ maxLength: 8000
4301
+ description: OPTIONAL free-text steering appended to the implementation agent's prompt for this run (via the implement task's `appendPrompt`). Blank/whitespace is treated as absent. Persists on the instance, so it also applies to the agent's answer-loop redispatch.
4302
+ readiness:
4303
+ type: array
4304
+ maxItems: 32
4305
+ items:
4306
+ description: 'A single durable readiness probe (issue #258, #295) the feature run must satisfy before its implementation agent is dispatched. `kind` selects the source; `target` + `match` are the per-kind predicate. The `capability` kind resolves "which published `pkg@version` first carries capability C?" from publish provenance and late-binds it into the run. See `app/readiness.ts` for the full per-kind semantics.'
4307
+ type: object
4308
+ additionalProperties: false
4309
+ required:
4310
+ - kind
4311
+ - target
4312
+ properties:
4313
+ kind:
4314
+ type: string
4315
+ enum:
4316
+ - http
4317
+ - command
4318
+ - npm
4319
+ - github-check
4320
+ - capability
4321
+ - pr
4322
+ - epic
4323
+ description: The readiness source. `command` is the escape hatch; `capability` resolves a cross-repo published-artifact edge; `pr` watches an in-flight PR's merge state (ADR 0005 §2); `epic` gates on an nwf plan-fanout epic reaching "fully merged", keyed by its `planKey` (issue
4324
+ target:
4325
+ type: string
4326
+ minLength: 1
4327
+ description: The kind-specific target (a URL, a shell command, a `pkg@version`, an `owner/repo@ref`, `github-releases:owner/repo`, an `owner/repo#123` PR reference for the `pr` kind, or an `owner/repo#NN` planKey — the epic issue — for the `epic` kind). For a `pr`/`epic` target used in a **delivery-graph `wait` node** it may instead be a `<nodeId>.<fact>` late-binding reference the delivery-graph compiler resolves at dispatch (issue
4328
+ onTimeout:
4329
+ type: string
4330
+ enum:
4331
+ - escalate
4332
+ - fail
4333
+ - continue
4334
+ description: What the gate does when the bounded wait elapses (default `escalate`).
4335
+ credentialEnv:
4336
+ type: string
4337
+ description: A declared env-contract key supplying a credential (http kind only). Names a key, never a secret value.
4338
+ match:
4339
+ type: object
4340
+ additionalProperties: false
4341
+ description: The per-kind readiness predicate; every field is optional and read only by the kinds that understand it.
4342
+ properties:
4343
+ status:
4344
+ type: integer
4345
+ description: 'http: the exact status that means ready (default any 2xx).'
4346
+ bodyIncludes:
4347
+ type: string
4348
+ description: 'http: a substring the response body must contain.'
4349
+ exitCode:
4350
+ type: integer
4351
+ description: 'command: the exit code that means ready (default 0).'
4352
+ stdoutIncludes:
4353
+ type: string
4354
+ description: 'command/npm: a substring stdout must contain.'
4355
+ version:
4356
+ type: string
4357
+ description: 'npm: the version that must be published.'
4358
+ conclusion:
4359
+ type: string
4360
+ description: 'github-check: the conclusion that means ready (default success).'
4361
+ checkName:
4362
+ type: string
4363
+ description: 'github-check: restrict to the named check run.'
4364
+ capabilityRef:
4365
+ type: string
4366
+ description: 'capability: the upstream issue/PR handle the resolved version must carry.'
4367
+ package:
4368
+ type: string
4369
+ description: 'capability: the package whose releases are scanned for provenance.'
4370
+ verifyCommand:
4371
+ type: string
4372
+ description: 'capability: optional empirical verifier run once at the gate boundary.'
4373
+ prState:
4374
+ type: string
4375
+ enum:
4376
+ - ready
4377
+ - merged
4378
+ - mergeable
4379
+ - checks-green
4380
+ description: 'pr: the declared PR state to wait for (default merged).'
4381
+ epicState:
4382
+ type: string
4383
+ enum:
4384
+ - merged
4385
+ - done
4386
+ description: "epic: the declared plan-fanout aggregate state to wait for (default merged) — both mean 'fully merged' (issue #568)."
4387
+ poll:
4388
+ type: object
4389
+ additionalProperties: false
4390
+ description: The poll cadence (how often to re-probe, how long to keep trying, and the backoff shape).
4391
+ properties:
4392
+ everyMs:
4393
+ type: integer
4394
+ description: Interval between poll attempts (ms).
4395
+ timeoutMs:
4396
+ type: integer
4397
+ description: Bounded budget (ms) before the gate escalates.
4398
+ backoff:
4399
+ type: string
4400
+ enum:
4401
+ - fixed
4402
+ - exponential
4403
+ description: Backoff shape between attempts.
4404
+ description: "OPTIONAL intake-time readiness gate (issue #295): one or more durable probes the run must ALL satisfy before its implementation agent is dispatched. The run parks (durably, bounded by the gate's escalating timer) at the leading readiness preflight until every probe goes green. Absent/empty ⇒ the run implements immediately, unchanged."
4405
+ blockedOn:
4406
+ type: array
4407
+ maxItems: 32
4408
+ items:
4409
+ type: string
4410
+ minLength: 1
4411
+ description: 'OPTIONAL ergonomic shorthand for `readiness` (issue #295): a list of upstream `owner/repo#123` issue/PR handles the run waits to land. With `consumerPackage` each desugars to a `capability` probe (resolve which published `pkg@version` first carries the handle, and late-bind it into the run); without it, to a `command` probe that goes green once the referenced issue/PR is closed/merged.'
4412
+ consumerPackage:
4413
+ type: string
4414
+ minLength: 1
4415
+ description: OPTIONAL npm package name (e.g. `@nanobpm/engine-wasm`) the `blockedOn` shorthand resolves its handles against — the consumer dependency whose published provenance must carry each awaited upstream. When present, `blockedOn` desugars to `capability` probes and the resolved `pkg@version` is late-bound into the implementation agent's brief.
4416
+ - type: object
4417
+ additionalProperties: false
4418
+ required:
4419
+ - url
4420
+ - baseBranch
4421
+ properties:
4422
+ url:
4423
+ type: string
4424
+ description: A bare issue URL, when no `owner/repo#123` reference is supplied.
4425
+ baseBranch:
4426
+ type: string
4427
+ minLength: 1
4428
+ maxLength: 255
4429
+ pattern: \S
4430
+ description: REQUIRED target branch the agent branches off and opens its PR against. See `FeatureStartByIssue.baseBranch`.
4431
+ converge:
4432
+ type: boolean
4433
+ description: When true, hand the opened PR to the convergence loop. See `FeatureStartByIssue.converge`.
4434
+ autoMerge:
4435
+ type: boolean
4436
+ description: When true (with `converge`), drive the merge-loop. See `FeatureStartByIssue.autoMerge`.
4437
+ confirmDefaultBase:
4438
+ type: boolean
4439
+ description: Acknowledge landing on the default branch. See `PlanStartByIssue.confirmDefaultBase`.
4440
+ allowSharedBase:
4441
+ type: boolean
4442
+ description: Share a custom integration base with another active epic. See `PlanStartByIssue.allowSharedBase`.
4443
+ customInstructions:
4444
+ type: string
4445
+ maxLength: 8000
4446
+ description: OPTIONAL free-text steering appended to the implementation agent's prompt for this run. See `FeatureStartByIssue.customInstructions`.
4447
+ readiness:
4448
+ type: array
4449
+ maxItems: 32
4450
+ items:
4451
+ description: 'A single durable readiness probe (issue #258, #295) the feature run must satisfy before its implementation agent is dispatched. `kind` selects the source; `target` + `match` are the per-kind predicate. The `capability` kind resolves "which published `pkg@version` first carries capability C?" from publish provenance and late-binds it into the run. See `app/readiness.ts` for the full per-kind semantics.'
4452
+ type: object
4453
+ additionalProperties: false
4454
+ required:
4455
+ - kind
4456
+ - target
4457
+ properties:
4458
+ kind:
4459
+ type: string
4460
+ enum:
4461
+ - http
4462
+ - command
4463
+ - npm
4464
+ - github-check
4465
+ - capability
4466
+ - pr
4467
+ - epic
4468
+ description: The readiness source. `command` is the escape hatch; `capability` resolves a cross-repo published-artifact edge; `pr` watches an in-flight PR's merge state (ADR 0005 §2); `epic` gates on an nwf plan-fanout epic reaching "fully merged", keyed by its `planKey` (issue
4469
+ target:
4470
+ type: string
4471
+ minLength: 1
4472
+ description: The kind-specific target (a URL, a shell command, a `pkg@version`, an `owner/repo@ref`, `github-releases:owner/repo`, an `owner/repo#123` PR reference for the `pr` kind, or an `owner/repo#NN` planKey — the epic issue — for the `epic` kind). For a `pr`/`epic` target used in a **delivery-graph `wait` node** it may instead be a `<nodeId>.<fact>` late-binding reference the delivery-graph compiler resolves at dispatch (issue
4473
+ onTimeout:
4474
+ type: string
4475
+ enum:
4476
+ - escalate
4477
+ - fail
4478
+ - continue
4479
+ description: What the gate does when the bounded wait elapses (default `escalate`).
4480
+ credentialEnv:
4481
+ type: string
4482
+ description: A declared env-contract key supplying a credential (http kind only). Names a key, never a secret value.
4483
+ match:
4484
+ type: object
4485
+ additionalProperties: false
4486
+ description: The per-kind readiness predicate; every field is optional and read only by the kinds that understand it.
4487
+ properties:
4488
+ status:
4489
+ type: integer
4490
+ description: 'http: the exact status that means ready (default any 2xx).'
4491
+ bodyIncludes:
4492
+ type: string
4493
+ description: 'http: a substring the response body must contain.'
4494
+ exitCode:
4495
+ type: integer
4496
+ description: 'command: the exit code that means ready (default 0).'
4497
+ stdoutIncludes:
4498
+ type: string
4499
+ description: 'command/npm: a substring stdout must contain.'
4500
+ version:
4501
+ type: string
4502
+ description: 'npm: the version that must be published.'
4503
+ conclusion:
4504
+ type: string
4505
+ description: 'github-check: the conclusion that means ready (default success).'
4506
+ checkName:
4507
+ type: string
4508
+ description: 'github-check: restrict to the named check run.'
4509
+ capabilityRef:
4510
+ type: string
4511
+ description: 'capability: the upstream issue/PR handle the resolved version must carry.'
4512
+ package:
4513
+ type: string
4514
+ description: 'capability: the package whose releases are scanned for provenance.'
4515
+ verifyCommand:
4516
+ type: string
4517
+ description: 'capability: optional empirical verifier run once at the gate boundary.'
4518
+ prState:
4519
+ type: string
4520
+ enum:
4521
+ - ready
4522
+ - merged
4523
+ - mergeable
4524
+ - checks-green
4525
+ description: 'pr: the declared PR state to wait for (default merged).'
4526
+ epicState:
4527
+ type: string
4528
+ enum:
4529
+ - merged
4530
+ - done
4531
+ description: "epic: the declared plan-fanout aggregate state to wait for (default merged) — both mean 'fully merged' (issue #568)."
4532
+ poll:
4533
+ type: object
4534
+ additionalProperties: false
4535
+ description: The poll cadence (how often to re-probe, how long to keep trying, and the backoff shape).
4536
+ properties:
4537
+ everyMs:
4538
+ type: integer
4539
+ description: Interval between poll attempts (ms).
4540
+ timeoutMs:
4541
+ type: integer
4542
+ description: Bounded budget (ms) before the gate escalates.
4543
+ backoff:
4544
+ type: string
4545
+ enum:
4546
+ - fixed
4547
+ - exponential
4548
+ description: Backoff shape between attempts.
4549
+ description: OPTIONAL intake-time readiness gate. See `FeatureStartByIssue.readiness`.
4550
+ blockedOn:
4551
+ type: array
4552
+ maxItems: 32
4553
+ items:
4554
+ type: string
4555
+ minLength: 1
4556
+ description: OPTIONAL readiness shorthand — upstream `owner/repo#123` handles to wait on. See `FeatureStartByIssue.blockedOn`.
4557
+ consumerPackage:
4558
+ type: string
4559
+ minLength: 1
4560
+ description: OPTIONAL package the `blockedOn` handles resolve against. See `FeatureStartByIssue.consumerPackage`.
4561
+ type: object
4562
+ # END generated:mcp-body
3521
4563
  responses:
3522
4564
  "202":
3523
4565
  description: The feature run was started (or was already running).
@@ -3751,7 +4793,28 @@ paths:
3751
4793
  content:
3752
4794
  application/json:
3753
4795
  schema:
3754
- $ref: "#/components/schemas/AgentCompleteRequest"
4796
+ # BEGIN generated:mcp-body source=#/components/schemas/AgentCompleteRequest (scripts/inline-mcp-bodies.ts — do not hand-edit)
4797
+ type: object
4798
+ additionalProperties: false
4799
+ description: "Complete an escalation user task AS AN AGENT (epic #156 / ADR 0046). The agent submits the SAME typed form variables a human would through the task inbox; the host routes them through the one canonical attributed completer, records the agent's identity for the audit trail, and resumes the process. Only the migrated escalation user tasks may be completed this way."
4800
+ required:
4801
+ - userTaskKey
4802
+ - agentId
4803
+ - variables
4804
+ properties:
4805
+ userTaskKey:
4806
+ type: string
4807
+ minLength: 1
4808
+ description: The engine user-task key of the parked escalation task (from GET /tasks/api/tasks).
4809
+ agentId:
4810
+ type: string
4811
+ minLength: 1
4812
+ description: The completing agent's identity (ADR 0046), recorded for attribution.
4813
+ variables:
4814
+ type: object
4815
+ additionalProperties: true
4816
+ description: The typed form completion variables — the SAME shape a human submits (e.g. `{ resolution, answer }`, `{ directive, notes }`, `{ action, notes }`, or `{ answer }`).
4817
+ # END generated:mcp-body
3755
4818
  responses:
3756
4819
  "200":
3757
4820
  description: The agent completed the escalation task and the process resumed.
@@ -3792,7 +4855,25 @@ paths:
3792
4855
  content:
3793
4856
  application/json:
3794
4857
  schema:
3795
- $ref: "#/components/schemas/RevertCompletionRequest"
4858
+ # BEGIN generated:mcp-body source=#/components/schemas/RevertCompletionRequest (scripts/inline-mcp-bodies.ts — do not hand-edit)
4859
+ type: object
4860
+ additionalProperties: false
4861
+ description: Revert/override an agent escalation completion (the reversibility guarantee of ADR 0046). A human marks a reversible agent completion reverted so the agent's answer is no longer treated as authoritative; the reverter's identity + timestamp are recorded.
4862
+ required:
4863
+ - completionId
4864
+ - reverterId
4865
+ properties:
4866
+ completionId:
4867
+ type: integer
4868
+ description: The `task_completions` id returned when the agent completion was recorded.
4869
+ reverterId:
4870
+ type: string
4871
+ minLength: 1
4872
+ description: The human identity overriding the agent completion, recorded for the audit trail.
4873
+ note:
4874
+ type: string
4875
+ description: Optional corrective guidance from the human that overrides the agent's answer.
4876
+ # END generated:mcp-body
3796
4877
  responses:
3797
4878
  "200":
3798
4879
  description: The agent completion was reverted.
@@ -3879,7 +4960,34 @@ paths:
3879
4960
  content:
3880
4961
  application/json:
3881
4962
  schema:
3882
- $ref: "#/components/schemas/BlackboardAppendRequest"
4963
+ # BEGIN generated:mcp-body source=#/components/schemas/BlackboardAppendRequest (scripts/inline-mcp-bodies.ts — do not hand-edit)
4964
+ type: object
4965
+ description: Append one blackboard entry. Idempotent on (plan, dedupe_key).
4966
+ required:
4967
+ - body
4968
+ properties:
4969
+ author_task:
4970
+ type: string
4971
+ description: The authoring task id; defaults to "system" when omitted/blank.
4972
+ kind:
4973
+ type: string
4974
+ description: Entry kind (e.g. note, file-claim); normalized by the delegate.
4975
+ files:
4976
+ type: array
4977
+ items:
4978
+ type: string
4979
+ description: Files this entry concerns (used by advisory file-claim conflict detection).
4980
+ body:
4981
+ type: string
4982
+ minLength: 1
4983
+ description: The note text (required, non-blank).
4984
+ wave:
4985
+ type: integer
4986
+ description: Optional plan wave the entry belongs to.
4987
+ dedupe_key:
4988
+ type: string
4989
+ description: 'Idempotency key: a retry with the same (plan, dedupe_key) returns the existing entry.'
4990
+ # END generated:mcp-body
3883
4991
  responses:
3884
4992
  "200":
3885
4993
  description: "An idempotent retry: the entry already existed (inserted=false)."