mandrel 1.81.0 → 1.83.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 (121) hide show
  1. package/.agents/README.md +46 -5
  2. package/.agents/docs/SDLC.md +97 -82
  3. package/.agents/docs/agentrc-reference.json +10 -2
  4. package/.agents/docs/configuration.md +4 -1
  5. package/.agents/docs/execution-reference.md +52 -0
  6. package/.agents/docs/workflows.md +1 -1
  7. package/.agents/instructions.md +85 -45
  8. package/.agents/personas/architect.md +8 -5
  9. package/.agents/personas/engineer-mobile.md +3 -2
  10. package/.agents/personas/engineer-web.md +3 -2
  11. package/.agents/personas/engineer.md +6 -5
  12. package/.agents/personas/product.md +19 -13
  13. package/.agents/personas/project-manager.md +9 -8
  14. package/.agents/personas/qa-engineer.md +10 -6
  15. package/.agents/personas/refactorer.md +3 -2
  16. package/.agents/personas/technical-writer.md +2 -1
  17. package/.agents/personas/ux-designer.md +2 -2
  18. package/.agents/schemas/agentrc.schema.json +41 -3
  19. package/.agents/schemas/qa-ledger.schema.json +2 -2
  20. package/.agents/scripts/acceptance-spec-reconciler.js +143 -59
  21. package/.agents/scripts/epic-deliver-prepare.js +40 -31
  22. package/.agents/scripts/epic-plan-decompose.js +2 -5
  23. package/.agents/scripts/epic-plan-spec.js +16 -19
  24. package/.agents/scripts/hierarchy-gate.js +11 -11
  25. package/.agents/scripts/lib/ITicketingProvider.js +4 -3
  26. package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
  27. package/.agents/scripts/lib/bdd-scenario-scanner.js +1 -1
  28. package/.agents/scripts/lib/cli-args.js +1 -5
  29. package/.agents/scripts/lib/codebase-snapshot.js +1 -1
  30. package/.agents/scripts/lib/config/explain.js +4 -1
  31. package/.agents/scripts/lib/config/temp-paths.js +1 -4
  32. package/.agents/scripts/lib/config-settings-schema.js +30 -1
  33. package/.agents/scripts/lib/epic-body-sections.js +310 -0
  34. package/.agents/scripts/lib/epic-plan-clarity.js +38 -1
  35. package/.agents/scripts/lib/epic-plan-ideation.js +15 -3
  36. package/.agents/scripts/lib/findings/promote-finding.js +3 -3
  37. package/.agents/scripts/lib/findings/severity.js +5 -6
  38. package/.agents/scripts/lib/label-constants.js +7 -17
  39. package/.agents/scripts/lib/label-taxonomy.js +4 -21
  40. package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +65 -2
  41. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +105 -9
  42. package/.agents/scripts/lib/orchestration/doc-reader.js +29 -0
  43. package/.agents/scripts/lib/orchestration/docs-digest.js +134 -0
  44. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +23 -22
  45. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +7 -10
  46. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +4 -38
  47. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +8 -9
  48. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +11 -5
  49. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +26 -5
  50. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +102 -304
  51. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +32 -29
  52. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +19 -20
  53. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-authoring-grounding.js +1 -1
  54. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +6 -9
  55. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +3 -4
  56. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +1 -1
  57. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +20 -27
  58. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +11 -5
  59. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +22 -59
  60. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
  61. package/.agents/scripts/lib/orchestration/planning-context-budget.js +1 -1
  62. package/.agents/scripts/lib/orchestration/preflight-cache.js +1 -1
  63. package/.agents/scripts/lib/orchestration/spec-freshness.js +3 -3
  64. package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
  65. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +15 -1
  66. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +122 -1
  67. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +5 -8
  68. package/.agents/scripts/lib/orchestration/ticketing/reads.js +2 -2
  69. package/.agents/scripts/lib/plan-phase-cleanup.js +1 -2
  70. package/.agents/scripts/lib/qa/console-allowlist.js +5 -4
  71. package/.agents/scripts/lib/qa/qa-context-hydrator.js +6 -85
  72. package/.agents/scripts/lib/qa/resolve-qa-contract.js +144 -8
  73. package/.agents/scripts/lib/templates/decomposer-prompts.js +14 -8
  74. package/.agents/scripts/lifecycle-emit.js +1 -1
  75. package/.agents/scripts/lint-label-vocabulary.js +2 -3
  76. package/.agents/scripts/providers/github/mappers.js +0 -3
  77. package/.agents/scripts/providers/github/tickets.js +7 -18
  78. package/.agents/scripts/single-story-init.js +0 -1
  79. package/.agents/scripts/story-init.js +1 -29
  80. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +43 -22
  81. package/.agents/skills/core/epic-plan-consolidate/examples.md +51 -0
  82. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +27 -40
  83. package/.agents/skills/core/epic-plan-decompose-author/examples.md +47 -0
  84. package/.agents/skills/core/epic-plan-premortem/SKILL.md +15 -13
  85. package/.agents/skills/core/epic-plan-premortem/examples.md +53 -0
  86. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +143 -151
  87. package/.agents/skills/core/epic-plan-spec-author/examples.md +91 -0
  88. package/.agents/skills/core/hydrate-context/SKILL.md +10 -5
  89. package/.agents/skills/core/knowledge-transfer/SKILL.md +3 -2
  90. package/.agents/skills/core/scope-triage/SKILL.md +2 -1
  91. package/.agents/skills/skills.index.json +8 -8
  92. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +52 -38
  93. package/.agents/templates/epic-from-idea.md +4 -0
  94. package/.agents/workflows/audit-to-stories.md +2 -2
  95. package/.agents/workflows/helpers/code-review.md +11 -9
  96. package/.agents/workflows/helpers/deliver-epic-reference.md +514 -0
  97. package/.agents/workflows/helpers/deliver-epic.md +173 -490
  98. package/.agents/workflows/helpers/epic-audit.md +11 -8
  99. package/.agents/workflows/helpers/epic-deliver-story.md +45 -27
  100. package/.agents/workflows/helpers/epic-plan-decompose.md +17 -12
  101. package/.agents/workflows/helpers/epic-plan-spec.md +68 -68
  102. package/.agents/workflows/helpers/parallel-tooling.md +2 -1
  103. package/.agents/workflows/helpers/plan-epic-reference.md +136 -0
  104. package/.agents/workflows/helpers/plan-epic.md +141 -256
  105. package/.agents/workflows/helpers/plan-story.md +31 -61
  106. package/.agents/workflows/helpers/qa-run-scenario.md +194 -0
  107. package/.agents/workflows/helpers/scope-triage-gate.md +97 -0
  108. package/.agents/workflows/helpers/single-story-deliver-reference.md +423 -0
  109. package/.agents/workflows/helpers/single-story-deliver.md +129 -393
  110. package/.agents/workflows/helpers/worktree-lifecycle.md +1 -1
  111. package/.agents/workflows/plan.md +8 -8
  112. package/.agents/workflows/qa-assist.md +2 -1
  113. package/.agents/workflows/qa-explore.md +63 -32
  114. package/.agents/workflows/qa-run.md +293 -130
  115. package/docs/CHANGELOG.md +35 -0
  116. package/package.json +1 -1
  117. package/.agents/schemas/qa-finding.schema.json +0 -133
  118. package/.agents/scripts/lib/issue-link-parser.js +0 -74
  119. package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +0 -116
  120. package/.agents/scripts/lib/orchestration/planning-state-manager.js +0 -318
  121. package/.agents/scripts/lib/story-init/hierarchy-tracer.js +0 -57
