mandrel 2.14.0 → 2.16.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/.agents/audit-checklists/navigability.md +1 -1
- package/.agents/docs/workflows.md +4 -4
- package/.agents/scripts/acceptance-eval.js +18 -1
- package/.agents/scripts/agents-bootstrap-github.js +22 -1
- package/.agents/scripts/apply-quality-bootstrap.js +6 -0
- package/.agents/scripts/audit-labels-bootstrap.js +15 -1
- package/.agents/scripts/audit-to-stories.js +26 -1
- package/.agents/scripts/boot-sweep.js +4 -1
- package/.agents/scripts/bootstrap.js +1 -0
- package/.agents/scripts/check-arch-cycles.js +20 -0
- package/.agents/scripts/check-baselines.js +8 -2
- package/.agents/scripts/check-context-budget.js +40 -5
- package/.agents/scripts/check-dead-exports.js +21 -0
- package/.agents/scripts/check-doc-links.js +12 -1
- package/.agents/scripts/check-lifecycle-doc-drift.js +9 -0
- package/.agents/scripts/check-workflow-citations.js +332 -0
- package/.agents/scripts/deliver-light.js +32 -3
- package/.agents/scripts/deliver-recover.js +4 -1
- package/.agents/scripts/diagnose-friction.js +17 -1
- package/.agents/scripts/diagnose.js +20 -14
- package/.agents/scripts/drain-pending-cleanup.js +20 -1
- package/.agents/scripts/evidence-gate.js +20 -1
- package/.agents/scripts/generate-config-docs.js +14 -1
- package/.agents/scripts/generate-lifecycle-docs.js +14 -1
- package/.agents/scripts/generate-workflows-doc.js +14 -1
- package/.agents/scripts/git-cleanup.js +32 -1
- package/.agents/scripts/lib/cli-usage.js +174 -0
- package/.agents/scripts/lib/cli-utils.js +12 -0
- package/.agents/scripts/lib/close-validation/process.js +61 -15
- package/.agents/scripts/lib/doc-tiers.js +53 -10
- package/.agents/scripts/lib/orchestration/complexity-gate.js +307 -89
- package/.agents/scripts/lib/orchestration/light-suitability.js +31 -9
- package/.agents/scripts/lib/orchestration/plan-context.js +205 -20
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +87 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +24 -15
- package/.agents/scripts/lib/workflow-closure.js +431 -0
- package/.agents/scripts/mandrel-update-preflight.js +9 -0
- package/.agents/scripts/nav-registry-diff.js +13 -0
- package/.agents/scripts/plan-context.js +21 -2
- package/.agents/scripts/plan-critics.js +10 -0
- package/.agents/scripts/plan-persist.js +33 -1
- package/.agents/scripts/plan-run-epilogue.js +12 -1
- package/.agents/scripts/quality-preview.js +17 -1
- package/.agents/scripts/resolve-doc-tiers.js +13 -0
- package/.agents/scripts/resolve-stories.js +1 -0
- package/.agents/scripts/resync-status-column.js +4 -1
- package/.agents/scripts/signals-view.js +11 -0
- package/.agents/scripts/single-story-close.js +24 -0
- package/.agents/scripts/single-story-confirm-merge.js +16 -0
- package/.agents/scripts/single-story-init.js +21 -1
- package/.agents/scripts/stories-wave-tick.js +1 -0
- package/.agents/scripts/sync-agentrc.js +16 -4
- package/.agents/scripts/update-ticket-state.js +23 -2
- package/.agents/workflows/audit-navigability.md +2 -2
- package/.agents/workflows/audit-to-stories.md +1 -1
- package/.agents/workflows/deliver.md +80 -81
- package/.agents/workflows/git-cleanup.md +9 -14
- package/.agents/workflows/helpers/acceptance-self-eval.md +14 -13
- package/.agents/workflows/helpers/audit-lens-core.md +2 -2
- package/.agents/workflows/helpers/code-review.md +11 -11
- package/.agents/workflows/helpers/deliver-digest.md +7 -8
- package/.agents/workflows/helpers/deliver-light.md +222 -0
- package/.agents/workflows/helpers/deliver-reference.md +46 -14
- package/.agents/workflows/helpers/deliver-story-reference.md +55 -63
- package/.agents/workflows/helpers/deliver-story.md +22 -22
- package/.agents/workflows/helpers/mandrel-sync-config.md +2 -2
- package/.agents/workflows/helpers/parallel-tooling.md +1 -2
- package/.agents/workflows/helpers/plan-reference.md +96 -17
- package/.agents/workflows/helpers/worktree-lifecycle.md +1 -4
- package/.agents/workflows/mandrel-update.md +6 -6
- package/.agents/workflows/plan.md +90 -85
- package/.agents/workflows/prototype.md +104 -0
- package/docs/CHANGELOG.md +32 -0
- package/package.json +2 -1
- package/.agents/workflows/deliver-light.md +0 -148
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: >-
|
|
3
|
-
The deliver path's one bundled framework read
|
|
3
|
+
The deliver path's one bundled framework read. Carries what
|
|
4
4
|
every Story delivery always needs — dispatch decision, engine invariants,
|
|
5
5
|
the change-set/ceremony incantation, the acceptance-eval gate, and the
|
|
6
6
|
terminal envelope contract — so the engine reads one file instead of
|
|
@@ -23,10 +23,10 @@ description: >-
|
|
|
23
23
|
Read `stories[].dispatchMode` from the `resolve-stories.js` envelope. Two
|
|
24
24
|
rules produce it, in order:
|
|
25
25
|
|
|
26
|
-
1. **Run topology
|
|
26
|
+
1. **Run topology.** A run resolving **one** Story is `inline`
|
|
27
27
|
whatever its shape — sub-agent isolation is load-bearing only against a
|
|
28
28
|
*concurrent* sibling racing the same checkout, and a one-Story run has none.
|
|
29
|
-
2. **Body shape
|
|
29
|
+
2. **Body shape.** In a multi-Story run, a lite-shaped body is
|
|
30
30
|
`inline`; a full-shaped body, an unparseable one, or a footprint touching a
|
|
31
31
|
sensitive-path class is `subagent`. The `route::lite` label is a
|
|
32
32
|
human-visible hint, never the control signal.
|
|
@@ -42,7 +42,6 @@ gates, same PR to `main`, same terminal envelope, byte for byte.
|
|
|
42
42
|
| Ticket type | `type::story` only; an `Epic: #N` footer means **stop and re-plan** |
|
|
43
43
|
| Branch | `story-<id>`, seeded from `project.baseBranch` (`main`) |
|
|
44
44
|
| Merge target | `main` via PR (squash + required checks) — never a direct push |
|
|
45
|
-
| Integration branch | **None** — no `epic/<id>`, no `--no-ff` wave merge |
|
|
46
45
|
| Gates | Every close gate runs regardless of route; no route bypasses one |
|
|
47
46
|
| State | Only via `update-ticket-state.js --ticket <id> --state <state>` |
|
|
48
47
|
| Paths | Prefix every path-based tool with the absolute `workCwd` — `cd` does not scope them |
|
|
@@ -52,7 +51,7 @@ the only sanctioned landing. A silent local build is not a delivery.
|
|
|
52
51
|
|
|
53
52
|
## 3. Change set — computed once, handed to everyone
|
|
54
53
|
|
|
55
|
-
One enumeration per Story
|
|
54
|
+
One enumeration per Story. A critic that re-runs its own `git diff`
|
|
56
55
|
can score a different set than the one that routed it:
|
|
57
56
|
|
|
58
57
|
```bash
|
|
@@ -76,7 +75,7 @@ fresh. An `inline` dispatch mode overrides all of it to inline critics. Close's
|
|
|
76
75
|
|
|
77
76
|
## 4. Acceptance self-eval (Step 1a, required)
|
|
78
77
|
|
|
79
|
-
**One verdict-owner per cluster**
|
|
78
|
+
**One verdict-owner per cluster** — the fresh critic *or* the inline
|
|
80
79
|
self-eval, named by `verdictOwner`, never both and never a warm-up pass. It
|
|
81
80
|
scores each `acceptance[]` item against the change set above, with `verify[]`
|
|
82
81
|
output as evidence. Bounded by `delivery.acceptanceEval.maxRounds` (default 2).
|
|
@@ -96,7 +95,7 @@ Per-round mechanics: [`acceptance-self-eval.md`](acceptance-self-eval.md).
|
|
|
96
95
|
`single-story-close.js` emits exactly one envelope on stdout between
|
|
97
96
|
`--- STORY DELIVER TERMINAL ---` markers, schema-validated against
|
|
98
97
|
[`story-deliver-terminal.schema.json`](../../schemas/story-deliver-terminal.schema.json)
|
|
99
|
-
|
|
98
|
+
— the SSOT; read the JSON only when you need a field this table omits.
|
|
100
99
|
Relay it verbatim; never hand-compose one, never substitute prose.
|
|
101
100
|
|
|
102
101
|
| `status` | Exit | Meaning | You do |
|
|
@@ -113,7 +112,7 @@ Required fields: `kind` (`story-deliver-terminal`), `storyId`, `status`,
|
|
|
113
112
|
reports every gate as `passed` / `failed` / `skipped` — a skipped gate is
|
|
114
113
|
reported, never omitted, so a missing gate is never read as a passing one.
|
|
115
114
|
|
|
116
|
-
**Gate output is captured, not streamed
|
|
115
|
+
**Gate output is captured, not streamed.** Close writes gate lines to
|
|
117
116
|
`temp/orchestration/close-gates-<storyId>.log` and reports a one-line digest on
|
|
118
117
|
success; a failed gate replays its tail inline. `AGENT_LOG_LEVEL=verbose`
|
|
119
118
|
restores live streaming.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
description:
|
|
3
|
+
The unplanned prompt path shared by /deliver and /plan Gate #1. Judges a
|
|
4
|
+
prompt's predicted footprint, authors a receipt Story, then lands it through
|
|
5
|
+
the same single-story-init / single-story-close engine — every close gate
|
|
6
|
+
unchanged.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Unplanned delivery (the prompt path)
|
|
10
|
+
|
|
11
|
+
> **A path, not a command.** There is no `/deliver-light` to type. This file is
|
|
12
|
+
> reached two ways — `/deliver "<prompt>"` (an operator describing small work)
|
|
13
|
+
> and `/plan` Gate #1 (a seed the suggestion says fits the light ceilings, once
|
|
14
|
+
> the operator confirms). Read
|
|
15
|
+
> [`deliver-digest.md`](deliver-digest.md) once first — the engine invariants,
|
|
16
|
+
> gates, and terminal-envelope contract below are its.
|
|
17
|
+
|
|
18
|
+
## Role
|
|
19
|
+
|
|
20
|
+
For a genuinely trivial change — a one-file fix, a small addition, a small
|
|
21
|
+
amendment — the multi-session plan→deliver ceremony buys nothing the bare model
|
|
22
|
+
lacks except **gates and landing**. This path keeps exactly those: one session
|
|
23
|
+
straight to execution from a prompt, landing through the unchanged close path.
|
|
24
|
+
It never relaxes a close gate, never bypasses the PR to `main`, and never lands
|
|
25
|
+
over-scope work silently.
|
|
26
|
+
|
|
27
|
+
Two callers, one gate: whichever door you arrived through, the suitability gate
|
|
28
|
+
below is the decision. A `/plan` Gate #1 suggestion is a *suggestion* — it is
|
|
29
|
+
read against seed-time signals (`DELIVER_LIGHT_SUGGESTION_CEILINGS`: artifacts,
|
|
30
|
+
risk hits, sensitive-path classes), while the gate here is read against the
|
|
31
|
+
predicted work's *effort and risk* (`STORY_SHAPE_CEILINGS`: change kinds,
|
|
32
|
+
magnitude, uncertainty, deployable span). They are deliberately two different
|
|
33
|
+
checks, so the gate still runs after a confirm.
|
|
34
|
+
|
|
35
|
+
## Scope by effort, not by artifact count {#scope-by-effort}
|
|
36
|
+
|
|
37
|
+
**Counting the footprint is the wrong axis.** Three identical one-line edits
|
|
38
|
+
across three files is trivial work with a high count; a 200-line rewrite of one
|
|
39
|
+
module is a single change. The axes are therefore effort and risk: distinct
|
|
40
|
+
change **kinds** (N instances of one mechanical edit is one kind at N sites), a
|
|
41
|
+
coarse **magnitude** bucket, and **uncertainty** — is the shape determined by
|
|
42
|
+
the request, or does it still need the design decisions `/plan` exists to
|
|
43
|
+
resolve?
|
|
44
|
+
|
|
45
|
+
Because the predicted footprint is a *declaration* — a guess, and a gameable one
|
|
46
|
+
— this gate is deliberately **coarse**: it rejects clearly-epic work only
|
|
47
|
+
(multiple deployables, a migration plus its consumers, an explicit
|
|
48
|
+
multi-capability enumeration). Size is enforced where ground truth is available:
|
|
49
|
+
the diff backstop in step 4. Do not talk yourself past that one.
|
|
50
|
+
|
|
51
|
+
Sensitivity is the exception and stays absolute: a footprint touching an auth,
|
|
52
|
+
crypto, billing, or migration class routes `full` however small or mechanical.
|
|
53
|
+
|
|
54
|
+
## Four invariants (do not skip one)
|
|
55
|
+
|
|
56
|
+
1. **Suitability gate.** The prompt's predicted footprint is judged by the
|
|
57
|
+
shared effort/risk machinery (`deriveStoryShape` / `deriveChangeLevel`)
|
|
58
|
+
**and** a ledgered model verdict with a recorded reason. Both must agree on
|
|
59
|
+
`lite`.
|
|
60
|
+
2. **Over-scope stops — it never hard-fails.** An over-ceiling prompt STOPS and
|
|
61
|
+
asks the operator to escalate to `/plan` or proceed light. Under `--yes` it
|
|
62
|
+
fails closed to an **`escalated` terminal envelope** that ends the session
|
|
63
|
+
(§ Escalation is terminal).
|
|
64
|
+
3. **Diff-derived backstop.** After implementation the ACTUAL change set is
|
|
65
|
+
re-checked — the diff is the real scope signal — and an over-ceiling diff is
|
|
66
|
+
blocked rather than landed.
|
|
67
|
+
4. **Minimal receipt Story.** A `type::story` is authored inline so `refs #`,
|
|
68
|
+
history, telemetry, and the `agent::executing → agent::done` state machine
|
|
69
|
+
all survive.
|
|
70
|
+
|
|
71
|
+
## Procedure
|
|
72
|
+
|
|
73
|
+
1. **Predict + gate.** Form the predicted footprint (new files, edited files,
|
|
74
|
+
acceptance count), judge its effort honestly (`--kinds` / `--magnitude` /
|
|
75
|
+
`--uncertainty`, per § Scope by effort), and record your ledgered verdict (a
|
|
76
|
+
recorded reason for `lite`), then run the gate — it documents every flag
|
|
77
|
+
itself, so run it with `--help` rather than guessing:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
node .agents/scripts/deliver-light.js --prompt "<prompt>" \
|
|
81
|
+
--creates <csv> --refactors <csv> --acceptance <n> \
|
|
82
|
+
--kinds <csv> --magnitude trivial|moderate|substantial \
|
|
83
|
+
--uncertainty determined|needs-design \
|
|
84
|
+
--route lite --reason "<why this is trivial>" [--amends '#<id>'] [--yes]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Branch on `action` in the JSON envelope:
|
|
88
|
+
- **`proceed-light`** — the receipt Story is authored; read `storyId` and
|
|
89
|
+
`nextCommands`. Continue to step 2.
|
|
90
|
+
- **`ask-operator`** — predicted scope exceeds the light ceilings. STOP and
|
|
91
|
+
ask the operator to escalate to `/plan` or proceed light. Do not proceed
|
|
92
|
+
on your own. This is a **question, not a terminal** — wait for the answer.
|
|
93
|
+
- **over-scope under `--yes`** — no `action` to branch on: the gate emits an
|
|
94
|
+
**`escalated` terminal envelope** instead (exit 2). § Escalation is
|
|
95
|
+
terminal governs; you are finished.
|
|
96
|
+
|
|
97
|
+
`--amends '#<id>'` is the canonical light case — shape-checked identically; a
|
|
98
|
+
heavy amendment escalates to `/plan` like any other over-scope prompt.
|
|
99
|
+
|
|
100
|
+
**Entered from `/plan` Gate #1?** Fill `--creates` / `--refactors` /
|
|
101
|
+
`--acceptance` / `--reason` from the plan-context envelope's codebase
|
|
102
|
+
snapshot and `complexitySignals` rather than re-deriving them from the seed
|
|
103
|
+
text — Gate #1 has already done that work, and re-deriving throws away the
|
|
104
|
+
better signal. An `ask-operator` verdict here means the two ceiling sets
|
|
105
|
+
disagreed: **return to [`../plan.md`](../plan.md) step 2 (Author) in the same
|
|
106
|
+
session**, carrying the interrogation you already paid for. That bounce-back
|
|
107
|
+
is not an escalation and does not need a fresh session (§ Why the two
|
|
108
|
+
directions differ).
|
|
109
|
+
|
|
110
|
+
2. **Init (same engine).** From the main checkout, synchronously, with the
|
|
111
|
+
maximum Bash timeout:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
node .agents/scripts/single-story-init.js --story <storyId>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Capture `workCwd`; `remoteVerified: false` → flip `agent::blocked` and stop.
|
|
118
|
+
This is [`/deliver`](../deliver.md)'s worktree/branch/lease/label engine,
|
|
119
|
+
invoked, not reimplemented.
|
|
120
|
+
|
|
121
|
+
3. **Implement + self-eval.** `cd` into `workCwd`, implement the change, run
|
|
122
|
+
`npm test` once in the worktree, then run the bounded acceptance self-eval
|
|
123
|
+
loop ([`deliver-story.md`](deliver-story.md) Step 1a). Commit
|
|
124
|
+
on `story-<id>` with `(refs #<storyId>)`.
|
|
125
|
+
|
|
126
|
+
4. **Diff backstop.** Before close, re-check the ACTUAL diff:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
node .agents/scripts/deliver-light.js --backstop --story <storyId>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Exit `3` (`blocked: true`) means the landed diff exceeds the light ceilings
|
|
133
|
+
(file count or a sensitive-path class). STOP, flip `agent::blocked`, and
|
|
134
|
+
escalate to `/plan` — do not land. This is the pass that actually bounds
|
|
135
|
+
size, which is why the prediction gate above can afford to be coarse.
|
|
136
|
+
|
|
137
|
+
5. **Close and land (same engine).** Exactly [`/deliver`](../deliver.md)'s close:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
node .agents/scripts/single-story-close.js --story <storyId> --cwd <main-repo>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Branch on the terminal envelope's `status` per
|
|
144
|
+
[`deliver-digest.md`](deliver-digest.md) § 5 — every close
|
|
145
|
+
gate runs byte-identical to the full path.
|
|
146
|
+
|
|
147
|
+
## Escalation is terminal {#escalation-is-terminal}
|
|
148
|
+
|
|
149
|
+
Over-scope under `--yes` emits a schema-validated `story-deliver-terminal`
|
|
150
|
+
envelope with **`status: "escalated"`**, `storyId: null`, and a `nextCommand`
|
|
151
|
+
naming the `/plan` invocation that owns the work.
|
|
152
|
+
|
|
153
|
+
**That envelope IS this session's terminal output.** Relay it and stop. There is
|
|
154
|
+
no remaining step, no degraded fallback, and no smaller version of the work to
|
|
155
|
+
attempt.
|
|
156
|
+
|
|
157
|
+
**Invoking `/plan` in this same session is forbidden.** Hand the operator the
|
|
158
|
+
`nextCommand`; `/plan` runs in a **fresh** session.
|
|
159
|
+
|
|
160
|
+
This is not style — it is the empirical finding that motivated the envelope.
|
|
161
|
+
A mandrel-bench 2.13.0 light-arm run read the escalation and continued anyway:
|
|
162
|
+
it invoked `/plan` in-session and delivered. The in-session plan authored **one**
|
|
163
|
+
Story against the scenario's 3–5 contract, where a fresh `/plan` session on the
|
|
164
|
+
identical seed authored **four**. Planning inside a session already framed as
|
|
165
|
+
small work under-decomposes, so walking past the escalation silently produced
|
|
166
|
+
the very outcome the guard exists to prevent. The gate's decision was right both
|
|
167
|
+
times; only the outcome's finality was missing.
|
|
168
|
+
|
|
169
|
+
Nothing is left half-started: an escalated run creates **no receipt Story, no
|
|
170
|
+
`story-<id>` branch, and no worktree** — the escalation path returns before
|
|
171
|
+
every creation call site, and `escalation.created` records all three as `false`
|
|
172
|
+
in a shape the schema pins, so a later run finds nothing to trip over.
|
|
173
|
+
|
|
174
|
+
## Why the two directions differ {#why-the-two-directions-differ}
|
|
175
|
+
|
|
176
|
+
Traffic runs both ways between this path and `/plan`, and the two directions
|
|
177
|
+
have **deliberately different session rules**. It reads like an inconsistency;
|
|
178
|
+
it is not. The rule:
|
|
179
|
+
|
|
180
|
+
> **The direction whose guard is model judgment must break the session. The
|
|
181
|
+
> direction whose guard is mechanical need not.**
|
|
182
|
+
|
|
183
|
+
**Light → `/plan` must be a fresh session.** What is being protected is
|
|
184
|
+
*authoring judgment*, and the empirical finding above is that a session already
|
|
185
|
+
framed as small work under-decomposes — one Story against a 3–5 contract where
|
|
186
|
+
a fresh session on the identical seed authored four. The frame is the hazard,
|
|
187
|
+
so only a new session removes it.
|
|
188
|
+
|
|
189
|
+
**`/plan` → light may stay in-session.** Gate #1 fires **before** authoring, so
|
|
190
|
+
there is no authoring to corrupt, and the frame at that point is "plan this
|
|
191
|
+
seed" — the neutral one, not the small one. Everything on the receiving side is
|
|
192
|
+
mechanical: `STORY_SHAPE_CEILINGS`, the ledgered verdict, the diff backstop.
|
|
193
|
+
None of them degrade because the context is large, so nothing is gained by
|
|
194
|
+
paying for a fresh session.
|
|
195
|
+
|
|
196
|
+
Do not "fix" this into symmetry in either direction. Making `/plan` → light
|
|
197
|
+
require a fresh session throws away a paid-for interrogation for no guard.
|
|
198
|
+
Letting light → `/plan` run in-session reintroduces the exact failure the
|
|
199
|
+
`escalated` envelope exists to prevent.
|
|
200
|
+
|
|
201
|
+
## Constraints
|
|
202
|
+
|
|
203
|
+
- **Land, block, or escalate — never a silent local build.** The close push is
|
|
204
|
+
the only sanctioned landing; an `escalated` terminal is the only sanctioned
|
|
205
|
+
ending that delivers nothing, and it ends the session
|
|
206
|
+
(§ Escalation is terminal).
|
|
207
|
+
- **No parallel engine.** This path invokes `single-story-init.js` and
|
|
208
|
+
`single-story-close.js`; it never reimplements worktree, branch, PR, or merge
|
|
209
|
+
mechanics.
|
|
210
|
+
- **State only via `update-ticket-state.js`.** Drive every `agent::*`
|
|
211
|
+
transition through the script; report state, not process.
|
|
212
|
+
|
|
213
|
+
## See also
|
|
214
|
+
|
|
215
|
+
- [`/deliver`](../deliver.md) — the delivery entry point; routes here on a
|
|
216
|
+
free-text prompt.
|
|
217
|
+
- [`/plan`](../plan.md) — routes here from Gate #1 on a confirmed suggestion,
|
|
218
|
+
and owns the work an over-scope prompt escalates to.
|
|
219
|
+
- [`deliver-story.md`](deliver-story.md) — the one Story delivery engine every
|
|
220
|
+
path shares.
|
|
221
|
+
- [`deliver-digest.md`](deliver-digest.md) — engine invariants, gates, and the
|
|
222
|
+
terminal-envelope contract.
|
|
@@ -9,7 +9,7 @@ description:
|
|
|
9
9
|
# /deliver — reference appendix (on-demand)
|
|
10
10
|
|
|
11
11
|
Reference-only detail split out of [`deliver.md`](../deliver.md) so the
|
|
12
|
-
always-resident spine stays lean
|
|
12
|
+
always-resident spine stays lean. Nothing here is a new MUST —
|
|
13
13
|
it is the mechanics an operator consults when the matching lever is engaged.
|
|
14
14
|
|
|
15
15
|
## Sequencing edge cases (`stories-wave-tick.js`)
|
|
@@ -18,13 +18,13 @@ Each beat re-probes live state: it re-resolves the graph, classifies **done**
|
|
|
18
18
|
(`agent::done` or a closed issue — including foreign blockers that landed in
|
|
19
19
|
another run), and derives **in-flight** from live `agent::executing` /
|
|
20
20
|
`agent::closing` labels. You never compute `done` or `in-flight` — that
|
|
21
|
-
accounting is read from reality every beat
|
|
21
|
+
accounting is read from reality every beat.
|
|
22
22
|
|
|
23
|
-
**`--dispatched` is the one thing you must tell it
|
|
23
|
+
**`--dispatched` is the one thing you must tell it.** List every
|
|
24
24
|
Story id you have spawned this run. Live state cannot instantly report a Story
|
|
25
25
|
you dispatched moments ago: `single-story-init.js` publishes `agent::executing`
|
|
26
|
-
before the worktree install (
|
|
27
|
-
|
|
26
|
+
before the worktree install (ahead of the multi-minute install, so the
|
|
27
|
+
window is short rather than minutes-long), but it is not
|
|
28
28
|
zero — until the label lands the Story still reads `agent::ready` and, without
|
|
29
29
|
`--dispatched`, the next beat would hand it back and a second sub-agent would
|
|
30
30
|
join the first on the same branch and worktree, interleaving commits.
|
|
@@ -34,10 +34,10 @@ is additive, not authoritative — the probe unions it into the label-derived se
|
|
|
34
34
|
and then filters it against live state, so an id that has since gone
|
|
35
35
|
`agent::done` is dropped for you. Re-listing an id costs nothing and cannot
|
|
36
36
|
double-count a slot; *omitting* one is the only way to get this wrong. This is
|
|
37
|
-
why `--dispatched` is not the `--done` bookkeeping
|
|
37
|
+
why `--dispatched` is not the retired `--done` bookkeeping, and why
|
|
38
38
|
`--in-flight` remains rejected under `--probe-live`.
|
|
39
39
|
|
|
40
|
-
**Cross-run de-confliction is automatic
|
|
40
|
+
**Cross-run de-confliction is automatic.** A Story another
|
|
41
41
|
operator is delivering is withheld without any bookkeeping from you: the probe
|
|
42
42
|
reads the Story's assignee lease and, when it belongs to a different operator,
|
|
43
43
|
withholds the Story and reports it in the envelope's
|
|
@@ -51,7 +51,7 @@ probe logs a warning and leans on init's lease refusal alone.
|
|
|
51
51
|
|
|
52
52
|
## Dispatch mechanics (role-scoped by default)
|
|
53
53
|
|
|
54
|
-
**A single-Story run executes inline
|
|
54
|
+
**A single-Story run executes inline.** Sub-agent isolation is
|
|
55
55
|
load-bearing only for **concurrent** dispatch — two workers sharing a checkout
|
|
56
56
|
would race on worktrees and branch refs — so a run resolving exactly one Story
|
|
57
57
|
has no sibling to isolate from and pays the spawn premium for nothing (a boot is
|
|
@@ -61,7 +61,7 @@ a cache write at full rate; an inline continuation is a cache read at ~10%).
|
|
|
61
61
|
retained in full for multi-Story waves, and the rule changes **where** the
|
|
62
62
|
engine runs, never what runs — gates, PR, and terminal envelope are identical.
|
|
63
63
|
|
|
64
|
-
**Lite-shaped Stories execute inline
|
|
64
|
+
**Lite-shaped Stories execute inline.** Before spawning anything,
|
|
65
65
|
read the Story's `dispatchMode` from the resolver envelope
|
|
66
66
|
(`stories[].dispatchMode`, derived by `resolveStoryDispatchMode` in
|
|
67
67
|
`lib/orchestration/complexity-gate.js` **from the fetched Story body's own
|
|
@@ -91,9 +91,10 @@ prompt: `storyId`; `docsDigestPath` (the per-run docs digest, null when
|
|
|
91
91
|
`project.docsContextFiles` is unset); `checklistPath` (the footprint-matched
|
|
92
92
|
write-time audit checklist, produced at dispatch, below); and the
|
|
93
93
|
**change-set discipline** — the worker computes the change set once with
|
|
94
|
-
`computeChangeSet` and hands that one list to every acceptance critic
|
|
94
|
+
`computeChangeSet` and hands that one list to every acceptance critic; it
|
|
95
|
+
never lets a critic re-derive the diff.
|
|
95
96
|
|
|
96
|
-
**Produce `checklistPath` before the spawn
|
|
97
|
+
**Produce `checklistPath` before the spawn.** Compute the payload
|
|
97
98
|
from the Story's predicted footprint (its `changes[]` / `references[]` path
|
|
98
99
|
entries) with `buildDispatchChecklist` and write it to the run temp dir, then
|
|
99
100
|
thread the resulting path (empty when nothing matched):
|
|
@@ -124,6 +125,38 @@ execute it directly, in this turn, threading the same `docsDigestPath` /
|
|
|
124
125
|
content, execute directly without a re-read turn. The engine, gates, and
|
|
125
126
|
terminal envelope are identical either way — only the isolation differs.
|
|
126
127
|
|
|
128
|
+
## Intent phrases (what replaced the flag table)
|
|
129
|
+
|
|
130
|
+
`/deliver` has no operator-facing flags. The scripts still take every flag they
|
|
131
|
+
always did — the workflow fills them in from what the operator said, the same
|
|
132
|
+
derive-then-announce contract `/git-deliver` uses for its terminal level.
|
|
133
|
+
|
|
134
|
+
| The operator says | You pass | Effect |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| "I'll merge it myself", "don't wait", "just open the PR" | `--no-wait-merge` | Rest at `agent::closing` for a human land |
|
|
137
|
+
| "wait for the merge", "land it" | `--wait-merge` | Close-and-land — already the default (`delivery.routing.closeAndLand`) |
|
|
138
|
+
| "take the lease", "steal it", "it's mine, override" | `--steal` | Forwarded to `single-story-init.js` |
|
|
139
|
+
| "one at a time", "sequentially", "no parallelism" | `--concurrency 1` | Serialize a multi-Story run |
|
|
140
|
+
| "run <n> at once" | `--concurrency <n>` | One-run cap only |
|
|
141
|
+
|
|
142
|
+
Two rules keep this honest:
|
|
143
|
+
|
|
144
|
+
1. **Announce before acting.** Name the intent you read and the flag it fills
|
|
145
|
+
in. A misread phrase is then visible in one line rather than discovered at
|
|
146
|
+
the terminal envelope.
|
|
147
|
+
2. **Silence means config, not a literal.** With no intent phrase, omit the
|
|
148
|
+
flag entirely so `delivery.deliverRunner.concurrencyCap` (and any
|
|
149
|
+
`.agentrc.local.json` override) wins. Filling in the config default as a
|
|
150
|
+
literal silently defeats that override — the failure this table most easily
|
|
151
|
+
causes.
|
|
152
|
+
|
|
153
|
+
`--yes` is deliberately **absent** from the table. It is not an intent an
|
|
154
|
+
operator expresses; it is a runner asserting *nobody is at the keyboard*, and
|
|
155
|
+
it changes fail-closed behavior (it is what turns the unplanned path's
|
|
156
|
+
over-scope stop into an `escalated` terminal envelope, and what auto-proceeds
|
|
157
|
+
`/plan`'s gates). Cron, `/loop`, and headless dispatch set it. An attended run
|
|
158
|
+
never does, however the operator phrases their impatience.
|
|
159
|
+
|
|
127
160
|
## Operator-merge implies no-wait
|
|
128
161
|
|
|
129
162
|
`--no-auto-merge` and `delivery.ci.autoMerge: "strict"` leave the PR
|
|
@@ -163,8 +196,7 @@ Ceremony depth is selected by `delivery.routing.ceremonyProfile`
|
|
|
163
196
|
(`minimal` | `standard` | `strict`, default `standard`) and the **change level
|
|
164
197
|
derived from the Story's own diff** — the changed files' intersection with the
|
|
165
198
|
sensitive-path classes in `audit-rules.json`
|
|
166
|
-
(`review-depth.js#deriveChangeLevel`), not a planner-authored verdict
|
|
167
|
-
(Story #4542):
|
|
199
|
+
(`review-depth.js#deriveChangeLevel`), not a planner-authored verdict:
|
|
168
200
|
|
|
169
201
|
| Profile | Acceptance critic | When to use |
|
|
170
202
|
| --- | --- | --- |
|
|
@@ -179,7 +211,7 @@ sensitive-path classes in `audit-rules.json`
|
|
|
179
211
|
| **Per-run (N>1)** | Audit roster · follow-up roll-up · sibling coherence | `plan-run-epilogue.js` once at run end |
|
|
180
212
|
| **Per-Story land tail** | Follow-up capture · status resync · ref cleanup · base fast-forward | `single-story-close/phases/post-land.js` (in-process, per-step reported) |
|
|
181
213
|
|
|
182
|
-
## Async merge-confirm mode (`delivery.mergeWatch.mode: "async"
|
|
214
|
+
## Async merge-confirm mode (`delivery.mergeWatch.mode: "async"`)
|
|
183
215
|
|
|
184
216
|
A slow-CI consumer can opt the close into `"async"` mode so the merge wait
|
|
185
217
|
probes once for ~60s (catching an instant merge or an instantly-red required
|