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.
Files changed (75) hide show
  1. package/.agents/audit-checklists/navigability.md +1 -1
  2. package/.agents/docs/workflows.md +4 -4
  3. package/.agents/scripts/acceptance-eval.js +18 -1
  4. package/.agents/scripts/agents-bootstrap-github.js +22 -1
  5. package/.agents/scripts/apply-quality-bootstrap.js +6 -0
  6. package/.agents/scripts/audit-labels-bootstrap.js +15 -1
  7. package/.agents/scripts/audit-to-stories.js +26 -1
  8. package/.agents/scripts/boot-sweep.js +4 -1
  9. package/.agents/scripts/bootstrap.js +1 -0
  10. package/.agents/scripts/check-arch-cycles.js +20 -0
  11. package/.agents/scripts/check-baselines.js +8 -2
  12. package/.agents/scripts/check-context-budget.js +40 -5
  13. package/.agents/scripts/check-dead-exports.js +21 -0
  14. package/.agents/scripts/check-doc-links.js +12 -1
  15. package/.agents/scripts/check-lifecycle-doc-drift.js +9 -0
  16. package/.agents/scripts/check-workflow-citations.js +332 -0
  17. package/.agents/scripts/deliver-light.js +32 -3
  18. package/.agents/scripts/deliver-recover.js +4 -1
  19. package/.agents/scripts/diagnose-friction.js +17 -1
  20. package/.agents/scripts/diagnose.js +20 -14
  21. package/.agents/scripts/drain-pending-cleanup.js +20 -1
  22. package/.agents/scripts/evidence-gate.js +20 -1
  23. package/.agents/scripts/generate-config-docs.js +14 -1
  24. package/.agents/scripts/generate-lifecycle-docs.js +14 -1
  25. package/.agents/scripts/generate-workflows-doc.js +14 -1
  26. package/.agents/scripts/git-cleanup.js +32 -1
  27. package/.agents/scripts/lib/cli-usage.js +174 -0
  28. package/.agents/scripts/lib/cli-utils.js +12 -0
  29. package/.agents/scripts/lib/close-validation/process.js +61 -15
  30. package/.agents/scripts/lib/doc-tiers.js +53 -10
  31. package/.agents/scripts/lib/orchestration/complexity-gate.js +307 -89
  32. package/.agents/scripts/lib/orchestration/light-suitability.js +31 -9
  33. package/.agents/scripts/lib/orchestration/plan-context.js +205 -20
  34. package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +87 -13
  35. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +24 -15
  36. package/.agents/scripts/lib/workflow-closure.js +431 -0
  37. package/.agents/scripts/mandrel-update-preflight.js +9 -0
  38. package/.agents/scripts/nav-registry-diff.js +13 -0
  39. package/.agents/scripts/plan-context.js +21 -2
  40. package/.agents/scripts/plan-critics.js +10 -0
  41. package/.agents/scripts/plan-persist.js +33 -1
  42. package/.agents/scripts/plan-run-epilogue.js +12 -1
  43. package/.agents/scripts/quality-preview.js +17 -1
  44. package/.agents/scripts/resolve-doc-tiers.js +13 -0
  45. package/.agents/scripts/resolve-stories.js +1 -0
  46. package/.agents/scripts/resync-status-column.js +4 -1
  47. package/.agents/scripts/signals-view.js +11 -0
  48. package/.agents/scripts/single-story-close.js +24 -0
  49. package/.agents/scripts/single-story-confirm-merge.js +16 -0
  50. package/.agents/scripts/single-story-init.js +21 -1
  51. package/.agents/scripts/stories-wave-tick.js +1 -0
  52. package/.agents/scripts/sync-agentrc.js +16 -4
  53. package/.agents/scripts/update-ticket-state.js +23 -2
  54. package/.agents/workflows/audit-navigability.md +2 -2
  55. package/.agents/workflows/audit-to-stories.md +1 -1
  56. package/.agents/workflows/deliver.md +80 -81
  57. package/.agents/workflows/git-cleanup.md +9 -14
  58. package/.agents/workflows/helpers/acceptance-self-eval.md +14 -13
  59. package/.agents/workflows/helpers/audit-lens-core.md +2 -2
  60. package/.agents/workflows/helpers/code-review.md +11 -11
  61. package/.agents/workflows/helpers/deliver-digest.md +7 -8
  62. package/.agents/workflows/helpers/deliver-light.md +222 -0
  63. package/.agents/workflows/helpers/deliver-reference.md +46 -14
  64. package/.agents/workflows/helpers/deliver-story-reference.md +55 -63
  65. package/.agents/workflows/helpers/deliver-story.md +22 -22
  66. package/.agents/workflows/helpers/mandrel-sync-config.md +2 -2
  67. package/.agents/workflows/helpers/parallel-tooling.md +1 -2
  68. package/.agents/workflows/helpers/plan-reference.md +96 -17
  69. package/.agents/workflows/helpers/worktree-lifecycle.md +1 -4
  70. package/.agents/workflows/mandrel-update.md +6 -6
  71. package/.agents/workflows/plan.md +90 -85
  72. package/.agents/workflows/prototype.md +104 -0
  73. package/docs/CHANGELOG.md +32 -0
  74. package/package.json +2 -1
  75. package/.agents/workflows/deliver-light.md +0 -148