@@ -44,12 +44,15 @@ change-set selection. Both lens sources fire through the **same**
44
44
  2. Resolve `[EPIC_BRANCH]` — `epic/<epicId>`.
45
45
  3. Resolve `[BASE_BRANCH]` from `baseBranch` in `.agentrc.json` (default:
46
46
  `main`).
47
- 4. Fetch the Epic ticket and identify linked context tickets:
48
- - **PRD** — the `context::prd` ticket linked in the Epic body.
49
- - **Tech Spec** — the `context::tech-spec` ticket linked in the Epic
50
- body.
51
- 5. Read both the PRD and Tech Spec fully to understand the intended scope,
52
- selected lenses, and acceptance criteria.
47
+ 4. Fetch the Epic ticket — the Epic body is the single planning
48
+ document:
49
+ - **Narrative sections** — Context / Goal / Scope / User Stories /
50
+ Acceptance Criteria.
51
+ - **Tech Spec** — the folded Tech Spec sections (opening with
52
+ `## Delivery Slicing`) inside the body's managed region.
53
+ 5. Read the Epic body fully (including its Tech Spec sections) to
54
+ understand the intended
55
+ scope, selected lenses, and acceptance criteria.
53
56
 
54
57
  ## Step 1 — Prepare (`epic-audit-prepare.js`)
55
58
 
@@ -226,7 +229,7 @@ For each 🔴 / 🟠 finding, the host LLM MUST decide between two paths:
226
229
  (path 2) and record the attempt context in Step 4.
227
230
  2. **Escalate to the operator via Step 4.** Required when the finding
228
231
  falls into any of the following classes:
229
- - `spec-deviation` — the change diverges from the PRD/Tech Spec.
232
+ - `spec-deviation` — the change diverges from the Epic/Tech Spec.
230
233
  - `secrets` — credentials, tokens, or PII surfaced in the diff.
231
234
  - `test-deletion` — coverage was removed without an explicit
232
235
  decision in the spec.
@@ -282,7 +285,7 @@ The body MUST include:
282
285
 
283
286
  - **Always** diff against `[BASE_BRANCH]`, not against individual Story
284
287
  branches. The audit examines the cumulative effect of the entire Epic.
285
- - **Always** read the PRD and Tech Spec before walking lenses. Findings
288
+ - **Always** read the Epic body and Tech Spec before walking lenses. Findings
286
289
  without spec context are noise.
287
290
  - **Always** cap focused fixes at one attempt per finding (Step 3). The
288
291
  host LLM is the executor; there is no shared retry/anti-thrash module
@@ -77,21 +77,15 @@ the parent's permissions but have **no input channel** mid-run.
77
77
  Run from the **main checkout** (the worktree does not exist yet):
78
78
 
79
79
  ```bash
80
- node .agents/scripts/story-init.js --story <storyId> \
81
- --prd <prdId> --tech-spec <techSpecId>
80
+ node .agents/scripts/story-init.js --story <storyId>
82
81
  ```
83
82
 
