mandrel 1.91.0 → 1.92.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 (109) hide show
  1. package/.agents/README.md +5 -5
  2. package/.agents/docs/SDLC.md +75 -107
  3. package/.agents/docs/configuration.md +1 -1
  4. package/.agents/docs/quality-gates.md +8 -7
  5. package/.agents/docs/workflows.md +4 -10
  6. package/.agents/instructions.md +2 -2
  7. package/.agents/schemas/agentrc.schema.json +1 -1
  8. package/.agents/schemas/lifecycle/README.md +2 -1
  9. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  10. package/.agents/schemas/risk-verdict.schema.json +14 -1
  11. package/.agents/scripts/README.md +0 -46
  12. package/.agents/scripts/analyze-execution.js +76 -1
  13. package/.agents/scripts/check-doc-links.js +3 -0
  14. package/.agents/scripts/check-workflow-cli-lint.js +208 -0
  15. package/.agents/scripts/epic-audit-recheck.js +1 -1
  16. package/.agents/scripts/epic-plan-clarity.js +16 -6
  17. package/.agents/scripts/epic-plan-decompose.js +37 -59
  18. package/.agents/scripts/epic-plan-healthcheck.js +39 -6
  19. package/.agents/scripts/epic-plan-spec.js +41 -168
  20. package/.agents/scripts/epic-reconcile.js +7 -1
  21. package/.agents/scripts/lib/Logger.js +4 -4
  22. package/.agents/scripts/lib/audit-suite/index.js +4 -5
  23. package/.agents/scripts/lib/audit-suite/runner.js +6 -4
  24. package/.agents/scripts/lib/audit-suite/selector.js +2 -3
  25. package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
  26. package/.agents/scripts/lib/command-header.js +20 -0
  27. package/.agents/scripts/lib/config/github.js +1 -3
  28. package/.agents/scripts/lib/config-settings-schema.js +4 -3
  29. package/.agents/scripts/lib/degraded-mode.js +1 -1
  30. package/.agents/scripts/lib/label-constants.js +18 -3
  31. package/.agents/scripts/lib/label-taxonomy.js +14 -3
  32. package/.agents/scripts/lib/mutation/baseline-snapshot.js +7 -6
  33. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +18 -8
  34. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +3 -4
  35. package/.agents/scripts/lib/orchestration/docs-digest.js +2 -2
  36. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +4 -0
  37. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +22 -12
  38. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +6 -1
  39. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +18 -2
  40. package/.agents/scripts/{lifecycle-diff.js → lib/orchestration/lifecycle/ledger-diff.js} +10 -76
  41. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +1 -1
  42. package/.agents/scripts/lib/orchestration/plan-context.js +510 -0
  43. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +177 -0
  44. package/.agents/scripts/lib/orchestration/plan-metrics.js +445 -0
  45. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +359 -0
  46. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +127 -0
  47. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +978 -0
  48. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +191 -0
  49. package/.agents/scripts/lib/orchestration/plan-reachability.js +160 -0
  50. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +3 -3
  51. package/.agents/scripts/lib/orchestration/planning-risk.js +1 -1
  52. package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
  53. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +1 -1
  54. package/.agents/scripts/lib/orchestration/ticketing/reads.js +11 -2
  55. package/.agents/scripts/lib/plan-phase-cleanup.js +16 -0
  56. package/.agents/scripts/lib/presentation/manifest-persistence.js +2 -3
  57. package/.agents/scripts/lib/templates/spec-author-prompts.js +74 -0
  58. package/.agents/scripts/plan-context.js +186 -0
  59. package/.agents/scripts/plan-critics.js +227 -0
  60. package/.agents/scripts/plan-persist.js +383 -0
  61. package/.agents/scripts/pr-watch-with-update.js +8 -7
  62. package/.agents/scripts/run-lint.js +10 -11
  63. package/.agents/scripts/story-plan.js +19 -7
  64. package/.agents/scripts/sync-claude-commands.js +10 -5
  65. package/.agents/skills/core/knowledge-transfer/SKILL.md +11 -7
  66. package/.agents/workflows/audit-documentation.md +5 -7
  67. package/.agents/workflows/audit-lighthouse.md +1 -0
  68. package/.agents/workflows/audit-security.md +1 -0
  69. package/.agents/workflows/audit-to-stories.md +16 -5
  70. package/.agents/workflows/git-deliver.md +76 -243
  71. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  72. package/.agents/workflows/helpers/code-review.md +7 -6
  73. package/.agents/workflows/helpers/deliver-epic.md +5 -4
  74. package/.agents/workflows/helpers/plan-epic-reference.md +109 -96
  75. package/.agents/workflows/helpers/plan-epic.md +246 -999
  76. package/.agents/workflows/helpers/plan-story.md +14 -14
  77. package/.agents/workflows/helpers/scope-triage-gate.md +6 -4
  78. package/.agents/workflows/helpers/single-story-deliver.md +5 -4
  79. package/.agents/workflows/helpers/worktree-lifecycle.md +9 -7
  80. package/.agents/workflows/mandrel-update.md +144 -466
  81. package/.agents/workflows/plan.md +73 -143
  82. package/docs/CHANGELOG.md +13 -0
  83. package/lib/cli/registry.js +21 -3
  84. package/package.json +1 -1
  85. package/.agents/schemas/loop-unit.schema.json +0 -70
  86. package/.agents/scripts/assert-branch.js +0 -81
  87. package/.agents/scripts/check-loop-units.js +0 -204
  88. package/.agents/scripts/detect-merges.js +0 -111
  89. package/.agents/scripts/git-pr-quality-gate.js +0 -205
  90. package/.agents/scripts/git-rebase-and-resolve.js +0 -234
  91. package/.agents/scripts/hierarchy-gate.js +0 -192
  92. package/.agents/scripts/hydrate-context.js +0 -179
  93. package/.agents/scripts/lib/loop-units/validate-loop-unit.js +0 -197
  94. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/cli.js +0 -167
  95. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +0 -69
  96. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +0 -86
  97. package/.agents/scripts/loc-delta.js +0 -205
  98. package/.agents/scripts/render-manifest.js +0 -143
  99. package/.agents/scripts/run-audit-suite.js +0 -97
  100. package/.agents/scripts/select-audits.js +0 -155
  101. package/.agents/scripts/update-mutation-baseline.js +0 -189
  102. package/.agents/workflows/explain.md +0 -118
  103. package/.agents/workflows/git-merge-pr.md +0 -377
  104. package/.agents/workflows/helpers/epic-plan-decompose.md +0 -22
  105. package/.agents/workflows/helpers/epic-plan-spec.md +0 -22
  106. package/.agents/workflows/loops/README.md +0 -65
  107. package/.agents/workflows/loops/fix-failing-tests.md +0 -74
  108. package/.agents/workflows/loops/nightly-audit.md +0 -81
  109. package/.agents/workflows/loops/watch-ci.md +0 -68
@@ -1,1038 +1,285 @@
1
1
  ---
2
2
  description:
3
- Orchestrates end-to-end Epic planning (Tech Spec, Acceptance Spec, and
4
- Work Breakdown) for a GitHub Epic.
3
+ Epic planning path invoked by /plan — three steps (interrogate author
4
+ persist) that produce the Epic body's Tech Spec + Acceptance Table managed
5
+ sections and the Story backlog (or a single-delivery routing marker).
5
6
  ---
6
7
 
7
8
  # helpers/plan-epic — Epic planning path (invoked by /plan)
8
9
 
9
- ## Role
10
+ ## Shape
10
11
 