@@ -251,4 +251,28 @@ async function main() {
251
251
  runAsCli(import.meta.url, main, {
252
252
  source: 'single-story-close',
253
253
  propagateExitCode: true,
254
+ usage: {
255
+ invocation:
256
+ 'node .agents/scripts/single-story-close.js --story <id> [--cwd <main-repo>] [options]',
257
+ summary:
258
+ 'Run the whole delivery tail for one Story — close gates, base sync, push, PR to the base branch, merge wait, agent::done flip — and emit the terminal envelope.',
259
+ flags: [
260
+ ['--story <id>', 'GitHub issue number of the Story (required).'],
261
+ [
262
+ '--cwd <main-repo>',
263
+ 'Main-repo checkout to run from (default: project root).',
264
+ ],
265
+ ['--skip-validation', 'Skip the close-validation gate chain.'],
266
+ ['--skip-sync', 'Skip the base-branch sync phase.'],
267
+ ['--no-auto-merge', 'Open the PR without arming native auto-merge.'],
268
+ ['--wait-merge', 'Force the in-close merge wait.'],
269
+ ['--no-wait-merge', 'Return as soon as the PR is open; do not wait.'],
270
+ ['--max-wait-seconds <n>', 'Per-invocation merge-wait bound.'],
271
+ ['--no-evidence', 'Do not reuse or write gate evidence stamps.'],
272
+ ['--dry-run', 'Report the plan; mutate nothing.'],
273
+ ],
274
+ notes: [
275
+ 'Exit codes:\n 0 landed\n 1 blocked or failed\n 3 pending (resumable — run the envelope’s nextCommand)',
276
+ ],
277
+ },
254
278
  });
@@ -538,4 +538,20 @@ async function main() {
538
538
  runAsCli(import.meta.url, main, {
539
539
  source: 'single-story-confirm-merge',
540
540
  propagateExitCode: true,
541
+ usage: {
542
+ invocation:
543
+ 'node .agents/scripts/single-story-confirm-merge.js --story <id> [--pr <n>] [--wait] [--max-wait-seconds <n>] [--cwd <main-repo>]',
544
+ summary:
545
+ 'Confirm a Story PR merged and flip the Story to agent::done. With --wait, resumes the bounded merge wait a close handed off.',
546
+ flags: [
547
+ ['--story <id>', 'GitHub issue number of the Story (required).'],
548
+ ['--pr <n>', 'PR number (default: resolved from the Story branch).'],
549
+ ['--wait', 'Resume the bounded merge wait instead of probing once.'],
550
+ ['--max-wait-seconds <n>', 'Per-invocation bound for the --wait path.'],
551
+ [
552
+ '--cwd <main-repo>',
553
+ 'Main-repo checkout to run from (default: project root).',
554
+ ],
555
+ ],
556
+ },
541
557
  });
@@ -831,4 +831,24 @@ export function renderSingleStoryInitComment(result) {
831
831
  ].join('\n');
832
832
  }
833
833
 
834
- runAsCli(import.meta.url, runSingleStoryInit, { source: 'single-story-init' });
834
+ runAsCli(import.meta.url, runSingleStoryInit, {
835
+ source: 'single-story-init',
836
+ usage: {
837
+ invocation:
838
+ 'node .agents/scripts/single-story-init.js --story <id> [--dry-run] [--steal] [--cwd <main-repo>]',
839
+ summary:
840
+ 'Initialize a Story for delivery: acquire the lease, seed story-<id> from the base branch, materialize the worktree, and flip the Story to agent::executing.',
841
+ flags: [
842
+ ['--story <id>', 'GitHub issue number of the Story (required).'],
843
+ [
844
+ '--dry-run',
845
+ 'Report what would happen; no mutations, no lease, no sweep.',
846
+ ],
847
+ ['--steal', 'Forcibly transfer a lease held by another assignee.'],
848
+ [
849
+ '--cwd <main-repo>',
850
+ 'Main-repo checkout to run from (default: project root).',
851
+ ],
852
+ ],
853
+ },
854
+ });
@@ -880,4 +880,5 @@ async function main(argv) {
880
880
 
881
881
  runAsCli(import.meta.url, () => main(process.argv.slice(2)), {
882
882
  source: 'stories-wave-tick',
883
+ usage: HELP,
883
884
  });
@@ -21,15 +21,27 @@
21
21
  * 0 — Config is valid (advisories may still appear).
22
22
  * 1 — Config is missing, malformed, or fails schema validation.
23
23
  *
24
- * Flags:
25
- * --cwd <path> Project root (defaults to process.cwd()).
26
- * --quiet Suppress advisory rows (only print the status line).
24
+ * The flag contract lives in `USAGE` below — `--help` is the one home for it.
27
25
  */
28
26
 
29
27
  import { fileURLToPath } from 'node:url';
28
+ import { respondToHelp } from './lib/cli-usage.js';
30
29
  import { formatSyncReport, syncAgentrc } from './lib/config/sync-agentrc.js';
31
30
  import { Logger } from './lib/Logger.js';
32
31
 
32
+ const USAGE = {
33
+ invocation: 'node .agents/scripts/sync-agentrc.js [--cwd <path>] [--quiet]',
34
+ summary:
35
+ 'Validate `.agentrc.json` against the framework schema and report every project leaf that merely restates a framework default. Never writes the config.',
36
+ flags: [
37
+ ['--cwd <path>', 'Project root (default: process cwd).'],
38
+ ['--quiet', 'Suppress advisory rows; print only the status line.'],
39
+ ],
40
+ notes: [
41
+ 'Exit codes:\n 0 config is valid (advisories may still appear)\n 1 config is missing, malformed, or fails schema validation',
42
+ ],
43
+ };
44
+
33
45
  function parseArgs(argv) {
34
46
  const out = { cwd: null, quiet: false };
35
47
  for (let i = 0; i < argv.length; i += 1) {
@@ -67,5 +79,5 @@ function trimAdvisories(report) {
67
79
  // cli-opt-out: synchronous CLI with explicit exit-code return.
68
80
  const isMain = process.argv[1] === fileURLToPath(import.meta.url);
69
81
  if (isMain) {
70
- process.exit(main());
82
+ process.exit(respondToHelp(process.argv.slice(2), USAGE) ? 0 : main());
71
83
  }
@@ -6,16 +6,37 @@
6
6
  */
7
7
 
8
8
  import { parseArgs } from 'node:util';
9
+ import { respondToHelp } from './lib/cli-usage.js';
9
10
  import { resolveConfig } from './lib/config-resolver.js';
10
11
  import { Logger } from './lib/Logger.js';
11
12
  import { transitionTicketState } from './lib/orchestration/ticketing.js';
12
13
  import { createProvider } from './lib/provider-factory.js';
13
14
 
15
+ const USAGE = {
16
+ invocation:
17
+ 'node .agents/scripts/update-ticket-state.js --ticket <id> [--state <state> | --remove-label <label>]',
18
+ summary:
19
+ 'The one sanctioned surface for an agent::* label transition on a ticket.',
20
+ flags: [
21
+ ['--ticket <id>', 'GitHub issue number to transition (required).'],
22
+ [
23
+ '--state <state>',
24
+ 'Target agent state (e.g. agent::ready, agent::executing, agent::done).',
25
+ ],
26
+ [
27
+ '--remove-label <label>',
28
+ 'Drop a single label without flipping the agent state.',
29
+ ],
30
+ ],
31
+ notes: ['Exactly one of --state or --remove-label is required.'],
32
+ };
33
+
14
34
  // ── CLI Main Block ────────────────────────────────────────────────────────
15
35
  // cli-opt-out: re-export shim with a DEBUG_MAIN escape hatch for tests; runAsCli's strict path-equality guard would block the env-flag entry path.
16
36
  if (
17
- process.argv[1]?.endsWith('update-ticket-state.js') ||
18
- process.env.DEBUG_MAIN
37
+ (process.argv[1]?.endsWith('update-ticket-state.js') ||
38
+ process.env.DEBUG_MAIN) &&
39
+ !respondToHelp(process.argv.slice(2), USAGE)
19
40
  ) {
20
41
  const { values } = parseArgs({
21
42
  args: process.argv.slice(2),
@@ -2,8 +2,8 @@
2
2
  description: >-
3
3
  Audit the whole route tree against the consumer's nav-registry SSOT —
4
4
  every route has a persona nav door and no nav href is dead. A
5
- deliberately-global lens (Epic #4131, F2/F3) exempt from the
6
- cross-epic-leak guard and routed onto route-adding change sets.
5
+ deliberately-global lens exempt from the cross-epic-leak guard and
6
+ routed onto route-adding change sets.
7
7
  ---
8
8
 
9
9
  # Navigability Audit
@@ -204,7 +204,7 @@ workflow owns **no** parallel dedup or footer-parsing code: the
204
204
  fingerprint, footer round-trip, and routing all live in that one shared
205
205
  module.
206
206
 
207
- Dedup runs in **two stages** when a provider resolves (Story #4626): a
207
+ Dedup runs in **two stages** when a provider resolves: a
208
208
  meaning-first **semantic candidate** pass (`searchCandidates`, wired to
209
209
  [`lib/findings/semantic-issue-search.js`](../scripts/lib/findings/semantic-issue-search.js))
210
210
  runs FIRST and widens the net across open + closed issues; the exact
@@ -1,65 +1,72 @@
1
1
  ---
2
2
  description:
3
- Unified delivery entry point. Takes a list of Story ids, resolves their
4
- dependency graph from live state, and delivers each via the single
3
+ Unified delivery entry point. Takes Story ids or a plain-language prompt,
4
+ derives which path the work belongs on, and lands it via the single
5
5
  deliver-story engine — story-<id> → PR → main.
6
6
  ---
7
7
 
8
- # /deliver <storyId...>
8
+ # /deliver
9
9
 
10
- > **Lean spine.** Happy path + gate list. Sequencing edge cases, dispatch
11
- > mechanics, lite-route inline execution, checklist threading, ceremony, and
12
- > the per-run epilogue live in the on-demand
13
- > [`helpers/deliver-reference.md`](helpers/deliver-reference.md). What every
14
- > delivery always needs is bundled into one read:
15
- > [`helpers/deliver-digest.md`](helpers/deliver-digest.md) (Story #4736).
10
+ > **Lean spine.** Happy path + gate list. Sequencing, dispatch mechanics,
11
+ > intent phrases, ceremony, and the epilogue live in the on-demand
12
+ > [`helpers/deliver-reference.md`](helpers/deliver-reference.md); the unplanned
13
+ > path in [`helpers/deliver-light.md`](helpers/deliver-light.md). What every
14
+ > delivery always needs is one read:
15
+ > [`helpers/deliver-digest.md`](helpers/deliver-digest.md).
16
16
 
17
17
  ## Role
18
18
 
19
- Single delivery path, single input shape: **a list of Story ids**. `/deliver`
20
- owns input resolution and sequencing only — every Story runs through
21
- [`helpers/deliver-story.md`](helpers/deliver-story.md). No Epic wave loop, no
22
- `epic/<id>` integration branch, no `--no-ff` wave merges.
23
-
24
- The dependency graph is **discovered, not declared**: `resolve-stories.js`
25
- reads it from live state (body edges native GitHub `blocked_by` edges, each
26
- blocker resolved against its real issue state). You never hand it a graph and
27
- there is no batch label which is what lets you deliver Stories **across plan
28
- runs and over time**. `plan-run::<id>` is filter metadata, never a resolution
29
- input.
30
- Per-Story routes are **body-derived** too (#4722); `route::lite` is a hint
31
- only. Ahead of that: a **single-Story run runs the engine inline** whatever the
32
- shape (#4736) — sub-agent isolation only earns its cost against a concurrent
33
- sibling.
19
+ One delivery door. `/deliver` owns input resolution and sequencing only every
20
+ Story lands through [`helpers/deliver-story.md`](helpers/deliver-story.md).
21
+
22
+ Nothing about the route is declared at the invocation; it is **derived, then
23
+ announced, then acted on**. The dependency graph is **discovered, not
24
+ declared** `resolve-stories.js` reads it from live state (body edges ∪ native
25
+ `blocked_by` edges, each blocker resolved against its real issue state), so
26
+ there is no graph to hand it and no batch label, which is what lets you deliver
27
+ Stories **across plan runs and over time**.
28
+ `plan-run::<id>` is filter metadata, never a resolution input; `route::lite` is
29
+ a body-derived hint only. Ahead of all of it, a **single-Story run runs the
30
+ engine inline** whatever the shape — sub-agent isolation only earns its cost
31
+ against a concurrent sibling.
34
32
 
35
33
  ## Inputs
36
34
 
37
- | Invocation | Behavior |
38
- | --- | --- |
39
- | `/deliver <storyId>` | Deliver one Story via `helpers/deliver-story.md`, executed **inline in this session** — no `story-worker` spawn. |
40
- | `/deliver <storyId> <storyId> ...` | Resolve the set with `resolve-stories.js`, then sequence by the discovered graph via `stories-wave-tick.js`, dispatching role-scoped sub-agents. Default concurrency is **3**. |
35
+ Classify what the operator typed **before** doing anything else, and say which
36
+ shape you read it as:
37
+
38
+ | Invocation | Shape | Behavior |
39
+ | --- | --- | --- |
40
+ | `/deliver` | bare | List the open `agent::ready` Stories and ask which to deliver. Deliver nothing until answered. |
41
+ | `/deliver 4712` | ids | One Story via `helpers/deliver-story.md`, **inline in this session** — no `story-worker` spawn. |
42
+ | `/deliver 4712 4713 …` | ids | Resolve the set, then sequence by the discovered graph via `stories-wave-tick.js`, dispatching role-scoped sub-agents. |
43
+ | `/deliver add a --json flag to doctor` | prompt | Unplanned work: gate, author a receipt Story, land it — [`helpers/deliver-light.md`](helpers/deliver-light.md). |
41
44
 
42
- Any named ticket that is not `type::story`, or still carrying an `Epic: #N`
43
- footer, is a **hard error** naming the id and the fix (close or re-plan as a v2
44
- Story). Resolution refuses the whole set rather than silently under-delivering.
45
+ **The discriminator is lexical and total.** Every positional argument matching
46
+ `^#?\d+$` means ids; anything else means a prompt. A **mixed** invocation (ids
47
+ *and* prose) is a **hard error** refuse it and ask which was meant, the way
48
+ resolution refuses a whole set rather than under-delivering. A named ticket
49
+ that is not `type::story`, or carries an `Epic: #N` footer, is a hard error too.
45
50
 
46
- ## Flags
51
+ ## Saying what you want
47
52
 
48
- | Flag | Meaning |
49
- | --- | --- |
50
- | `--concurrency <n>` | **Optional** per-run override of the fan-out cap. Omit it to honor `delivery.deliverRunner.concurrencyCap` (config default **3**, incl. any `.agentrc.local.json` override); pass **only** for a one-run cap. `1` = sequential. |
51
- | `--yes` | Suppress the multi-Story confirmation gate. |
52
- | `--steal` | Forwarded to `single-story-init.js` / lease steal. |
53
- | `--wait-merge` | Force close-and-land (the default; `delivery.routing.closeAndLand`). |
54
- | `--no-wait-merge` | Opt out; stop at `agent::closing` for a human land. |
53
+ No flags to remember: state intent — *"…but I'll merge it myself"*, *"…take the
54
+ lease"*, *"…one at a time"* — and announce what you read before acting.
55
+ Phrasings and the flag each fills in:
56
+ [`helpers/deliver-reference.md` § Intent phrases](helpers/deliver-reference.md).
55
57
 
56
- **Operator-merge implies no-wait.** `--no-auto-merge` and
57
- `delivery.ci.autoMerge: "strict"` rest the Story at `agent::closing`, not
58
- `agent::blocked` a genuine *arm failure* still waits and still blocks
59
- ([`helpers/deliver-reference.md` § Operator-merge](helpers/deliver-reference.md)).
58
+ `--yes` is **runner-set, never operator-typed**: cron, `/loop`, and headless
59
+ dispatch set it to mean *nobody is at the keyboard*, which is what makes the
60
+ unplanned path's over-scope stop fail closed to a terminal envelope instead of
61
+ a question. Never offer it to an operator or add it to an attended run.
60
62
 
61
63
  ## Procedure
62
64
 
65
+ 0. **Classify and announce.** Read the invocation per § Inputs and state the
66
+ shape you derived. A prompt leaves for
67
+ [`helpers/deliver-light.md`](helpers/deliver-light.md); bare asks; ids
68
+ continue below.
69
+
63
70
  1. **Resolve the set.** One command, for one Story or many:
64
71
  `node .agents/scripts/resolve-stories.js --ids <id,id,...>`. It validates
65
72
  the set and shows what will run: read `stories[]`, `dag[]`, and `done[]` to
@@ -81,15 +88,14 @@ Story). Resolution refuses the whole set rather than silently under-delivering.
81
88
 
82
89
  **Do not add `--concurrency` unless the operator explicitly asked for a
83
90
  per-run cap** — an explicit value wins over config, so a filled-in literal
84
- silently defeats a `.agentrc.local.json` override (see Flags).
91
+ silently defeats a `.agentrc.local.json` override.
85
92
 
86
93
  Each beat re-probes live state to derive done / in-flight itself; you never
87
- compute them (Story #4594). `--dispatched` is the one thing you must supply —
88
- the append-only list of every id you spawned this run — and cross-run
94
+ compute them. `--dispatched` is the one thing you must supply — the
95
+ append-only list of every id you spawned this run — and cross-run
89
96
  de-confliction via the assignee lease is automatic
90
- ([`helpers/deliver-reference.md` § Sequencing edge cases](helpers/deliver-reference.md);
91
- Dispatch mechanics](helpers/deliver-reference.md) covers role-scoped
92
- spawn, lite-route execution, and `checklistPath`).
97
+ ([`helpers/deliver-reference.md`](helpers/deliver-reference.md) §§ Sequencing
98
+ edge cases, Dispatch mechanics).
93
99
 
94
100
  Branch on the exit code:
95
101
  - **0** — dispatch each `ready` id (already capped and overlap-free). Empty
@@ -98,64 +104,57 @@ Story). Resolution refuses the whole set rather than silently under-delivering.
98
104
  - **2** — `cycleError`: the graph is self-referential. Fix the `depends_on`
99
105
  declarations; do not retry.
100
106
  - **3** — `wedged`: nothing dispatchable, nothing in flight, undone Stories
101
- waiting on blockers that are not done. The envelope names the stuck ids and
102
- unmet blockers. Land the blocker or include it in `--ids`; do not retry
103
- unchanged.
107
+ waiting on unmet blockers both named in the envelope. Land the blocker
108
+ or include it in `--ids`; do not retry unchanged.
104
109
  - **4** — `blocked`: a Story carries `agent::blocked`, named in `blocked[]`
105
110
  with `blockedReason` — the protocol's HITL pause
106
111
  ([`instructions.md` § 1.J](../instructions.md)). **Stop the loop and
107
112
  surface it; do not poll.** Read the friction comment
108
113
  (`gh issue view <id> --comments`) and resume only once the operator
109
114
  unblocks it (`update-ticket-state.js --ticket <id> --state agent::ready`).
110
- A blocked Story outranks a wedge but not a cycle (fix the graph first).
115
+ Blocked outranks a wedge but not a cycle (fix the graph first).
111
116
 
112
117
  4. **Per-run epilogue (N>1).** Once step 3 reports `epilogueDue: true`, run
113
118
  `node .agents/scripts/plan-run-epilogue.js --stories 101,102` — audit
114
- roster, follow-up roll-up, sibling coherence. A single-Story run skips it.
115
- Detail:
116
- [`helpers/deliver-reference.md` § Per-run epilogue](helpers/deliver-reference.md).
119
+ roster, follow-up roll-up, sibling coherence. A single-Story run skips it
120
+ ([reference § Per-run epilogue](helpers/deliver-reference.md)).
117
121
 
118
122
  ## Branch model (authoritative)
119
123
 
120
- ```text
121
- story-<id> → PR → main (squash + required checks)
122
- ```
123
-
124
- No `epic/<id>` integration branch and no `--no-ff` wave merge. Dependent
125
- Stories land sequentially so each builds on the previous merge to `main`.
126
- Ceremony depth (profiles + derived level via `ceremony-routing.js`,
127
- review depth reading the same level) and the mechanism table:
124
+ `story-<id>` → PR → `main` (squash + required checks), per digest § 2.
125
+ Dependent Stories land sequentially so each builds on the previous merge.
126
+ Ceremony depth (profiles + derived level via `ceremony-routing.js`, review
127
+ depth reading the same level):
128
128
  [`helpers/deliver-reference.md` § Ceremony](helpers/deliver-reference.md).
129
129
 
130
130
  ## Reading a Story's outcome
131
131
 
132
- Each Story's delivery ends in exactly one schema-validated terminal envelope —
133
- `landed` | `pending` | `blocked` | `failed`. Statuses, exits, and fields:
134
- [`helpers/deliver-digest.md`](helpers/deliver-digest.md) § 5, over the shipped
135
- [schema](../schemas/story-deliver-terminal.schema.json) (Story #4543).
132
+ Each Story ends in exactly one schema-validated terminal envelope — `landed` |
133
+ `pending` | `blocked` | `failed`. Statuses, exits, and fields:
134
+ [`helpers/deliver-digest.md`](helpers/deliver-digest.md) § 5.
136
135
 
137
- `pending` is **not** a failure: the bounded merge wait expired with the PR
138
- healthy (or a human owns the merge), nothing was mutated, and the
139
- `nextCommand` resumes it — run that rather than re-dispatching. The slow-CI
140
- `async` mode (Story #4698) returns `pending` by design — launch its
141
- `nextCommand` as a background invocation (reference appendix).
136
+ `pending` is **not** a failure: the bounded wait expired with the PR healthy
137
+ (or a human owns the merge), nothing was mutated, and `nextCommand` resumes it
138
+ — run that rather than re-dispatching.
142
139
 
143
140
  For a Story in an unclear state — including the merged-but-label-stale one a
144
- `/deliver` re-run refuses outright — probe it read-only with
141
+ re-run refuses outright — probe it read-only with
145
142
  `node .agents/scripts/deliver-recover.js --story <storyId>`.
146
143
 
147
144
  ## Constraints
148
145
 
149
146
  - **Land or block — never a silent local build** (digest § 2). Attended
150
147
  delivers default to close-and-land (`delivery.routing.closeAndLand: true`);
151
- use `--no-wait-merge` only when a human lands the PR.
152
- - `/deliver` never plans tickets come from [`/plan`](plan.md). The router
153
- performs no git/label mutations; `deliver-story` owns every script.
148
+ rest at `agent::closing` only when a human owns the merge.
149
+ - **`/deliver` never plans.** Planned tickets come from [`/plan`](plan.md), and
150
+ an over-scope prompt **escalates and ends** — never invoke `/plan` in this
151
+ session to rescue it ([`helpers/deliver-light.md`](helpers/deliver-light.md)
152
+ § Escalation is terminal). The router performs no git/label mutations;
153
+ `deliver-story` owns every script.
154
154
 
155
155
  ## See also
156
156
 
157
157
  - [`/plan`](plan.md) — unified planning entry point.
158
- - [`helpers/deliver-story.md`](helpers/deliver-story.md) — the one Story
159
- delivery engine.
160
- - [`helpers/deliver-reference.md`](helpers/deliver-reference.md) sequencing,
161
- dispatch, ceremony, and epilogue detail.
158
+ - [`helpers/deliver-story.md`](helpers/deliver-story.md) — the one engine.
159
+ - [`helpers/deliver-light.md`](helpers/deliver-light.md) — the unplanned
160
+ prompt path, shared with `/plan` Gate #1.
@@ -22,12 +22,12 @@ Reach for it when the automated hygiene left an unusual state behind.
22
22
 
23
23
  The enumeration + reap logic lives in
24
24
  [`git-cleanup.js`](../scripts/git-cleanup.js) — it computes the candidate list,
25
- the skip taxonomy, the detection signals, and the JSON envelope (add `--json`),
26
- and prints them itself. Without `--execute` the script is a **dry-run preview**; nothing is
27
- mutated. When no phase flag is passed, **all four phases run** sequentially; pass
28
- any of `--fast-forward-main`, `--prune-remotes`, `--branches`, `--stashes` to
29
- narrow the run. A failure in one phase does not short-circuit the others — each
30
- runs and reports independently.
25
+ the skip taxonomy, the detection signals, and the JSON envelope, and prints them
26
+ itself. Without `--execute` the script is a **dry-run preview**; nothing is
27
+ mutated. When no phase flag is passed, **all four phases run** sequentially; a
28
+ phase flag narrows the run. A failure in one phase does not short-circuit the
29
+ others each runs and reports independently. The script documents its own
30
+ flags: `node .agents/scripts/git-cleanup.js --help`.
31
31
 
32
32
  ## Phases
33
33
 
@@ -44,14 +44,9 @@ runs and reports independently.
44
44
  > branches, delete remote refs (with `--remote`), and drop stashes. Without
45
45
  > `--execute` the script only previews.
46
46
 
47
- - **`--execute`** the master gate. Omit it for a preview of all four phases.
48
- - **`--remote`** extends the branches phase to delete the matching
49
- `origin/<branch>` ref (and to delete remote-only merged branches). Cannot be
50
- undone without re-pushing.
51
- - **`--yes`** — bypass every per-step prompt (CI / non-interactive). Under it,
52
- stash drops still require `--drop-stashes <ref>`.
53
- - **`--exclude '<pattern>'`** — carve a branch out of the reap. This is the only
54
- way to protect an in-scope merged-PR branch you want to keep.
47
+ Two consequences the flag list alone does not carry: `--remote` deletions cannot
48
+ be undone without re-pushing, and `--exclude '<pattern>'` is the **only** way to
49
+ protect an in-scope merged-PR branch you want to keep.
55
50
 
56
51
  Do **not** run with `--execute` if there is unmerged work that needs saving. The
57
52
  fast-forward phase skips on a dirty tree (safe), but the branches phase reaps any
@@ -15,7 +15,7 @@ description: >-
15
15
  After the implementation commits land and **before** the Story proceeds to
16
16
  close, run an explicit, **independent** eval pass that scores the change set
17
17
  computed once for this Story and injected into the critic — never one the
18
- critic re-derives (Story #4593) — against **each** `acceptance[]` item
18
+ critic re-derives — against **each** `acceptance[]` item
19
19
  individually. This is the acceptance gate
20
20
  the close-validation chain does not provide: that chain (lint / test / format /
21
21
  maintainability / coverage / crap) proves the code is *healthy*, not that it
@@ -30,7 +30,7 @@ mid-delivery, and evaluates the actual work product.
30
30
 
31
31
  ## Per round
32
32
 
33
- 1. **Eval pass — one verdict-owner per cluster (Story #4723).** Exactly
33
+ 1. **Eval pass — one verdict-owner per cluster.** Exactly
34
34
  **one** pass authors each cluster's verdict: the **fresh-context critic**
35
35
  when the ceremony routing below resolves `fresh` (a sub-agent via the
36
36
  `Agent` tool, *not* a continuation of your implementing turn — the
@@ -44,7 +44,7 @@ mid-delivery, and evaluates the actual work product.
44
44
  of the one authored verdict, not a second (or third) pass over the
45
45
  criteria.
46
46
 
47
- > **Sub-agent type + derived-level ceremony (Epic #4478, M7-B).** When
47
+ > **Sub-agent type + derived-level ceremony.** When
48
48
  > `delivery.routing.roleScopedAgents` is enabled (the **default**), dispatch
49
49
  > the critic with `subagent_type: acceptance-critic` — it boots on the
50
50
  > role-scoped [`acceptance-critic`](../../agents/acceptance-critic.md) context
@@ -57,8 +57,8 @@ mid-delivery, and evaluates the actual work product.
57
57
  > — the same signal `review-depth.js` resolves depth from, so the two
58
58
  > decisions cannot disagree. Derive it with `deriveChangeLevel` from
59
59
  > [`review-depth.js`](../../scripts/lib/orchestration/review-depth.js) over
60
- > the **change set your caller computed once** for this Story (Story #4593 —
61
- > `computeChangeSet` from
60
+ > the **change set your caller computed once** for this Story
61
+ > (`computeChangeSet` from
62
62
  > [`change-set.js`](../../scripts/lib/orchestration/change-set.js); see
63
63
  > [`deliver-story.md`](deliver-story.md) Step 2), then
64
64
  > resolve the ceremony per cluster with `resolveCeremonyForRisk` from
@@ -73,9 +73,10 @@ mid-delivery, and evaluates the actual work product.
73
73
  > full ceremony** (fail-safe). This chooses fresh-vs-inline **per cluster
74
74
  > only — it never changes the cluster count**.
75
75
  >
76
- > Story #4542 re-based this off the planner-authored risk verdict: a level
77
- > the plan asserted about itself was exactly the signal that could *reduce*
78
- > independent checking, and nothing verified it against the diff.
76
+ > The routing signal is deliberately **not** a planner-authored risk
77
+ > verdict: a level the plan asserted about itself was exactly the signal
78
+ > that could *reduce* independent checking, and nothing verified it
79
+ > against the diff.
79
80
  >
80
81
  > **Inline-critic path (low-level-routed OR nesting-absent harness).** The
81
82
  > verdict is authored **inline** whenever the risk router above resolves to
@@ -83,8 +84,8 @@ mid-delivery, and evaluates the actual work product.
83
84
  > a **fallback** on any harness that cannot spawn the fresh critic.
84
85
  > Dispatching the critic as a nested `Agent` is the fresh-context shape and
85
86
  > works on any harness that carries `Agent` into sub-agents (Claude Code ≥
86
- > 2.1.202; see [#2870](https://github.com/dsj1984/mandrel/issues/2870)). This
87
- > eval loop itself runs inside a Story delivery sub-agent, so the nested
87
+ > 2.1.202). This eval loop itself runs inside a Story delivery
88
+ > sub-agent, so the nested
88
89
  > critic sits at nesting depth 2. If the host does **not** support nested
89
90
  > `Agent` dispatch at that depth — the tool is absent, or a spawn attempt
90
91
  > returns an unsupported-capability error — do **not** stall the Story
@@ -104,7 +105,7 @@ mid-delivery, and evaluates the actual work product.
104
105
  - Inspects the **change set handed to it in its spawn context** — the one
105
106
  list computed above — and the Story's inline `acceptance[]` / `verify[]`
106
107
  arrays. Pass the file list explicitly when you dispatch the critic; it
107
- does not re-enumerate the diff for itself (Story #4593), so a commit
108
+ does not re-enumerate the diff for itself, so a commit
108
109
  landing mid-ceremony cannot leave the critic scoring a different change
109
110
  than the one that routed it.
110
111
  - **Runs the `verify[]` commands** and consumes their output as **required
@@ -112,7 +113,7 @@ mid-delivery, and evaluates the actual work product.
112
113
  optional advisory pre-flight — a criterion cannot be scored `met` without
113
114
  the supporting `verify[]` evidence where a `verify[]` command is relevant
114
115
  to it.
115
- - **Shares `lint` / `typecheck` evidence with close (Story #4250).** When a
116
+ - **Shares `lint` / `typecheck` evidence with close.** When a
116
117
  `verify[]` command is **byte-identical** to a close-validation gate — in
117
118
  practice only the cheap, command-identical `lint` and `typecheck` gates
118
119
  (`npm run lint` and the resolved `project.commands.typecheck`) — the
@@ -140,7 +141,7 @@ mid-delivery, and evaluates the actual work product.
140
141
  2. **Decide.** Run the gate against the verdict (the caller's Step 1a names the
141
142
  exact invocation — omit `--epic`). The gate **scores the single verdict
142
143
  the round's owner authored** — schema validation, round cap, decision —
143
- and never re-scores the criteria itself (Story #4723):
144
+ and never re-scores the criteria itself:
144
145
 
145
146
  ```bash
146
147
  node <main-repo>/.agents/scripts/acceptance-eval.js \
@@ -1,7 +1,7 @@
1
1
  # Audit lens core (shared contract)
2
2
 
3
- > **Single source of truth for every audit lens's shared machinery
4
- > (Story #4665).** Each `audit-<lens>.md` workflow references this file instead
3
+ > **Single source of truth for every audit lens's shared machinery.**
4
+ > Each `audit-<lens>.md` workflow references this file instead
5
5
  > of re-stating the blocks below. A lens carries only its own frontmatter, a
6
6
  > short preamble, its `{{changedFiles}}` fence, and its genuinely lens-specific
7
7
  > dimensions / detection batteries / applicability gates / boundary
@@ -53,9 +53,9 @@ envelope.
53
53
  ### Review depth (`depth`)
54
54
 
55
55
  `depth` is the thoroughness lever: `runCodeReview` derives it from the diff via
56
- [`review-depth.js`](../../scripts/lib/orchestration/review-depth.js) (Story #4542
57
- re-based it on that observable signal, so it takes no planner-authored input) and
58
- forwards it to every provider's `runReview` input.
56
+ [`review-depth.js`](../../scripts/lib/orchestration/review-depth.js) an
57
+ observable signal that takes no planner-authored input and forwards it to
58
+ every provider's `runReview` input.
59
59
 
60
60
  It is an **input-only** signal: it changes *how thorough* the review is, never
61
61
  the findings envelope (`{ status, severity, posted, report, halted,
@@ -98,7 +98,7 @@ The caller invokes the in-process code-review pipeline
98
98
  (`runCodeReview` in `.agents/scripts/lib/orchestration/code-review.js`)
99
99
  with the resolved `{ scope, ticketId, baseRef, headRef, depth }` envelope
100
100
  (`depth` defaults to `standard` when the caller omits it). The
101
- pluggable `ReviewProvider` adapter chain (Epic #2815) runs against the
101
+ pluggable `ReviewProvider` adapter chain runs against the
102
102
  diff `baseRef..headRef`, with the LLM-backed providers honoring `depth`
103
103
  (see **Review depth** above), and posts a structured summary to `[TICKET_ID]`.
104
104
  The pipeline will:
@@ -108,7 +108,7 @@ The pipeline will:
108
108
  - Run a focused lint check on the change set.
109
109
  - Post a structured summary report to the `[TICKET_ID]` issue.
110
110
 
111
- ### Step 1a — Story-scope local-lens pass (`scope: story` only, Epic #4405)
111
+ ### Step 1a — Story-scope local-lens pass (`scope: story` only)
112
112
 
113
113
  When `scope === 'story'`, the shared review spine
114
114
  [`runStoryReviewCore`](../../scripts/lib/orchestration/story-close/phases/review-core.js)
@@ -173,7 +173,7 @@ The diff under review is `baseRef..headRef`
173
173
  (`main..story-<storyId>`, or the configured base branch to the Story
174
174
  branch). The Story-scope local-lens pass (Step 1a) has already covered the
175
175
  local-tier concerns. Lens findings and pillar findings share the single
176
- `verification-results` comment this pass posts (Story #4411). The
176
+ `verification-results` comment this pass posts. The
177
177
  integration view here focuses on cross-cutting ripple within the Story and
178
178
  contract drift against the base branch. Look for:
179
179
 
@@ -257,9 +257,9 @@ prior baseline before merging.
257
257
  ## Step 4 — Produce Findings Report
258
258
 
259
259
  Findings are **persisted as a `verification-results` structured comment on
260
- the `[TICKET_ID]` issue** by `runCodeReview` (the unified findings contract of
261
- Story #4411; this single comment carries the
262
- Story-scope lens findings). The target ticket is the Story. The comment
260
+ the `[TICKET_ID]` issue** by `runCodeReview` (the unified findings contract
261
+ this single comment carries the Story-scope lens findings). The target
262
+ ticket is the Story. The comment
263
263
  is idempotent — re-runs replace the prior one — and its body includes
264
264
  severity-tier counts plus the full findings list so downstream workflows
265
265
  (notably the retro helper) can summarise blockers/high findings without
@@ -289,7 +289,7 @@ For every finding, provide:
289
289
  fix worked. Keep it tight (≤ 5 sentences); the sub-agent will read the
290
290
  surrounding code itself.
291
291
 
292
- ### The `## Fixed on-branch` section (Story #4399)
292
+ ### The `## Fixed on-branch` section
293
293
 
294
294
  Findings that Step 4.5 remediated on `[HEAD_REF]` MUST be rendered under a
295
295
  dedicated **`## Fixed on-branch`** heading, **not** in the severity groups
@@ -322,7 +322,7 @@ the executor: it decides, per finding, between a focused fix on
322
322
  `[HEAD_REF]` and leaving the finding on the `verification-results`
323
323
  structured comment for the operator.
324
324
 
325
- ### Resolve the remediation threshold (Story #4399)
325
+ ### Resolve the remediation threshold
326
326
 
327
327
  Read `delivery.codeReview.autoFixSeverity` from the resolved `.agentrc.json`
328
328
  (default **`medium`**; the resolver in