84
- **Thread the Epic linkages (Story #4253).** The parent `/deliver` resolved
85
- the Epic's `prdId` / `techSpecId` **once** in its Phase 1 prepare and passed
86
- them into your dispatch prompt. Forward them as `--prd` / `--tech-spec` so
87
- this `story-init.js` run **skips** the per-Story `getEpic` round-trip — the
88
- two ids are invariant for the whole delivery run, so re-fetching the
89
- immutable Epic per Story is pure waste (and secondary-rate-limit pressure
90
- during wide fan-out). **Omit** whichever flag the prompt reported as `null`;
91
- `story-init.js` then falls back to its own `getEpic` resolution for the
92
- missing id (graceful degradation on a missing Epic linkage). When dispatched
93
- interactively with neither flag, drop both — the legacy single-fetch path is
94
- unchanged.
83
+ **No spec-ticket threading (Story #4324).** The Tech Spec lives as managed
84
+ sections of the Epic body — there is no separate Tech-Spec issue, no
85
+ `--tech-spec` flag, and no per-Story hierarchy trace to a spec ticket.
86
+ Your hydrated prompt already embeds the Epic body (with the
87
+ `## Acceptance Table` section stripped), which carries the folded Tech
88
+ Spec sections; do not fetch a Tech Spec issue.
95
89
 
96
90
  > **Execution mode (sub-agents must read).** This command typically takes
97
91
  > 3–6 minutes when the worktree's per-tree install runs. Invoke it
@@ -105,15 +99,15 @@ unchanged.
105
99
  > partial state, so the recovery is to re-run it synchronously, but
106
100
  > prevention is cheaper: just give Bash the 10-minute timeout and block.
107
101
 
108
- The script validates `type::story`, checks blockers, traces the
109
- Epic → PRD/Tech-Spec hierarchy, seeds `story-<id>` from the
102
+ The script validates `type::story`, checks blockers, resolves the parent
103
+ Epic id, seeds `story-<id>` from the
110
104
  Epic branch, and (when worktree isolation is on) runs `git worktree add`
111
105
  at `.worktrees/story-<id>/`. The Story flips to `agent::executing`. A
112
106
  `story-init` structured comment is upserted with the Story's inline
113
107
  `acceptance[]` and `verify[]` arrays from the body.
114
108
 
115
109
  Capture `workCwd`, `dependenciesInstalled` (tri-state), and
116
- `context.{prdId,techSpecId,acceptance,verify}`. Add `--dry-run` to check
110
+ `context.parentId`. Add `--dry-run` to check
117
111
  status without git or ticket changes.
118
112
 
119
113
  ### Step 0.5 — `cd` into the workCwd
@@ -139,11 +133,15 @@ in-process (retrying the install command when
139
133
  `dependenciesInstalled === 'false'`, default `npm ci`) and rendered the
140
134
  initial snapshot (`phase: "init"`). There is no separate command to run.
141
135
 
142
- The Step 0 result envelope carries a `prepare.renderedBody` field — the
143
- markdown body for the initial Story-phase table. **Relay it verbatim to
144
- chat** so operators see the initial progress block before the first commit
145
- lands. Do the same after every transition in Step 1 / Step 3 (the body is
146
- the Story-level rollup the parent `/deliver` aggregator reads).
136
+ Step 0's init run already upserted the initial `story-run-progress`
137
+ snapshot (`phase: "init"`) as a structured comment on the Story — that
138
+ comment, refreshed by `story-phase.js` at each transition, is the
139
+ authoritative Story-level rollup the parent `/deliver` aggregator reads.
140
+ You do **not** relay `prepare.renderedBody` verbatim to chat. Instead,
141
+ relay **one line per phase transition** (e.g. `Story #<id>: init →
142
+ implementing`), and do the same after every transition in Step 1 / Step 3.
143
+ The snapshot CLI carries the full body; the chat line is a terse progress
144
+ delta, not a body dump.
147
145
 
148
146
  ---
149
147
 
@@ -168,6 +166,20 @@ Run a single Story-implementation phase against the inline `acceptance[]`
168
166
  `context.verify`). Treat the acceptance items as the contract and
169
167
  the verify items as the canonical at-keyboard checks.
170
168
 
169
+ **Docs context — read the digest, not the full set.** Do **not**
170
+ re-read every file in `project.docsContextFiles`. The parent prompt
171
+ passes a `docsDigestPath` (the per-Epic docs digest at
172
+ `temp/epic-<epicId>/docs-digest.md`, written by
173
+ `epic-deliver-prepare.js`). Read that digest — a compact per-file
174
+ outline (path, size, heading outline with line numbers, first
175
+ paragraph under each `##`) — to decide which docs bear on this Story,
176
+ then **pull the full file on demand** (jump to the section at the line
177
+ number the digest names) only when relevant. When `docsDigestPath` is
178
+ null (the project configured no `docsContextFiles`), there is no
179
+ digest and no per-Story docs mandate — read a full doc only if the
180
+ Story's own context points you at one. See
181
+ [`.agents/instructions.md` § 3](../../instructions.md).
182
+
171
183
  3. Implement the work as one or more commits on `story-<storyId>`.
172
184
  Author commits directly with the project's editor / `git commit`,
173
185
  following
@@ -246,10 +258,14 @@ partially-implemented Story picks up from whatever commits are already
246
258
  on `story-<storyId>`; the agent inspects `git log` to decide what work
247
259
  remains.
248
260
 
249
- After each `story-phase.js` call, **relay the envelope's
250
- `renderedBody` to chat** as the Story's progress update. Skip chat
251
- relay only when running in a non-interactive sub-agent context where
252
- the parent will aggregate.
261
+ After each `story-phase.js` call, relay **one line naming the phase
262
+ transition** (e.g. `Story #<id>: implementing → closing`) as the Story's
263
+ progress update — not the envelope's `renderedBody` verbatim. The
264
+ `story-phase.js` CLI has already upserted the full body into the
265
+ `story-run-progress` snapshot; that comment is the authoritative rollup
266
+ the parent `/deliver` aggregator reads. Skip chat relay entirely when
267
+ running in a non-interactive sub-agent context where the parent will
268
+ aggregate.
253
269
 
254
270
  > Rebase pauses on conflicts → follow
255
271
  > [`_merge-conflict-template.md`](_merge-conflict-template.md).
@@ -344,8 +360,10 @@ regardless of the reap status.
344
360
  `story-phase.js` (typically the `phase: 'done'` snapshot at close,
345
361
  or the `phase: 'blocked'` snapshot on a blocker). The parent
346
362
  `/deliver` may inline a digest of this in its wave-level Notable
347
- section. When run interactively (no parent), omit it — the chat already
348
- has the latest body relayed during Step 1 / Step 3.
363
+ section. When run interactively (no parent), omit it — the authoritative
364
+ body lives in the `story-run-progress` snapshot the phase CLI upserted,
365
+ and the chat already carries the per-transition progress lines from
366
+ Step 1 / Step 3.
349
367
 
350
368
  ---
351
369
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: >-
3
- Phase 8 of sprint planning — decompose an Epic's PRD and Tech Spec into a
3
+ Phase 8 of sprint planning — decompose an Epic's sectioned body (which
4
+ carries the folded Tech Spec) into a
4
5
  backlog of child Stories, persist the backlog, and flip the Epic to
