mandrel 1.59.0 → 1.60.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 (240) hide show
  1. package/.agents/README.md +14 -14
  2. package/.agents/docs/SDLC.md +129 -134
  3. package/.agents/docs/configuration.md +16 -16
  4. package/.agents/docs/workflows.md +6 -8
  5. package/.agents/instructions.md +12 -11
  6. package/.agents/personas/architect.md +1 -1
  7. package/.agents/personas/product.md +1 -1
  8. package/.agents/personas/project-manager.md +14 -14
  9. package/.agents/personas/technical-writer.md +1 -1
  10. package/.agents/rules/changelog-style.md +5 -5
  11. package/.agents/rules/git-conventions.md +3 -3
  12. package/.agents/schemas/agentrc.schema.json +3 -3
  13. package/.agents/schemas/dispatch-manifest.json +4 -4
  14. package/.agents/schemas/epic-spec.schema.json +15 -45
  15. package/.agents/schemas/lifecycle/README.md +1 -1
  16. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
  17. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
  18. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
  19. package/.agents/schemas/validation-evidence.schema.json +1 -1
  20. package/.agents/scripts/README.md +1 -1
  21. package/.agents/scripts/acceptance-eval.js +1 -1
  22. package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
  23. package/.agents/scripts/analyze-execution.js +2 -2
  24. package/.agents/scripts/audit-to-stories.js +1 -1
  25. package/.agents/scripts/check-doc-links.js +2 -3
  26. package/.agents/scripts/diagnose-friction.js +1 -1
  27. package/.agents/scripts/dispatcher.js +2 -2
  28. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  29. package/.agents/scripts/epic-audit-prepare.js +3 -3
  30. package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
  31. package/.agents/scripts/epic-deliver-preflight.js +6 -6
  32. package/.agents/scripts/epic-deliver-prepare.js +1 -1
  33. package/.agents/scripts/epic-execute-record-wave.js +4 -4
  34. package/.agents/scripts/epic-plan-healthcheck.js +6 -10
  35. package/.agents/scripts/epic-plan-spec-validate.js +1 -1
  36. package/.agents/scripts/epic-reconcile.js +11 -29
  37. package/.agents/scripts/evidence-gate.js +1 -1
  38. package/.agents/scripts/generate-workflows-doc.js +1 -1
  39. package/.agents/scripts/hierarchy-gate.js +7 -11
  40. package/.agents/scripts/lib/ITicketingProvider.js +1 -1
  41. package/.agents/scripts/lib/audit-suite/selector.js +1 -1
  42. package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
  43. package/.agents/scripts/lib/baseline-snapshot.js +7 -7
  44. package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
  45. package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
  46. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
  47. package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
  48. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +1 -1
  49. package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
  50. package/.agents/scripts/lib/codebase-snapshot.js +1 -1
  51. package/.agents/scripts/lib/config/explain.js +1 -1
  52. package/.agents/scripts/lib/config/runners.js +2 -2
  53. package/.agents/scripts/lib/config/runtime.js +1 -1
  54. package/.agents/scripts/lib/config/temp-paths.js +2 -2
  55. package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
  56. package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
  57. package/.agents/scripts/lib/config-settings-schema.js +3 -3
  58. package/.agents/scripts/lib/duplicate-search.js +1 -1
  59. package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
  60. package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
  61. package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
  62. package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
  63. package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
  64. package/.agents/scripts/lib/findings/classify-finding.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +10 -10
  66. package/.agents/scripts/lib/label-constants.js +3 -4
  67. package/.agents/scripts/lib/label-taxonomy.js +3 -8
  68. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
  69. package/.agents/scripts/lib/orchestration/code-review.js +5 -5
  70. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
  71. package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
  72. package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
  73. package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
  74. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +9 -25
  75. package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
  76. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +8 -8
  77. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
  78. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
  79. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
  80. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +26 -13
  81. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +1 -1
  82. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
  83. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +2 -2
  84. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
  85. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
  86. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
  87. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
  88. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +6 -21
  89. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
  90. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +1 -1
  91. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -2
  92. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
  93. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
  94. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +8 -8
  95. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +4 -4
  96. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
  97. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
  98. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
  99. package/.agents/scripts/lib/orchestration/file-assumptions.js +2 -2
  100. package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
  101. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
  102. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
  103. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -3
  104. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
  105. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +1 -1
  106. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
  107. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
  108. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
  109. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
  110. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
  111. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
  112. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
  113. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
  114. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +1 -1
  115. package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
  116. package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
  117. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
  118. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
  119. package/.agents/scripts/lib/orchestration/preflight-cache.js +1 -1
  120. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
  121. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
  122. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
  123. package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
  124. package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
  126. package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
  127. package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
  128. package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
  129. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
  130. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +2 -2
  131. package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
  132. package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
  133. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +2 -2
  134. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
  135. package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
  136. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +5 -12
  137. package/.agents/scripts/lib/orchestration/ticketing/reads.js +8 -8
  138. package/.agents/scripts/lib/orchestration/ticketing/state.js +3 -3
  139. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +2 -2
  140. package/.agents/scripts/lib/orchestration/wave-record-projection.js +1 -1
  141. package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
  142. package/.agents/scripts/lib/preflight-runner.js +1 -1
  143. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
  144. package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
  145. package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
  146. package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
  147. package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
  148. package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
  149. package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
  150. package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
  151. package/.agents/scripts/lib/signals/schema.js +1 -1
  152. package/.agents/scripts/lib/spec/index.js +1 -1
  153. package/.agents/scripts/lib/spec/loader.js +2 -2
  154. package/.agents/scripts/lib/spec/state.js +7 -16
  155. package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
  156. package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
  157. package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
  158. package/.agents/scripts/lib/story-lifecycle.js +8 -8
  159. package/.agents/scripts/lib/story-plan.js +1 -1
  160. package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
  161. package/.agents/scripts/lib/wave-runner/tick.js +1 -1
  162. package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
  163. package/.agents/scripts/lifecycle-emit.js +1 -1
  164. package/.agents/scripts/providers/github/board-add.js +1 -1
  165. package/.agents/scripts/providers/github/errors.js +1 -1
  166. package/.agents/scripts/providers/github/mappers.js +2 -2
  167. package/.agents/scripts/providers/github/tickets.js +4 -4
  168. package/.agents/scripts/resync-status-column.js +1 -1
  169. package/.agents/scripts/retro-run.js +2 -2
  170. package/.agents/scripts/run-lint.js +1 -1
  171. package/.agents/scripts/single-story-init.js +1 -1
  172. package/.agents/scripts/stories-wave-tick.js +5 -5
  173. package/.agents/scripts/story-close.js +1 -1
  174. package/.agents/scripts/story-init.js +13 -16
  175. package/.agents/scripts/story-phase.js +5 -5
  176. package/.agents/scripts/story-plan.js +3 -3
  177. package/.agents/scripts/sync-branch-from-base.js +1 -1
  178. package/.agents/scripts/validate-docs-freshness.js +1 -1
  179. package/.agents/scripts/wave-tick.js +1 -1
  180. package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
  181. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
  182. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
  183. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
  184. package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
  185. package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
  186. package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
  187. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
  188. package/.agents/skills/core/scope-triage/SKILL.md +9 -10
  189. package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
  190. package/.agents/skills/skills.index.json +7 -7
  191. package/.agents/templates/agent-protocol.md +2 -2
  192. package/.agents/workflows/agents-update.md +2 -2
  193. package/.agents/workflows/audit-architecture.md +2 -2
  194. package/.agents/workflows/audit-clean-code.md +2 -2
  195. package/.agents/workflows/audit-dependencies.md +1 -1
  196. package/.agents/workflows/audit-devops.md +1 -1
  197. package/.agents/workflows/audit-documentation.md +2 -2
  198. package/.agents/workflows/audit-lighthouse.md +1 -1
  199. package/.agents/workflows/audit-performance.md +2 -2
  200. package/.agents/workflows/audit-privacy.md +1 -1
  201. package/.agents/workflows/audit-quality.md +2 -2
  202. package/.agents/workflows/audit-security.md +2 -2
  203. package/.agents/workflows/audit-seo.md +1 -1
  204. package/.agents/workflows/audit-sre.md +1 -1
  205. package/.agents/workflows/audit-to-stories.md +10 -10
  206. package/.agents/workflows/audit-ux-ui.md +1 -1
  207. package/.agents/workflows/deliver.md +85 -0
  208. package/.agents/workflows/explain.md +3 -3
  209. package/.agents/workflows/git-merge-pr.md +1 -1
  210. package/.agents/workflows/git-pr-all.md +13 -10
  211. package/.agents/workflows/git-push.md +6 -3
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
  214. package/.agents/workflows/helpers/code-review.md +5 -5
  215. package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +43 -43
  216. package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
  217. package/.agents/workflows/helpers/diagnose.md +1 -1
  218. package/.agents/workflows/helpers/epic-audit.md +6 -6
  219. package/.agents/workflows/helpers/epic-deliver-story.md +13 -13
  220. package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
  221. package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
  222. package/.agents/workflows/helpers/epic-testing.md +3 -3
  223. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  224. package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
  225. package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
  226. package/.agents/workflows/helpers/signals.md +1 -1
  227. package/.agents/workflows/helpers/single-story-deliver.md +11 -11
  228. package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
  229. package/.agents/workflows/onboard.md +17 -17
  230. package/.agents/workflows/plan.md +89 -0
  231. package/.agents/workflows/qa-explore.md +1 -1
  232. package/.agents/workflows/qa-run-harness.md +1 -1
  233. package/README.md +4 -12
  234. package/docs/CHANGELOG.md +1149 -0
  235. package/lib/cli/__tests__/update-changelog-surface.test.js +357 -0
  236. package/lib/cli/__tests__/update-reexec.test.js +513 -0
  237. package/lib/cli/init.js +31 -29
  238. package/lib/cli/update.js +413 -52
  239. package/package.json +2 -1
  240. package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
