@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/.github/workflows/ci.yml +8 -0
- package/.github/workflows/invariants.yml +7 -0
- package/CHANGELOG.md +12 -0
- package/app/agentic/cockpit/supply-boot.test.ts +29 -5
- package/app/agentic/cockpit/supply-boot.ts +17 -7
- package/docs/mcp-runbook.md +46 -0
- package/e2e/mcp-surface.e2e.ts +235 -0
- package/e2e/support/mcp-harness.ts +373 -0
- package/openapi.yaml +1121 -13
- package/package.json +5 -2
- package/pages/cockpit/mount.js +32 -12
- package/scripts/inline-mcp-bodies.ts +316 -0
- package/test/cockpit-embed-endpoints.test.ts +84 -0
- package/test/mcp-tool-schemas.test.ts +127 -0
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)."
|