mandrel 2.24.0 → 2.26.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 (189) hide show
  1. package/.agents/agents/acceptance-critic.md +19 -21
  2. package/.agents/agents/auditor.md +16 -19
  3. package/.agents/agents/story-worker.md +41 -54
  4. package/.agents/audit-checklists/architecture.md +5 -1
  5. package/.agents/audit-checklists/baselines.md +21 -0
  6. package/.agents/audit-checklists/quality.md +3 -0
  7. package/.agents/docs/agentrc-reference.json +2 -1
  8. package/.agents/docs/configuration.md +2 -1
  9. package/.agents/docs/quality-gates.md +80 -18
  10. package/.agents/docs/workflows.md +4 -2
  11. package/.agents/instructions.md +1 -1
  12. package/.agents/rules/ci-remediation.md +68 -3
  13. package/.agents/schemas/agentrc.schema.json +6 -1
  14. package/.agents/schemas/audit-rules.json +15 -0
  15. package/.agents/schemas/baselines/audit-baselines-envelope.schema.json +242 -0
  16. package/.agents/schemas/baselines/baseline-envelope.schema.json +8 -0
  17. package/.agents/schemas/baselines/crap.schema.json +13 -1
  18. package/.agents/schemas/crap-report.schema.json +37 -0
  19. package/.agents/schemas/model-attribution.schema.json +4 -0
  20. package/.agents/scripts/acceptance-eval.js +124 -15
  21. package/.agents/scripts/audit-baselines.js +136 -0
  22. package/.agents/scripts/audit-labels-bootstrap.js +16 -95
  23. package/.agents/scripts/audit-to-stories.js +33 -3
  24. package/.agents/scripts/check-arch-cycles.js +12 -93
  25. package/.agents/scripts/check-baseline-drift.js +16 -3
  26. package/.agents/scripts/check-baselines.js +19 -3
  27. package/.agents/scripts/check-context-budget.js +95 -14
  28. package/.agents/scripts/check-cyclomatic.js +214 -0
  29. package/.agents/scripts/check-schema-references.js +392 -0
  30. package/.agents/scripts/check-test-temp-hygiene.js +121 -1
  31. package/.agents/scripts/check-workflow-timeouts.js +291 -0
  32. package/.agents/scripts/cleanup-repo-test-temp.js +7 -5
  33. package/.agents/scripts/deliver-light.js +3 -4
  34. package/.agents/scripts/deliver-recover.js +13 -0
  35. package/.agents/scripts/diagnose-friction.js +85 -19
  36. package/.agents/scripts/lib/audit-baselines/engine.js +177 -0
  37. package/.agents/scripts/lib/audit-baselines/gate-surface.js +63 -0
  38. package/.agents/scripts/lib/audit-baselines/headroom.js +72 -0
  39. package/.agents/scripts/lib/audit-baselines/hotspots.js +69 -0
  40. package/.agents/scripts/lib/audit-baselines/kinds.js +313 -0
  41. package/.agents/scripts/lib/audit-baselines/outliers.js +100 -0
  42. package/.agents/scripts/lib/audit-baselines/read.js +87 -0
  43. package/.agents/scripts/lib/audit-baselines/staleness.js +123 -0
  44. package/.agents/scripts/lib/audit-baselines/surface-entry.js +106 -0
  45. package/.agents/scripts/lib/audit-baselines/trend.js +125 -0
  46. package/.agents/scripts/lib/audit-baselines/weights.js +193 -0
  47. package/.agents/scripts/lib/audit-suite/index.js +0 -5
  48. package/.agents/scripts/lib/audit-suite/selector.js +9 -62
  49. package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +177 -0
  50. package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +1 -0
  51. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +35 -3
  52. package/.agents/scripts/lib/audit-to-stories/group-findings.js +20 -11
  53. package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +23 -9
  54. package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +9 -2
  55. package/.agents/scripts/lib/baseline-loader.js +0 -0
  56. package/.agents/scripts/lib/baseline-schema-registry.js +13 -1
  57. package/.agents/scripts/lib/baselines/diff-scope-cli.js +22 -160
  58. package/.agents/scripts/lib/baselines/duplication-scanner.js +27 -0
  59. package/.agents/scripts/lib/baselines/git-base.js +0 -0
  60. package/.agents/scripts/lib/baselines/kinds/crap.js +499 -57
  61. package/.agents/scripts/lib/baselines/preview-gates.js +58 -15
  62. package/.agents/scripts/lib/baselines/reader.js +10 -0
  63. package/.agents/scripts/lib/baselines/refresh-service.js +69 -11
  64. package/.agents/scripts/lib/baselines/scope.js +39 -90
  65. package/.agents/scripts/lib/baselines/writer.js +16 -7
  66. package/.agents/scripts/lib/changed-files.js +8 -1
  67. package/.agents/scripts/lib/cli-args.js +115 -1
  68. package/.agents/scripts/lib/close-validation/runner.js +70 -25
  69. package/.agents/scripts/lib/config-settings-schema-delivery.js +5 -0
  70. package/.agents/scripts/lib/crap-engine.js +124 -27
  71. package/.agents/scripts/lib/crap-method-identity.js +153 -0
  72. package/.agents/scripts/lib/crap-utils.js +86 -13
  73. package/.agents/scripts/lib/cyclomatic-ceiling.js +265 -0
  74. package/.agents/scripts/lib/env-loader.js +46 -16
  75. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -2
  76. package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +0 -2
  77. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +0 -2
  78. package/.agents/scripts/lib/findings/route-finding.js +123 -17
  79. package/.agents/scripts/lib/findings/severity.js +80 -2
  80. package/.agents/scripts/lib/git/cached-fetch.js +0 -0
  81. package/.agents/scripts/lib/git-utils.js +136 -80
  82. package/.agents/scripts/lib/import-graph.js +156 -0
  83. package/.agents/scripts/lib/label-constants.js +17 -0
  84. package/.agents/scripts/lib/observability/runtime-friction.js +17 -2
  85. package/.agents/scripts/lib/observability/source-classifier.js +175 -2
  86. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +110 -17
  87. package/.agents/scripts/lib/orchestration/ceremony-routing.js +17 -12
  88. package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +36 -6
  89. package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +5 -0
  90. package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +12 -1
  91. package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +8 -1
  92. package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +548 -0
  93. package/.agents/scripts/lib/orchestration/deliver-recover.js +2 -2
  94. package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +10 -5
  95. package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +39 -3
  96. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +71 -20
  97. package/.agents/scripts/lib/orchestration/light-backstop.js +20 -3
  98. package/.agents/scripts/lib/orchestration/light-escalation.js +82 -3
  99. package/.agents/scripts/lib/orchestration/light-suitability.js +103 -5
  100. package/.agents/scripts/lib/orchestration/plan-context.js +119 -66
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +31 -5
  102. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +216 -109
  103. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +61 -13
  104. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +79 -22
  105. package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +51 -20
  106. package/.agents/scripts/lib/orchestration/planning/authoring-context.js +70 -74
  107. package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +231 -0
  108. package/.agents/scripts/lib/orchestration/resolve-stories.js +18 -17
  109. package/.agents/scripts/lib/orchestration/retro-proposals.js +0 -0
  110. package/.agents/scripts/lib/orchestration/run-epilogue.js +12 -0
  111. package/.agents/scripts/lib/orchestration/run-scoped-config.js +276 -0
  112. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +41 -10
  113. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +125 -37
  114. package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +6 -6
  115. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +42 -38
  116. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +129 -21
  117. package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -1
  118. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +267 -125
  119. package/.agents/scripts/lib/orchestration/spec-budget.js +16 -5
  120. package/.agents/scripts/lib/orchestration/story-follow-ups.js +182 -95
  121. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +22 -0
  122. package/.agents/scripts/lib/orchestration/ticket-validator.js +5 -11
  123. package/.agents/scripts/lib/orchestration/ticketing/reads.js +4 -4
  124. package/.agents/scripts/lib/reserved-test-ids.js +77 -0
  125. package/.agents/scripts/lib/story-adjacency.js +3 -3
  126. package/.agents/scripts/lib/story-plan.js +137 -42
  127. package/.agents/scripts/lib/templates/decomposer-prompts.js +4 -4
  128. package/.agents/scripts/lib/test-runner-contract.js +134 -0
  129. package/.agents/scripts/lib/test-tiers.js +11 -2
  130. package/.agents/scripts/lib/ticket-body-sections.js +1 -1
  131. package/.agents/scripts/lib/util/concurrent-map.js +17 -0
  132. package/.agents/scripts/lib/util/parse-id-list.js +103 -0
  133. package/.agents/scripts/lib/util/poll-loop.js +18 -2
  134. package/.agents/scripts/lib/wave-runner/live-probe.js +29 -13
  135. package/.agents/scripts/lib/wave-runner/ready-set.js +254 -43
  136. package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +10 -13
  137. package/.agents/scripts/lib/workers/crap-worker.js +8 -13
  138. package/.agents/scripts/lib/workers/maintainability-report-worker.js +4 -10
  139. package/.agents/scripts/lib/workers/maintainability-worker.js +4 -10
  140. package/.agents/scripts/lib/workers/serve-worker-messages.js +35 -0
  141. package/.agents/scripts/lib/worktree/git-hooks.js +206 -0
  142. package/.agents/scripts/lib/worktree/lifecycle/creation.js +6 -0
  143. package/.agents/scripts/lib/worktree-manager.js +14 -0
  144. package/.agents/scripts/plan-run-epilogue.js +17 -5
  145. package/.agents/scripts/pr-watch-with-update.js +568 -213
  146. package/.agents/scripts/providers/github/tickets.js +33 -10
  147. package/.agents/scripts/provision-git-hooks.js +85 -0
  148. package/.agents/scripts/quality-preview.js +137 -28
  149. package/.agents/scripts/resolve-stories.js +4 -1
  150. package/.agents/scripts/run-coverage.js +86 -35
  151. package/.agents/scripts/run-lint.js +20 -0
  152. package/.agents/scripts/run-tests.js +36 -36
  153. package/.agents/scripts/single-story-close.js +34 -2
  154. package/.agents/scripts/single-story-confirm-merge.js +22 -6
  155. package/.agents/scripts/single-story-init.js +7 -0
  156. package/.agents/scripts/stories-wave-tick.js +308 -47
  157. package/.agents/scripts/story-plan.js +65 -9
  158. package/.agents/scripts/update-coverage-baseline.js +34 -4
  159. package/.agents/scripts/update-crap-baseline.js +42 -4
  160. package/.agents/scripts/update-duplication-baseline.js +209 -83
  161. package/.agents/scripts/update-maintainability-baseline.js +31 -4
  162. package/.agents/scripts/validate-docs-freshness.js +1 -0
  163. package/.agents/skills/core/diagnose-friction/SKILL.md +4 -1
  164. package/.agents/skills/core/gates-and-baselines/SKILL.md +17 -11
  165. package/.agents/skills/skills.index.json +2 -2
  166. package/.agents/templates/single-story-body.md +16 -8
  167. package/.agents/workflows/audit-architecture.md +69 -13
  168. package/.agents/workflows/audit-baselines.md +289 -0
  169. package/.agents/workflows/audit-navigability.md +5 -4
  170. package/.agents/workflows/audit-quality.md +26 -0
  171. package/.agents/workflows/audit-to-stories.md +30 -4
  172. package/.agents/workflows/deliver.md +92 -97
  173. package/.agents/workflows/helpers/acceptance-self-eval.md +47 -10
  174. package/.agents/workflows/helpers/audit-lens-core.md +25 -4
  175. package/.agents/workflows/helpers/code-quality-guardrails.md +9 -2
  176. package/.agents/workflows/helpers/deliver-digest.md +41 -21
  177. package/.agents/workflows/helpers/deliver-reference.md +95 -4
  178. package/.agents/workflows/helpers/deliver-story-reference.md +174 -52
  179. package/.agents/workflows/helpers/deliver-story.md +104 -119
  180. package/.agents/workflows/helpers/plan-reference.md +49 -5
  181. package/.agents/workflows/memory-consolidate.md +116 -0
  182. package/.agents/workflows/plan.md +62 -75
  183. package/README.md +13 -6
  184. package/docs/CHANGELOG.md +93 -0
  185. package/lib/cli/update.js +14 -11
  186. package/lib/cli/version-check.js +9 -1
  187. package/package.json +9 -4
  188. package/.agents/schemas/friction-event.schema.json +0 -56
  189. package/.agents/scripts/lib/feedback-loop/memory-freshness.js +0 -707