11
- Director / Architect
12
+ Three steps replace the retired 12-phase pipeline (Epic #4474). All GitHub
13
+ reads concentrate in `plan-context.js` (step 1), all GitHub writes in
14
+ `plan-persist.js` (step 3); the authoring middle reads one JSON envelope and
15
+ writes 2–4 files. Exactly two HITL STOP gates: **gate #1** at the exit of
16
+ interrogate, **gate #2** risk-routed before persist. Every deterministic
17
+ validator of the old pipeline survives inside the persist CLI.
12
18
 
13
- ## Context
19
+ ## Constraints
14
20
 
15
- You are the master orchestrator for the v5 Epic-Centric ticketing pipeline. Your
16
- goal is to transform a high-level Epic into a fully decomposed, ready-to-execute
17
- backlog of Stories.
21
+ - Do not modify existing issues without explicit permission. Every GitHub
22
+ mutation runs inside `plan-persist.js` or `epic-plan-clarity.js` for a
23
+ gate-#1-approved body refinement — never via ad-hoc `gh issue edit`.
24
+ - Never bypass a persist rejection by editing GitHub directly: fix the named
25
+ artifact and re-run the CLI (one targeted amend pass, below).
18
26
 
19
- `/plan` is the unified planning entry point. This file (`helpers/plan-epic.md`)
20
- is the single authoritative home for Phase 7 (spec) and Phase 8 (decompose) —
21
- it carries the full step-by-step procedure for both and delegates only the
22
- authoring middle of each to the
23
- [`epic-plan-spec-author`](../../skills/core/epic-plan-spec-author/SKILL.md) /
24
- [`epic-plan-decompose-author`](../../skills/core/epic-plan-decompose-author/SKILL.md)
25
- skills. It runs both phases sequentially with a human confirmation gate
26
- between them. The Epic ID is the single positional argument.
27
+ ## Step 1 Interrogate
27
28
 
28
- > **Thin pointers, not duplicate procedures.** [`helpers/epic-plan-spec.md`](epic-plan-spec.md)
29
- > and [`helpers/epic-plan-decompose.md`](epic-plan-decompose.md) used to
30
- > restate Phase 7/8 as their own inline step lists a drifted, pre-skill
31
- > pattern now that authoring is delegated to the two skills above. Both files
32
- > are now thin pointers back to this one; do not resurrect inline step lists
33
- > in either.
29
+ Goal: shared understanding and a confirmed planning basis. Grilling
30
+ discipline: ask questions **one at a time** — asking multiple questions at
31
+ once is bewildering. If a **fact** can be found by exploring the codebase,
32
+ look it up rather than asking; the **decisions** are the operator's put
33
+ each one to them. Do not proceed to authoring until shared understanding is
34
+ confirmed (gate #1).
34
35
 
35
- As of v5.6, planning artifacts (Tech Spec, ticket decomposition) are
36
- authored **directly by you, the host LLM** — no external Gemini / Anthropic /
37
- OpenAI API is called. The Node scripts are deterministic GitHub I/O wrappers
38
- that (a) emit the authoring context you need and (b) validate and persist the
39
- artifacts you author.
36
+ ### Ideation entry (`--idea "<seed>"` or no argument)
40
37
 
41
- ## Constraint
42
-
43
- - Do not modify existing issues without explicit permission.
44
- - Wait for user validation before migrating to Phase 8 when
45
- `planningRisk.requiresReview` is true (or the operator passes
46
- `--force-review`). Low-risk Epics auto-proceed after spec validation.
47
- See [SDLC § Adaptive planning risk routing](../../docs/SDLC.md#adaptive-planning-risk-routing)
48
- for the full envelope shape and the planner-selected
49
- `acceptance::n-a` route.
50
- - Delegate Phase 7 and Phase 8 authoring to the
51
- [`epic-plan-spec-author`](../../skills/core/epic-plan-spec-author/SKILL.md)
52
- and [`epic-plan-decompose-author`](../../skills/core/epic-plan-decompose-author/SKILL.md)
53
- skills respectively — the deterministic `epic-plan-spec.js` /
54
- `epic-plan-decompose.js` CLIs (invoked by this file's own Phase 7 / Phase 8
55
- steps) own the Epic lifecycle label transitions and the `epic-plan-state`
56
- checkpoint. This wrapper must not apply those labels directly.
57
-
58
- ## Prerequisites
59
-
60
- 1. **GitHub Epic**: An existing GitHub Issue with the `type::epic` label.
61
- Skipped when entering via Phase 1 / `--idea` (the Epic does not exist
62
- yet — Phases 1–4 will create it).
63
- 2. **API Keys**: `GITHUB_TOKEN` must be set in the `.env` file.
64
-
65
- ## Phase 1: Idea Refinement (s-plan-ideation entry)
66
-
67
- This phase runs **only** when no `<epic#>` argument is supplied, or when
68
- `--idea "<seed>"` is passed. If an Epic ID was provided, skip directly to
69
- Phase 5 (Re-Plan Detection).
70
-
71
- 1. **Activate the ideation skill**: Read
72
- `<agentRoot>/skills/core/idea-refinement/SKILL.md` via the `Read`
73
- tool (resolve `<agentRoot>` from `project.paths.agentRoot` —
74
- default `.agents`) and execute its procedure with the `--idea` value
75
- (or a user-supplied seed if no argument was given) as the seed. The
76
- skill drives its own three-phase divergent → convergent → sharpen
77
- loop and returns a markdown one-pager with the canonical sections
78
- (Problem Statement, Recommended Direction, Key Assumptions, MVP
79
- Scope, Not Doing). This is the canonical pattern for framework
80
- skills — they are library-style content read on-demand per
81
- `<agentRoot>/instructions.md` section 1.B, not entries in the
82
- host's harness-level skill registry.
83
-
84
- 2. **Run Phase 1.5 (Scope Triage) before the HITL stop**: The sharpened
85
- one-pager feeds the scope-triage gate below, whose verdict folds into
86
- the **same** Phase 1 HITL confirmation. Do not stop twice.
87
-
88
- 3. **HITL stop — confirm the sharpened one-pager** (**gate #1**): Display
89
- the one-pager to the operator and **STOP**. Do not proceed to Phase 2
90
- until the user explicitly confirms the direction. This is the same gate
91
- the skill's own Phase 3 enforces; surfacing it here makes the wait
92
- contract visible to `/plan` callers. When the Phase 1.5 verdict is
93
- `story` or `borderline`, this stop carries the three-way choice the
94
- triage gate defines (below) instead of a plain confirm.
95
-
96
- > **`--yes` (headless) auto-proceed.** When `/plan` was invoked with
97
- > `--yes`, this gate does **not** STOP: the one-pager confirm resolves as
98
- > **approved** and the run continues to Phase 2. A `story` / `borderline`
99
- > triage verdict resolves to its **Recommended** branch (below) rather
100
- > than prompting the three-way choice. Display the one-pager and the
101
- > verdict line for the record, then proceed without waiting. See
102
- > [`plan.md` § Headless / non-interactive mode](../plan.md#headless--non-interactive-mode---yes).
103
-
104
- ## Phase 1.5: Scope Triage (ideation path only)
105
-
106
- This phase runs the shared scope-triage gate over the Phase 1 one-pager. The
107
- gate mechanics — verdict meanings, the three-way operator choice, the `--yes`
108
- resolution, and the no-re-triage rule — live in the single-homed fragment
109
- [`scope-triage-gate.md`](scope-triage-gate.md); read it and follow it. This
110
- phase supplies only its path-specific firing conditions:
111
-
112
- - **When it runs**: only on the ideation path, immediately after Phase 1
113
- produces the sharpened one-pager. The rubric is applied to the **Phase 1
114
- one-pager**, and the verdict folds into the **existing Phase 1 HITL stop**
115
- (do **not** add a second stop).
116
- - **When it is skipped**: entirely, when an Epic ID argument was supplied (the
117
- existing-Epic path jumps straight to Phase 5); and when `/plan` was entered
118
- via a scope-triage handoff from [`/plan`](plan-story.md) (the no-re-triage
119
- rule in the fragment).
120
- - **Recommended branch on a `story` / `borderline` verdict**: persist the
121
- one-pager to a notes file and hand off to `/plan --from-notes <path>`,
122
- identifying the invocation as a scope-triage handoff so `/plan` skips its
123
- own gate, then **exit `/plan`**. The alternative branches are **plan as Epic
124
- anyway** (continue to Phase 2) and **abort**.
125
-
126
- ## Phase 2: Cross-Epic Duplicate Search
127
-
128
- Runs immediately after Phase 1 (and only on the s-plan-ideation path).
129
- Its job is to surface open Epics whose scope already overlaps with the
130
- sharpened one-pager so the operator can fold the work in rather than
131
- opening a duplicate.
132
-
133
- 1. **Invoke the duplicate-search module**: Call
134
- `findSimilarOpenEpics({ onePager, provider })` exported from
135
- [`.agents/scripts/lib/duplicate-search.js`](../../scripts/lib/duplicate-search.js).
136
- The `provider` is the resolved ticketing provider
137
- (`provider-factory.js`), and `onePager` is the markdown returned by
138
- Phase 1.
139
-
140
- 2. **HITL pause on match**: If the module returns a non-empty ranked
141
- list, render the candidates (id, title, score, URL) and **STOP**. Do
142
- not proceed to Phase 3 until the user either (a) confirms the new
143
- Epic is genuinely distinct or (b) chooses to fold the idea into one of
144
- the existing Epics, in which case `/plan` exits and the operator
145
- resumes work on the existing Epic ID.
146
-
147
- 3. **No-match fast path**: If the module returns `[]`, proceed
148
- immediately to Phase 3 — no operator intervention required.
149
-
150
- ## Phase 3: Render Epic Body from One-Pager
151
-
152
- Runs after Phase 2 clears (no duplicates, or operator confirmed the
153
- new Epic is genuinely distinct).
154
-
155
- 1. **Render the body**: Call
156
- `renderEpicBody({ onePager, template })` exported from
157
- [`.agents/scripts/lib/epic-plan-ideation.js`](../../scripts/lib/epic-plan-ideation.js).
158
- The `template` argument is the contents of
159
- [`.agents/templates/epic-from-idea.md`](../../templates/epic-from-idea.md),
160
- which carries the five canonical sections (Context, Goal, Non-Goals,
161
- Scope, Acceptance Criteria). Sections missing from the one-pager are
162
- rendered as `_(not specified)_` rather than left as raw `{{token}}`
163
- placeholders.
164
-
165
- 2. **HITL stop — confirm the body**: Display the rendered body to the
166
- operator and **STOP**. Do not proceed to Phase 4 until the user
167
- explicitly confirms the body is correct. This is the last chance to
168
- tweak wording before the GitHub Issue is opened.
169
-
170
- ## Phase 4: Open the GitHub Issue (`type::epic` only)
171
-
172
- 1. **Open the Epic Issue**: Call
173
- `openEpicFromOnePager({ onePager, template, createIssue })` from the
174
- same `epic-plan-ideation.js` module. Pass a `createIssue` port that
175
- delegates to the resolved ticketing provider's `createIssue` method
176
- (`provider-factory.js`; GitHub: `TicketGateway.createIssue`) so the
177
- labels and body land via the canonical I/O surface.
178
-
179
- **Board membership (Story #3822)**: the provider's `createIssue`
180
- adds the new Epic to the configured Projects V2 board via the
181
- shared `addIssueToBoard` helper
182
- ([`providers/github/board-add.js`](../../scripts/providers/github/board-add.js))
183
- — idempotent, non-fatal (warn-on-error), and a no-op when no
184
- project number is configured — so the Epic lands on the board
185
- without relying on GitHub's "Auto-add to project" built-in
186
- workflow (off by default on fresh boards and not enableable via
187
- API). The created issue's GraphQL `node_id` is surfaced as
188
- `nodeId` on the returned envelope for follow-up board operations.
189
-
190
- 2. **Label discipline**: The Issue is opened with **only** the
191
- `type::epic` label. **Do not** add any `state::*` label at creation
192
- time — the Epic carries only `type::epic` until spec authoring
193
- advances it to `agent::review-spec` in Phase 7. The
194
- `openEpicFromOnePager` helper already enforces this; the workflow
195
- prose codifies the intent so future label-set tweaks don't silently
196
- widen it.
197
-
198
- 3. **Continue to Phase 5**: The captured Epic ID becomes the new
199
- `[Epic_ID]` for the rest of the planning pipeline. Re-Plan Detection
200
- (Phase 5) will short-circuit because the fresh Epic body carries no
201
- Tech Spec sections yet, so the run flows naturally into Phase 6
202
- (Epic Clarity Gate) and then Phase 7.
203
-
204
- ## Phase 5: Re-Plan Detection
205
-
206
- Before generating any artifacts, check whether the Epic has already been
207
- planned.
208
-
209
- 1. **Fetch Epic**: Read the Epic issue body and check for Tech Spec
210
- content — the managed `<!-- mandrel:tech-spec:start/end -->` section or
211
- a bare `## Delivery Slicing` heading (`hasTechSpecContent` in
212
- [`lib/epic-body-sections.js`](../../scripts/lib/epic-body-sections.js)).
213
- The Tech Spec sections alone are the already-planned signal. Historical
214
- Epics may still carry a legacy `## Planning Artifacts` section linking
215
- retired `context::*` tickets — those links are **ignored** (never
216
- fetched); only the body sections count.
217
- 2. **If already planned**: Inform the user that this Epic already carries
218
- planning sections. Ask:
219
-
220
- > "Epic #[ID] already carries a Tech Spec (`## Delivery Slicing`) with
221
- > YY decomposed tickets. Do you want to **re-plan**? This will
222
- > **overwrite the Tech Spec and Acceptance Table sections of the Epic
223
- > body in place** (comment history preserved) and **close-and-recreate**
224
- > all child Story tickets."
225
-
226
- 3. **If user confirms re-plan**: Pass `--force` to all subsequent script
227
- invocations. Under `--force`, the Epic body's managed sections (Tech
228
- Spec, Acceptance Table) are overwritten in place — the Epic's issue
229
- number and prior discussion are preserved, and the Epic receives a
230
- one-line regeneration audit comment. Child Story tickets are still
231
- closed and recreated, because a re-decomposition can legitimately produce a
232
- different ticket set.
233
- 4. **If user declines**: Abort gracefully.
234
-
235
- ## Phase 5.5: Story-Sized Advisory (existing-Epic path)
236
-
237
- An **advisory** scope-triage check that catches a story-sized scope which was
238
- hand-opened directly as a `type::epic` issue before any ceremony is paid for.
239
- Phase 6's Epic Clarity Gate scores section *presence*, not scope *size* — a
240
- perfectly clear but story-sized Epic (typically a thin, freshly opened issue)
241
- sails straight through to full planning. This advisory is the size check the
242
- clarity gate does not make.
243
-
244
- ### Firing condition (load-bearing)
245
-
246
- The advisory runs **only** when **both** hold:
247
-
248
- 1. **Phase 5 found no planning sections** — the Epic body carries no Tech
249
- Spec content (no managed section, no `## Delivery Slicing` heading —
250
- i.e. Phase 5 did **not** enter its re-plan branch).
251
- 2. **The Epic has no open Story children** — no open `type::story`
252
- sub-issues are linked to this Epic.
253
-
254
- If **either** condition fails, **skip this phase silently** and continue to
255
- Phase 6. It must **never** fire on the re-plan path: recommending a "downgrade
256
- to a Story" on an Epic that already carries folded Tech Spec sections and a
257
- ticket tree is nonsense and would collide with the `--force` re-plan flow. The advisory also
258
- does not fire on the ideation path — that path already ran the Phase 1.5 scope
259
- triage on the one-pager before the Epic existed.
260
-
261
- ### Triage
262
-
263
- Run the shared scope-triage gate over the **Epic body** — the gate mechanics
264
- (verdict meanings, the three-way operator choice, the `--yes` resolution, and
265
- the no-re-triage rule) live in [`scope-triage-gate.md`](scope-triage-gate.md);
266
- read it and follow it. The scope-triage skill is artifact-agnostic, so it
267
- reads the same against an Epic body as against a one-pager or a Story draft.
268
- The path-specific bindings for this advisory:
269
-
270
- - **`epic` verdict** → proceed silently to Phase 6. No extra prompt, no HITL
271
- stop.
272
- - **`story` / `borderline` verdict** → **STOP** and present the three-way
273
- choice, whose **Recommended** branch here is **convert to a standalone
274
- Story** via the conversion path below. The alternative branches are
275
- **proceed as Epic anyway** (continue to Phase 6 with the Epic unchanged) and
276
- **abort** (the Epic is left exactly as it was; no labels move and nothing is
277
- closed).
278
-
279
- ### Conversion path (close-and-recreate)
280
-
281
- Conversion is **close-and-recreate**, not in-place relabeling. A `type::epic`
282
- body does not satisfy `validateStoryBody` (it lacks the required Story
283
- sections and would have to drop the Epic shape), and editing or relabeling the
284
- existing issue violates the workflow's "Do not modify existing issues without
285
- explicit permission" Constraint. So the conversion seeds a fresh Story and
286
- closes the Epic in its favor, and **every** issue mutation below happens
287
- **only after the operator explicitly confirms the conversion in-session**:
288
-
289
- 1. **Seed a notes file from the Epic body.** Write the Epic's Context / Goal /
290
- Scope / Acceptance Criteria into a seed file under
291
- `temp/epic-[Epic_ID]/scope-triage-seed.md` (the `temp/` tree is gitignored).
292
- This is the same notes-file shape `/plan --from-notes` consumes.
293
-
294
- 2. **Hand off to `/plan --from-notes`.** Invoke
295
- [`/plan --from-notes temp/epic-[Epic_ID]/scope-triage-seed.md`](plan-story.md),
296
- **identifying the invocation as a scope-triage handoff** so `/plan`
297
- skips its own escalation gate (the skill's no-re-triage rule — a handoff is
298
- a settled triage decision, and re-running the gate on the receiving side
299
- would re-litigate it and risk a ping-pong between the two workflows). The
300
- replacement Story's `## Notes` section links back to the closed Epic
301
- (`Converted from Epic #[Epic_ID] — scope triaged as a standalone Story`) so
302
- the audit trail is bidirectional.
303
-
304
- 3. **Close the Epic in favor of the replacement.** Once `/plan` has
305
- created the replacement Story (capture its number as `#N`), close the Epic
306
- with a cross-linking comment:
38
+ 1. Activate the [`core/idea-refinement`](../../skills/core/idea-refinement/SKILL.md)
39
+ skill with the seed. It returns a one-pager with the canonical sections
40
+ (Problem Statement, Recommended Direction, Key Assumptions, MVP Scope,
41
+ Not Doing). Write it to `temp/plan-ideation/<slug>/one-pager.md` (slug
42
+ from the title; the tree is gitignored).
43
+ 2. Emit the authoring envelope:
307
44
 
308
45
  ```bash
309
- gh issue close [Epic_ID] --repo <owner>/<repo> \
310
- --comment "Closed in favor of #N — scope triaged as a standalone Story."
46
+ node .agents/scripts/plan-context.js \
47
+ --one-pager temp/plan-ideation/<slug>/one-pager.md \
48
+ > temp/plan-ideation/<slug>/plan-context.json
311
49
  ```
312
50
 
313
- This is the only `gh issue close` in the path, and it runs **after** the
314
- replacement Story exists, so the conversion never strands a closed Epic
315
- with no successor. The replacement-Story back-link plus this close comment
316
- give a reviewer the full bidirectional trail.
317
-
318
- The conversion mutates two issues (creates the Story, closes the Epic) — both
319
- behind the single operator confirmation above. After conversion `/plan`
320
- exits: the work now lives on the standalone Story, which the operator delivers
321
- via [`/single-story-deliver`](single-story-deliver.md) or
322
- [`/deliver`](deliver-stories.md).
323
-
324
- ## Phase 6: Epic Clarity Gate
325
-
326
- Runs on every existing-Epic invocation, after Phase 5 (Re-Plan
327
- Detection) and the Phase 5.5 story-sized advisory, and before Phase 7
328
- (Tech Spec & Acceptance Spec). The gate scores the Epic body
329
- against the five clarity-scored canonical
330
- sections from
331
- [`.agents/templates/epic-from-idea.md`](../../templates/epic-from-idea.md)
332
- (Context, Goal, Non-Goals, Scope, Acceptance Criteria — the template
333
- also carries a `## User Stories` section, which the clarity rubric does
334
- not score) and either
335
- skips fast (when the Epic body is already clear) or drops into a
336
- refinement loop seeded from the current Epic body. The scorer also
337
- accepts common heading variants for back-compat (e.g. `## Problem`,
338
- `## Direction`, `## MVP Scope`, `## Not Doing`, `## Out of Scope`) so
339
- hand-authored Epics that predate the canonical headings continue to
340
- pass without rewording.
341
-
342
- The rubric is deterministic: section-presence against the five
343
- canonical headings. A `clear` verdict requires **both** ≥ 4 of 5
344
- sections present **and** the **Acceptance Criteria** section present —
345
- AC is a required section, not one of the four optional passers, so an
346
- Epic with no Acceptance Criteria is always `needs-refinement` (it would
347
- otherwise hard-fail the `/deliver` start gate downstream). See
348
- [`lib/epic-plan-clarity.js`](../../scripts/lib/epic-plan-clarity.js)
349
- for the scoring logic.
350
-
351
- 1. **Score the body**: Run the clarity-check CLI in context-emission
352
- mode.
51
+ The ideation envelope carries `duplicates[]` (cross-Epic dup search),
52
+ `deliveryShapeSignal`, `docsContext`, `codebaseSnapshot`, `ticketSchema`,
53
+ and the rendered `systemPrompts`. The Epic does **not** exist yet
54
+ creation happens in step 3.
55
+ 3. Run the shared scope-triage gate over the one-pager — mechanics in
56
+ [`scope-triage-gate.md`](scope-triage-gate.md). The verdict folds into
57
+ gate #1. The Recommended branch on a `story` / `borderline` verdict:
58
+ persist the one-pager as a notes file and hand off to
59
+ [`plan-story.md`](plan-story.md) via `/plan --from-notes <path>` as a
60
+ scope-triage handoff (no re-triage on the receiving side), then exit this
61
+ path. Skipped entirely when `/plan` was itself entered via a scope-triage
62
+ handoff.
63
+ 4. Review `duplicates[]`. A non-empty ranked list folds into gate #1: the
64
+ operator either confirms the new Epic is distinct or folds the idea into
65
+ an existing Epic (in which case `/plan` exits).
66
+
67
+ ### Existing-Epic entry (`/plan <epicId>`)
68
+
69
+ 1. Emit the authoring envelope:
353
70
 
354
71
  ```bash
355
- node .agents/scripts/epic-plan-clarity.js --epic [Epic_ID] --emit-context \
356
- > temp/epic-[Epic_ID]/clarity-context.json
72
+ node .agents/scripts/plan-context.js --epic [Epic_ID] \
73
+ > temp/epic-[Epic_ID]/plan-context.json
357
74
  ```
358
75
 
359
- The envelope carries
360
- `{ epicId, epicBody, verdict, sections, missingOrPlaceholder }`.
361
-
362
- 2. **Clear fast path**: When `verdict === 'clear'`, print
363
- `Epic clarity: clear proceeding to Phase 7.` and continue. No
364
- HITL, no prompt.
365
-
366
- 3. **Needs-refinement path**: When `verdict === 'needs-refinement'`,
367
- activate the
368
- [`core/idea-refinement`](../../skills/core/idea-refinement/SKILL.md)
369
- skill **seeded from the current Epic body** (not a blank seed),
370
- with `missingOrPlaceholder` as the convergence target. The skill
371
- runs its three-phase divergent convergent sharpen loop and
372
- returns a sharpened one-pager.
373
-
374
- 4. **Re-render the body**: Call
375
- `renderEpicBody({ onePager, template })` from
376
- [`lib/epic-plan-ideation.js`](../../scripts/lib/epic-plan-ideation.js)
377
- (the same helper Phase 3 uses), passing the contents of
378
- [`.agents/templates/epic-from-idea.md`](../../templates/epic-from-idea.md).
379
- Write the result to `temp/epic-[Epic_ID]/clarity-update.md`.
380
-
381
- 5. **HITL stop confirm the diff**: Display the diff between the
382
- current Epic body and the sharpened body and **STOP**. Operator
383
- approves, edits, or aborts. Flag the blast radius in the
384
- confirmation prompt: an approved body change feeds **two**
385
- downstream artifacts (Tech Spec, Acceptance Spec) — treat
386
- this gate as a one-shot rewrite, not an iterative draft. The
387
- Constraint ("Do not modify existing issues without explicit
388
- permission") is honored — no `gh issue edit` call until the
389
- operator confirms.
390
-
391
- > **`--yes` (headless) auto-proceed.** This refinement-diff confirm is the
392
- > clarity-gate face of `/plan`'s **gate #1** on the existing-Epic
393
- > (`/plan <epicId>`) path — it is an operator *wait*, not a deterministic
394
- > validator (the deterministic half is the section-presence *scoring* in
395
- > step 1, which always runs). When `/plan` was invoked with `--yes`, this
396
- > confirm does **not** STOP: the sharpened body is auto-**approved** and the
397
- > run proceeds to step 6 (persist). The blast-radius note is still displayed
398
- > for the record; only the operator wait is suppressed. This keeps
399
- > `/plan <epicId> --yes` driveable headlessly even when the Epic body needs
400
- > refinement (`gh issue edit` still runs only via the step 6 persist call,
401
- > which the auto-approval authorizes). See
402
- > [`plan.md` § Headless / non-interactive mode](../plan.md#headless--non-interactive-mode---yes).
403
-
404
- 6. **Persist**: On approval, run the persist mode:
76
+ The epic envelope additionally carries `clarity` (section-presence
77
+ rubric), `replan` (already-planned signals), and `planState`.
78
+ 2. **Re-plan detection** (`replan.alreadyPlanned === true`): the Epic body
79
+ already carries Tech Spec sections. Fold the decision into gate #1: a
80
+ confirmed re-plan runs step 3 with `--force` (managed sections are
81
+ overwritten in place; child Stories are closed and recreated); a decline
82
+ aborts gracefully.
83
+ 3. **Story-sized advisory**: only when the Epic is not already planned
84
+ **and** `replan.openStoryCount` is 0, run the shared scope-triage gate
85
+ over the Epic body ([`scope-triage-gate.md`](scope-triage-gate.md)). On a
86
+ `story` / `borderline` verdict the Recommended branch converts via
87
+ close-and-recreate: seed `temp/epic-[Epic_ID]/scope-triage-seed.md` from
88
+ the Epic body, hand off to `/plan --from-notes <path>` as a scope-triage
89
+ handoff, and only after the replacement Story `#N` exists — close the
90
+ Epic with a cross-linking comment
91
+ (`gh issue close [Epic_ID] --comment "Closed in favor of #N — scope triaged as a standalone Story."`).
92
+ Both mutations happen only after the operator confirms at gate #1.
93
+ 4. **Clarity refinement** (`clarity.verdict === 'needs-refinement'`): the
94
+ deterministic scoring already ran inside the envelope build (a `clear`
95
+ verdict requires ≥ 4 of 5 canonical sections **and** Acceptance
96
+ Criteria). Interrogate the operator on the named gaps
97
+ (`clarity.missingOrPlaceholder`) — one question at a time — and draft the
98
+ refined body to `temp/epic-[Epic_ID]/clarity-update.md`. The refined-body
99
+ diff folds into gate #1; on approval persist it:
405
100
 
406
101
  ```bash
407
102
  node .agents/scripts/epic-plan-clarity.js --epic [Epic_ID] \
408
103
  --updated-body temp/epic-[Epic_ID]/clarity-update.md
409
104
  ```
410
105
 
411
- The CLI persists the new body via `provider.updateTicket` and
412
- posts a `clarity-gate-update` audit comment recording the change.
413
- Idempotent: no-op when the file content matches the current body.
414
-
415
- 7. **Re-verify**: Re-run the `--emit-context` step once to confirm
416
- the verdict flipped to `clear`. If it still reads
417
- `needs-refinement`, abort with a non-zero exit and surface a
418
- remediation hint to the operator. Do not loop — one refinement
419
- pass per invocation, matching the `--force` re-plan pattern.
420
-
421
- ## Phase 7: Epic Planning (Tech Spec & Acceptance Spec)
422
-
423
- > **Phase-7 guards & managed-section rationale (reference).** This phase runs
424
- > behind an **Epic-lease preflight** (`--steal` transfers a confirmed-dead
425
- > claim; the lease releases after Phase 8), writes **idempotent managed
426
- > sections** (`--force` overwrites them in place), lands **one planning
427
- > document** (Tech Spec + Acceptance Table folded into the Epic body;
428
- > `acceptance::n-a` waives the table), and namespaces every temp file under
429
- > the durable **per-Epic tree** (`temp/epic-[Epic_ID]/…`). The full rationale
430
- > for each guard is in
431
- > [`plan-epic-reference.md` § Phase 7 background rationale](plan-epic-reference.md#phase-7--background-rationale).
432
-
433
- 1. **Gather Authoring Context**: Run the spec-phase CLI in context-emission
434
- mode to fetch the Epic body, scraped project docs, and the recommended
435
- system prompts.
436
-
437
- ```bash
438
- node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] --emit-context > temp/epic-[Epic_ID]/planner-context.json
439
- ```
440
-
441
- 2. **Activate the `epic-plan-spec-author` skill**: Read
442
- [`<agentRoot>/skills/core/epic-plan-spec-author/SKILL.md`](../../skills/core/epic-plan-spec-author/SKILL.md)
443
- via the `Read` tool (resolve `<agentRoot>` from
444
- `project.paths.agentRoot` default `.agents`) and execute its
445
- procedure with `[Epic_ID]` as input. The skill reads
446
- `temp/epic-[Epic_ID]/planner-context.json`, authors the Tech
447
- Spec, **risk verdict**, and **Acceptance Spec** against the embedded
448
- system prompts, and writes them to
449
- `temp/epic-[Epic_ID]/techspec.md`,
450
- `temp/epic-[Epic_ID]/risk-verdict.json`, and
451
- `temp/epic-[Epic_ID]/acceptance-spec.md`. The skill is the
452
- authoritative authoring stepdo **not** inline the Tech
453
- Spec / risk-verdict / Acceptance Spec drafting in the workflow
454
- body. The skill front-matter declares
455
- `allowed_tools: [Read, Write, Bash]`; it never calls GitHub.
456
-
457
- The skill body carries the authoritative Tech Spec and
458
- Acceptance Spec system prompts. The `systemPrompts` field on the
459
- `--emit-context` envelope is a backstop for legacy callers; the
460
- skill body wins when the two surfaces diverge.
461
-
462
- > **One-pass refinement contract (amend, don't regenerate).** When step 3's
463
- > persist call rejects the authored artifacts (missing `## Delivery
464
- > Slicing`, a schema-invalid risk verdict), re-entering this step applies
465
- > **targeted edits** to the existing `temp/epic-[Epic_ID]/{techspec.md,
466
- > risk-verdict.json,acceptance-spec.md}` files — fix only what the
467
- > rejection named — per the `epic-plan-spec-author` skill's re-emit rule.
468
- > This refinement is bounded to **one pass**: fix the named gap and
469
- > re-run step 3 once: do not loop wholesale re-authoring across multiple
470
- > rejections. The same one-pass shape already governs the Phase 6 Epic
471
- > Clarity Gate's refinement loop above ("Do not loop — one refinement
472
- > pass per invocation").
473
-
474
- 3. **Persist to GitHub**: Run the spec-phase CLI's persist half. It
475
- schema-validates the planner-authored risk verdict (`--risk-verdict`,
476
- required — a missing or malformed verdict fails closed before any
477
- GitHub mutation), derives the `planningRisk` envelope from it
478
- (`deriveRiskEnvelope`), records a `risk-verdict` structured comment
479
- on the Epic, flips the Epic to `agent::review-spec`, and writes the
480
- `epic-plan-state` checkpoint (including the `riskVerdict` field).
481
- The `--acceptance-table` flag persists the AC-ID table as the Epic
482
- body's `## Acceptance Table` managed section alongside the Tech Spec
483
- sections; the persist half fails loudly if any file is missing or
484
- empty. Omit `--acceptance-table` only when the Epic carries the
485
- `acceptance::n-a` waiver label.
486
-
487
- ```bash
488
- # Normal planning (both managed sections)
489
- node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
490
- --tech-spec temp/epic-[Epic_ID]/techspec.md \
491
- --risk-verdict temp/epic-[Epic_ID]/risk-verdict.json \
492
- --acceptance-table temp/epic-[Epic_ID]/acceptance-spec.md
493
-
494
- # Re-planning (--force overwrites the Epic body's managed sections
495
- # IN PLACE — same Epic issue, refreshed section bodies, one
496
- # regeneration audit comment on the Epic. Child Story tickets are
497
- # still close-and-recreate at decomposition time.)
498
- node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
499
- --tech-spec temp/epic-[Epic_ID]/techspec.md \
500
- --risk-verdict temp/epic-[Epic_ID]/risk-verdict.json \
501
- --acceptance-table temp/epic-[Epic_ID]/acceptance-spec.md --force
502
-
503
- # Waived (acceptance::n-a label on Epic — no acceptance table authored)
504
- node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
505
- --tech-spec temp/epic-[Epic_ID]/techspec.md \
506
- --risk-verdict temp/epic-[Epic_ID]/risk-verdict.json
507
- ```
508
-
509
- 4. **Verification and review routing**:
510
- - Verify that the Technical Specification sections and (when not
511
- waived) the `## Acceptance Table` section have landed as managed
512
- sections of the Epic body.
513
- - Read `planningRisk` from the persist stdout JSON (or the
514
- `epic-plan-state` checkpoint). Branch on
515
- `planningRisk.requiresReview` unless the operator passed
516
- `--force-review`:
517
- - **High risk** (`requiresReview === true`) or **operator override**
518
- (`--force-review`) — **gate #2**: **STOP**. Ask the USER to review the
519
- updated Epic body (its Tech Spec sections and `## Acceptance
520
- Table`) on GitHub. Approval is the user's verbal OK in this
521
- session — the sections live on the Epic itself, so there is
522
- nothing to close at delivery time. Do NOT proceed
523
- to decomposition until the user confirms the plan is accurate.
524
-
525
- > **`--yes` (headless) auto-proceed.** When `/plan` was invoked with
526
- > `--yes`, this review gate does **not** STOP, even when
527
- > `requiresReview === true` or `--force-review` was also passed: the
528
- > review resolves as **approved** and the run **continues directly to
529
- > Phase 8**, exactly as the low-risk auto-proceed branch below; only
530
- > the operator *wait* is suppressed. This is `/plan`'s **gate #2** —
531
- > the second and last HITL STOP `--yes` suppresses. `--yes` does
532
- > **not** alter risk routing or the review criteria themselves; it
533
- > only forces a proceed where this gate would otherwise STOP. See
534
- > [`plan.md` § Headless / non-interactive mode](../plan.md#headless--non-interactive-mode---yes).
535
- - **Low risk** (`requiresReview === false` and no `--force-review`):
536
- Emit the auto-proceed message from the persist stdout
537
- (`reviewRouting.operatorMessage`) and **continue directly to Phase 8**
538
- without an extra review stop. The Epic still carries
539
- `agent::review-spec` until decomposition completes; the routing
540
- decision is recorded in the `epic-plan-state` checkpoint. (`--yes` is
541
- a no-op on this branch — there is no STOP to suppress.)
542
-
543
- 5. **Tech Spec freshness check (advisory)**: After the Tech Spec sections
544
- are persisted, `epic-plan-spec.js` runs
545
- [`validateSpecFreshness`](../../scripts/lib/orchestration/spec-freshness.js)
546
- against the authored Tech Spec body, probing every cited path-shape
547
- reference (backticked paths, `// header` lines in code blocks, and
548
- inline mentions of paths under `.agents/`, `src/`, `lib/`, `app/`,
549
- `tests/`, `packages/`, `scripts/`, `docs/`) against the configured
550
- `baseBranch`. Results land in three buckets:
551
- - **fresh** — path exists at the base ref (no action).
552
- - **ambiguous** — path is absent but surrounding prose carries a
553
- net-new cue (`introduce`, `add`, `create`, `new file`, `to be
554
- created`, etc.); surfaced for review without alarm.
555
- - **stale** — path is absent and no net-new cue is nearby; likely a
556
- reference the Architect inherited from drift-stale docs.
557
-
558
- When ≥1 stale reference is detected, a `spec-freshness` structured
559
- comment is upserted on the **Epic** listing each citation
560
- with its line number. The full report is also written to
561
- `<tempRoot>/epic-<id>-spec-freshness.json` for downstream tooling.
562
- The check is **advisory and non-blocking** — Phase 7 completes even
563
- when stale references are present, so the operator retains final
564
- judgment on edge cases. If the run summary shows
565
- `⚠️ Spec freshness: N stale / M ambiguous`, review the Epic's
566
- `spec-freshness` comment and correct the cited spec sections
567
- before approving the plan for Phase 8.
568
-
569
- 6. **BDD scenario cross-reference (advisory)**: When the project has
570
- adopted BDD, `epic-plan-spec.js` populates the planner-context
571
- envelope with `bddScenarios` — the output of
572
- [`scanBddScenarios`](../../scripts/lib/bdd-scenario-scanner.js) over
573
- the canonical feature roots resolved by
574
- [`resolveFeatureRoots`](../../scripts/lib/bdd-runner-detect.js)
575
- (`tests/features`, `features`, `test/features`). The Acceptance
576
- Engineer step in the [`epic-plan-spec-author`](../../skills/core/epic-plan-spec-author/SKILL.md)
577
- skill scores each planned AC against the scenario index via
578
- `findBestScenarioMatch`; when an existing scenario covers an AC's
579
- outcome, the AC's `Scenario` column is annotated with `<file>:L<line>`
580
- and the `Disposition` becomes `unchanged` / `refined` instead of
581
- `new`. When `bddScenarios` is empty (no `.feature` files), the skill
582
- degrades silently and the spec is authored exactly as before. The
583
- matcher is keyword-based and deterministic so re-runs produce stable
584
- dispositions.
585
-
586
- 7. **Cleanup**: The wrapper script (`epic-plan-spec.js`) deletes the Phase 7
587
- temp files automatically on success — no operator action required. The
588
- cleanup contract lives in
589
- [`lib/plan-phase-cleanup.js`](../../scripts/lib/plan-phase-cleanup.js).
590
-
591
- > **Tech Spec section gate (folded into Step 3 persist).** The persist call
592
- > in Step 3 above validates the authored Tech Spec for the required
593
- > `## Delivery Slicing` heading (case-insensitive; also accepts the variant
594
- > `## Delivery slicing` and the shorthand `## Slicing`) via
595
- > [`lib/orchestration/spec-section-validator.js`](../../scripts/lib/orchestration/spec-section-validator.js#validateSpecSections)
596
- > **before** acquiring the Epic-lease or making any GitHub mutation — a
597
- > Tech Spec missing the section fails the persist call closed with a message
598
- > naming the gap and the two recovery paths (re-author, or add the section by
599
- > hand). This used to run as a separate, standalone
600
- > `epic-plan-spec-validate.js` CLI invoked as its own Phase 7.5 workflow
601
- > step; that ordering ran the check *after* the persist had already written
602
- > to GitHub and *after* `cleanupPhaseTempFiles` had deleted the temp spec
603
- > file the check read, so the "blocking gate" could never actually block.
604
- > Folding the check into the persist path's input validation makes it a
605
- > real hard gate. **Why this gate exists**: Phase 8.3 (Holistic
606
- > Consolidation) reconciles the draft ticket array against the Tech Spec's
607
- > `## Delivery Slicing` section, which the
608
- > [`epic-plan-decompose-author`](../../skills/core/epic-plan-decompose-author/SKILL.md)
609
- > skill uses as the capability-boundary anchor (see Phase 8 step 2 below).
610
- > Without it, the consolidation pass runs against a void and produces
611
- > groupings that reflect **technical shape** (e.g. cron jobs together)
612
- > rather than **capability boundaries** — reproduced on Epic #18 in
613
- > `dsj1984/athportal` (planned with v1.54.0), whose spec carried a detailed
614
- > `## Core Components` table but no `## Delivery Slicing` section. On a
615
- > persist failure, re-enter the Step 2 spec-author step and apply a
616
- > **targeted edit** adding the missing `## Delivery Slicing` section to the
617
- > existing `techspec.md` (amend, don't regenerate — the one-pass refinement
618
- > contract above) — or add the section by hand — then re-run Step 3 once.
619
-
620
- ## Phase 8: Work Breakdown Decomposition
621
-
622
- > **Open-children guard (workflow guard).** Before persisting the breakdown,
623
- > `epic-plan-decompose.js` refuses to run when the Epic **already has open
624
- > Story children**, unless `--force` (close + recreate the tree) or
625
- > `--resume` (continue a partial persist) is set. This stops a re-run from
626
- > stacking a duplicate Story set on top of an existing one — the
627
- > phase exits non-zero and lists the open children. Once persist completes,
628
- > the Epic-lease acquired in Phase 7 is **released** (best-effort; a release
629
- > failure never fails decompose).
630
-
631
- <!-- separator: adjacent blockquotes -->
632
-
633
- > **Hierarchy.** The decomposer emits a flat Story backlog under the Epic.
634
- > Acceptance criteria and verification steps are inlined on each Story
635
- > body (`acceptance[]` / `verify[]` fields) and resolved against the
636
- > Epic body's `## Acceptance Table` section at close time. See
637
- > [`.agents/instructions.md` § 5.D](../../instructions.md) for the full
638
- > contract.
639
-
640
- 1. **Gather Decomposition Context**:
641
-
642
- ```bash
643
- node .agents/scripts/epic-plan-decompose.js --epic [Epic_ID] --emit-context > temp/epic-[Epic_ID]/decomposer-context.json
644
- ```
645
-
646
- 2. **Activate the `epic-plan-decompose-author` skill**: Read
647
- [`<agentRoot>/skills/core/epic-plan-decompose-author/SKILL.md`](../../skills/core/epic-plan-decompose-author/SKILL.md)
648
- via the `Read` tool (resolve `<agentRoot>` from
649
- `project.paths.agentRoot` — default `.agents`) and execute its
650
- procedure with `[Epic_ID]` as input. The skill reads
651
- `temp/epic-[Epic_ID]/decomposer-context.json` (`epicBody` — carrying
652
- the folded Tech Spec sections and Acceptance Table — risk
653
- heuristics, `maxTickets` cap, `contextMode`), applies its
654
- embedded decomposer system prompt + ticket schema, and writes the
655
- ticket array to `temp/epic-[Epic_ID]/tickets.json`. Do **not** inline
656
- the JSON authoring in the workflow body.
657
-
658
- The `maxTickets` cap is a **framework constant**
659
- (`LIMITS_DEFAULTS.maxTickets` in
660
- `.agents/scripts/lib/config/limits.js`; not operator-configurable) and
661
- a **reviewability budget**, not a hard authoring ceiling: a draft over
662
- budget warns at authoring time and is rejected at persist unless rerun
663
- with `--allow-over-budget` (after confirming the over-budget rationale
664
- on the Epic). The `epic-plan-decompose.js` script also logs the
665
- resolved budget to stderr. The decomposer system prompt is
666
- single-sourced in
667
- `.agents/scripts/lib/templates/decomposer-prompts.js`
668
- (`renderDecomposerSystemPrompt`); the `epic-plan-decompose-author`
669
- skill references that rendered `systemPrompt` rather than carrying
670
- its own copy of the prompt body.
671
-
672
- When the Tech Spec carries a `## Delivery Slicing` section (authored by
673
- `epic-plan-spec-author` in Phase 7), the decompose-author skill authors
674
- toward the Architect's proposed shippable-Story clusters; it degrades
675
- gracefully when the section is absent.
676
-
677
- > **One-pass refinement contract (amend, don't regenerate).** When the
678
- > deterministic validator (`validateAndNormalizeTickets`) rejects the
679
- > draft, or the 8.3 / 8.4 / 8.5 critics below flag specific Stories,
680
- > re-entering this step applies
681
- > **targeted edits** to the existing `temp/epic-[Epic_ID]/tickets.json` —
682
- > fix only the rejected or flagged Stories — per the
683
- > `epic-plan-decompose-author` skill's re-emit rule, rather than
684
- > re-authoring the whole array from scratch. Each critic's feedback gets
685
- > **one refinement pass**: apply the targeted edit and re-run the
686
- > relevant downstream step (validator or persist) once, matching the
687
- > Phase 7 spec-author contract above; do not loop wholesale re-authoring
688
- > across repeated rejections.
689
-
690
- 3. **Phase 8.3 — Holistic Consolidation (HITL diff gate, precondition-gated
691
- dispatch)**: After the draft `temp/epic-[Epic_ID]/tickets.json` exists and
692
- **before** the persist call below, first consult the deterministic
693
- dispatch precondition — [`evaluateConsolidationPrecondition`](../../scripts/lib/orchestration/consolidation-precondition.js),
694
- called with the draft Story array and the Epic body (which carries the
695
- folded Tech Spec `## Delivery Slicing` section). The precondition compares
696
- the draft against the Delivery Slicing table **1:1** — same shippable-Story
697
- count (excluding the wave-0 `bdd-scaffold` Story) and a `depends_on` shape
698
- that agrees with each slice's `Independent?` answer — and returns
699
- `{ dispatch, reasons }`. It **fails open** (`dispatch: true`) on every
700
- ambiguous input: a missing or unparseable Delivery Slicing section, or an
701
- unparseable `Independent?` cell.
702
-
703
- - **`dispatch: false`** — the draft already matches the Delivery Slicing
704
- target, so the consolidation critic has nothing to reconcile. **Skip the
705
- sub-agent dispatch** and surface the skip as a **one-line progress
706
- note** naming the precondition's `reasons` — quoting verbatim the
707
- string `evaluateConsolidationPrecondition` actually emits: "Draft
708
- matches Delivery Slicing 1:1 in count and dependency shape (N
709
- slice(s)) — skipping the 8.3 consolidation dispatch." (`N` is the
710
- interpolated `slicing.length`). Proceed straight to Phase 8.4 with the
711
- draft `tickets.json` unchanged (no `consolidation-report.md` is
712
- produced when the dispatch is skipped).
713
- - **`dispatch: true`** — **dispatch a genuine fresh-context sub-agent**
714
- (`Agent` tool, `subagent_type: general-purpose`) whose task is to read
715
- the
716
- [`epic-plan-consolidate`](../../skills/core/epic-plan-consolidate/SKILL.md)
717
- skill and execute its procedure with `[Epic_ID]` as input, including the
718
- precondition's `reasons` in the HITL diff context so the operator sees
719
- *why* the critic ran. Dispatching the critic as a sub-agent — **not**
720
- activating the skill inline in your authoring turn — is what makes it a
721
- **separate critic pass with fresh context**: the sub-agent does not
722
- inherit the conversation that authored the draft, so it cannot grade its
723
- own homework (the same nested-dispatch mechanic the acceptance self-eval
724
- loop uses, now that the sub-agent depth limit is lifted — see
725
- [`.agents/instructions.md` § 4](../../instructions.md)). The sub-agent
726
- reads the draft array plus the Epic body (which carries the Tech Spec
727
- sections), reconciles the draft against the Tech Spec `## Delivery
728
- Slicing` target, and emits a **consolidated** `tickets.json` plus a
729
- human-readable `temp/epic-[Epic_ID]/consolidation-report.md`. Its operations are scope-preserving only — **merge sibling Stories and
730
- rewire `depends_on`** — and it MUST NOT add scope or invent tickets; it
731
- consolidates fragmented slices by merging them into a cohesive Story,
732
- never by splitting one. The sub-agent **never writes to GitHub**: it
733
- emits only the two temp artifacts and returns control to this operator
734
- session. It runs **before** the deterministic validator
735
- (`validateAndNormalizeTickets`), so the validator re-checks its output
736
- and the critic cannot emit an invalid plan. **Show the operator the
737
- consolidation report (the before/after
738
- diff + rationale) before persisting.** The HITL diff-confirm and the
739
- persist call both run here in the **operator session**, never inside
740
- the sub-agent — consolidation is never auto-applied without review: on
741
- operator approval, persist the consolidated `tickets.json`; on
742
- rejection, persist the draft instead.
743
-
744
- Phase 8.4 (Reachability Completeness Critic), Phase 8.5 (Planning
745
- Pre-Mortem Critic), and the deterministic ticket validator
746
- (`validateAndNormalizeTickets`) are
747
- **unconditional** — the precondition governs only the 8.3 sub-agent
748
- dispatch, never any other Phase 8 gate. This is a sub-step of Phase 8 — it
749
- does **not** renumber the top-level lifecycle phases (9–12).
750
-
751
- 4. **Phase 8.4 — Reachability Completeness Critic (HITL diff gate, F6)**:
752
- After consolidation (8.3) and **before** the persist call below, run the
753
- completeness critic. This is a **distinct pass** from
754
- [`epic-plan-consolidate`](../../skills/core/epic-plan-consolidate/SKILL.md)
755
- and **must NOT relax** that skill's scope-preserving conservation invariant:
756
- the consolidate critic is merge-and-rewire-only (it MUST NOT add scope or
757
- invent tickets), whereas this critic is permitted exactly one **additive**
758
- operation — appending a **single reachability Story** when, and only when, an
759
- Epic introduces a user-facing surface (a new route/page) that **no Story
760
- gives a navigation owner** (no nav-registry entry, no menu/link door from an
761
- authenticated home). The two passes are deliberately separate so the
762
- conservation invariant stays intact: consolidation never adds, and this
763
- critic's only addition is the reachability Story.
764
-
765
- - **Detection.** Scan the consolidated `tickets.json` for Stories that add a
766
- route-shaped surface (paths under the consumer-configured
767
- `planning.navigation.routeGlobs`, mirroring the
768
- `epic-plan-healthcheck.js --paranoid` reachability check, F7). For each
769
- such surface, confirm some Story's `acceptance[]` / `changes[]` references
770
- the consumer's nav-registry SSOT (`planning.navigation.navRegistry`). A
771
- surface with **no** nav owner is an orphan.
772
- - **Action.** When at least one orphan surface exists, append **one**
773
- reachability Story whose `acceptance[]` requires the orphaned surface to be
774
- reachable by navigation from the relevant persona's authenticated home
775
- (never by deep-link), and wire its `depends_on` to the surface-adding
776
- Story. Append **at most one** reachability Story per decompose run — batch
777
- every orphan under it — so the critic never fans out a parallel backlog.
778
- - **No-op when unconfigured.** With no `planning.navigation` config present,
779
- the critic degrades to a silent no-op (it cannot identify route-shaped
780
- surfaces or a nav registry), exactly like the F7 healthcheck flag.
781
- - **HITL.** The added Story is surfaced in the **same Phase 8 HITL diff** as
782
- consolidation, **before** any GitHub write — never auto-persisted. On
783
- operator rejection, drop the added Story and persist without it. The
784
- deterministic validator (`validateAndNormalizeTickets`) re-checks the
785
- critic's output, so an invalid addition cannot reach GitHub.
786
-
787
- 5. **Phase 8.5 — Planning Pre-Mortem Critic (code-reading, F9)**: After the
788
- reachability critic (8.4) and **before** the persist call below, **dispatch a
789
- genuine fresh-context sub-agent** (`Agent` tool,
790
- `subagent_type: general-purpose`) whose task is to read the
791
- [`epic-plan-premortem`](../../skills/core/epic-plan-premortem/SKILL.md)
792
- skill and execute its procedure with `[Epic_ID]` as input. Like the 8.3
793
- consolidate pass, dispatching the critic as a sub-agent — **not** activating
794
- the skill inline in your authoring turn — is what makes it a genuine
795
- **fresh-context critic** sibling to `epic-plan-consolidate`: the sub-agent
796
- does not inherit the authoring conversation, so its code-reading review is
797
- independent of the draft it grades. It reads the drafted `tickets.json`, the
798
- Epic body (with its folded Tech Spec sections), **and the actual cited code
799
- surfaces** (the files each Story's
800
- `changes[]` / `references[]` name), then emits predicted-rework findings —
801
- unverifiable acceptance criteria, over- or under-specified Stories, and
802
- semantically-wrong assumptions the structural file-assumption gate (step 7)
803
- cannot catch — to `temp/epic-[Epic_ID]/premortem-report.md`.
804
-
805
- Unlike the consolidate critic it is **not** scope-preserving-only: it may
806
- recommend splitting an under-specified Story or tightening an AC. But it
807
- **never writes to GitHub** and never persists `tickets.json` — it only emits
808
- the report and returns control to this operator session. Its findings are
809
- shown in the **same Phase 8 HITL diff** (which stays in the operator
810
- session), and on
811
- operator approval the author re-runs (Step 2) on the findings **before** the
812
- persist call — applying **targeted edits** to the flagged Stories in the
813
- existing `tickets.json` (amend, don't regenerate; **one refinement pass**
814
- per the contract above), not a wholesale re-author. The critic runs
815
- **before** the deterministic validator (`validateAndNormalizeTickets`),
816
- so the persist below is the single GitHub write for the whole phase.
817
-
818
- 6. **Persist to GitHub**: Run the decompose CLI's persist half. It
819
- validates the ticket array (`validateAndNormalizeTickets`), creates
820
- the Story issues, flips the Epic to `agent::ready`, and
821
- writes the `epic-plan-state` checkpoint.
822
-
823
- ```bash
824
- # Normal decomposition
825
- node .agents/scripts/epic-plan-decompose.js --epic [Epic_ID] \
826
- --tickets temp/epic-[Epic_ID]/tickets.json
827
-
828
- # Re-planning (close old tickets first)
829
- node .agents/scripts/epic-plan-decompose.js --epic [Epic_ID] \
830
- --tickets temp/epic-[Epic_ID]/tickets.json --force
831
- ```
832
-
833
- > On a large Epic (~60+ tickets) the persist can trip GitHub's secondary
834
- > rate limit mid-run. Resume from the partial backlog with `--resume` — the
835
- > full recovery contract is in
836
- > [`plan-epic-reference.md` § Phase 8 — `--resume` recovery (secondary rate limit)](plan-epic-reference.md#phase-8----resume-recovery-secondary-rate-limit).
837
-
838
- 7. **Cross-Validation**:
839
- - Hierarchy completeness, dependency-DAG acyclicity, and `risk::high`
840
- labelling are deterministic invariants enforced by
841
- `validateAndNormalizeTickets` in
842
- [`lib/orchestration/ticket-validator.js`](../../scripts/lib/orchestration/ticket-validator.js);
843
- its output during decomposition is the canonical proof — no manual
844
- re-check needed.
845
- - **File-assumption gate (Story #2636)**: Each Story's `body.changes`
846
- and `body.references` entries declare an explicit `assumption` ∈
847
- `creates | refactors-existing | exists | deletes`. The validator
848
- probes the base branch for every declared path and rejects the
849
- decompose when the declaration contradicts reality:
850
- - `creates` + path **exists** at base → error.
851
- - `refactors-existing` / `exists` / `deletes` + path **absent** at
852
- base → error.
853
- Errors are batched per-Story into the validator's `errors` envelope
854
- so the decompose loop surfaces every mismatch in a single re-prompt
855
- rather than one at a time.
856
- - **Scope-overlap check (docs/runbook downstream of config work)**:
857
- Scan for Stories whose scope is "docs update", "runbook", or
858
- "README" that land downstream of an earlier "config + runbook"
859
- Story in the same Epic. If the earlier Story's AC already covers
860
- the same document, the downstream Story's deliverable is likely
861
- absorbed. Append a "Scope verification note" to the downstream
862
- Story body pointing the executor to `git diff main -- <path>`
863
- against the upstream Story branch so they can confirm whether a
864
- substantive edit is still required (or only a cross-reference
865
- remains). The decomposer system prompt emits this flag
866
- automatically where it can detect the pattern — this checklist
867
- item is the human/host-LLM backstop.
868
- - **Action**: Fix any scope-overlap exceptions or validator failures by
869
- re-running the scripted force path so the change is recorded in tooling
870
- rather than hand-applied:
871
-
872
- ```bash
873
- node .agents/scripts/epic-plan-decompose.js \
874
- --epic [Epic_ID] \
875
- --tickets temp/epic-[Epic_ID]/tickets.json \
876
- --force
877
- ```
878
-
879
- 8. **Audit**:
880
- - Check the Epic's comment thread to ensure the backlog summary was posted.
881
- - Verify that at least one `type::story` issue was created.
882
-
883
- 9. **Cleanup**: The wrapper script (`epic-plan-decompose.js`) deletes the
884
- Phase 8 temp files automatically on success — no operator action required.
885
- The cleanup contract lives in
886
- [`lib/plan-phase-cleanup.js`](../../scripts/lib/plan-phase-cleanup.js).
887
-
888
- ## Phase 9: Execution Roadmap (Story Dispatch)
889
-
890
- 1. **Generate Roadmap**: Automatically invoke the dispatcher in dry-run mode to
891
- calculate execution waves and model recommendations:
892
-
893
- ```bash
894
- node .agents/scripts/dispatcher.js [Epic_ID] --dry-run
895
- ```
896
-
897
- 2. **Verify Output**:
898
- - Confirm the **Story Dispatch Table** is printed.
899
- - Check for any stories in **Wave 0** — these are ready for immediate
900
- execution.
901
-
902
- > **Manifest persistence (v5.9.0):** the dispatcher also posts the manifest
903
- > as a `dispatch-manifest` structured comment on the Epic (idempotent —
904
- > re-runs replace the prior comment). That comment is the source of truth for
905
- > the Wave Completeness Gate in `/deliver` Step 0.5 and for any external
906
- > wave-tracking tooling.
907
-
908
- 3. **Handoff**: Provide the user with the recommended next step:
909
-
910
- > "Planning is complete. Run `/deliver #[Epic ID]` to start the wave
911
- > loop, or pick a single Story from Wave 0 and run `/deliver #[Story
912
- > ID]` to drive it directly."
913
-
914
- ## Phase 10: Readiness Health Check
915
-
916
- Run the post-plan health check to validate the backlog before handing off to
917
- `/deliver`. The default mode runs only the cheap checks
918
- (config + git remote) and targets sub-2-second turnaround. The script itself
919
- always exits 0; the structured JSON on stdout reports findings.
106
+ One refinement pass per invocation do not loop.
107
+
108
+ ### Gate #1 exit of interrogate (HITL STOP)
109
+
110
+ One operator confirmation folds every interrogate outcome: the one-pager (or
111
+ the refined-body diff), the scope-triage verdict, the duplicate candidates,
112
+ and the re-plan decision. Display them together and **STOP**. Do not enter
113
+ step 2 until the operator explicitly confirms.
114
+
115
+ > **`--yes` (headless) auto-proceed.** Under `--yes` this gate does **not**
116
+ > STOP: the confirm resolves as **approved**, and a `story` / `borderline`
117
+ > triage verdict resolves to its **Recommended** branch. The interrogation
118
+ > itself runs exactly **one bounded pass** no operator questions are asked;
119
+ > facts come from the codebase and every unresolved unknown lands in the
120
+ > one-pager's **Key Assumptions** section instead of a question, so a
121
+ > headless driver can never hang. See
122
+ > [`plan.md` § Headless / non-interactive mode](../plan.md#headless--non-interactive-mode---yes).
123
+
124
+ ## Step 2 Author
125
+
126
+ Read the envelope with the `Read` tool and write the planning artifacts to
127
+ `temp/epic-[Epic_ID]/` (ideation: the `temp/plan-ideation/<slug>/` tree).
128
+ The single `plan-context.json` envelope supersedes the per-phase
129
+ `planner-context.json` / `decomposer-context.json` files the authoring
130
+ skills name — read the envelope wherever a skill asks for either.
131
+
132
+ 1. **`techspec.md`** — activate the
133
+ [`epic-plan-spec-author`](../../skills/core/epic-plan-spec-author/SKILL.md)
134
+ skill. The Tech Spec opens with `## Delivery Slicing` and never restates
135
+ the Epic's Context/Goal/Scope.
136
+ 2. **`risk-verdict.json`** — same skill; the schema-conformant verdict
137
+ **plus `deliveryShape: "fan-out"|"single"`** and a one-line rationale.
138
+ Seed the shape from the envelope's `deliveryShapeSignal` (advisory
139
+ the operator vetoes it at gate #2). `"single"` means one-pass-sized or a
140
+ pure dependent chain: the plan ships as spec-only, with **no tickets**.
141
+ 3. **`acceptance-spec.md`** same skill; omit only when the Epic carries
142
+ the `acceptance::n-a` waiver label.
143
+ 4. **`tickets.json`** fan-out shape only: activate the
144
+ [`epic-plan-decompose-author`](../../skills/core/epic-plan-decompose-author/SKILL.md)
145
+ skill against the same envelope (its `systemPrompts.decompose`,
146
+ `ticketSchema`, and `maxTickets` fields). In single-delivery shape author
147
+ **no** tickets filethe Delivery Slicing table is the plan.
148
+
149
+ > **One-pass refinement contract (amend, don't regenerate).** When a critic
150
+ > flags Stories or the step 3 persist rejects an artifact, apply **targeted
151
+ > edits** to the existing files — fix only what was named — and re-run the
152
+ > rejected step **once**. Never loop wholesale re-authoring.
153
+
154
+ ### Conditional critics (between authoring and gate #2)
155
+
156
+ Evaluate the dispatch conditions deterministically first — one git-local
157
+ CLI call, zero GitHub reads:
920
158
 
921
159
  ```bash
922
- node .agents/scripts/epic-plan-healthcheck.js --epic [Epic_ID]
160
+ node .agents/scripts/plan-critics.js --epic [Epic_ID]
923
161
  ```
924
162
 
925
- **The healthcheck is a blocking exit condition for `agent::ready`.**
926
- Story #2921 (Epic #2880 F7) wired the persist half of
927
- `epic-plan-decompose.js` to re-run the same default check before
928
- flipping the Epic to `agent::ready`.
929
- When the inline run reports `ok: false`, the persist phase **refuses the
930
- flip** and throws with the failing check's `reason`. The Epic stays on its
931
- prior label (`agent::review-spec` in the normal flow) until either the
932
- underlying check passes on a rerun, or the operator applies the
933
- `planning::healthcheck-waived` label to the Epic and reruns the persist
934
- phase. See `.agents/docs/SDLC.md` § "`agent::ready` exit conditions" for the
935
- full handoff contract and the waiver scope.
163
+ (ideation: pass `--tech-spec`/`--risk-verdict`/`--tickets` explicitly). The
164
+ verdict names each critic with `dispatch: true|false` and reasons. Dispatch
165
+ a sub-agent ONLY for a critic with `dispatch: true`; surface each skip as a
166
+ one-line note. Every skip decision is appended to the plan-metrics ledger
167
+ (`kind: "critic-skip"`, with reasons) so under-firing is auditable the
168
+ persist validators remain unchanged hard gates either way.
169
+
170
+ Both critics are **fresh-context sub-agents** (`Agent` tool,
171
+ `subagent_type: general-purpose`) never inline skill activations, so they
172
+ cannot grade their own homework. Both are report-only: they never write to
173
+ GitHub and never persist `tickets.json`; their findings fold into the gate #2
174
+ view, and accepted findings get one targeted amend pass (above).
175
+
176
+ - **Consolidation critic** (fan-out only): fires when the draft does NOT
177
+ already match the Tech Spec's Delivery Slicing table 1:1 in Story count
178
+ and dependency shape, AND the divergence is worth a dispatch — the draft
179
+ has more than 5 stories, or the mismatch is confirmed (a small draft
180
+ whose table is merely missing/unparseable skips: gate #2's single view
181
+ covers it). On dispatch the sub-agent reads the
182
+ [`epic-plan-consolidate`](../../skills/core/epic-plan-consolidate/SKILL.md)
183
+ skill and reconciles the draft against the slicing target. Its operations
184
+ are scope-preserving only — merge sibling Stories and rewire `depends_on`;
185
+ it MUST NOT add scope or invent tickets.
186
+ - **Pre-mortem critic**: fires when the risk verdict's overall level is
187
+ high, OR the ticket count is at least half `maxTickets`, OR any
188
+ `planning.riskHeuristics` phrase matches the plan text. On dispatch the
189
+ sub-agent reads the
190
+ [`epic-plan-premortem`](../../skills/core/epic-plan-premortem/SKILL.md)
191
+ skill, reads the actual cited code surfaces, and emits predicted-rework
192
+ findings to `temp/epic-[Epic_ID]/premortem-report.md`.
193
+
194
+ ## Step 3 — Persist
195
+
196
+ ### Gate #2 — risk-routed review (HITL STOP, before any GitHub write)
197
+
198
+ Present the whole plan in **one view**: the Tech Spec, the Acceptance Table,
199
+ the tickets (or the Delivery Slicing table in single shape), the risk
200
+ verdict, the `deliveryShape`, and any critic reports. This is the single
201
+ seam where the operator vetoes single-vs-fan-out routing.
202
+
203
+ - **High risk** (any risk axis high / `requiresReview`-shaped verdict) or
204
+ **operator override** (`--force-review`): **STOP** for explicit operator
205
+ approval before running the persist CLI.
206
+ - **Low risk**: emit a one-line auto-proceed note and continue directly to
207
+ the persist call — no operator wait. (`--yes` is a no-op on this branch —
208
+ there is no STOP to suppress.)
209
+
210
+ > **`--yes` (headless) auto-proceed.** Under `--yes` this review gate does
211
+ > **not** STOP, even when the verdict is high-risk or `--force-review` was
212
+ > passed: the review resolves as **approved** and the run continues to the
213
+ > persist call. `--yes` does **not** alter risk routing or the review
214
+ > criteria themselves — it only forces a proceed where this gate would
215
+ > otherwise STOP. See
216
+ > [`plan.md` § Headless / non-interactive mode](../plan.md#headless--non-interactive-mode---yes).
217
+
218
+ ### Run the persist CLI
936
219
 
937
- The script emits a single line of JSON to stdout:
938
-
939
- ```json
940
- {
941
- "ok": true,
942
- "degraded": false,
943
- "reason": null,
944
- "checks": [
945
- { "name": "config", "ok": true, "durationMs": 12, "detail": "..." },
946
- { "name": "git-remote", "ok": true, "durationMs": 234, "detail": "..." }
947
- ]
948
- }
220
+ ```bash
221
+ # Normal persist (artifact paths default to temp/epic-[Epic_ID]/)
222
+ node .agents/scripts/plan-persist.js --epic [Epic_ID]
223
+
224
+ # Re-plan (overwrite managed sections in place; close + recreate the tree)
225
+ node .agents/scripts/plan-persist.js --epic [Epic_ID] --force
226
+
227
+ # Ideation (opens the Epic itself; artifact paths must be explicit)
228
+ node .agents/scripts/plan-persist.js \
229
+ --one-pager temp/plan-ideation/<slug>/one-pager.md \
230
+ --tech-spec temp/plan-ideation/<slug>/techspec.md \
231
+ --risk-verdict temp/plan-ideation/<slug>/risk-verdict.json \
232
+ --acceptance-table temp/plan-ideation/<slug>/acceptance-spec.md \
233
+ --tickets temp/plan-ideation/<slug>/tickets.json
234
+
235
+ # Change-request delta (tickets carry op: add|modify|keep|close;
236
+ # close ops additionally require --explicit-delete after the dry-run diff)
237
+ node .agents/scripts/plan-persist.js --epic [Epic_ID] --amend
949
238
  ```
950
239
 
951
- Modes (additive the fast checks always run):
952
-
953
- - **(default)** config validation + git remote check only.
954
- - **`--paranoid`** adds ticket-hierarchy revalidation. Requires `--epic`.
955
- Use this when you want the full backlog audit before execution.
956
- - **`--prime-install`** adds the pnpm content-addressable-store prime
957
- (`pnpm install --frozen-lockfile`, up to 300s). Run only when
958
- `nodeModulesStrategy: 'pnpm-store'` is configured and you want subsequent
959
- worktree installs to be near-instant instead of fetching from scratch.
960
-
961
- If `ok` is `false`, review the entries in `checks[]`, resolve the failing
962
- check(s), and rerun the persist phase. Apply `planning::healthcheck-waived`
963
- to the Epic only when the failure is environmental and the operator has
964
- triaged it (e.g. a known `origin` outage during a maintenance window).
965
-
966
- ## Phase 11: Plan Comprehension Gate
967
-
968
- An **opt-in, advisory** gate that offers the operator a guided walkthrough of
969
- the freshly planned backlog before they hand off to `/deliver`. The plan
970
- is the moment the operator authorizes an autonomous fan-out of subagents — this
971
- phase exists so they can *understand and endorse* the approach while it is
972
- still free to change, not after the code lands.
973
-
974
- > **Non-blocking by construction.** This phase runs **after** Phase 10 has
975
- > already flipped the Epic to `agent::ready`. It never gates that flip, never
976
- > blocks the handoff, and the operator can decline or stop it at any point.
977
- > `risk::high` remains planning metadata and `agent::blocked` remains the only
978
- > mandatory runtime pause this gate adds neither.
979
-
980
- ### 1. Decide whether to offer the walkthrough (LM judgment)
981
-
982
- There is **no `--flag`**. Evaluate the plan with judgment and **default to
983
- skipping silently**. Offer the walkthrough only when the plan is genuinely
984
- worth one. Signals that warrant offering:
985
-
986
- - The roadmap spans **multiple waves** or a **large Story count**.
987
- - Any Story or the Epic carries **`risk::high`**, or the plan matches the
988
- `planning.riskHeuristics` in `.agentrc.json` (destructive/irreversible
989
- changes, shared auth/security, CI/CD gate changes, monorepo-wide rewrites,
990
- destructive migrations).
991
- - The Tech Spec introduces a **novel architectural decision** or a wide
992
- **blast radius** across subsystems.
993
-
994
- A small, single-wave, low-risk plan proceeds straight to Phase 12 with no
995
- prompt. When in doubt on a borderline plan, make a one-line offer rather than
996
- forcing the walkthrough.
997
-
998
- ### 2. Run the walkthrough (when offered and accepted)
999
-
1000
- Activate the
1001
- [`core/knowledge-transfer`](../../skills/core/knowledge-transfer/SKILL.md) skill
1002
- with the **plan** as the subject — the Epic body (whose managed sections
1003
- carry the Tech Spec), the decomposition (Stories with inline
1004
- `acceptance[]` / `verify[]`), and the Phase 9 wave roadmap. The skill owns the
1005
- method (restate-first, the why-ladder, mastery gates, depth levels, optional
1006
- quizzing, the persistent `temp/comprehension-*.md` checklist).
1007
-
1008
- **Interruptible at every checkpoint.** Each step MUST offer an explicit
1009
- "I'm good — proceed to `/deliver`" exit. The instant the operator takes
1010
- it, stop the walkthrough and advance to Phase 12. Never trap the operator in
1011
- the loop.
1012
-
1013
- ### 3. Advance
1014
-
1015
- Whether the walkthrough was skipped, declined, completed, or stopped early,
1016
- proceed to Phase 12. This gate produces no label transition and no blocking
1017
- condition.
1018
-
1019
- ## Phase 12: Notification & Handoff
1020
-
1021
- 1. **Notify Operator (INFO)**:
1022
- - Post a summary comment on the Epic issue with work breakdown stats.
1023
- - @mention the operator (informational — no webhook for planning) by running
1024
- the notification script:
1025
-
1026
- ```bash
1027
- node .agents/scripts/notify.js [Epic_ID] "Planning complete, review tickets. Backlog decomposition complete. Epic is ready for /deliver." --action
1028
- ```
240
+ The CLI runs every deterministic step in one ordered, fail-closed pass:
241
+ section gate (`## Delivery Slicing` required) → risk-verdict validation +
242
+ mode-coherence hard error (`deliveryShape: "single"` with tickets, or
243
+ fan-out without them, refuses) `validateAndNormalizeTickets` +
244
+ file-assumption gate + DAG + sizing/budget (fan-out and amend) ideation
245
+ Epic creation Epic lease (`--steal` transfers a confirmed-dead claim) →
246
+ managed sections + `risk-verdict` comment + spec-freshness advisory story
247
+ tree via the structural reconciler (single shape: the `delivery::single`
248
+ routing marker and a zero-ticket checkpoint instead) inline healthcheck
249
+ (the **blocking** `agent::ready` exit condition; waive only via the
250
+ `planning::healthcheck-waived` label) one terminal `agent::ready` flip (no
251
+ intermediate `agent::review-spec`) checkpoint v2 + a single `plan-summary`
252
+ comment carrying the dry-run wave table temp cleanup **only at terminal
253
+ success**, so a failed run leaves the artifacts in place for `--force` /
254
+ `--resume` reuse.
255
+
256
+ ### Persist rejections and soft failures
257
+
258
+ Each rejection names the artifact and the gap; apply the one-pass amend
259
+ contract (step 2) and re-run the persist once:
260
+
261
+ - **Section gate / validator / file-assumption / DAG errors** — targeted
262
+ edit to `techspec.md` or `tickets.json`.
263
+ - **Reachability orphans** (deterministic route-glob vs `navRegistry` check;
264
+ a silent no-op when `planning.navigation` is unconfigured) a named
265
+ **soft failure** (exit 3, before any GitHub write) listing the orphaned
266
+ surfaces: apply one targeted amend adding a navigation owner
267
+ (at most one reachability Story per plan), then re-persist.
268
+ - **Over budget** (`maxTickets`) — re-scope, or re-run with
269
+ `--allow-over-budget` after confirming the rationale on the Epic.
270
+ - **Rate-limit abort on a large Epic** — resume with `--resume`; see
271
+ [`plan-epic-reference.md` § `--resume` recovery](plan-epic-reference.md#persist----resume-recovery-secondary-rate-limit).
272
+
273
+ ### Handoff
274
+
275
+ > "Planning is complete. Run `/deliver #[Epic_ID]` to start the wave loop,
276
+ > or pick a single Story from Wave 0 (the `plan-summary` comment's wave
277
+ > table) and run `/deliver #[Story_ID]` to drive it directly."
1029
278
 
1030
279
  ## Troubleshooting & recovery
1031
280
 
1032
- Troubleshooting symptoms (emit-context failures, tickets-file rejections, a
1033
- decomposition that persisted but left the Epic off `agent::ready`) and the
1034
- large-Epic **secondary-rate-limit `--resume`** recovery path live in the
1035
- reference companion — they are consulted only when a run hits the edge:
281
+ Edge-case procedures live in the reference companion:
1036
282
 
1037
283
  - [`plan-epic-reference.md` § Troubleshooting](plan-epic-reference.md#troubleshooting)
1038
- - [`plan-epic-reference.md` § Phase 8`--resume` recovery (secondary rate limit)](plan-epic-reference.md#phase-8----resume-recovery-secondary-rate-limit)
284
+ - [`plan-epic-reference.md` § Persist guardsbackground rationale](plan-epic-reference.md#persist-guards--background-rationale)
285
+ - [`plan-epic-reference.md` § `--resume` recovery](plan-epic-reference.md#persist----resume-recovery-secondary-rate-limit)