5
6
  `agent::ready`. Host-LLM authored; no external API calls.
6
7
  ---
@@ -18,8 +19,9 @@ Director / Architect
18
19
  ## Context
19
20
 
20
21
  This helper is the **decompose phase** of the split planning pipeline. It
21
- reads the PRD and Tech Spec previously produced by the spec phase helper
22
- ([`epic-plan-spec.md`](epic-plan-spec.md)), generates the Epic's child
22
+ reads the Epic body — whose managed sections carry the Tech Spec previously
23
+ produced by the spec phase
24
+ helper ([`epic-plan-spec.md`](epic-plan-spec.md)) — generates the Epic's child
23
25
  Story tickets, persists them to GitHub, and flips the Epic to
24
26
  `agent::ready` (parking) so a human can run `/deliver` when
25
27
  execution should begin.
@@ -38,9 +40,9 @@ skill.
38
40
 
39
41
  ## Constraint
40
42
 
41
- - **Do not** run this skill until the spec phase is complete. The Epic must
42
- have linked `context::prd` and `context::tech-spec` issues; the script will
43
- refuse to proceed otherwise.
43
+ - **Do not** run this skill until the spec phase is complete. The Epic body
44
+ must carry Tech Spec content (the managed section or a `## Delivery
45
+ Slicing` heading); the script will refuse to proceed otherwise.
44
46
  - **Do not** restructure the Story set after the decomposition
45
47
  writes — the `epic-plan-state` checkpoint records the structure as
46
48
  committed. Use `--force` to rebuild from scratch.
@@ -52,7 +54,7 @@ skill.
52
54
  ## Prerequisites
53
55
 
54
56
  1. **Epic is on `agent::review-spec`** — i.e. the spec phase has already run
55
- and the PRD / Tech Spec exist.
57
+ and the Epic body carries the Tech Spec sections.
56
58
  2. **API keys** — `GITHUB_TOKEN` set in `.env`.
57
59
 
58
60
  ## Step 1 — Gather decomposition context
@@ -62,7 +64,8 @@ node .agents/scripts/epic-plan-decompose.js --epic [Epic_ID] --emit-context \
62
64
  > temp/epic-[Epic_ID]/decomposer-context.json
63
65
  ```
64
66
 
65
- The emitted JSON contains the PRD body, Tech Spec body, risk heuristics, the
67
+ The emitted JSON contains the Epic body (`epicBody` — the spec sections and
68
+ acceptance table travel inside it), risk heuristics, the
66
69
  decomposer system prompt, and the `maxTickets` **reviewability budget**
67
70
  (Story #2798 — not a hard cap; over-budget plans require an explicit
68
71
  `--allow-over-budget` override at persist time).
@@ -74,7 +77,7 @@ Story objects that conforms to the schema in the system prompt
74
77
  and write it to `temp/epic-[Epic_ID]/tickets.json`.
75
78
 
76
79
  When the Tech Spec carries a `## Delivery Slicing` section, author toward the
77
- Architect's proposed shippable-Story clusters rather than mapping PRD
80
+ Architect's proposed shippable-Story clusters rather than mapping Epic
78
81
  capabilities 1:1; degrade gracefully (current behaviour) when it is absent.
79
82
 
80
83
  ## Step 2.5 — Phase 8.3: Holistic Consolidation (HITL diff gate)
@@ -87,7 +90,8 @@ deterministic validator and **before** the GitHub write.
87
90
  Activate the
88
91
  [`epic-plan-consolidate`](../../skills/core/epic-plan-consolidate/SKILL.md)
89
92
  skill with `[Epic_ID]` as input. It reads the draft
90
- `temp/epic-[Epic_ID]/tickets.json` plus the PRD / Tech Spec from
93
+ `temp/epic-[Epic_ID]/tickets.json` plus the Epic body (with its folded
94
+ Tech Spec sections) from
91
95
  `decomposer-context.json`, reconciles the draft against the Tech Spec
92
96
  `## Delivery Slicing` target (degrading gracefully when absent), and emits:
93
97
 
@@ -187,8 +191,9 @@ is the single source of truth for which temp paths this phase owns.
187
191
 
188
192
  ## Troubleshooting
189
193
 
190
- - "Epic #N is missing a linked PRD or Tech Spec" — run `/plan [Epic_ID]`
191
- first (it will run the spec phase if the PRD / Tech Spec are missing).
194
+ - "Epic #N body carries no Tech Spec sections (no ## Delivery Slicing)" —
195
+ run `/plan [Epic_ID]`
196
+ first (it will run the spec phase if the Tech Spec sections are missing).
192
197
  - Validator rejects the tickets file — the most common causes are a
193
198
  Story whose `parent_slug` does not point at a Feature, a missing
194
199
  `acceptance[]` / `verify[]` array on a Story body, or a Story
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  description: >-
3
- Phase 7 of sprint planning — generate the PRD and Tech Spec for an Epic,
4
- persist them as linked GitHub issues, and flip the Epic to
5
- `agent::review-spec`. Host-LLM authored; no external API calls.
3
+ Phase 7 of sprint planning — generate the Tech Spec and Acceptance Table for
4
+ an Epic, persist them as managed sections of the Epic body, and flip the
5
+ Epic to `agent::review-spec`. Host-LLM authored; no external API calls.
6
6
  ---
7
7
 
8
8
  # Sprint Plan — Spec Phase (helper)