@@ -2,7 +2,7 @@
2
2
  * Epic snapshot phase — fetch Epic ticket and enforce the acceptance-spec
3
3
  * start gate.
4
4
  *
5
- * Auto-close is now the default for `/epic-deliver` (the human PR-merge is
5
+ * Auto-close is now the default for `/deliver` (the human PR-merge is
6
6
  * the gate); no per-Epic label snapshot is required.
7
7
  *
8
8
  * Acceptance-spec start gate (relaxed): an Epic may be delivered when
@@ -11,9 +11,9 @@
11
11
  * `context::acceptance-spec` ticket is linked to the Epic. The ticket's
12
12
  * GitHub state (open / closed) is **not** checked — presence is
13
13
  * sufficient, matching the PRD and Tech Spec contract. The reviewer's
14
- * OK during /epic-plan Phase 7 is the approval signal, not a manual
14
+ * OK during /plan Phase 7 is the approval signal, not a manual
15
15
  * ticket-close action. This still refuses to launch Epics that skipped
16
- * the /epic-plan Phase 7 acceptance-spec authoring step (or didn't
16
+ * the /plan Phase 7 acceptance-spec authoring step (or didn't
17
17
  * waive), surfacing the gap at delivery time rather than letting Story
18
18
  * dispatch race ahead without a spec at all.
19
19
  */
@@ -66,8 +66,8 @@ export async function runSnapshotPhase(ctx, collaborators, state) {
66
66
  /**
67
67
  * Enumerate the Story IDs owned by an Epic. Delegates to
68
68
  * `discoverOpenStories` so the snapshot.end payload and the wave DAG
69
- * input set never disagree — both now walk Epic Feature → Story and
70
- * exclude closed reverse-referenced tickets.
69
+ * input set never disagree — both enumerate the Epic's direct Story
70
+ * children and exclude closed reverse-referenced tickets.
71
71
  *
72
72
  * Returns a sorted array of positive integers (sort order makes the
73
73
  * ledger record deterministic across runs and platform iteration
@@ -82,7 +82,7 @@ async function discoverStoryIds({ epicId, provider }) {
82
82
  }
83
83
 
84
84
  /**
85
- * Refuse to launch /epic-deliver when the acceptance-spec precondition has
85
+ * Refuse to launch /deliver when the acceptance-spec precondition has
86
86
  * not been satisfied. Throws a clear `Error` (per
87
87
  * orchestration-error-handling rule) so the `runAsCli` boundary maps it to
88
88
  * `process.exit(1)` with the operator-visible message intact.
@@ -104,7 +104,7 @@ function assertAcceptanceSpecGate({ epic, epicId }) {
104
104
  if (!acceptanceSpecId) {
105
105
  throw new Error(
106
106
  `[epic-deliver] Epic #${epicId} cannot launch: no context::acceptance-spec is linked and the acceptance::n-a waiver label is absent. ` +
107
- 'Run /epic-plan Phase 7 to author an acceptance-spec, or apply the acceptance::n-a label to the Epic to opt out.',
107
+ 'Run /plan Phase 7 to author an acceptance-spec, or apply the acceptance::n-a label to the Epic to opt out.',
108
108
  );
109
109
  }
110
110
  }
@@ -240,7 +240,7 @@ export async function renderProgressBody({
240
240
  /**
241
241
  * Render and upsert the rolled-up `epic-run-progress` comment on the Epic.
242
242
  *
243
- * Called by `/epic-deliver` Step 2b (`epic-execute-record-wave.js`) after
243
+ * Called by `/deliver` Step 2b (`epic-execute-record-wave.js`) after
244
244
  * each wave completes. The caller folds `state.waves[]` from the
245
245
  * `epic-run-state` checkpoint into the per-wave rows and persists the
246
246
  * unified rollup as a fenced-JSON payload on the Epic ticket via
@@ -29,7 +29,7 @@ export const PHASE_TIMINGS_TYPE = 'phase-timings';
29
29
 
30
30
  /**
31
31
  * Structured-comment kind for the per-Story run-progress snapshot that
32
- * `/story-deliver` upserts on every Task transition. Read by
32
+ * `/deliver` upserts on every Task transition. Read by
33
33
  * ProgressReporter so the Epic-level table reflects sub-agent state in
34
34
  * near-real time instead of label-derived classifications.
35
35
  */
@@ -91,7 +91,7 @@ export function phaseToState(phase) {
91
91
  }
92
92
 
93
93
  /**
94
- * Parse a `story-run-progress` structured comment posted by `/story-deliver`.
94
+ * Parse a `story-run-progress` structured comment posted by `/deliver`.
95
95
  * Returns `null` for any malformed body — the caller falls back to the
96
96
  * ticket-label state derivation in that case.
97
97
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * progress-reporter/transport.js — outbound I/O for the
3
- * `/epic-deliver` progress narrative.
3
+ * `/deliver` progress narrative.
4
4
  *
5
5
  * Extracted from the parent `progress-reporter.js` so the
6
6
  * GitHub-comment posting surface (in `composition.js`) and the
@@ -16,7 +16,7 @@
16
16
  *
17
17
  * The webhook events emitted from this module are:
18
18
  *
19
- * - `epic-started` — fired once at /epic-deliver kickoff
19
+ * - `epic-started` — fired once at /deliver kickoff
20
20
  * - `epic-progress` — fired at wave boundaries / blocker transitions
21
21
  * - `epic-blocked` — wave aggregated to blocked/failed outside halt path
22
22
  * - `epic-unblocked` — operator flipped back to executing
@@ -118,7 +118,7 @@ export async function emitEpicProgress({
118
118
  }
119
119
 
120
120
  /**
121
- * Fire a curated `epic-started` webhook event at /epic-deliver kickoff.
121
+ * Fire a curated `epic-started` webhook event at /deliver kickoff.
122
122
  * The Slack consumer anchors the rest of the epic narrative to this fire.
123
123
  * Failures are swallowed.
124
124
  */
@@ -157,7 +157,7 @@ export async function emitEpicStarted({
157
157
  /**
158
158
  * Fire a curated `epic-blocked` webhook event when a wave aggregates to
159
159
  * `blocked` or `failed` outside the `BlockerHandler.halt` code path (the
160
- * /epic-deliver host-LLM loop has no handler instance — it calls this
160
+ * /deliver host-LLM loop has no handler instance — it calls this
161
161
  * helper directly from `epic-execute-record-wave.js`). The payload shape
162
162
  * matches the inline emit in `BlockerHandler.halt` so downstream consumers
163
163
  * see one canonical envelope regardless of which entry point fired.
@@ -5,10 +5,10 @@
5
5
  * After Story #908, in-session Agent-tool fan-out replaces the subprocess
6
6
  * spawn pipeline. The launcher's primary responsibility is `planWave(stories)`:
7
7
  * given a wave's Story tickets it returns a stable list of
8
- * `{ storyId, worktree }` entries. The `/epic-deliver` skill consumes that
8
+ * `{ storyId, worktree }` entries. The `/deliver` skill consumes that
9
9
  * list (one wave at a time) to format one assistant turn containing N
10
10
  * parallel `Agent` tool calls (subagent_type `general-purpose`), each of
11
- * which drives `/story-deliver <storyId>` for one Story.
11
+ * which drives `/deliver <storyId>` for one Story.
12
12
  *
13
13
  * `launchWave(stories)` is a convenience for callers that already hold a
14
14
  * concrete dispatch adapter (tests, future programmatic harnesses). It calls
@@ -46,7 +46,7 @@ export class StoryLauncher {
46
46
 
47
47
  /**
48
48
  * Produce the dispatch plan for a wave. Pure: no side effects, no IO. The
49
- * caller (the `/epic-deliver` skill's wave loop, or `launchWave` below)
49
+ * caller (the `/deliver` skill's wave loop, or `launchWave` below)
50
50
  * decides what to do with the plan.
51
51
  *
52
52
  * @param {Array<number|{id?:number,storyId?:number,number?:number}>} stories
@@ -78,7 +78,7 @@ export class StoryLauncher {
78
78
  async launchWave(stories, signal) {
79
79
  if (typeof this.dispatch !== 'function') {
80
80
  throw new TypeError(
81
- 'StoryLauncher.launchWave requires a dispatch adapter (in-session Agent-tool fan-out is the responsibility of the /epic-deliver skill).',
81
+ 'StoryLauncher.launchWave requires a dispatch adapter (in-session Agent-tool fan-out is the responsibility of the /deliver skill).',
82
82
  );
83
83
  }
84
84
  const plan = this.planWave(stories);
@@ -12,7 +12,7 @@
12
12
  * removed.
13
13
  *
14
14
  * The renderer survives because its `{ body, payload }` output still feeds
15
- * two non-comment contracts: the `renderedBody` markdown the `/story-deliver`
15
+ * two non-comment contracts: the `renderedBody` markdown the `/deliver`
16
16
  * and `single-story-deliver` CLIs (`story-phase.js`, the inline `story-init.js` prepare step)
17
17
  * relay to chat so the operator sees the phase table inline, and the snapshot
18
18
  * payload returned in those CLIs' JSON envelopes. `upsertStoryRunProgress`
@@ -71,10 +71,10 @@ const PHASE_EMOJI = {
71
71
  };
72
72
 
73
73
  /**
74
- * Canonical 3-tier Story-phase order. The Story-phase snapshot replaces the
74
+ * Canonical 2-tier Story-phase order. The Story-phase snapshot replaces the
75
75
  * 4-tier per-Task list when the Story carries inline acceptance (no child
76
76
  * Tasks). Each entry tracks `status` + `startedAt` / `endedAt` so the parent
77
- * `/epic-deliver` aggregator can render a coarse progress bar without
77
+ * `/deliver` aggregator can render a coarse progress bar without
78
78
  * walking Task tickets.
79
79
  */
80
80
  export const STORY_PHASE_ORDER = ['init', 'implement', 'validate', 'close'];
@@ -89,7 +89,7 @@ const STORY_PHASE_STATUS_EMOJI = {
89
89
 
90
90
  /**
91
91
  * Build the canonical default `phases[]` array for a freshly-initialized
92
- * 3-tier Story snapshot. All entries are `pending`; timestamps are null.
92
+ * 2-tier Story snapshot. All entries are `pending`; timestamps are null.
93
93
  * Exported so call sites (the story-init prepare step, story-phase) and
94
94
  * tests can build the same shape without re-implementing it.
95
95
  *
@@ -175,7 +175,7 @@ function normalizeTask(task) {
175
175
  * Exported so tests can pin the rendered shape without going through the
176
176
  * upsert path.
177
177
  *
178
- * Two shapes are supported, selected by whether `input.phases` (3-tier
178
+ * Two shapes are supported, selected by whether `input.phases` (2-tier
179
179
  * Story-phase snapshot) or `input.tasks` (legacy 4-tier per-Task list) is
180
180
  * provided. Callers MUST pass exactly one of the two — passing both is
181
181
  * rejected as a contract violation so a mistake at the call site fails
@@ -216,7 +216,7 @@ export function renderStoryRunProgressBody(input) {
216
216
  const hasTasks = Array.isArray(input.tasks);
217
217
  if (hasPhases && hasTasks) {
218
218
  throw new TypeError(
219
- 'renderStoryRunProgressBody: pass either `phases` (3-tier) or `tasks` ' +
219
+ 'renderStoryRunProgressBody: pass either `phases` (2-tier) or `tasks` ' +
220
220
  '(4-tier), not both — the snapshot shape is mutually exclusive.',
221
221
  );
222
222
  }
@@ -296,7 +296,7 @@ function renderTasksBody({
296
296
  }
297
297
 
298
298
  /**
299
- * Render the 3-tier Story-phase body. Pure helper for
299
+ * Render the 2-tier Story-phase body. Pure helper for
300
300
  * `renderStoryRunProgressBody`. Emits a `phases[]` payload whose entries
301
301
  * carry `{ name, status, startedAt, endedAt }` for init/implement/validate/close.
302
302
  */
@@ -351,7 +351,7 @@ function renderPhasesBody({ storyId, branch, phase, phases: raw, updatedAt }) {
351
351
  * renders only and, when `notify` is supplied, mirrors a low-severity webhook
352
352
  * event for operators who wire one up.
353
353
  *
354
- * Two shapes are supported, selected by whether `args.phases` (3-tier
354
+ * Two shapes are supported, selected by whether `args.phases` (2-tier
355
355
  * Story-phase snapshot) or `args.tasks` (legacy 4-tier per-Task list) is
356
356
  * provided. The webhook mirror's `done/total` count is computed from whichever
357
357
  * shape is active.
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * sub-agent-return.js — parse and reconcile per-Story sub-agent return text.
3
3
  *
4
- * `/epic-deliver` Step 2 dispatches one `Agent` tool call per Story per
4
+ * `/deliver` Step 2 dispatches one `Agent` tool call per Story per
5
5
  * wave. Each sub-agent owes its parent the JSON return contract documented
6
- * in `.agents/workflows/epic-deliver.md`:
6
+ * in `.agents/workflows/helpers/deliver-epic.md`:
7
7
  *
8
8
  * {
9
9
  * "storyId": <number>,
@@ -27,7 +27,7 @@
27
27
  * directly to GitHub-state reconciliation plus a friction record — the
28
28
  * stronger backstop that already caught everything the heuristics caught.
29
29
  *
30
- * This module provides the two helpers `/epic-deliver`'s wave dispatcher
30
+ * This module provides the two helpers `/deliver`'s wave dispatcher
31
31
  * now uses:
32
32
  *
33
33
  * - `parseStoryAgentReturn(raw)` — accept an already-parsed object or a
@@ -257,7 +257,7 @@ export function renderMalformedReturnsFriction({ epicId, wave, failures }) {
257
257
  '',
258
258
  `**Reason:** \`malformed-subagent-return\``,
259
259
  '',
260
- `${failures.length} sub-agent return(s) did not match the /story-deliver return contract.`,
260
+ `${failures.length} sub-agent return(s) did not match the /deliver return contract.`,
261
261
  'Each Story below was reconciled from GitHub (labels + `story-run-progress`)',
262
262
  'and its wave-row downgraded to `failed` unless the live ticket already carried',
263
263
  '`agent::done`.',
@@ -730,21 +730,13 @@ function collectStructuralEdges(spec) {
730
730
  const out = {};
731
731
  if (!spec || typeof spec !== 'object') return out;
732
732
  const epicSlug = 'epic';
733
- for (const feature of spec.features ?? []) {
734
- if (!feature?.slug) continue;
735
- out[feature.slug] = { entity: 'feature', parentSlug: epicSlug };
736
- for (const story of feature.stories ?? []) {
737
- if (!story?.slug) continue;
738
- out[story.slug] = {
739
- entity: 'story',
740
- parentSlug: feature.slug,
741
- dependsOn: [...(story.dependsOn ?? [])].sort(),
742
- };
743
- for (const task of story.tasks ?? []) {
744
- if (!task?.slug) continue;
745
- out[task.slug] = { entity: 'task', parentSlug: story.slug };
746
- }
747
- }
733
+ for (const story of spec.stories ?? []) {
734
+ if (!story?.slug) continue;
735
+ out[story.slug] = {
736
+ entity: 'story',
737
+ parentSlug: epicSlug,
738
+ dependsOn: [...(story.dependsOn ?? [])].sort(),
739
+ };
748
740
  }
749
741
  return out;
750
742
  }
@@ -18,12 +18,12 @@
18
18
  *
19
19
  * @typedef {object} SpecInput
20
20
  * The parsed YAML returned by `lib/spec/loader.js#loadSpec`. Shape is
21
- * `{ epic: {...}, features: [{slug, stories: [...]}], gates?: {...} }`
21
+ * `{ epic: {...}, stories: [...], gates?: {...} }`
22
22
  * per `.agents/schemas/epic-spec.schema.json`.
23
23
  *
24
24
  * @typedef {object} StateMappingEntry
25
25
  * @property {number} issueNumber GH issue number this slug maps to.
26
- * @property {string} entity 'epic'|'feature'|'story'|'task'.
26
+ * @property {string} entity 'epic'|'story'.
27
27
  * @property {string} [contentHash] Content hash captured at last
28
28
  * reconcile; absence forces an
29
29
  * update when ghState carries
@@ -115,7 +115,7 @@ function labelsEqual(a, b) {
115
115
  * a naive replace-style label diff would propose removing operator-
116
116
  * managed metadata that lives in these namespaces.
117
117
  *
118
- * Why: Story #2056 / Epic #1994 — `/epic-plan` was silently stripping
118
+ * Why: Story #2056 / Epic #1994 — `/plan` was silently stripping
119
119
  * `type::epic` and `risk::*` from the parent Epic on every decompose,
120
120
  * which then broke `dispatcher.js` (`type "unknown"`). Defence-in-depth
121
121
  * lives here in the diff engine: even if a future spec author drops
@@ -133,7 +133,7 @@ const PROTECTED_EPIC_LABEL_NAMESPACES = Object.freeze([
133
133
  'risk::',
134
134
  // Story #3050 — `acceptance::*` is set by Phase 7 spec-persist when
135
135
  // `planningRisk.acceptanceDisposition='not-applicable'` (or another
136
- // disposition) and gates downstream `/epic-deliver` start/finalize
136
+ // disposition) and gates downstream `/deliver` start/finalize
137
137
  // behavior. Before this namespace was protected, Phase 8 decompose
138
138
  // diffed the Epic's labels against a spec entry that doesn't carry
139
139
  // `acceptance::*`, silently emitting an Update that stripped the
@@ -190,7 +190,7 @@ function normaliseBody(value) {
190
190
  * duplicate footer blocks and trailing `blocked by` lines are removed in
191
191
  * a single pass. Kept local to this module so the diff engine does not
192
192
  * depend on the Task-body renderer (Story #3185 / Epic #3163: the renderer
193
- * is going away with the 3-tier producer cutover).
193
+ * is going away with the 2-tier producer cutover).
194
194
  */
195
195
  const ORCHESTRATOR_FOOTER_RE = /\n?---[ \t]*\r?\n+parent:\s*#\d+[\s\S]*$/;
196
196
 
@@ -247,9 +247,8 @@ function renderFooter({ parentId, epicId, dependencies = [] }) {
247
247
  * `parent: #N` / `Epic: #M` / `blocked by #X` and breaking the cascade.
248
248
  *
249
249
  * Story #3185 — the footer compose/strip logic is inlined here rather
250
- * than reused from the legacy Task-body renderer module. Under the
251
- * 3-tier hierarchy (Epic Feature Story) that renderer is being
252
- * removed, so the diff engine carries its own footer shape. The shape
250
+ * than reused from the legacy Task-body renderer module. That renderer
251
+ * was removed, so the diff engine carries its own footer shape. The shape
253
252
  * is byte-identical to the legacy renderer's `parent: #<n>` /
254
253
  * `Epic: #<m>` / `blocked by #<x>` output so cascade-readers continue
255
254
  * to parse it unchanged.
@@ -326,7 +325,7 @@ function fieldChanges(specEntity, obs, mapping, ctx = {}) {
326
325
  // feature/story/task body fields): "When omitted, the GH issue body
327
326
  // is left untouched". Pre-Story-#2283 the engine treated `undefined`
328
327
  // as `""`, which emitted a destructive `body: <existing> → ""` Update
329
- // on every `/epic-plan` Phase 8 because the decomposer's renderer
328
+ // on every `/plan` Phase 8 because the decomposer's renderer
330
329
  // projects the Epic spec entry from `{ id, title }` only. Skip the
331
330
  // body diff entirely when the spec did not carry a body string. An
332
331
  // explicit `body: ""` in the spec still produces a clear-op when the
@@ -413,9 +412,8 @@ function sortBySlug(ops) {
413
412
 
414
413
  /**
415
414
  * Walk the spec and yield one structural-entity record per visited
416
- * node. The walker is iterative-via-recursion but bounded by the spec's
417
- * nesting (epic features → stories tasks); the depth never exceeds
418
- * 4 so an explicit work-queue would just obscure the shape.
415
+ * node. The spec is 2-tier (epic stories), so the walk is a single
416
+ * flat pass over `spec.stories` after the Epic record.
419
417
  *
420
418
  * @param {SpecInput} spec
421
419
  * @returns {Array<{
@@ -446,37 +444,35 @@ function flattenSpec(spec) {
446
444
  }
447
445
 
448
446
  const epicAnchor = spec.epic ? epicSlug(spec.epic) : null;
449
- for (const feature of spec.features ?? []) {
447
+ // Duplicate-slug guard. The schema cannot express slug uniqueness across
448
+ // a hand-edited spec, and two same-slug Creates would orphan one GH
449
+ // issue (the second create overwrites the first's mapping entry).
450
+ // flattenSpec is the chokepoint both the loader path and the diff path
451
+ // flow through, so the check lives here.
452
+ const seenSlugs = new Set();
453
+ const duplicateSlugs = new Set();
454
+ for (const story of spec.stories ?? []) {
455
+ if (seenSlugs.has(story.slug)) duplicateSlugs.add(story.slug);
456
+ seenSlugs.add(story.slug);
457
+ }
458
+ if (duplicateSlugs.size > 0) {
459
+ throw new Error(
460
+ `spec contains duplicate story slug(s): ${[...duplicateSlugs].join(', ')}. ` +
461
+ `Each story slug must be unique — rename the duplicated entries in ` +
462
+ `the spec and re-run.`,
463
+ );
464
+ }
465
+ for (const story of spec.stories ?? []) {
450
466
  out.push({
451
- slug: feature.slug,
452
- entity: ENTITY_KINDS.FEATURE,
453
- title: String(feature.title ?? ''),
454
- body: feature.body,
455
- labels: feature.labels,
467
+ slug: story.slug,
468
+ entity: ENTITY_KINDS.STORY,
469
+ title: String(story.title ?? ''),
470
+ body: story.body,
471
+ labels: story.labels,
472
+ wave: story.wave,
456
473
  parentSlug: epicAnchor,
474
+ dependsOn: story.dependsOn ?? [],
457
475
  });
458
- for (const story of feature.stories ?? []) {
459
- out.push({
460
- slug: story.slug,
461
- entity: ENTITY_KINDS.STORY,
462
- title: String(story.title ?? ''),
463
- body: story.body,
464
- labels: story.labels,
465
- wave: story.wave,
466
- parentSlug: feature.slug,
467
- dependsOn: story.dependsOn ?? [],
468
- });
469
- for (const task of story.tasks ?? []) {
470
- out.push({
471
- slug: task.slug,
472
- entity: ENTITY_KINDS.TASK,
473
- title: String(task.title ?? ''),
474
- body: task.body,
475
- labels: task.labels,
476
- parentSlug: story.slug,
477
- });
478
- }
479
- }
480
476
  }
481
477
  return out;
482
478
  }
@@ -509,6 +505,40 @@ function dependsOnEqual(a, b) {
509
505
  return labelsEqual(a, b);
510
506
  }
511
507
 
508
+ /**
509
+ * Entity kinds that only exist in pre-v4 (3-tier) state files. The v4
510
+ * hard cutover (v1.60.0) removed the Feature/Task tiers; encountering one
511
+ * of these in `state.mapping` means the state file predates the cutover
512
+ * and must be migrated by the operator — there is deliberately no legacy
513
+ * close-op support (hard-cutover policy, git-conventions.md).
514
+ */
515
+ const LEGACY_ENTITY_KINDS = Object.freeze(new Set(['feature', 'task']));
516
+
517
+ /**
518
+ * Throw a loud, actionable error when the state mapping carries legacy
519
+ * Feature/Task entries. Raised early in `diff()` so the operator sees a
520
+ * migration instruction instead of `unknown entity kind: feature` from
521
+ * deep inside `closeOp`.
522
+ *
523
+ * @param {Record<string, StateMappingEntry>} mapping
524
+ */
525
+ function assertNoLegacyEntities(mapping) {
526
+ const legacy = Object.entries(mapping).filter(([, entry]) =>
527
+ LEGACY_ENTITY_KINDS.has(entry?.entity),
528
+ );
529
+ if (legacy.length === 0) return;
530
+ const summary = legacy
531
+ .map(([slug, entry]) => `${slug} (#${entry.issueNumber}, ${entry.entity})`)
532
+ .join(', ');
533
+ throw new Error(
534
+ `diff: the epic state file is pre-v4 — it carries legacy Feature/Task ` +
535
+ `mapping entries: ${summary}. The 2-tier reconciler cannot process ` +
536
+ `these. Close the legacy Feature issues manually, then delete (or ` +
537
+ `reseed) the .agents/epics/<epicId>.state.json file per the v1.60.0 ` +
538
+ `migration notes, and re-run.`,
539
+ );
540
+ }
541
+
512
542
  /**
513
543
  * Diff `(spec, state, ghState)` into a `Plan`. See the module header for
514
544
  * the full contract.
@@ -523,6 +553,7 @@ export function diff({ spec, state, ghState } = {}) {
523
553
  throw new TypeError('diff: state argument is required');
524
554
  }
525
555
  const mapping = state.mapping ?? {};
556
+ assertNoLegacyEntities(mapping);
526
557
  const seenSpecSlugs = new Set();
527
558
 
528
559
  for (const entity of flattenSpec(spec)) {
@@ -595,7 +626,7 @@ export function diff({ spec, state, ghState } = {}) {
595
626
  plan.closes.push(
596
627
  closeOp({
597
628
  slug,
598
- entity: mapped.entity ?? ENTITY_KINDS.TASK,
629
+ entity: mapped.entity ?? ENTITY_KINDS.STORY,
599
630
  issueNumber: mapped.issueNumber,
600
631
  title: mapped.title,
601
632
  }),
@@ -44,7 +44,7 @@
44
44
  * apply pipeline. Arrays are always present (never undefined); an empty
45
45
  * plan has all four arrays at length 0.
46
46
  *
47
- * @typedef {'epic'|'feature'|'story'|'task'} EntityKind
47
+ * @typedef {'epic'|'story'} EntityKind
48
48
  * The structural entity kind. Matches schema $defs — agent-execution
49
49
  * labels (agent::*) are owned by the wave-runner and never appear in
50
50
  * the structural surface.
@@ -87,7 +87,7 @@
87
87
  * @typedef {object} RelinkOp
88
88
  * @property {'relink'} kind
89
89
  * @property {string} slug
90
- * @property {EntityKind} entity 'story' (dependsOn) or 'feature'|'story'|'task' (parent).
90
+ * @property {EntityKind} entity 'story' (dependsOn / parent).
91
91
  * @property {number} issueNumber
92
92
  * @property {{ before: string|null, after: string|null }} [parent]
93
93
  * Parent slug change. `null` on either side means "no parent" (epic
@@ -117,9 +117,7 @@ export const OP_KINDS = Object.freeze({
117
117
  /** Entity-kind discriminator values, matching the schema $defs. */
118
118
  export const ENTITY_KINDS = Object.freeze({
119
119
  EPIC: 'epic',
120
- FEATURE: 'feature',
121
120
  STORY: 'story',
122
- TASK: 'task',
123
121
  });
124
122
 
125
123
  const VALID_OP_KINDS = new Set(Object.values(OP_KINDS));
@@ -8,7 +8,7 @@
8
8
  * are batched per-Story and surfaced through the same error envelope the
9
9
  * decompose loop already uses.
10
10
  *
11
- * Under the 3-tier hierarchy (Epic → Feature → Story; Epic #3078 / #3238)
11
+ * Under the 2-tier hierarchy (Epic → Story; Epic #3078 / #3238)
12
12
  * the Story is the implementation unit — there is no `type::task` ticket
13
13
  * layer — so the gate scans `type === 'story'` tickets and reads the
14
14
  * `{ path, assumption }` entries inlined on each Story body.
@@ -255,7 +255,7 @@ function predecessorMutator(index, path, predecessors) {
255
255
  * mismatches: object[] // structured payload for downstream tooling
256
256
  * }
257
257
  *
258
- * Under the 3-tier hierarchy the Story is the implementation unit, so the
258
+ * Under the 2-tier hierarchy the Story is the implementation unit, so the
259
259
  * gate scans `type === 'story'` tickets and reads the inline
260
260
  * `{ path, assumption }` entries on each Story body.
261
261
  *
@@ -4,7 +4,7 @@
4
4
  * planning context tickets (PRD / Tech Spec / Acceptance Spec) linked
5
5
  * from the Epic body's `## Planning Artifacts` section.
6
6
  *
7
- * Extracted from `/epic-deliver` Phase 7.1 prose (the `gh issue close`
7
+ * Extracted from `/deliver` Phase 7.1 prose (the `gh issue close`
8
8
  * sequence) so the lifecycle Finalizer listener has a single async
9
9
  * helper to call. Reuses `parseLinkedIssues` so the three planning ids
10
10
  * are read from the same canonical body shape that `epic-plan` writes
@@ -4,7 +4,7 @@
4
4
  * request, or locates the existing one when finalize is replaying after
5
5
  * a crash between `gh pr create` and the `pr.created` emit.
6
6
  *
7
- * Extracted from `/epic-deliver` Phase 7.1 prose so the lifecycle
7
+ * Extracted from `/deliver` Phase 7.1 prose so the lifecycle
8
8
  * Finalizer listener has a single async helper that returns the
9
9
  * `{ prNumber, url, created }` envelope it needs to compose
10
10
  * downstream emits.
@@ -26,7 +26,7 @@
26
26
  * the same head branch: the second call short-circuits at the probe and
27
27
  * does not attempt to create a duplicate PR. This is the AC-10
28
28
  * idempotency contract the Finalizer relies on for cross-process
29
- * re-runs of `/epic-deliver`.
29
+ * re-runs of `/deliver`.
30
30
  */
31
31
 
32
32
  import { spawnSync } from 'node:child_process';
@@ -4,7 +4,7 @@
4
4
  * `[skip ci]` markers (and the four variant spellings GitHub honours)
5
5
  * from a text payload.
6
6
  *
7
- * Story #3165: `/epic-deliver` Phase 7 opens a PR squashed into `main`
7
+ * Story #3165: `/deliver` Phase 7 opens a PR squashed into `main`
8
8
  * via `gh pr merge --squash`. Story commits legitimately carry
9
9
  * `[skip ci]` markers under `delivery.ci.skipForStoryPushes: true` to
10
10
  * keep CI from firing on the wave's intermediate pushes. When GitHub
@@ -19,7 +19,7 @@
19
19
  *
20
20
  * - **Operator candidates** — each surface supplies its own ordered
21
21
  * candidate list (e.g. `--as` flag → `github.operatorHandle` →
22
- * `git user.email` for `/epic-deliver`; bare `operatorHandle` for the
22
+ * `git user.email` for `/deliver`; bare `operatorHandle` for the
23
23
  * plan/standalone paths).
24
24
  * - **Missing-handle behaviour** — `'null'` (return null; the caller fails
25
25
  * closed at acquire time) vs `'throw'` (refuse immediately with surface
@@ -31,7 +31,7 @@
31
31
  * message via `renderRefusal(result, ticketId)`.
32
32
  * - **Liveness anchoring** — the plan/standalone paths have no heartbeat
33
33
  * ledger, so they anchor `heartbeatAt` to `now` (fail-closed: every
34
- * foreign claim reads live). `/epic-deliver` threads a real
34
+ * foreign claim reads live). `/deliver` threads a real
35
35
  * `heartbeatAt` through from the lifecycle ledger, so it opts out of
36
36
  * anchoring.
37
37
  *
@@ -91,7 +91,7 @@ export function resolveOperatorFromCandidates({
91
91
  * same resolved clock value so `isClaimLive` returns true for ANY foreign
92
92
  * owner — `acquireLease` then refuses a foreign assignee unless `steal` is
93
93
  * set, while unclaimed and self-held tickets still proceed without a write.
94
- * When unset (`/epic-deliver`), the caller-supplied `heartbeatAt` / `now`
94
+ * When unset (`/deliver`), the caller-supplied `heartbeatAt` / `now`
95
95
  * pass through untouched.
96
96
  *
97
97
  * @param {object} opts
@@ -12,7 +12,7 @@
12
12
  * `lib/orchestration/wave-session.js`, which nothing imports outside
13
13
  * tests — so every dispatched Story stayed "in-flight" forever and the
14
14
  * idle watchdog flagged completed Stories as stalled. The host-LLM driven
15
- * `/epic-deliver` path closes a wave through `epic-execute-record-wave.js`,
15
+ * `/deliver` path closes a wave through `epic-execute-record-wave.js`,
16
16
  * so that CLI is the correct place to emit the matching dispatch-end per
17
17
  * recorded Story.
18
18
  *
@@ -25,7 +25,7 @@
25
25
  * signature is deliberately narrow: only the schema-allowed fields are
26
26
  * accepted. The earlier per-child Task id and progress counters
27
27
  * were dropped under Epic #3078's
28
- * 3-tier hard cutover — they would fail strict validation and have no
28
+ * 2-tier hard cutover — they would fail strict validation and have no
29
29
  * meaning now that the Story is the leaf execution unit with no child
30
30
  * tickets. The optional `operator` field (Story #3480) records the handle
31
31
  * holding the assignee-as-lease claim; it is included only when supplied so
@@ -5,7 +5,7 @@ events and performs a single side effect. The canonical close-tail roster
5
5
  — in registration order — is wired by
6
6
  [`index.js`](./index.js) (`buildDefaultListenerChain`), the production
7
7
  entrypoint the standalone `lifecycle-emit.js` CLI shells in for
8
- `/epic-deliver`'s Phase 6 / 7.5 / 8 / 8.5 markdown invocations:
8
+ `/deliver`'s Phase 6 / 7.5 / 8 / 8.5 markdown invocations:
9
9
 
10
10
  - `ledger-writer.js` — privileged `onEmitted` hook that lands every
11
11
  `emitted` record on disk before any listener body runs (MUST be first).
@@ -41,7 +41,7 @@
41
41
  * This is the bus-level replay defence.
42
42
  * 2. The `gh pr view` probe — short-circuits across process
43
43
  * boundaries when a prior run already armed auto-merge. This is
44
- * the recovery defence: `/epic-deliver` restarted on the same PR
44
+ * the recovery defence: `/deliver` restarted on the same PR
45
45
  * will see the existing arm and emit `epic.merge.armed` exactly
46
46
  * once.
47
47
  *
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Subscribes to:
9
9
  * - `epic.automerge.start` (production path, Story #3901) → the
10
- * `/epic-deliver` Phase 8.5 boundary that the `lifecycle-emit.js`
10
+ * `/deliver` Phase 8.5 boundary that the `lifecycle-emit.js`
11
11
  * CLI actually fires. This event carries `prUrl` but NO
12
12
  * `checkOutcomes` (Phase 8's `pr-watch-with-update.js` has already
13
13
  * polled every required check to green before Phase 8.5 runs), so
@@ -1,7 +1,7 @@
1
1
  // .agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js
2
2
  /**
3
3
  * BranchCleaner — lifecycle listener that owns post-merge **branch** reap
4
- * for `/epic-deliver`. Story #2398 (companion to Cleaner, which owns the
4
+ * for `/deliver`. Story #2398 (companion to Cleaner, which owns the
5
5
  * temp-tree archival half of end-of-Epic cleanup).
6
6
  *
7
7
  * Subscribes to:
@@ -49,7 +49,7 @@
49
49
  * level replays short-circuit.
50
50
  * 2. The `gh pr list --head` probe + `openOrLocatePr`'s internal
51
51
  * locate path — both defend against cross-process re-runs
52
- * (`/epic-deliver` restarted on the same branch after a crash).
52
+ * (`/deliver` restarted on the same branch after a crash).
53
53
  *
54
54
  * Side-effect firewall: the listener emits on the bus, shells out to
55
55
  * `gh`/`git` (via the helpers), and upserts the `epic-handoff`