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
@@ -8,7 +8,7 @@
8
8
  * mirrored this roster for an in-session runner was deleted with the
9
9
  * dead epic-runner stratum in Story #3908; the host-LLM-drives-CLIs
10
10
  * model reaches every close-tail listener through the `lifecycle-emit.js`
11
- * CLI shells in `/epic-deliver`'s Phase 6 / 7.5 / 8 markdown invocations,
11
+ * CLI shells in `/deliver`'s Phase 6 / 7.5 / 8 markdown invocations,
12
12
  * which call this builder.)
13
13
  *
14
14
  * Canonical roster (registration order):
@@ -20,7 +20,7 @@
20
20
  * `{ epicId, prNumber, mergeCommitSha, mergedAt, pollAttempts }`.
21
21
  * 4. If the budget is exceeded without observing a merge, return
22
22
  * a `failed` classification with reason `budget-exceeded` and
23
- * do NOT emit `epic.merge.confirmed`. The /epic-deliver
23
+ * do NOT emit `epic.merge.confirmed`. The /deliver
24
24
  * blocker-handler flow surfaces this via `agent::blocked`.
25
25
  *
26
26
  * Resume contract (AC of Task #2907): the ledger is the source of
@@ -14,7 +14,7 @@
14
14
  *
15
15
  * webhookEvents entry lifecycle event
16
16
  * -------------------- ---------------------
17
- * `epic-started` (emitted at /epic-deliver kickoff;
17
+ * `epic-started` (emitted at /deliver kickoff;
18
18
  * this listener handles `epic.snapshot.start`)
19
19
  * `epic-blocked` `epic.blocked`
20
20
  * `epic-complete` `epic.complete`
@@ -23,7 +23,7 @@
23
23
  * Idempotency contract (AC-10): per-instance `Set<string>` of
24
24
  * `${event}:${seqId}` keys. A repeat `(event, seqId)` short-circuits
25
25
  * without re-polling and emits nothing. Combined with the bus-level
26
- * replay defence, this is sufficient — re-running `/epic-deliver` after
26
+ * replay defence, this is sufficient — re-running `/deliver` after
27
27
  * a crash will produce a NEW seqId and the listener legitimately
28
28
  * re-runs the poll loop (which is itself idempotent: the outcome map
29
29
  * always reflects the live GitHub state).
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * lib/orchestration/manifest-builder.js — Manifest Building Logic
3
3
  *
4
- * 3-tier-only producer. Reads Story tickets from `allTickets` directly,
4
+ * 2-tier-only producer. Reads Story tickets from `allTickets` directly,
5
5
  * computes Story-scoped waves, and emits the `waves[].stories[]` /
6
6
  * Story-only `storyManifest` shape. The pre-Epic-#3163 Task-tier branch
7
7
  * has been removed; the framework no longer carries a Task-tier
@@ -48,7 +48,7 @@ function extractSectionList(body, heading) {
48
48
 
49
49
  /**
50
50
  * Project a Story ticket into the inline-acceptance/verify shape required by
51
- * the 3-tier waves[].stories[] schema. Reads `## Acceptance` /
51
+ * the 2-tier waves[].stories[] schema. Reads `## Acceptance` /
52
52
  * `## Acceptance Criteria` and `## Verify` sections from the body.
53
53
  *
54
54
  * @param {object} story
@@ -95,7 +95,7 @@ function projectStoryForWave(story, epicId) {
95
95
  const AGENT_DONE_LABEL = STATE_LABELS.DONE;
96
96
 
97
97
  /**
98
- * Build the Story-only manifest array used by the 3-tier hierarchy path.
98
+ * Build the Story-only manifest array used by the 2-tier hierarchy path.
99
99
  * Reads Story tickets directly from `allTickets`; there is no Task tier
100
100
  * to walk. Each entry exposes an empty `tasks: []` to keep downstream
101
101
  * consumers (renderers, dispatch helpers) on a single per-Story shape
@@ -145,7 +145,7 @@ function buildStoryOnlyManifest(stories, epicId) {
145
145
  }
146
146
 
147
147
  /**
148
- * Build the wave records for a 3-tier manifest. Each wave entry exposes a
148
+ * Build the wave records for a 2-tier manifest. Each wave entry exposes a
149
149
  * `stories[]` projection (instead of the legacy `tasks[]`) so dispatch
150
150
  * consumers can fan Story execution out wave-by-wave without ever seeing
151
151
  * a `type::task` ticket.
@@ -200,7 +200,7 @@ export function buildManifest({
200
200
  epicTitle: epic?.title ?? '',
201
201
  executor: 'claude-code',
202
202
  dryRun,
203
- hierarchy: '3-tier',
203
+ hierarchy: '2-tier',
204
204
  summary: {
205
205
  totalStories,
206
206
  doneStories,
@@ -9,7 +9,7 @@
9
9
  * - "parked" — the Story is genuinely outside the manifest (carved off
10
10
  * mid-sprint, no recut lineage). The operator should explicitly
11
11
  * adopt it into the current Epic or defer it. Surfaced as a
12
- * structured comment so `/epic-deliver` has a single checkpoint.
12
+ * structured comment so `/deliver` has a single checkpoint.
13
13
  *
14
14
  * Both categories are informational at the wave-completeness gate — they do
15
15
  * not fail closure by themselves. The gate continues to enforce that every
@@ -81,7 +81,7 @@ export function renderParkedFollowOnsComment(epicId, classification) {
81
81
  `## 🪝 Parked Follow-Ons & Recuts — Epic #${epicId}`,
82
82
  '',
83
83
  'Stories created under this Epic that are **not** in the frozen dispatch',
84
- 'manifest. Surfaced here so `/epic-deliver` can gate on them at the',
84
+ 'manifest. Surfaced here so `/deliver` can gate on them at the',
85
85
  'completeness check.',
86
86
  '',
87
87
  `- **Recuts** (attributable to a manifest Story): ${recuts.length}`,
@@ -2,7 +2,7 @@
2
2
  * plan-router — given an Epic's current labels, decide which plan-phase CLI
3
3
  * should run next.
4
4
  *
5
- * Used by the local `/epic-plan` wrapper (chains spec → decompose).
5
+ * Used by the local `/plan` wrapper (chains spec → decompose).
6
6
  *
7
7
  * The router is intentionally stateless. Callers feed the current label set
8
8
  * (a string array, usually from `provider.getEpic(id).labels`) and receive a
@@ -21,7 +21,7 @@ export const PLAN_PHASE_NAMES = Object.freeze({
21
21
  * path used by the local wrapper; `command` is the slash-command invocation
22
22
  * operators fire.
23
23
  *
24
- * Spec and Decompose are served by the unified `/epic-plan` wrapper with a
24
+ * Spec and Decompose are served by the unified `/plan` wrapper with a
25
25
  * `--phase` flag — the phase workflows themselves live at
26
26
  * `.agents/workflows/helpers/epic-plan-{spec,decompose}.md` and are not
27
27
  * directly invokable slash commands.
@@ -33,20 +33,20 @@ export const PLAN_PHASE_DESCRIPTORS = Object.freeze({
33
33
  [PLAN_PHASE_NAMES.SPEC]: {
34
34
  phase: PLAN_PHASE_NAMES.SPEC,
35
35
  script: '.agents/scripts/epic-plan-spec.js',
36
- command: '/epic-plan --phase spec',
36
+ command: '/plan --phase spec',
37
37
  parkingLabel: AGENT_LABELS.REVIEW_SPEC,
38
38
  },
39
39
  [PLAN_PHASE_NAMES.DECOMPOSE]: {
40
40
  phase: PLAN_PHASE_NAMES.DECOMPOSE,
41
41
  script: '.agents/scripts/epic-plan-decompose.js',
42
- command: '/epic-plan --phase decompose',
42
+ command: '/plan --phase decompose',
43
43
  parkingLabel: AGENT_LABELS.READY,
44
44
  },
45
45
  });
46
46
 
47
47
  /**
48
48
  * Given the Epic's current labels, pick the next plan phase to run in the
49
- * local `/epic-plan` wrapper.
49
+ * local `/plan` wrapper.
50
50
  *
51
51
  * Precedence:
52
52
  * 1. If the Epic already carries `agent::ready`, there is nothing left to
@@ -2,14 +2,14 @@
2
2
  * phases/ticket-closure.js — post-merge ticket transition + cascade phase.
3
3
  *
4
4
  * Transitions the Story to `agent::done`, then runs cascade completion
5
- * so any parent Feature/Epic that is now fully resolved closes too.
5
+ * so any parent Epic-side rollup that is now fully resolved closes too.
6
6
  *
7
- * **3-tier closure (Story #3127).** Under the 3-tier hierarchy a Story
7
+ * **2-tier closure (Story #3127).** Under the 2-tier hierarchy a Story
8
8
  * is the leaf unit of execution and has no child tickets — `tasks`
9
9
  * arrives as an empty array. `batchTransitionTickets` handles the empty
10
10
  * input cleanly (the loop trivially completes), the Story is
11
11
  * transitioned alone, and cascade completion walks upward to
12
- * Feature/Epic. No branch on hierarchy mode is required here.
12
+ * parent. No branch on hierarchy mode is required here.
13
13
  *
14
14
  * Notifications are intentionally
15
15
  * NOT routed through the per-ticket transitions here — `notificationPhase`
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Cache adapter for the snapshot/DAG envelope produced by
5
5
  * `epic-deliver-preflight.js` so `epic-deliver-prepare.js` can skip the
6
- * second walk of Epic → Feature → Story when the underlying Epic ticket
6
+ * second walk of Epic → Story when the underlying Epic ticket
7
7
  * has not drifted between the two operator invocations.
8
8
  *
9
9
  * Contract:
@@ -6,7 +6,7 @@
6
6
  * `close-validate.end` `emitted` records and groups them by `failedGate`.
7
7
  * Returns one finding per gate that appears in **two or more distinct
8
8
  * Stories** within the same Epic. Findings are the substrate
9
- * `/epic-deliver` consumes when upserting the cross-Story
9
+ * `/deliver` consumes when upserting the cross-Story
10
10
  * `recurring-failure-class` structured comment on the Epic ticket.
11
11
  *
12
12
  * The helper is intentionally pure: no GitHub I/O, no global state. It
@@ -328,7 +328,7 @@ function followOnBody(s) {
328
328
  ``,
329
329
  `Trigger: ${trigger}.`,
330
330
  ``,
331
- `Apply the meta::framework-gap label so /epic-plan Phase 0 surfaces it on the next planning pass.`,
331
+ `Apply the meta::framework-gap label so /plan Phase 0 surfaces it on the next planning pass.`,
332
332
  ].join('\n');
333
333
  }
334
334
 
@@ -130,8 +130,8 @@ async function warnIfEpicLooksPopulated({ epicId, provider, logger }) {
130
130
  * `logger` so the silent failure becomes visible. Probe failure degrades
131
131
  * gracefully — the function never throws on the guard alone.
132
132
  *
133
- * **3-tier ledgers (Story #3151, Story #3200).** Under the 3-tier
134
- * hierarchy (Epic → Feature → Story; no Task-tier children), `friction`
133
+ * **2-tier ledgers (Story #3151, Story #3200).** Under the 2-tier
134
+ * hierarchy (Epic → Story; no Task-tier children), `friction`
135
135
  * / `parked` / `recuts` / `storyPerfSummaries` are all Story-scoped, so
136
136
  * the function continues to produce a non-empty signals report. The
137
137
  * empty-walk guard above is **not** triggered for this shape because
@@ -3,10 +3,10 @@
3
3
  *
4
4
  * Story #1155 (Epic #1142, 5.40.0) — extracts the helper-driven
5
5
  * `epic-retro` invocation into a callable module so the
6
- * `/epic-deliver` runner can fire Phase E without a separate LLM
6
+ * `/deliver` runner can fire Phase E without a separate LLM
7
7
  * helper turn. (Story #2259, Epic #2172: the legacy deliver-runner
8
8
  * CLI was retired once delivery moved entirely into the slash
9
- * command.) The retro fires before `/epic-deliver`'s finalize step
9
+ * command.) The retro fires before `/deliver`'s finalize step
10
10
  * opens the PR — the operator's PR-merge is the final human gate, not
11
11
  * the retro itself.
12
12
  *
@@ -56,7 +56,7 @@ export { gatherRetroSignals } from './retro/phases/gather-signals.js';
56
56
  /**
57
57
  * Public: compose and post the retro structured comment on the Epic.
58
58
  *
59
- * Story #1290 (Epic #1143) — at /epic-deliver Phase 5, the runner invokes
59
+ * Story #1290 (Epic #1143) — at /deliver Phase 5, the runner invokes
60
60
  * the self-healing checks registry with `scope: 'retro'` and
61
61
  * `autoFix: false`. The retro is **read-only by construction**: the
62
62
  * registry runner enforces the invariant by throwing if any caller flips
@@ -22,7 +22,7 @@
22
22
  * is enumerated).
23
23
  * - `standard` — everything else, including absent/malformed risk envelopes
24
24
  * and a `medium` level. Fail toward the middle, never toward
25
- * `light`: an Epic that skipped `/epic-plan` has no risk
25
+ * `light`: an Epic that skipped `/plan` has no risk
26
26
  * verdict, and treating it as `light` would under-review
27
27
  * unjudged work while `standard` preserves today's behaviour.
28
28
  *
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * phases/wrong-tree-guard.js — detect worktree/main-checkout edit divergence.
3
3
  *
4
- * Story #3364 — `/single-story-deliver` (and `/story-deliver`) materializes a
4
+ * Story #3364 — `/single-story-deliver` (and `/deliver`) materializes a
5
5
  * per-Story worktree and instructs the agent to `cd` into it before editing.
6
6
  * On Windows that guidance is silently insufficient: `cd <workCwd>` steers the
7
7
  * Bash tool's working directory, but the path-based Edit/Write tools operate on
@@ -2,7 +2,7 @@
2
2
  * spec-freshness.js — Tech Spec post-author cross-validation against the
3
3
  * current codebase.
4
4
  *
5
- * `/epic-plan` Phase 7 authors PRD + Tech Spec from documentation alone.
5
+ * `/plan` Phase 7 authors PRD + Tech Spec from documentation alone.
6
6
  * When `project.docsContextFiles` (architecture.md, etc.) drift from
7
7
  * the real source tree, the Architect persona happily cites modules and
8
8
  * paths that no longer exist. The mismatch only surfaces at delivery time,
@@ -1,30 +1,29 @@
1
1
  /**
2
2
  * lib/orchestration/spec-renderer.js — tickets.json → epic-spec.yaml
3
- * projection (3-tier shape, Epic #3163).
3
+ * projection (2-tier shape, Story #4041).
4
4
  *
5
5
  * The decomposer (`epic-plan-decompose-author`) produces a flat array
6
- * of ticket objects of two shapes (feature / story) keyed by stable
7
- * `slug`s and linked by `parent_slug` + `depends_on`. The spec
8
- * reconciler consumes the declarative structural representation
9
- * defined by `.agents/schemas/epic-spec.schema.json` — a nested
10
- * `{ epic, features: [{ stories: [...] }] }` tree with Story-level
11
- * `wave`, `dependsOn`, and inline `acceptance[]` / `verify[]` arrays
6
+ * of Story ticket objects keyed by stable `slug`s and linked by
7
+ * `depends_on`. The spec reconciler consumes the declarative
8
+ * structural representation defined by
9
+ * `.agents/schemas/epic-spec.schema.json` — a flat
10
+ * `{ epic, stories: [...] }` shape with Story-level `wave`,
11
+ * `dependsOn`, and inline `acceptance[]` / `verify[]` arrays
12
12
  * projected from the decomposer's edges.
13
13
  *
14
- * Under the 3-tier hierarchy (Epic #3078), Stories have no Task
15
- * children — acceptance and verify steps live inline on the Story.
16
- * Epic #3163 deletes the historical 4-tier Task emission code path
17
- * from this renderer (and its companion producers / consumers) in a
18
- * single hard cutover (see `.agents/rules/git-conventions.md` §
19
- * "Contract Cutovers — No Shim Layer"). A `task` ticket in the
20
- * decomposer input is rejected at index time.
14
+ * Under the 2-tier hierarchy (Story #4041), Stories have no Feature
15
+ * parent and no Task children — acceptance and verify steps live
16
+ * inline on the Story, and Stories attach directly to the Epic. Any
17
+ * `feature` or `task` ticket in the decomposer input is rejected at
18
+ * index time (hard cutover; see `.agents/rules/git-conventions.md` §
19
+ * "Contract Cutovers — No Shim Layer").
21
20
  *
22
21
  * `renderSpec(tickets, opts)` is the pure projection between those
23
22
  * two shapes. It:
24
23
  *
25
- * 1. Indexes the flat array by slug, partitioning into features /
26
- * stories. Any unrecognised type (including the historical
27
- * `task`) raises immediately.
24
+ * 1. Indexes the flat array by slug. Any unrecognised type
25
+ * (including the historical `feature` / `task`) raises
26
+ * immediately.
28
27
  * 2. Filters Story `depends_on` edges down to inter-Story
29
28
  * references in the same Epic.
30
29
  * 3. Layers Stories into waves via `Graph.assignLayers` (depth in
@@ -33,9 +32,9 @@
33
32
  * convention (`build-wave-dag.js` produces the same layering at
34
33
  * dispatch time from the live GH state, so the spec's waves are
35
34
  * observationally identical to what dispatch will compute).
36
- * 4. Walks the hierarchy in decomposer-declared order (feature →
37
- * story), preserving the order the LLM emitted so the
38
- * reconciler's diff stays human-readable.
35
+ * 4. Walks the Stories in decomposer-declared order, preserving
36
+ * the order the LLM emitted so the reconciler's diff stays
37
+ * human-readable.
39
38
  * 5. Strips `agent::*` labels from every entity. The decomposer
40
39
  * doesn't normally write them, but they can leak via reverse-
41
40
  * bootstrap from live GH state — and the schema forbids them
@@ -162,7 +161,7 @@ function sanitizeLabels(labels) {
162
161
  * Convert a decomposer body value into a spec `body` string. The
163
162
  * decomposer schema admits two shapes for a Story body:
164
163
  *
165
- * - A short string (preferred under the 3-tier hierarchy).
164
+ * - A short string (preferred under the 2-tier hierarchy).
166
165
  * - A structured object (`{ goal, changes[], acceptance[],
167
166
  * verify[] }`) carried over from the legacy 4-tier Task body
168
167
  * shape, when the decomposer chooses to inline the Story's
@@ -215,16 +214,12 @@ function assignNonEmpty(target, key, value) {
215
214
  }
216
215
 
217
216
  /**
218
- * Partition the flat ticket array into per-type maps keyed by slug.
219
- * Returns the ordered slug lists alongside the lookup map so the
220
- * renderer can walk the hierarchy in the decomposer's emit order
221
- * (parents-before-children is guaranteed by the validator's
222
- * topological sort, but we don't need that invariant here — we walk
223
- * features in array order, then look up their children by parent_slug
224
- * in the order the decomposer emitted them).
217
+ * Index the flat ticket array by slug. Returns the ordered Story slug
218
+ * list alongside the lookup map so the renderer can walk Stories in
219
+ * the decomposer's emit order.
225
220
  *
226
- * Under the 3-tier hierarchy (Epic #3078), only `feature` and `story`
227
- * types are recognised. Any other type — including the historical
221
+ * Under the 2-tier hierarchy (Story #4041), only the `story` type is
222
+ * recognised. Any other type — including the historical `feature` /
228
223
  * `task` — falls through to the unknown-type guard and raises
229
224
  * immediately; there is no silent drop.
230
225
  *
@@ -232,7 +227,6 @@ function assignNonEmpty(target, key, value) {
232
227
  */
233
228
  function indexTickets(tickets) {
234
229
  const bySlug = new Map();
235
- const featureSlugs = [];
236
230
  const storySlugs = [];
237
231
 
238
232
  for (const t of tickets) {
@@ -247,15 +241,14 @@ function indexTickets(tickets) {
247
241
  throw new Error(`[spec-renderer] duplicate slug "${slug}"`);
248
242
  }
249
243
  bySlug.set(slug, t);
250
- if (t.type === 'feature') featureSlugs.push(slug);
251
- else if (t.type === 'story') storySlugs.push(slug);
244
+ if (t.type === 'story') storySlugs.push(slug);
252
245
  else {
253
246
  throw new Error(
254
247
  `[spec-renderer] ticket "${slug}" has unknown type "${t.type}"`,
255
248
  );
256
249
  }
257
250
  }
258
- return { bySlug, featureSlugs, storySlugs };
251
+ return { bySlug, storySlugs };
259
252
  }
260
253
 
261
254
  /**
@@ -283,9 +276,8 @@ function layerStories(storySlugs, bySlug) {
283
276
  * Project the decomposer ticket array into the structural spec object.
284
277
  *
285
278
  * @param {Array<object>} tickets — flat ticket array as emitted by the
286
- * decomposer Skill (`type` {feature, story}, `slug`,
287
- * `parent_slug`, `depends_on`, `title`, `body`, `labels`,
288
- * `acceptance`, `verify`).
279
+ * decomposer Skill (`type` = story, `slug`, `depends_on`, `title`,
280
+ * `body`, `labels`, `acceptance`, `verify`).
289
281
  * @param {object} opts
290
282
  * @param {{id: number, title: string, body?: string, labels?: string[]}} opts.epic
291
283
  * — Epic descriptor (the decomposer doesn't emit the Epic row; it's
@@ -297,7 +289,7 @@ function layerStories(storySlugs, bySlug) {
297
289
  * @param {boolean} [opts.validate=true] — when `false`, skip final
298
290
  * schema validation (used by tests that intentionally craft invalid
299
291
  * inputs).
300
- * @returns {object} spec — `{ epic, features, gates? }` matching
292
+ * @returns {object} spec — `{ epic, stories, gates? }` matching
301
293
  * `.agents/schemas/epic-spec.schema.json`.
302
294
  */
303
295
  function validateRenderSpecInputs(tickets, opts) {
@@ -318,18 +310,6 @@ function validateRenderSpecInputs(tickets, opts) {
318
310
  }
319
311
  }
320
312
 
321
- function bucketStoriesByFeature({ storySlugs, bySlug }) {
322
- const storiesByFeature = new Map();
323
- for (const slug of storySlugs) {
324
- const story = bySlug.get(slug);
325
- const parent = story.parent_slug;
326
- if (typeof parent !== 'string' || !bySlug.has(parent)) continue;
327
- if (!storiesByFeature.has(parent)) storiesByFeature.set(parent, []);
328
- storiesByFeature.get(parent).push(slug);
329
- }
330
- return storiesByFeature;
331
- }
332
-
333
313
  function pickStringArray(primary, fallback) {
334
314
  const src = Array.isArray(primary)
335
315
  ? primary
@@ -342,7 +322,7 @@ function pickStringArray(primary, fallback) {
342
322
  }
343
323
 
344
324
  function extractStoryAcceptanceVerify(story) {
345
- // Under the 3-tier hierarchy (Epic #3078), Stories carry inline
325
+ // Stories carry inline
346
326
  // acceptance[] / verify[] arrays directly on the ticket. The
347
327
  // decomposer may emit these either at the top level of the ticket
348
328
  // (preferred) or nested under a structured `body` object (legacy
@@ -380,20 +360,6 @@ function buildStoryOut({ story, layers, storySet }) {
380
360
  return out;
381
361
  }
382
362
 
383
- function buildFeatureOut({ feature, storySlugs, bySlug, layers, storySet }) {
384
- const stories = storySlugs.map((storySlug) =>
385
- buildStoryOut({
386
- story: bySlug.get(storySlug),
387
- layers,
388
- storySet,
389
- }),
390
- );
391
- const out = { slug: feature.slug, title: feature.title, stories };
392
- assignNonEmpty(out, 'body', renderBody(feature.body));
393
- assignNonEmpty(out, 'labels', sanitizeLabels(feature.labels));
394
- return out;
395
- }
396
-
397
363
  function buildEpicOut(epic) {
398
364
  const out = { id: epic.id, title: epic.title };
399
365
  assignNonEmpty(out, 'body', renderBody(epic.body));
@@ -432,22 +398,19 @@ export function renderSpec(tickets, opts = {}) {
432
398
  validateRenderSpecInputs(tickets, opts);
433
399
  const { epic, gates, schemaPath, validate = true } = opts;
434
400
 
435
- const { bySlug, featureSlugs, storySlugs } = indexTickets(tickets);
401
+ const { bySlug, storySlugs } = indexTickets(tickets);
436
402
  const { layers } = layerStories(storySlugs, bySlug);
437
- const storiesByFeature = bucketStoriesByFeature({ storySlugs, bySlug });
438
403
  const storySet = new Set(storySlugs);
439
404
 
440
- const features = featureSlugs.map((featureSlug) =>
441
- buildFeatureOut({
442
- feature: bySlug.get(featureSlug),
443
- storySlugs: storiesByFeature.get(featureSlug) ?? [],
444
- bySlug,
405
+ const stories = storySlugs.map((storySlug) =>
406
+ buildStoryOut({
407
+ story: bySlug.get(storySlug),
445
408
  layers,
446
409
  storySet,
447
410
  }),
448
411
  );
449
412
 
450
- const spec = { epic: buildEpicOut(epic), features };
413
+ const spec = { epic: buildEpicOut(epic), stories };
451
414
  const gatesOut = buildGatesOut(gates);
452
415
  if (gatesOut) spec.gates = gatesOut;
453
416
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * spec-section-validator.js — Phase 7.5 Tech Spec post-authoring section gate.
3
3
  *
4
- * `/epic-plan` Phase 7 authors a Tech Spec from documentation and the PRD.
4
+ * `/plan` Phase 7 authors a Tech Spec from documentation and the PRD.
5
5
  * Phase 8.3 (Holistic Consolidation) then reconciles the draft ticket array
6
6
  * against the Tech Spec's `## Delivery Slicing` section, which the
7
7
  * decompose-author skill uses as the capability-boundary anchor. When the
@@ -100,7 +100,7 @@ export function renderBaselineFrictionBody({ rows, epicId, storyId } = {}) {
100
100
  const triage = [
101
101
  '**Triage:**',
102
102
  `1. Open each suspect Story above and run \`npm run maintainability:update\` (or \`npm run crap:update\`) on **its** branch, then commit with a \`baseline-refresh:\` subject and re-close it.`,
103
- `2. Re-run \`/story-deliver ${storyId}\` once the suspect Story's refresh has merged into \`epic/${epicId}\`.`,
103
+ `2. Re-run \`/deliver ${storyId}\` once the suspect Story's refresh has merged into \`epic/${epicId}\`.`,
104
104
  `3. If the suspect column reads \`_unknown_\`, the path has no commit on \`epic/${epicId}\` — investigate the baseline file directly before refreshing.`,
105
105
  ];
106
106
 
@@ -127,7 +127,7 @@ export async function runGatesAndRefresh(
127
127
  * Read the parent Epic's judged `planningRisk` envelope off its
128
128
  * `epic-plan-state` checkpoint so the Story-scope review can inherit the
129
129
  * Epic's review depth (Story #3940). Best-effort and total — it reuses the
130
- * shared `read` from `epic-plan-state-store.js` (the same reader `/epic-plan
130
+ * shared `read` from `epic-plan-state-store.js` (the same reader `/plan
131
131
  * --resume` and `epic-audit-prepare.js`'s `resolveRiskRoutedLenses` use, no
132
132
  * third bespoke reader) and never fails the close:
133
133
  *
@@ -137,7 +137,7 @@ export async function runGatesAndRefresh(
137
137
  *
138
138
  * A `null` result threads through `runStoryCodeReview` → `runCodeReview`
139
139
  * unchanged, so depth resolves from diff width alone (`standard`), preserving
140
- * today's behaviour for an Epic that skipped `/epic-plan`.
140
+ * today's behaviour for an Epic that skipped `/plan`.
141
141
  *
142
142
  * @param {{ provider: object, epicId: number|null|undefined, readPlanStateFn?: typeof readPlanState }} args
143
143
  * @returns {Promise<{ overallLevel?: string, axes?: Array<object> }|null>}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Story body schema validator (v5.33+).
3
3
  *
4
- * Enforces the four-section structured body shape on 3-tier Stories emitted
4
+ * Enforces the four-section structured body shape on 2-tier Stories emitted
5
5
  * by the decomposer. The canonical decomposition serializes every Story
6
6
  * `body` to a **markdown string** via `serialize()` from
7
7
  * `lib/story-body/story-body.js` (the decompose-author skill mandates this,
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * Only `type: 'story'` tickets are validated; Feature/Epic tickets and
19
19
  * null/empty bodies pass through. There is no `type::task` ticket layer in
20
- * the 3-tier hierarchy (Epic → Feature → Story).
20
+ * the 2-tier hierarchy (Epic → Story).
21
21
  *
22
22
  * Required after parse/normalize: a non-empty `goal`, and non-empty
23
23
  * `changes`, `acceptance`, and `verify` arrays — and `changes` items must
@@ -110,7 +110,7 @@ function vagueVerbWithoutTarget(bullet) {
110
110
  * - it has no body (null / undefined / empty-or-whitespace string — there
111
111
  * is nothing to inspect).
112
112
  *
113
- * Under the 3-tier hierarchy (Epic → Feature → Story), Stories carry the
113
+ * Under the 2-tier hierarchy (Epic → Story), Stories carry the
114
114
  * implementation scope inline. A canonical decomposition serializes the
115
115
  * Story body to a markdown string, so a *string* body is NOT skipped here
116
116
  * (Story #3906) — `validateTaskBodyShape` parses it back into structured
@@ -127,7 +127,7 @@ function vagueVerbWithoutTarget(bullet) {
127
127
  */
128
128
  function shouldSkipTicket(ticket) {
129
129
  if (!ticket) return true;
130
- // Only Stories carry an inline implementation contract in the 3-tier
130
+ // Only Stories carry an inline implementation contract in the 2-tier
131
131
  // world. Features (and everything else) use narrative bodies.
132
132
  if (ticket.type !== 'story') return true;
133
133
  const body = ticket.body;
@@ -197,7 +197,7 @@ export function validateTaskBodyShape(ticket) {
197
197
  }
198
198
  errors.push(...collectChangesErrors(prefix, body.changes));
199
199
  errors.push(...collectAcceptanceErrors(prefix, body.acceptance));
200
- // Tier-suffix validation is always enforced on Story bodies (3-tier world).
200
+ // Tier-suffix validation is always enforced on Story bodies (2-tier world).
201
201
  errors.push(...collectVerifyErrors(prefix, body.verify));
202
202
  errors.push(...collectReferencesErrors(prefix, body.references));
203
203
  return errors;
@@ -359,7 +359,7 @@ function collectVerifyErrors(prefix, rawVerify) {
359
359
  }
360
360
 
361
361
  /**
362
- * Validate every 3-tier Story in `tickets` whose `body` is a structured
362
+ * Validate every 2-tier Story in `tickets` whose `body` is a structured
363
363
  * object. Returns an array of error strings (one per offending slug); empty
364
364
  * array means clean.
365
365
  *
@@ -96,7 +96,7 @@ export function normalizeOperatorHandle(raw) {
96
96
  * observability artifact never wedges the lease preflight.
97
97
  *
98
98
  * This is the shared liveness source the lease guards thread into
99
- * `acquireLease` via `heartbeatAt`; `/epic-plan` and `/epic-deliver` both
99
+ * `acquireLease` via `heartbeatAt`; `/plan` and `/deliver` both
100
100
  * reuse it so a live foreign claim actually refuses.
101
101
  *
102
102
  * @param {object} args
@@ -170,7 +170,7 @@ function collectStoryProducerPaths(story) {
170
170
  }
171
171
 
172
172
  /**
173
- * Resolve the Story-identifying slug for a 3-tier Story. A Story is its
173
+ * Resolve the Story-identifying slug for a 2-tier Story. A Story is its
174
174
  * own implementation unit (Epic #3238) — there is no parent Task — so the
175
175
  * producer/consumer indices key on the Story's own `slug`.
176
176
  */
@@ -187,7 +187,7 @@ function storySlugOf(story) {
187
187
  * producers.
188
188
  *
189
189
  * `taskSlug` is retained in the entry shape for finding/render
190
- * compatibility; in the 3-tier model it carries the Story's own slug since
190
+ * compatibility; in the 2-tier model it carries the Story's own slug since
191
191
  * the Story is the implementation unit.
192
192
  */
193
193
  function indexProducers(stories) {
@@ -39,15 +39,6 @@ export const DEFAULT_TASK_SIZING = Object.freeze({
39
39
  maxAcceptance: 14,
40
40
  });
41
41
 
42
- /**
43
- * Soft prose guidance for how many Stories a Feature typically decomposes
44
- * into before the Feature scope smells like two Features. Rendered into the
45
- * decomposer prompt's Feature-count sentence from this single constant so
46
- * the prompt prose cannot drift from the SSOT module (Story #3874). Advisory
47
- * only — no validator finding keys off it.
48
- */
49
- export const SOFT_STORIES_PER_FEATURE = 7;
50
-
51
42
  /**
52
43
  * `DELIVERABLE_GRANULARITY_GUIDANCE` is the **single source of truth** for the
53
44
  * deliverable-granularity definition of a Story (Story #3777). It is stated
@@ -339,7 +330,7 @@ function computeStorySizingFindings(story, sizing) {
339
330
  * `findings`; the AC-visible `errors[]` channel is the rendered
340
331
  * subset where `severity === 'hard'`.
341
332
  *
342
- * 3-tier (Epic #3238): each Story is its own implementation unit and
333
+ * 2-tier (Epic #3238): each Story is its own implementation unit and
343
334
  * carries the `body` (acceptance / changes / wide) that the sizing layers
344
335
  * score. There is no Task tier, so findings are computed directly over
345
336
  * `stories`.