@@ -1,179 +1,164 @@
1
1
  ---
2
2
  description:
3
- Execute one Story end-to-end. Creates story-<id> from main, implements in a
4
- worktree (optional ## Slicing checkpoints), runs derived-level ceremony,
5
- opens a PR against main, and lands.
3
+ Execute one Story end-to-end: story-<id> from main, implemented in a worktree
4
+ (optional ## Slicing checkpoints), derived-level ceremony, PR against main.
6
5
  mandatoryReads: [deliver-digest.md]
7
6
  ---
8
7
 
9
8
  # /deliver-story #[Story ID]
10
9
 
11
- > **Lean spine.** Happy path + gate list; edge-case, recovery, and
12
- > reference detail lives in
13
- > [`deliver-story-reference.md`](deliver-story-reference.md) ("reference"
14
- > below); consult on demand. Invoked by [`/deliver`](../deliver.md).
15
- >
16
- > **Read [`deliver-digest.md`](deliver-digest.md) once, first.** It is the
17
- > one bundled read of what every delivery needs — dispatch decision, engine
18
- > invariants, the change-set/ceremony incantation, the acceptance-eval gate,
19
- > and the terminal-envelope contract — replacing the per-session re-reads of
20
- > the helper set and `story-deliver-terminal.schema.json`. The steps below
21
- > cite it as "digest § N" rather than restating it.
10
+ > **Lean spine.** Happy path + gate list; edge-case, recovery and reference
11
+ > detail lives in [`deliver-story-reference.md`](deliver-story-reference.md)
12
+ > ("reference" below). Invoked by [`/deliver`](../deliver.md).
13
+ > **Read [`deliver-digest.md`](deliver-digest.md) once, first** — the one
14
+ > bundled read every delivery needs. Steps cite it as "digest § N".
22
15
 
23
16
  ## Overview
24
17
 
25
- The **one** delivery engine in v2 — every Story (a **one-Story** run
26
- goes inline with inline critics; engine, gates, envelope byte-identical):
18
+ The **one** delivery engine in v2:
27
19
 
28
20
  ```text
29
- single-story-init.js → implement + commits → derived-level ceremony
30
- single-story-close.js (gates, push, PR → main, agent::closing)
21
+ single-story-init.js → implement + commits → derived-level ceremony → push
22
+ ──hand-off──▶ single-story-close.js (gates, PR → main, agent::closing)
31
23
  → CI watch + merge → single-story-confirm-merge.js (agent::done)
32
24
  ```
33
25
 
34
- An `Epic: #N` reference marks a v1 ticket — **stop** and re-plan. The
35
- engine's trait table is reference § Engine invariants. Prerequisites: a
36
- `type::story` issue, clean `gh auth status`, and `project.baseBranch` on
37
- local and `origin`.
26
+ An `Epic: #N` reference marks a v1 ticket — **stop** and re-plan. Engine
27
+ traits and prerequisites: reference § Engine invariants.
28
+
29
+ ## Who owns which step
30
+
31
+ Steps 0–2 belong to whoever implements. **Step 3 belongs to the orchestrator
32
+ that dispatched the work**, never to a spawned worker.
33
+
34
+ - **Inline dispatch** (a one-Story run — digest § 1): one session is both
35
+ roles and walks Steps 0→7, no hand-off.
36
+ - **Sub-agent dispatch**: the `story-worker` stops at Step 2.5 with the branch
37
+ pushed and returns a hand-off; the dispatching `/deliver` session runs Step 3
38
+ **in its own turn** and **serializes the tail — one close at a time across
39
+ the run**, even though implementation ran in parallel (reference § Step 3).
40
+
41
+ **A worker returning no terminal envelope is expected, not a failure.** Only
42
+ Step 3 mints one, so a hand-off is the normal sub-agent return. Never
43
+ re-dispatch the Story on it — the branch exists, and re-running Step 0 under
44
+ live work is how one Story gets two closes. Resume per § Recovery instead.
38
45
 
39
46
  ## Step 0 — Initialize (`single-story-init.js`)
40
47
 
41
- From the **main checkout**, **synchronously** with the maximum Bash
42
- timeout — the per-tree install can take minutes; never `run_in_background`:
48
+ From the **main checkout**, **synchronously** with the maximum Bash timeout —
49
+ the per-tree install can take minutes; never `run_in_background`:
43
50
 
44
51
  ```bash
45
52
  node .agents/scripts/single-story-init.js --story <storyId>
46
53
  ```
47
54
 
48
55
  Every script below documents its own flags — run it with `--help`.
49
- It validates `type::story`, **acquires the Story lease**
50
- (fails closed on a foreign assignee), fetches `origin`, seeds `story-<id>`
51
- from `baseBranch` (idempotent reuse), materializes a worktree, runs a
52
- guarded merged-`story-*` sweep, and flips `agent::executing` (reference
53
- § Step 0). Capture `workCwd` from the result envelope.
56
+ It validates `type::story`, takes the Story lease, seeds `story-<id>` from
57
+ `baseBranch`, materializes a worktree and flips `agent::executing` (reference
58
+ § Step 0). Capture `workCwd` from the envelope.
54
59
 
55
- **Land or block.** `remoteVerified: false` → flip
56
- `agent::blocked` quoting `remoteProbe.detail` and stop. Implementing outside
57
- the worktree/branch/PR path or committing to local `main` is forbidden
58
- close's push is the only sanctioned landing.
60
+ **Land or block.** `remoteVerified: false` → flip `agent::blocked` quoting
61
+ `remoteProbe.detail` and stop. Implementing outside the worktree/branch/PR path,
62
+ or committing to local `main`, is forbidden.
59
63
 
60
64
  **Step 0.5 — `cd "<workCwd>"`**, and prefix every path-based
61
- Edit/Write/Read with that absolute root — the `cd` alone does not scope
62
- those tools (reference § Worktree scope is not just the Bash cwd).
65
+ Edit/Write/Read with that absolute worktree root — the `cd` alone does not
66
+ scope those tools (reference § Worktree scope).
63
67
 
64
68
  ## Step 1 — Implementation
65
69
 
66
70
  One branch, one PR to `main`, commits against the inline `acceptance[]` /
67
- `verify[]` (and `## Spec`):
68
-
69
- 1. Read the Story body; the acceptance criteria are the contract. Docs are
70
- digest-first; read a caller-provided `checklistPath` before writing
71
- (reference § Step 1).
72
- 2. Implement. Walk any `## Slicing` rows as **intra-session checkpoints**
73
- (commit + flip each row) — never sibling tickets.
74
- 3. Commit on the Story branch; iterate with quick advisory gates
75
- (`typecheck`, `lint`, scoped tests) the full close chain runs in
76
- Step 3.
77
- 4. Run the **full test command** once in the worktree (`npm test`) **before
78
- Step 1a** — repo-invariant guards outside the Story's scoped greps are
79
- the failure class that bounces deliveries. Fix and commit first.
80
- 5. Run the self-eval loop (Step 1a).
71
+ `verify[]` and `## Spec`:
72
+
73
+ 1. Read the Story body; its acceptance criteria are the contract. Docs are
74
+ digest-first; read a caller-provided `checklistPath` first, and walk any
75
+ `## Slicing` rows as **intra-session checkpoints** (reference § Step 1).
76
+ 2. Implement and commit on the Story branch, iterating with quick advisory
77
+ gates (`typecheck`, `lint`, scoped tests) — the full chain runs in Step 3.
78
+ 3. Run `npm test` once in the worktree **before Step 1a**: repo-invariant
79
+ guards outside the Story's scoped greps are the failure class that bounces
80
+ deliveries. Fix and commit first, then run the self-eval loop.
81
81
 
82
82
  ### Step 1a — Bounded acceptance self-eval loop (**required**)
83
83
 
84
84
  Run the loop and score it with `acceptance-eval.js` — **digest § 4** carries
85
- the invocation and the proceed / redraft / block contract; per-round critic
86
- mechanics live in the single-homed include
87
- [`acceptance-self-eval.md`](acceptance-self-eval.md).
88
-
89
- **`proceed`** → Step 2 then Step 3. **`block`** → **do not close**: post a
90
- `friction` comment and flip `agent::blocked` — commands and the
91
- `evidence-gate.js --standalone` evidence-share mechanic: reference
92
- § Step 1a.
85
+ the invocation and the proceed / redraft / block contract; per-round mechanics
86
+ live in [`acceptance-self-eval.md`](acceptance-self-eval.md). **`proceed`** →
87
+ Step 2. **`block`** → **do not close**: post a `friction` comment and flip
88
+ `agent::blocked` (reference § Step 1a).
93
89
 
94
90
  ## Step 2 — Ceremony (profile + derived level)
95
91
 
96
- Ceremony is `delivery.routing.ceremonyProfile` × the **derived change
97
- level** — never a planner-authored verdict. **Digest § 3** is the
98
- incantation: compute the change set once, derive the level, resolve
99
- fresh-vs-inline critics with `ceremony-routing.js`; a lite Story runs
100
- inline regardless (routing edge cases: reference § Step 2). Hard gates always
101
- run in Step 3 — the derived level never disables them; do **not** pre-run the
102
- close chain here.
92
+ Ceremony is `delivery.routing.ceremonyProfile` × the **derived change level**,
93
+ never a planner-authored verdict. **Digest § 3** is the incantation (change set
94
+ once, derive the level, resolve critics with `ceremony-routing.js`); edge cases
95
+ are reference § Step 2. Hard gates always run in Step 3 — the derived level
96
+ never disables them; do **not** pre-run the chain here.
97
+
98
+ ### Step 2.5 — Push and hand off (sub-agent dispatch only)
99
+
100
+ Push `story-<storyId>` to `origin` and confirm the remote ref moved. Return the
101
+ hand-off — Story id, `workCwd`, branch, pushed head SHA, self-eval verdict,
102
+ `verify[]` evidence — then stop. Do not open the PR; do not compose a terminal
103
+ envelope. An inline run skips this.
103
104
 
104
105
  ## Step 3 — Close and land (`single-story-close.js`)
105
106
 
107
+ **The orchestrator's step** (§ Who owns which step), run in the **foreground**,
108
+ serialized against sibling Stories:
109
+
106
110
  ```bash
107
111
  node <main-repo>/.agents/scripts/single-story-close.js --story <storyId> --cwd <main-repo>
108
112
  ```
109
113
 
110
114
  **The whole delivery tail** — gates, PR, merge wait, `agent::done` flip,
111
- post-land tail in one process. Run it and **branch on the terminal envelope's
112
- `status`** per the table in **digest § 5** (`landed` Step 7; `pending` → run
113
- `nextCommand`; `blocked`/`checks-failed` Step 4; `failed` diagnose and
114
- re-run). Gate output is captured to
115
- `temp/orchestration/close-gates-<storyId>.log` a clean run prints a digest
116
- line, a red gate replays its tail inline.
117
-
118
- Internals (gate order, base-sync, auto-merge arming), the merge-wait
119
- budgets, the slow-CI **async** confirm mode (launch the `pending`
120
- envelope's `nextCommand` as **background** Bash, never a foreground
121
- poll), the `autoMerge` policy, and every close flag: reference
122
- § Step 3 Merge wait, async mode, and flags.
123
-
124
- ## Steps 4–6 — Recovery router (**recovery-only**)
125
-
126
- A `landed` envelope means everything ran — go straight to Step 7. Enter a
127
- recovery path **only** when the envelope routes you there:
128
-
129
- - **`blocked` / `checks-failed`** → fix, push a new commit (auto-merge stays
130
- armed), resume via `nextCommand`; triage per
131
- [`rules/ci-remediation.md`](../../rules/ci-remediation.md). The watch is
132
- internally blocking — never end a turn with prose and an unconfirmed
133
- merge. Reference § Step 4.
134
- - **`pending`** → run `nextCommand` (`single-story-confirm-merge.js`) until
135
- resolved. Reference § Step 5.
136
- - **`tail.statusResync: false`** → reference § Step 5.5;
137
- **`tail.refCleanup` / `tail.baseFastForward: false`** → reference § Step 6.
138
-
139
- ## Step 7 — Return contract (**required as a sub-agent**) {#return-contract}
140
-
141
- End your turn by relaying the validated envelope close emits between its
115
+ post-land tail in one process. Never background it, never delegate it to a
116
+ child, and never end your turn while it is still running: "close is running"
117
+ is not a return value. Branch on the envelope's `status` per **digest § 5**
118
+ (`landed` Step 7; `pending` → run `nextCommand`; `blocked`/`checks-failed`
119
+ → Step 4; `failed` diagnose, re-run). Gate output is captured.
120
+
121
+ Internals, merge-wait budgets, the slow-CI **async** confirm mode, the
122
+ `autoMerge` policy and every close flag: reference § Step 3.
123
+
124
+ ## Step 7 Return contract {#return-contract}
125
+
126
+ Relay the validated envelope close emits between its
142
127
  `--- STORY DELIVER TERMINAL ---` markers — never free-form prose, never a
143
- hand-composed object. Statuses, exits, and required fields: **digest § 5**
144
- (whose SSOT is the shipped
145
- [schema](../../schemas/story-deliver-terminal.schema.json)).
146
- `pending` is the only sanctioned no-merge ending, returned only when your own
147
- budget is exhausted. Reference § Step 7.
128
+ hand-composed object. Statuses, exits and fields: **digest § 5** (SSOT: the
129
+ shipped [schema](../../schemas/story-deliver-terminal.schema.json)).
130
+ `pending` is the only sanctioned no-merge ending.
148
131
 
149
- ## Recovering a stranded Story {#recover}
132
+ ## Steps 4–6 Recovery (**recovery-only**) {#recover}
133
+
134
+ A `landed` envelope means everything ran — go to Step 7. Enter recovery **only**
135
+ when the envelope routes you there; procedures are reference §§ Step 4–6.
136
+ Two rules the spine keeps: a red **disarms auto-merge**,
137
+ so only a green on a NEW head SHA re-arms it — a re-run is refused; fix at source
138
+ and push ([`rules/ci-remediation.md`](../../rules/ci-remediation.md)). And a
139
+ `tail.*: false` degrades the report, never the land.
140
+
141
+ **Watch exit codes** — `pr-watch-with-update.js` exits 0 green, 1 only when a
142
+ required check genuinely failed (or the PR is unreadable), 2 slow-but-not-red:
143
+ still-running, unresolved, **or** `notYetStarted` — no required context attached
144
+ inside `attachWindowMs`. Never route a 2 onto the red path; nothing is broken
145
+ and no digest exists to read.
150
146
 
151
147
  **Lost envelope first: read it off disk.** Close persists each to
152
148
  `temp/orchestration/story-deliver-terminal-<storyId>.json`; branch on it per
153
- digest § 5. Otherwise (killed run, re-run refusal, merged-but-label-stale)
154
- do not guess — probe **read-only** with
149
+ digest § 5. Otherwise do not guess probe **read-only** with
155
150
  `node .agents/scripts/deliver-recover.js --story <storyId>`; it prints the
156
151
  **one** next command with its evidence, never a menu. A live close answers
157
152
  `close-in-flight`: wait, never re-init underneath it.
158
153
 
159
154
  ## Idempotence & constraints
160
155
 
161
- Every script no-ops safely on re-run (init re-prints `workCwd`; close and
162
- confirm-merge short-circuit on a closed / `agent::done` Story; the PR probe
163
- reuses an open PR).
164
-
165
- - **Never** push the Story branch directly to `main` — the PR is the only
166
- merge surface.
167
- - **Always** prefix path-based tools with the absolute `workCwd` root
168
- (Step 0.5); close's wrong-tree guard is a backstop.
169
- - **Report state, not process** — mirror the close envelope's fields; no
170
- step narration.
171
- - Drive every `agent::*` transition through
172
- `update-ticket-state.js --ticket <id> --state <state>`.
156
+ Every script no-ops safely on re-run (reference § Idempotence). **Never** push
157
+ the Story branch to `main` the PR is the only merge surface. Report state,
158
+ not process. Drive `agent::*` through
159
+ `update-ticket-state.js --ticket <id> --state <state>`.
173
160
 
174
161
  ## See also
175
162
 
176
- - [`deliver-digest.md`](deliver-digest.md) — the one bundled framework read.
177
- - [`/deliver`](../deliver.md) — unified entry point.
178
- - [`deliver-story-reference.md`](deliver-story-reference.md) — all on-demand
179
- detail.
163
+ [`deliver-digest.md`](deliver-digest.md), [`/deliver`](../deliver.md),
164
+ [`deliver-story-reference.md`](deliver-story-reference.md).
@@ -36,6 +36,22 @@ whole surface exists to remove.
36
36
  Mixed ids and prose in one invocation is a **hard error**: refuse and ask which
37
37
  was meant, rather than guessing a mode and doing the wrong work.
38
38
 
39
+ ## Default-single split policy — what the seam means
40
+
41
+ The spine's two escape hatches from N=1 are narrow on purpose:
42
+
43
+ - **Near-zero overlap** — the pieces touch disjoint files and neither's
44
+ acceptance criteria can be scored without the other having landed.
45
+ - **Architectural seam** — different deployables, or a migration and its
46
+ consumer: work that cannot share one branch and one PR without one half
47
+ sitting unverifiable behind the other.
48
+
49
+ Everything else is one Story with `## Slicing` checkpoints. When N>1 does
50
+ apply, **every acceptance criterion belongs to exactly one Story** —
51
+ `assertAcceptancePartition` refuses a split whose criteria repeat across
52
+ siblings, because a verbatim-shared criterion is the signature of coupled work
53
+ cut in half rather than genuinely separable work.
54
+
39
55
  ## Unknown triage — AFK vs HITL
40
56
 
41
57
  Every open question interrogation surfaces is triaged by **who can resolve
@@ -98,6 +114,14 @@ Resume `/plan` at step 2 (Author) **in this same session** — the interrogation
98
114
  is still valid and re-paying for it buys nothing. This bounce-back is not an
99
115
  escalation.
100
116
 
117
+ **Under `--yes` the offer is recorded and planning proceeds** — it is *never*
118
+ auto-downgraded to light. An unattended run has nobody to confirm the reroute,
119
+ and a suggestion is not a confirmation. The same rule governs unknown triage
120
+ unattended: AFK unknowns are still researched, but no free-form operator
121
+ question is asked — each HITL unknown lands in Key Assumptions marked a
122
+ decision-made-by-default, so the record shows what was decided for the operator
123
+ rather than pretending it was decided with them.
124
+
101
125
  Escalation in the *other* direction — an over-scope prompt on the light path —
102
126
  is terminal and requires a fresh session. The rule that separates the two, and
103
127
  why it must not be flattened into symmetry:
@@ -191,12 +215,14 @@ ceilings on `STORY_SHAPE_CEILINGS` in
191
215
  against the repo before overriding one (authoring `creates` for a file
192
216
  that exists at base is a validator rejection). The persist gates stay
193
217
  authoritative: they probe the base branch ref, not the working tree.
194
- - **Keep `## Spec` near contract-level prose.** Persist emits an
195
- **advisory** warning past ~250 words (`SPEC_SOFT_WORD_BUDGET`) it never
196
- fails the persist, but it is the nudge toward a contract-level
218
+ - **Keep `## Spec` near contract-level prose.** **Aim for ~250 words; an
219
+ advisory warning fires past 350** (`SPEC_SOFT_WORD_BUDGET`). Two numbers,
220
+ two jobs: ~250 is the authoring target the nudge toward a contract-level
197
221
  Spec (interfaces, invariants, load-bearing constraints; no per-file
198
- behavior narration). The hard fail-closed ceiling (~1500 tokens,
199
- `spec-spill.js`) is unchanged.
222
+ behavior narration) while 350 is the slacker threshold at which persist
223
+ actually warns, so the warning marks a real outlier instead of ordinary
224
+ variance. Neither fails the persist. The hard fail-closed ceiling
225
+ (~1500 tokens, `spec-spill.js`) is unchanged.
200
226
 
201
227
  A faithfully-filled skeleton — placeholders replaced, pre-resolved entries
202
228
  kept, tags valid — passes the persist ticket validators with no
@@ -289,11 +315,29 @@ output shape standalone. When the kill-switch is off
289
315
  (`roleScopedAgents: false`) or the host cannot spawn at this depth, fall back
290
316
  to a generic sub-agent and hand it the same charter (the `consolidation` /
291
317
  `pre-mortem` definitions in [`plan-critic.md`](../../agents/plan-critic.md)).
318
+ **When both critics fire, dispatch them in a single turn.** Consolidation and
319
+ pre-mortem read the same immutable draft, share no write path, and neither
320
+ consumes the other's verdict — the textbook independent fan-out of
321
+ [`parallel-tooling.md`](parallel-tooling.md) Rule 3. Issue both `Agent` calls
322
+ together in one assistant turn rather than awaiting the first verdict before
323
+ spawning the second; serialized critics double the round's wall clock and buy
324
+ nothing, because you fold both verdicts into the same re-author round anyway.
325
+
292
326
  Either way the critic is **maker-blind**: hand it the draft artifacts
293
327
  (`stories.json`, and `techspec.md` when present) — never the authoring
294
328
  transcript or the reasons the planner believed its own draft is sound. A
295
329
  critic that reads the maker's case grades the case, not the draft.
296
330
 
331
+ ## What `--dry-run` actually gates
332
+
333
+ `plan-persist.js --dry-run` is the same command with GitHub writes suppressed,
334
+ and every gate runs before the first `createIssue` would fire — the validator,
335
+ the body parse, the DAG, the capacity and Spec-budget ceilings, the
336
+ reachability check, the split and supersede partitions, and the Tech Spec fold.
337
+ That is the whole point of running it first: a dry run that comes back clean
338
+ has already paid for every deterministic refusal, so the real persist has
339
+ nothing left to discover except network failure.
340
+
297
341
  ## Ready means fully persisted
298
342
 
299
343
  `agent::ready` is the **terminal** step, not part of the creating POST.
@@ -0,0 +1,116 @@
1
+ ---
2
+ description: >-
3
+ Attended consolidation pass over this project's agent memory pool — merge
4
+ duplicates, verify claims against the current tree, prune with operator
5
+ confirmation, rewrite the index, and stamp the pool so the /plan advisory
6
+ goes quiet.
7
+ ---
8
+
9
+ # /memory-consolidate [--dry-run]
10
+
11
+ Agent memory drifts as the codebase moves: a workaround gets fixed, a budget
12
+ changes, two sessions save the same lesson twice. This is the sweep that
13
+ corrects it — and the **only** sanctioned writer of the memory pool outside a
14
+ session's own point-of-write corrections.
15
+
16
+ **Attended by contract.** Mandrel ships the trigger, the grounding and the
17
+ receipt; it never mutates the operator's personal memory store unsupervised.
18
+ Nothing here runs on a schedule, and no step deletes a file before Gate #2.
19
+
20
+ ## Step 0 — Resolve the pool
21
+
22
+ `MANDREL_MEMORY_DIR` wins outright; otherwise the pool is
23
+ `~/.claude/projects/<cwd-slug>/memory/`, where `<cwd-slug>` is the absolute
24
+ working directory with every `/` and `.` replaced by `-`.
25
+
26
+ Report the resolved path and the entry count. **No pool → say so in one line
27
+ and stop** — an absent substrate is a clean no-op, never an error, and never a
28
+ reason to create one.
29
+
30
+ Each project (and each worktree) has its own pool: consolidate the pool of the
31
+ checkout you are in, and never reach across into another.
32
+
33
+ ## Step 1 — Read the pool
34
+
35
+ Read `MEMORY.md` and every `*.md` entry. Group them by subject so duplicates
36
+ and supersessions surface together. Do not judge an entry from its index line —
37
+ the index is a pointer, the file is the claim.
38
+
39
+ ## Step 2 — Classify each entry
40
+
41
+ Verify before you keep. Run `ls` / `grep` against the **current tree** for the
42
+ paths, flags, budgets and gate names an entry cites; re-measure a number rather
43
+ than trusting it (`wc -c` a file whose byte budget is quoted).
44
+
45
+ | Verdict | Means | Action |
46
+ | --- | --- | --- |
47
+ | `fresh` | Claims re-confirmed against the tree | Leave byte-identical |
48
+ | `correct` | Core lesson holds, a detail has moved | Rewrite the detail in place, keep the entry |
49
+ | `duplicate` | Same lesson as another entry | Merge into the richer one, propose the thinner for pruning |
50
+ | `superseded` | The thing it warns about is fixed or retired | Strike the claim, keep the correction visible |
51
+ | `dead` | Subject no longer exists at all | Propose for pruning |
52
+
53
+ **A closed issue is the subject of a retrospective, never evidence of
54
+ staleness.** These pools are largely delivery write-ups — "delivered this
55
+ Story", "fixed by that PR". The referenced issue being closed is what the
56
+ memory is *about*: the normal, healthy shape. A retired predecessor of this
57
+ workflow marked exactly that pattern stale, which is why it no longer exists.
58
+ Use `github.owner` / `github.repo` from `.agentrc.json` when an issue
59
+ genuinely needs probing, and treat an unreachable probe as unknown — never
60
+ as dead.
61
+
62
+ Prefer `correct` over `dead`. A rewritten entry keeps hard-won context; a
63
+ deleted one costs a future session the same mistake.
64
+
65
+ ## Step 3 — Gate #1: present the plan
66
+
67
+ Write the full proposal to `temp/memory/consolidation-<date>.md` — per entry:
68
+ verdict, evidence, and the exact edit or merge proposed. Summarize inline:
69
+ counts per verdict and the specific prune candidates by name.
70
+
71
+ **STOP.** Do not edit until the operator responds.
72
+
73
+ ## Step 4 — Apply the edits
74
+
75
+ On confirmation, apply the `correct`, `duplicate` and `superseded` rewrites.
76
+ Preserve each entry's frontmatter contract (`name`, `description`, `metadata`)
77
+ and keep `[[wiki-link]]` references resolvable — a merge that orphans a link
78
+ has moved the problem, not fixed it.
79
+
80
+ ## Step 5 — Gate #2: confirm every deletion
81
+
82
+ **Deletion is never implied by Gate #1.** Name each file proposed for pruning
83
+ with its one-line reason, and offer **mark-vs-delete**: marking the claim
84
+ superseded in place is the default and always available. Wait for an explicit
85
+ yes; delete only what the operator names. Silence is not consent.
86
+
87
+ ## Step 6 — Rewrite the index and stamp
88
+
89
+ Rewrite `MEMORY.md` so it holds exactly one pointer line per surviving entry —
90
+ title, link, hook. It is loaded into context every session, so it carries
91
+ pointers only, never memory content.
92
+
93
+ Then write the receipt to `.consolidation-stamp.json` in the pool root:
94
+
95
+ ```json
96
+ { "lastConsolidatedAt": "<ISO-8601 timestamp>" }
97
+ ```
98
+
99
+ The `/plan` Phase 0 advisory reads this file; until it is written, the nudge
100
+ keeps firing. Write it **only** after Gate #2 — the stamp asserts an operator
101
+ reviewed the pass, so writing it early makes it a lie.
102
+
103
+ Close with counts: entries read, corrected, merged, pruned, and the new total.
104
+
105
+ ## Constraints
106
+
107
+ - `--dry-run` runs Steps 0–3 and stops: the report is written, nothing mutates.
108
+ - Never delete an entry the operator did not name. Never write the stamp on a
109
+ dry run or a declined gate.
110
+ - Never invent memories here — this pass corrects and prunes what sessions
111
+ wrote; new memories come from the sessions that learned them.
112
+
113
+ ## See also
114
+
115
+ [`/plan`](plan.md) (surfaces the advisory at its Gate #1),
116
+ [`/deliver`](deliver.md) (point-of-write corrections as work lands).