@@ -18,22 +18,28 @@ Director / Architect
18
18
  ## Context
19
19
 
20
20
  This helper is the **spec phase** of the split planning pipeline. It produces
21
- **three** planning artifacts for an Epic — a Product Requirements Document, a
22
- Technical Specification, and an Acceptance Spec — persists them as
23
- `context::prd`, `context::tech-spec`, and `context::acceptance-spec` issues
24
- under the Epic, and flips the Epic to `agent::review-spec` (parking) so a human
25
- reviewer can read the artifacts on GitHub before decomposition.
21
+ two planning artifacts for an Epic — a Technical Specification and an
22
+ Acceptance Table — persists them as **marker-delimited managed sections of
23
+ the Epic body** (`<!-- mandrel:tech-spec:start/end -->` and
24
+ `<!-- mandrel:acceptance-table:start/end -->`), and flips the Epic to
25
+ `agent::review-spec` (parking) so a human reviewer can read the updated Epic
26
+ body on GitHub before decomposition. A `/plan` Epic run creates exactly
27
+ **one** issue — the Epic. The PRD artifact class was retired (Story #4314);
28
+ its one novel section, **User Stories**, lives inline in the Epic body.
29
+ Story #4324 retired the `context::tech-spec` / `context::acceptance-spec`
30
+ ticket classes the same way — the content semantics are unchanged, only
31
+ where the output lives moved.
26
32
 
27
33
  > **Single prose home.** The canonical, full-detail spec-phase contract
28
- > (idempotent context tickets, the three-ticket rationale, the
34
+ > (idempotent managed sections, the fold rationale, the
29
35
  > `acceptance::n-a` waiver, the Epic-lease preflight) lives in
30
36
  > [`epic-plan.md` § Phase 7](plan-epic.md). This helper carries only the
31
37
  > operational step list; when the two disagree, `epic-plan.md` wins.
32
38
 
33
- The PRD and Tech Spec are authored **directly by you, the host LLM**.
34
- `epic-plan-spec.js` is a deterministic wrapper that (a) emits the authoring
35
- context you need and (b) persists the artifacts and transitions the Epic
36
- lifecycle state.
39
+ The Tech Spec and Acceptance Table are authored **directly by you, the host
40
+ LLM**. `epic-plan-spec.js` is a deterministic wrapper that (a) emits the
41
+ authoring context you need and (b) persists the sections and transitions the
42
+ Epic lifecycle state.
37
43
 
38
44
  The complementary Phase 8 helper is
39
45
  [`epic-plan-decompose.md`](epic-plan-decompose.md). The `/plan`
@@ -41,14 +47,14 @@ wrapper chains both helpers with a confirmation gate in between.
41
47
 
42
48
  ## Constraint
43
49
 
44
- - **Do not** create or modify tickets outside the `context::prd` /
45
- `context::tech-spec` / `context::acceptance-spec` contract —
50
+ - **Do not** create any tickets from this phase — the only GitHub write is
51
+ the section-scoped Epic body update (plus structured comments);
46
52
  decomposition belongs to
47
53
  [`epic-plan-decompose.md`](epic-plan-decompose.md).
48
54
  - **Do not** flip the Epic to `agent::ready` from this skill. The terminal
49
55
  label for the spec phase is `agent::review-spec`.
50
56
  - **Every** temp file must include the Epic ID in its name. Multiple Epics may
51
- be planned concurrently; bare names like `temp/prd.md` will collide.
57
+ be planned concurrently; bare names like `temp/techspec.md` will collide.
52
58
  - **Stop and hand back to the operator** after Step 4 when
53
59
  `planningRisk.requiresReview` is true or the operator passed
54
60
  `--force-review` — do not chain into decomposition. Low-risk Epics
@@ -58,7 +64,8 @@ wrapper chains both helpers with a confirmation gate in between.
58
64
  ## Prerequisites
59
65
 
60
66
  1. **GitHub Epic** — an open issue with the `type::epic` label. The Epic's
61
- body should contain enough narrative context to seed the PRD.
67
+ body should contain enough narrative context (including its `## User
68
+ Stories` section) to seed the Tech Spec.
62
69
  2. **API keys** — `GITHUB_TOKEN` set in `.env`.
63
70
 
64
71
  ## Step 1 — Gather authoring context
@@ -71,23 +78,18 @@ node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] --emit-context \
71
78
  > temp/epic-[Epic_ID]/planner-context.json
72
79
  ```
73
80
 
74
- ## Step 2 — Author the PRD
81
+ ## Step 2 — Author the Tech Spec
75
82
 
76
- Read `temp/epic-[Epic_ID]/planner-context.json`. Using `systemPrompts.prd`
77
- combined with the Epic title/body, write the PRD markdown to
78
- `temp/epic-[Epic_ID]/prd.md`. Use the four-section structure (Context & Goals,
79
- User Stories, Acceptance Criteria, Out of Scope) and start the document with
80
- `## Overview` (no `<h1>`).
83
+ Read `temp/epic-[Epic_ID]/planner-context.json`. Using
84
+ `systemPrompts.techSpec`, the Epic body (its Context / Goal / Scope / User
85
+ Stories sections), and `docsContext`, write the Tech Spec to
86
+ `temp/epic-[Epic_ID]/techspec.md`. Open the document with the
87
+ `## Delivery Slicing` section (no `<h1>`); do not restate the Epic's
88
+ Context / Goal / Scope — the output lands as sections of the same Epic body.
81
89
 
82
- ## Step 3 — Author the Tech Spec
90
+ ## Step 2.5 — Author the risk verdict
83
91
 
84
- Using `systemPrompts.techSpec`, the PRD you just wrote, and `docsContext`,
85
- write the Tech Spec to `temp/epic-[Epic_ID]/techspec.md`. Start with
86
- `## Technical Overview` (no `<h1>`).
87
-
88
- ## Step 3.5 — Author the risk verdict
89
-
90
- Judge the change described by the PRD and Tech Spec you just wrote and
92
+ Judge the change described by the Epic body and Tech Spec you just wrote and
91
93
  write `temp/epic-[Epic_ID]/risk-verdict.json` conforming to
92
94
  [`risk-verdict.schema.json`](../../schemas/risk-verdict.schema.json):
93
95
  `{ axes: [{ axis, level, rationale }], summary }`. The authoritative
@@ -95,39 +97,36 @@ authoring rules (axis vocabulary, judgment-not-keywords, derivation
95
97
  preview) live in the
96
98
  [`epic-plan-spec-author` Skill, Step 4](../../skills/core/epic-plan-spec-author/SKILL.md).
97
99
 
98
- ## Step 3.6 — Author the Acceptance Spec
100
+ ## Step 2.6 — Author the Acceptance Table
99
101
 
100
- Using `systemPrompts.acceptanceSpec`, the PRD, and the Tech Spec, write the
101
- Acceptance Spec to `temp/epic-[Epic_ID]/acceptance-spec.md`. It captures the
102
- stable-ID acceptance criteria table
103
- (`| AC ID | Outcome | Feature File | Scenario | Disposition |`) that drives
104
- close-time reconciliation in `/deliver` Phase 6.
102
+ Using `systemPrompts.acceptanceSpec`, the Epic body, and the Tech Spec, write
103
+ the Acceptance Spec to `temp/epic-[Epic_ID]/acceptance-spec.md`. It opens
104
+ with `## Acceptance Table` and captures the stable-ID acceptance criteria
105
+ table (`| AC ID | Outcome | Feature File | Scenario | Disposition |`) that
106
+ drives close-time reconciliation in `/deliver` Phase 6.
105
107
 
106
108
  **Skip this step only** when the Epic carries the `acceptance::n-a` waiver
107
- label (refactor-only or docs-only Epics); in that case omit `--acceptance-spec`
108
- from Step 4.
109
+ label (refactor-only or docs-only Epics); in that case omit
110
+ `--acceptance-table` from Step 3.
109
111
 
110
- ## Step 4 — Persist and transition
112
+ ## Step 3 — Persist and transition
111
113
 
112
114
  ```bash
113
- # Normal flow (three context tickets)
115
+ # Normal flow (both managed sections)
114
116
  node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
115
- --prd temp/epic-[Epic_ID]/prd.md \
116
- --techspec temp/epic-[Epic_ID]/techspec.md \
117
+ --tech-spec temp/epic-[Epic_ID]/techspec.md \
117
118
  --risk-verdict temp/epic-[Epic_ID]/risk-verdict.json \
118
- --acceptance-spec temp/epic-[Epic_ID]/acceptance-spec.md
119
+ --acceptance-table temp/epic-[Epic_ID]/acceptance-spec.md
119
120
 
120
- # Re-plan (--force overwrites the three context tickets in place)
121
+ # Re-plan (--force overwrites the managed sections in place)
121
122
  node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
122
- --prd temp/epic-[Epic_ID]/prd.md \
123
- --techspec temp/epic-[Epic_ID]/techspec.md \
123
+ --tech-spec temp/epic-[Epic_ID]/techspec.md \
124
124
  --risk-verdict temp/epic-[Epic_ID]/risk-verdict.json \
125
- --acceptance-spec temp/epic-[Epic_ID]/acceptance-spec.md --force
125
+ --acceptance-table temp/epic-[Epic_ID]/acceptance-spec.md --force
126
126
 
127
- # Waived (acceptance::n-a label on Epic — no Acceptance Spec authored)
127
+ # Waived (acceptance::n-a label on Epic — no Acceptance Table authored)
128
128
  node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
129
- --prd temp/epic-[Epic_ID]/prd.md \
130
- --techspec temp/epic-[Epic_ID]/techspec.md \
129
+ --tech-spec temp/epic-[Epic_ID]/techspec.md \
131
130
  --risk-verdict temp/epic-[Epic_ID]/risk-verdict.json
132
131
  ```
133
132
 
@@ -136,22 +135,21 @@ On success the script:
136
135
  - Validates the risk verdict against `risk-verdict.schema.json` (a
137
136
  malformed verdict fails closed before any GitHub mutation) and derives
138
137
  the `planningRisk` envelope from it.
139
- - Creates `[PRD]`, `[Tech Spec]`, and `[Acceptance Spec]` child issues
140
- (`context::prd` / `context::tech-spec` / `context::acceptance-spec`
141
- labels). The Acceptance Spec is skipped when `--acceptance-spec` is
142
- omitted under the `acceptance::n-a` waiver.
143
- - Appends a `## Planning Artifacts` section to the Epic body.
138
+ - Upserts the Tech Spec content and (unless waived) the `## Acceptance
139
+ Table` as managed sections of the Epic body, stripping any legacy
140
+ `## Planning Artifacts` section. The Acceptance Table is skipped when
141
+ `--acceptance-table` is omitted under the `acceptance::n-a` waiver.
144
142
  - Upserts the `risk-verdict` structured comment recording the verdict and
145
143
  the derived envelope.
146
144
  - Upserts the `epic-plan-state` structured comment with the current phase,
147
- PRD / Tech Spec / Acceptance Spec IDs, the `riskVerdict` field, and
148
- timestamps.
145
+ the persisted-section flags (`techSpecPersisted`, `acceptanceTable`),
146
+ the `riskVerdict` field, and timestamps.
149
147
  - Flips the Epic to `agent::review-spec`.
150
148
 
151
- ## Step 5 — Cleanup
149
+ ## Step 4 — Cleanup
152
150
 
153
151
  The wrapper script deletes the phase-scoped temp files automatically when
154
- Step 4 succeeds — no operator action required. The cleanup contract lives in
152
+ Step 3 succeeds — no operator action required. The cleanup contract lives in
155
153
  [`lib/plan-phase-cleanup.js`](../../scripts/lib/plan-phase-cleanup.js), which
156
154
  is the single source of truth for which temp paths this phase owns. If you
157
155
  need to inspect the temp artefacts after the fact, re-run
@@ -162,12 +160,13 @@ need to inspect the temp artefacts after the fact, re-run
162
160
  Branch on the shared planning risk decision surfaced in the persist stdout
163
161
  JSON (`planningRisk`, `reviewRouting`):
164
162
 
165
- - **High risk or `--force-review` — STOP.** Surface the PRD and Tech Spec
166
- URLs to the operator:
163
+ - **High risk or `--force-review` — STOP.** Surface the Epic URL to the
164
+ operator:
167
165
 
168
- > "Spec phase complete for Epic #[ID]. Review PRD (#XX) and Tech Spec (#YY)
169
- > on GitHub. When you're ready, re-run `/plan [Epic_ID]` — the wrapper
170
- > will pick up where it left off and run the decompose phase."
166
+ > "Spec phase complete for Epic #[ID]. Review the updated Epic body
167
+ > (Tech Spec sections + `## Acceptance Table`) on GitHub. When you're
168
+ > ready, re-run `/plan [Epic_ID]` — the wrapper will pick up where it
169
+ > left off and run the decompose phase."
171
170
 
172
171
  - **Low risk — auto-proceed.** Relay `reviewRouting.operatorMessage` and
173
172
  continue directly to Phase 8 decomposition without waiting for verbal
@@ -177,8 +176,9 @@ JSON (`planningRisk`, `reviewRouting`):
177
176
 
178
177
  - If `--emit-context` fails with "Epic not found", confirm the ID matches the
179
178
  GitHub issue number and the token has `issues:read`.
180
- - If the persist call fails after creating the PRD but before the Tech Spec,
181
- re-run with `--force` (the script reuses the existing PRD when appropriate).
179
+ - If the persist call fails after writing the Tech Spec section but before
180
+ the Acceptance Table, re-run with `--force` (the section upsert is
181
+ idempotent — it replaces the managed regions in place).
182
182
  - If the Epic does not flip to `agent::review-spec` after the script claims
183
183
  success, the label write likely races with a concurrent mutation — re-run the
184
- persist step; it's idempotent against the existing PRD/Tech Spec.
184
+ persist step; it's idempotent against the already-persisted sections.
@@ -20,7 +20,8 @@ them in one assistant turn rather than serially. The host runtime executes
20
20
  the batch in parallel; serial calls cost N round-trips for no gain.
21
21
 
22
22
  - **Tool primitives:** `Read`, `Grep`, `Glob`, MCP `list_*` / `get_*` calls.
23
- - **When:** reading the PRD, Tech Spec, and Story body up front; grepping
23
+ - **When:** reading the Epic body (with its folded Tech Spec sections)
24
+ and Story body up front; grepping
24
25
  for multiple unrelated patterns; globbing several directory trees;
25
26
  fetching independent GitHub tickets.
26
27
  - **Anti-pattern:** sequential `Read` → wait → `Read` → wait → `Grep` chains
@@ -0,0 +1,136 @@
1
+ ---
2
+ description: >-
3
+ Reference companion to plan-epic.md — the recovery procedures, --resume
4
+ mechanics, troubleshooting, and background rationale blocks moved out of the
5
+ runtime core so every /plan run ingests only the phase flow. Read on demand
6
+ from the trigger-point pointers in plan-epic.md.
7
+ caller: plan-epic.md
8
+ ---
9
+
10
+ # helpers/plan-epic-reference — Epic-planning reference & recovery
11
+
12
+ > **Not a slash command.** This file lives in `helpers/` and is a
13
+ > path-included reference module (not projected into the plugin command
14
+ > tree). [`plan-epic.md`](plan-epic.md) is the runtime core — the phase
15
+ > flow, commands, and gate contracts. This file holds the secondary
16
+ > material a run needs only when it hits an edge (a recovery path, a
17
+ > troubleshooting symptom) or wants the design rationale behind a phase.
18
+ > Each section below is reached from a one-line pointer at its trigger
19
+ > point in the core.
20
+
21
+ ## Phase 7 — background rationale
22
+
23
+ The Phase 7 (Tech Spec & Acceptance Spec) core carries only the commands and
24
+ the gate contract. The design rationale for the phase's guards and managed
25
+ sections lives here.
26
+
27
+ ### Epic-lease preflight (workflow guard)
28
+
29
+ Before any Phase 7 mutation, `epic-plan-spec.js` acquires the Epic-lease via
30
+ the assignee-as-lease primitive (`lib/orchestration/ticket-lease.js`, wired
31
+ through `lib/orchestration/epic-plan-lease-guard.js`). The lease rides the
32
+ Epic's single assignee: the operator (`github.operatorHandle` in
33
+ `.agentrc.json`) claims the Epic for the duration of the plan. The guard
34
+ **fails closed**: `/plan` emits no `story.heartbeat` during its run
35
+ (heartbeats are a delivery-time signal), so there is no live-heartbeat source
36
+ to judge a concurrent plan's liveness from. Any **foreign assignee** is
37
+ therefore treated as a live claim — the persist half **exits non-zero and
38
+ names the current owner**, so two `/plan` runs cannot drive the same Epic
39
+ concurrently. Pass **`--steal`** to forcibly transfer a foreign claim once you
40
+ have confirmed the other run is dead. An **unassigned** Epic, or one **already
41
+ held by this operator**, is taken (or re-affirmed) silently. The lease is
42
+ **released after Phase 8** (decompose) completes.
43
+
44
+ ### Idempotent managed sections
45
+
46
+ The persist half is section-scoped and keyed on the Epic body: a re-run that
47
+ finds the requested sections already present
48
+ (`<!-- mandrel:tech-spec:start/end -->` /
49
+ `<!-- mandrel:acceptance-table:start/end -->`) short-circuits as
50
+ `already-planned` instead of duplicating content. Pass `--force` to overwrite
51
+ the managed sections in place (same Epic issue, refreshed section bodies).
52
+
53
+ ### One planning document
54
+
55
+ A `/plan` Epic run creates exactly **one** issue — the Epic. The planning
56
+ artifacts land as marker-delimited managed sections of the Epic body: the Tech
57
+ Spec (opening with `## Delivery Slicing`) inside
58
+ `<!-- mandrel:tech-spec:start/end -->`, and the Acceptance Spec's AC-ID table
59
+ (headed `## Acceptance Table`) inside
60
+ `<!-- mandrel:acceptance-table:start/end -->`. The PRD artifact class was
61
+ retired (Story #4314) — its one novel section, **User Stories**, lives inline
62
+ in the Epic body as a `## User Stories` section — and Story #4324 retired the
63
+ `context::tech-spec` / `context::acceptance-spec` ticket classes the same way.
64
+ The `## Acceptance Table` section captures the stable-ID acceptance criteria
65
+ table (`| AC ID | Outcome | Feature File | Scenario | Disposition |`) that
66
+ drives close-time reconciliation during `/deliver` Phase 6. Operators may opt
67
+ out for refactor-only or docs-only Epics by applying the `acceptance::n-a`
68
+ label to the Epic ticket — when present, the `epic-plan-spec-author` skill
69
+ skips the Acceptance Table output and the runtime gates (start gate, finalize
70
+ reconciler) honour the waiver — the section need not be authored when the
71
+ waiver is set. See [SDLC § Acceptance Table — the second folded planning
72
+ section](../../docs/SDLC.md#acceptance-table--the-second-folded-planning-section)
73
+ for the full lifecycle.
74
+
75
+ ### Parallel-safe file naming (per-Epic tree)
76
+
77
+ Multiple Epics may be planned or decomposed concurrently. Every temp file
78
+ written in the workflow lives under the per-Epic tree
79
+ (`temp/epic-[Epic_ID]/<artifact>`) — e.g.
80
+ `temp/epic-[Epic_ID]/planner-context.json`,
81
+ `temp/epic-[Epic_ID]/techspec.md`,
82
+ `temp/epic-[Epic_ID]/decomposer-context.json`,
83
+ `temp/epic-[Epic_ID]/tickets.json`. The directory namespace is the isolation
84
+ boundary; basenames inside it are stable. Do **not** reuse bare flat names
85
+ like `temp/techspec.md` or the legacy `temp/<artifact>-epic-<id>.<ext>` shape
86
+ — both have been retired.
87
+
88
+ **Durability.** The per-Epic tree is durable across runs: only the wrapper
89
+ scripts perform intra-phase cleanup of files they wrote in the same invocation
90
+ (see [`lib/plan-phase-cleanup.js`](../../scripts/lib/plan-phase-cleanup.js)).
91
+ Nothing else garbage-collects the tree, so cross-Epic artifacts — retros, perf
92
+ reports, signals, manifests — accumulate until an operator explicitly removes
93
+ them.
94
+
95
+ ## Phase 8 — `--resume` recovery (secondary rate limit)
96
+
97
+ The Phase 8 (Work Breakdown Decomposition) core carries the normal-path and
98
+ `--force` persist commands. The `--resume` recovery path — reached when a
99
+ large decomposition aborts mid-persist — lives here.
100
+
101
+ **Secondary rate limit on large Epics.** For backlogs over ~60 tickets,
102
+ GitHub's secondary rate limit (HTTP 403, body contains "secondary rate limit")
103
+ can trip mid-decomposition after ~80 issue creations. The http-client retries
104
+ automatically with a 30–120s backoff and the decomposer drops `concurrencyCap`
105
+ to 1 for the rest of the run on the first observation. If the run still aborts
106
+ (network drop, exhausted retries, etc.), resume from the partial backlog with:
107
+
108
+ ```bash
109
+ node .agents/scripts/epic-plan-decompose.js --epic [Epic_ID] \
110
+ --tickets temp/epic-[Epic_ID]/tickets.json --resume
111
+ ```
112
+
113
+ `--resume` is idempotent: the reconciler recovers the slug→issue map from
114
+ `temp/epic-[Epic_ID]/[Epic_ID].state.json`, and when that file is missing or
115
+ incomplete it **reseeds the map from live GitHub state** by matching each spec
116
+ slug against the open children of the Epic by title. Slugs that resolve to an
117
+ existing open child diff as Updates/no-ops; only the genuinely-missing children
118
+ are created — the existing tree is never duplicated. To force-throttle from the
119
+ first call on a known-large Epic, set `(framework constant: decomposer
120
+ concurrency): 1` in `.agentrc.json`.
121
+
122
+ ## Troubleshooting
123
+
124
+ - If `epic-plan-spec.js --emit-context` fails, confirm the Epic exists and
125
+ has a body with enough initial context.
126
+ - If `epic-plan-decompose.js` rejects the tickets file, re-read the
127
+ validator's error message — the most common causes are a ticket whose
128
+ `type` is not `story`, a Story missing its inline `acceptance[]` /
129
+ `verify[]` contract, or a dependency cycle in the Story `depends_on`
130
+ graph.
131
+ - If decomposition persisted the tickets but the Epic is not on `agent::ready`,
132
+ you likely called `runDecomposePhase` from `epic-plan-decompose.js`
133
+ directly without completing the persist flow — only the CLI surface
134
+ (`node epic-plan-decompose.js --tickets ...`) drives the full
135
+ reconciler pipeline and flips the lifecycle label. Apply `agent::ready`
136
+ by hand and re-run via the CLI next time.