mandrel 1.94.0 → 2.0.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 (393) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/story-worker.md +12 -13
  3. package/.agents/docs/SDLC.md +489 -1285
  4. package/.agents/docs/agentrc-reference.json +177 -67
  5. package/.agents/docs/configuration.md +104 -138
  6. package/.agents/docs/execution-reference.md +17 -20
  7. package/.agents/docs/quality-gates.md +13 -19
  8. package/.agents/docs/workflows.md +3 -3
  9. package/.agents/instructions.md +70 -81
  10. package/.agents/rules/ci-remediation.md +8 -12
  11. package/.agents/rules/git-conventions-reference.md +6 -7
  12. package/.agents/rules/git-conventions.md +16 -22
  13. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  14. package/.agents/schemas/agentrc.schema.json +54 -214
  15. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  16. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  17. package/.agents/schemas/risk-verdict.schema.json +0 -13
  18. package/.agents/scripts/analyze-execution.js +1 -1
  19. package/.agents/scripts/audit-to-stories.js +7 -7
  20. package/.agents/scripts/boot-sweep.js +1 -1
  21. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  22. package/.agents/scripts/check-prepush-recovery.js +1 -1
  23. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  24. package/.agents/scripts/lib/Logger.js +6 -10
  25. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  26. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  27. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  28. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  29. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  30. package/.agents/scripts/lib/baselines/reader.js +1 -6
  31. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  32. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  33. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  34. package/.agents/scripts/lib/checks/index.js +2 -1
  35. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  36. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  37. package/.agents/scripts/lib/cli-args.js +16 -7
  38. package/.agents/scripts/lib/close-validation/gates.js +2 -2
  39. package/.agents/scripts/lib/config/ci.js +6 -31
  40. package/.agents/scripts/lib/config/delivery-routing.js +45 -29
  41. package/.agents/scripts/lib/config/explain.js +55 -36
  42. package/.agents/scripts/lib/config/limits.js +17 -58
  43. package/.agents/scripts/lib/config/paths.js +0 -2
  44. package/.agents/scripts/lib/config/quality.js +1 -1
  45. package/.agents/scripts/lib/config/runners.js +17 -50
  46. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  47. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  48. package/.agents/scripts/lib/config-resolver.js +2 -7
  49. package/.agents/scripts/lib/config-settings-schema-delivery.js +24 -148
  50. package/.agents/scripts/lib/config-settings-schema-quality.js +8 -14
  51. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  52. package/.agents/scripts/lib/dependency-parser.js +3 -2
  53. package/.agents/scripts/lib/doc-tiers.js +2 -2
  54. package/.agents/scripts/lib/duplicate-search.js +211 -41
  55. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  56. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  57. package/.agents/scripts/lib/framework-version.js +2 -3
  58. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  59. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  60. package/.agents/scripts/lib/git-utils.js +32 -6
  61. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  62. package/.agents/scripts/lib/label-constants.js +10 -23
  63. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  64. package/.agents/scripts/lib/observability/active-story-env.js +1 -1
  65. package/.agents/scripts/lib/observability/hook-heartbeat.js +20 -52
  66. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  67. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  68. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  69. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +8 -5
  70. package/.agents/scripts/lib/orchestration/ceremony-routing.js +83 -20
  71. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  72. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  73. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  74. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  75. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  76. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  77. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  78. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  79. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  80. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  81. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  82. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  83. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  84. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  85. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  86. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  87. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  88. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  89. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  90. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  91. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  92. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  93. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  94. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  95. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +13 -13
  96. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  97. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  98. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  99. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  100. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  101. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  102. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  103. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  104. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  105. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  106. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  107. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  108. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  109. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  110. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  111. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  112. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  113. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  114. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  115. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  116. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  117. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  118. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  119. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  120. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  121. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  122. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  123. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  124. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  125. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  126. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  127. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  128. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  129. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  130. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  131. package/.agents/scripts/lib/orchestration/ticket-validator.js +2 -7
  132. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  133. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  134. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  135. package/.agents/scripts/lib/planning-corpus.js +16 -11
  136. package/.agents/scripts/lib/preflight-runner.js +2 -2
  137. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  138. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  139. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  140. package/.agents/scripts/lib/story-adjacency.js +11 -14
  141. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  142. package/.agents/scripts/lib/story-plan.js +2 -4
  143. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  144. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  145. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  146. package/.agents/scripts/lib/validation-evidence.js +1 -1
  147. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  148. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  149. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  150. package/.agents/scripts/lint-issue-body.js +71 -40
  151. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  152. package/.agents/scripts/notify.js +4 -3
  153. package/.agents/scripts/plan-context.js +64 -74
  154. package/.agents/scripts/plan-persist.js +121 -280
  155. package/.agents/scripts/plan-run-epilogue.js +97 -0
  156. package/.agents/scripts/providers/github/issues.js +17 -33
  157. package/.agents/scripts/providers/github/mappers.js +0 -12
  158. package/.agents/scripts/providers/github/tickets.js +2 -5
  159. package/.agents/scripts/resolve-plan-run.js +117 -0
  160. package/.agents/scripts/signals-view.js +24 -19
  161. package/.agents/scripts/single-story-close.js +11 -14
  162. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  163. package/.agents/scripts/single-story-init.js +29 -20
  164. package/.agents/scripts/stories-wave-tick.js +6 -6
  165. package/.agents/scripts/story-plan.js +26 -47
  166. package/.agents/scripts/update-ticket-state.js +6 -15
  167. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  168. package/.agents/skills/core/idea-refinement/SKILL.md +6 -6
  169. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  170. package/.agents/skills/skills.index.json +3 -43
  171. package/.agents/starter-agentrc.json +0 -5
  172. package/.agents/templates/agent-protocol.md +9 -10
  173. package/.agents/workflows/audit-architecture.md +3 -3
  174. package/.agents/workflows/audit-clean-code.md +3 -3
  175. package/.agents/workflows/audit-dependencies.md +3 -3
  176. package/.agents/workflows/audit-devops.md +3 -3
  177. package/.agents/workflows/audit-documentation.md +5 -5
  178. package/.agents/workflows/audit-lighthouse.md +3 -3
  179. package/.agents/workflows/audit-navigability.md +3 -2
  180. package/.agents/workflows/audit-performance.md +3 -3
  181. package/.agents/workflows/audit-privacy.md +3 -3
  182. package/.agents/workflows/audit-quality.md +3 -3
  183. package/.agents/workflows/audit-security.md +3 -3
  184. package/.agents/workflows/audit-seo.md +3 -3
  185. package/.agents/workflows/audit-sre.md +3 -3
  186. package/.agents/workflows/audit-to-stories.md +20 -20
  187. package/.agents/workflows/audit-ux-ui.md +3 -3
  188. package/.agents/workflows/deliver.md +122 -174
  189. package/.agents/workflows/git-cleanup.md +3 -4
  190. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  191. package/.agents/workflows/helpers/acceptance-self-eval.md +16 -29
  192. package/.agents/workflows/helpers/code-review.md +70 -193
  193. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  194. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  195. package/.agents/workflows/helpers/diagnose.md +10 -10
  196. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  197. package/.agents/workflows/helpers/signals.md +16 -16
  198. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  199. package/.agents/workflows/mandrel-update.md +2 -1
  200. package/.agents/workflows/plan.md +112 -145
  201. package/.agents/workflows/qa-assist.md +24 -30
  202. package/.agents/workflows/qa-explore.md +29 -38
  203. package/.agents/workflows/qa-run.md +2 -2
  204. package/README.md +9 -8
  205. package/docs/CHANGELOG.md +30 -0
  206. package/lib/migrations/index.js +6 -5
  207. package/package.json +2 -2
  208. package/.agents/agents/retro.md +0 -42
  209. package/.agents/personas/architect.md +0 -113
  210. package/.agents/personas/devops-engineer.md +0 -38
  211. package/.agents/personas/engineer.md +0 -33
  212. package/.agents/personas/project-manager.md +0 -114
  213. package/.agents/personas/qa-engineer.md +0 -95
  214. package/.agents/personas/security-engineer.md +0 -111
  215. package/.agents/personas/technical-writer.md +0 -101
  216. package/.agents/schemas/dispatch-manifest.json +0 -232
  217. package/.agents/schemas/epic-spec.schema.json +0 -153
  218. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  219. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  220. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  221. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  222. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  223. package/.agents/scripts/dispatcher.js +0 -295
  224. package/.agents/scripts/epic-audit-prepare.js +0 -497
  225. package/.agents/scripts/epic-audit-recheck.js +0 -274
  226. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  227. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  228. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  229. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  230. package/.agents/scripts/epic-plan-clarity.js +0 -211
  231. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  232. package/.agents/scripts/epic-reconcile.js +0 -625
  233. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  234. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  235. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  236. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  237. package/.agents/scripts/lib/config/preflight.js +0 -58
  238. package/.agents/scripts/lib/config/retro.js +0 -77
  239. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  240. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  241. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  242. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  243. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  244. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  245. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  246. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  247. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  248. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  249. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  250. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  251. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  252. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  253. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  254. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  255. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  256. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  257. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  258. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  259. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  260. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  261. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  262. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  263. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  264. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  265. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  266. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  267. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  268. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  269. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  270. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  271. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  272. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  273. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  274. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  275. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  276. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  277. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  278. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  279. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  280. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  281. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  282. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  283. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  284. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  285. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  286. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  287. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  288. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  289. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  290. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  291. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  292. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  293. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  294. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  295. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  296. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  297. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  298. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  299. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  300. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  301. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  302. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  303. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  304. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  305. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  306. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  307. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  308. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  309. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  310. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  311. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  312. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  313. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  314. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  315. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  316. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  317. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  318. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  319. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  320. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  321. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  322. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  323. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  324. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  325. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  326. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  327. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  328. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  329. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  330. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  331. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  332. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  333. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  334. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  335. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  336. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  337. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  338. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  339. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  340. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  341. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  342. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  343. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  344. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  345. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  346. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  347. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  348. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  349. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  350. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  351. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  352. package/.agents/scripts/lib/spec/index.js +0 -36
  353. package/.agents/scripts/lib/spec/loader.js +0 -425
  354. package/.agents/scripts/lib/spec/state.js +0 -208
  355. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  356. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  357. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  358. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  359. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  360. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  361. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  362. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  363. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  364. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  365. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  366. package/.agents/scripts/lifecycle-emit.js +0 -510
  367. package/.agents/scripts/retro-run.js +0 -218
  368. package/.agents/scripts/slice-phase.js +0 -361
  369. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  370. package/.agents/scripts/story-close.js +0 -294
  371. package/.agents/scripts/story-init.js +0 -599
  372. package/.agents/scripts/story-phase.js +0 -369
  373. package/.agents/scripts/wave-tick.js +0 -464
  374. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  375. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  376. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  377. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  378. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  379. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  380. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  381. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  382. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  383. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  384. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  385. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  386. package/.agents/workflows/helpers/epic-audit.md +0 -189
  387. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  388. package/.agents/workflows/helpers/epic-testing.md +0 -125
  389. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  390. package/.agents/workflows/helpers/plan-epic.md +0 -353
  391. package/.agents/workflows/helpers/plan-story.md +0 -251
  392. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  393. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -11,6 +11,8 @@
11
11
  * ```js
12
12
  * {
13
13
  * goal: string, // one-sentence purpose
14
+ * slicing: string, // v2 intra-Story delivery slice plan (optional; '' when absent)
15
+ * spec: string, // folded Tech Spec text block (optional; '' when absent)
14
16
  * changes: PathEntry[], // files/globs this Story touches
15
17
  * acceptance: string[], // observable criteria
16
18
  * verify: string[], // exact commands / tier annotation
@@ -23,10 +25,9 @@
23
25
  * }
24
26
  * ```
25
27
  *
26
- * Where `PathEntry` is one of:
28
+ * Where `PathEntry` is:
27
29
  * - `{ path: string, assumption: "creates"|"refactors-existing"|"exists"|"deletes" }`
28
- * (canonical form)
29
- * - `string` (legacy form — emits a `legacy-path-entry` warning)
30
+ * (canonical form — string bullets are rejected at parse time)
30
31
  *
31
32
  * ## Round-trip contract
32
33
  *
@@ -61,16 +62,15 @@ import { FILE_ASSUMPTION_VALUES } from '../orchestration/file-assumption-enum.js
61
62
  */
62
63
 
63
64
  /**
64
- * @typedef {PathEntry | string} ChangeEntry
65
- * Canonical: PathEntry object.
66
- * Legacy: bare string bullet (emits a `legacy-path-entry` warning via
67
- * the `warnings` array on {@link ParseResult}).
65
+ * @typedef {PathEntry} ChangeEntry
68
66
  */
69
67
 
70
68
  /**
71
69
  * @typedef {object} StoryBody
72
70
  * @property {string} goal - One-sentence purpose statement.
73
- * @property {ChangeEntry[]} changes - Files / globs this Story modifies.
71
+ * @property {string} slicing - Optional v2 intra-Story delivery slice plan text block; '' when absent.
72
+ * @property {string} spec - Optional folded Tech Spec text block; '' when absent.
73
+ * @property {PathEntry[]} changes - Files / globs this Story modifies.
74
74
  * @property {string[]} acceptance - Observable acceptance criteria.
75
75
  * @property {string[]} verify - Exact commands with tier annotation.
76
76
  * @property {PathEntry[]} references - Read-only paths (may be empty).
@@ -86,7 +86,7 @@ import { FILE_ASSUMPTION_VALUES } from '../orchestration/file-assumption-enum.js
86
86
  /**
87
87
  * @typedef {object} ParseResult
88
88
  * @property {StoryBody} body - The parsed structured body.
89
- * @property {string[]} warnings - Non-fatal issues (e.g. legacy-path-entry).
89
+ * @property {string[]} warnings - Non-fatal issues (e.g. unstructured-body).
90
90
  * @property {ParseInfo} info - Metadata about the parse.
91
91
  */
92
92
 
@@ -98,7 +98,9 @@ import { FILE_ASSUMPTION_VALUES } from '../orchestration/file-assumption-enum.js
98
98
  * @property {boolean} hasVerifySection - Whether a `## Verify` section was found.
99
99
  * @property {boolean} hasReferencesSection - Whether a `## References` section was found.
100
100
  * @property {boolean} hasNonGoalsSection - Whether a `## Non-Goals` section was found.
101
- * @property {boolean} isLegacyStringBody - True when no structured sections were found.
101
+ * @property {boolean} hasSlicingSection - Whether a `## Slicing` section was found (v2 folded slice plan).
102
+ * @property {boolean} hasSpecSection - Whether a `## Spec` section was found (folded Tech Spec).
103
+ * @property {boolean} isUnstructuredBody - True when no structured sections were found.
102
104
  */
103
105
 
104
106
  /**
@@ -139,12 +141,15 @@ export class StoryBodyParseError extends Error {
139
141
  // maps to the `non_goals` field.
140
142
  const HEADING_TO_FIELD = new Map([
141
143
  ['goal', 'goal'],
144
+ ['slicing', 'slicing'],
145
+ ['spec', 'spec'],
142
146
  ['changes', 'changes'],
143
147
  ['acceptance', 'acceptance'],
144
148
  ['verify', 'verify'],
145
149
  ['references', 'references'],
146
150
  ['non_goals', 'non_goals'],
147
151
  ]);
152
+ const TEXT_BLOCK_FIELDS = new Set(['slicing', 'spec']);
148
153
 
149
154
  // ---------------------------------------------------------------------------
150
155
  // Helpers
@@ -162,19 +167,16 @@ function stripListMarker(line) {
162
167
  }
163
168
 
164
169
  /**
165
- * Parse a single `changes` / `references` bullet into a `PathEntry` or
166
- * legacy string. Emits a `legacy-path-entry` warning for string form.
170
+ * Parse a single `changes` / `references` bullet into a `PathEntry`.
167
171
  *
168
172
  * Object form: `{ path: "...", assumption: "creates" }` (stored as
169
173
  * `- { "path": "...", "assumption": "..." }` or just recognized from the
170
174
  * structured body directly — when deserializing from a structured object
171
175
  * that was never serialized to markdown, the entry arrives as-is).
172
176
  *
173
- * String form: `src/foo.js: create handleSubmit`
174
- *
175
177
  * @param {string|object} raw
176
178
  * @param {string[]} warnings
177
- * @returns {PathEntry | string}
179
+ * @returns {PathEntry}
178
180
  */
179
181
  function parsePathEntry(raw, warnings) {
180
182
  // Already a structured object (from a parsed JSON body, not markdown).
@@ -218,15 +220,14 @@ function parsePathEntry(raw, warnings) {
218
220
  } catch (err) {
219
221
  // Re-throw StoryBodyParseError so it propagates.
220
222
  if (err instanceof StoryBodyParseError) throw err;
221
- // JSON parse failed — fall through to legacy string handling.
223
+ // JSON parse failed — fall through to reject plain-string form.
222
224
  }
223
225
  }
224
226
 
225
- // Legacy string form — warn but accept.
226
- warnings.push(
227
- `legacy-path-entry: change entry "${str.slice(0, 80)}" is a plain string; prefer { path, assumption } object form.`,
227
+ throw new StoryBodyParseError(
228
+ `changes/references entry must be a { path, assumption } object; plain string bullets are no longer accepted: ${str.slice(0, 120)}`,
229
+ { field: 'changes', raw: str },
228
230
  );
229
- return str;
230
231
  }
231
232
 
232
233
  /**
@@ -245,8 +246,11 @@ function extractBlockedBy(footerBlock) {
245
246
  return deps;
246
247
  }
247
248
 
248
- // Matches the trailing `<!-- meta: {...} -->` block serialize() emits.
249
- const META_BLOCK_RE = /<!--\s*meta:\s*(\{[\s\S]*?\})\s*-->/;
249
+ // Matches any trailing `<!-- meta: -->` block. Object payloads are the
250
+ // canonical serialize() shape; non-object / malformed payloads are still
251
+ // recognized so section parsing can skip them and extractMeta can degrade.
252
+ const META_BLOCK_RE = /<!--\s*meta:\s*([\s\S]*?)\s*-->/;
253
+ const META_OBJECT_RE = /<!--\s*meta:\s*(\{[\s\S]*?\})\s*-->/;
250
254
 
251
255
  /**
252
256
  * Extract the `wide` / `estimated_test_files` fields from the trailing
@@ -275,7 +279,7 @@ function extractMeta(markdown) {
275
279
  mandrel_version: null,
276
280
  authored_at: null,
277
281
  };
278
- const match = markdown.match(META_BLOCK_RE);
282
+ const match = markdown.match(META_OBJECT_RE) ?? markdown.match(META_BLOCK_RE);
279
283
  if (!match) return result;
280
284
 
281
285
  let parsed;
@@ -285,7 +289,10 @@ function extractMeta(markdown) {
285
289
  // Malformed meta comment — degrade to defaults rather than corrupt the body.
286
290
  return result;
287
291
  }
288
- if (parsed === null || typeof parsed !== 'object') return result;
292
+ // Non-object JSON (array / scalar / null) is treated as absent meta.
293
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
294
+ return result;
295
+ }
289
296
 
290
297
  result.wide = normalizeWide(parsed.wide);
291
298
  result.reason_to_exist = normalizeReasonToExist(parsed.reason_to_exist);
@@ -385,27 +392,11 @@ function splitSections(markdown) {
385
392
  // below, which closes the open section. The chosen canonical spelling is
386
393
  // therefore the hyphenated single token `## Non-Goals`.
387
394
  const fieldHeadingMatch = line.match(/^#{2,3}\s+([\w-]+)\s*$/i);
388
- if (fieldHeadingMatch) {
389
- const name = fieldHeadingMatch[1].toLowerCase().replace(/-/g, '_');
390
- if (HEADING_TO_FIELD.has(name)) {
391
- inPreamble = false;
392
- currentSection = name;
393
- if (!sections.has(currentSection)) sections.set(currentSection, []);
394
- continue;
395
- }
396
- // A heading that matches the canonical `## Word` shape but is not a
397
- // recognized field name (e.g. a trailing free-form `## Notes`) closes
398
- // the currently-open section. Without this reset, the unknown heading
399
- // and its bullets bleed into the previously-recognized section,
400
- // silently corrupting `verify[]` / `acceptance[]`. We do NOT re-enter
401
- // the preamble (`inPreamble` stays false), so a later recognized
402
- // heading still registers normally; we only stop appending to the
403
- // closed section. The heading line and its body are dropped from all
404
- // sections. (Multi-word free-form headings like `## Out of Scope` —
405
- // with internal spaces — do not match the `[\w-]+` single-token shape
406
- // and reach this branch too. The hyphenated single-token canonical
407
- // negative-scope heading is `## Non-Goals`, which IS recognized above.)
408
- currentSection = null;
395
+ const fieldName = fieldHeadingMatch?.[1]?.toLowerCase().replace(/-/g, '_');
396
+ if (HEADING_TO_FIELD.has(fieldName)) {
397
+ inPreamble = false;
398
+ currentSection = fieldName;
399
+ if (!sections.has(currentSection)) sections.set(currentSection, []);
409
400
  continue;
410
401
  }
411
402
 
@@ -418,7 +409,11 @@ function splitSections(markdown) {
418
409
  // lines were silently absorbed into `verify[]` / `acceptance[]`. The
419
410
  // heading and everything under it is dropped from structured parsing
420
411
  // (it is extended, non-canonical markdown).
421
- if (!inPreamble && /^#{1,6}\s+\S/.test(line)) {
412
+ if (
413
+ !inPreamble &&
414
+ /^#{1,6}\s+\S/.test(line) &&
415
+ !TEXT_BLOCK_FIELDS.has(currentSection)
416
+ ) {
422
417
  currentSection = null;
423
418
  continue;
424
419
  }
@@ -442,10 +437,7 @@ function splitSections(markdown) {
442
437
  if (inPreamble) {
443
438
  preambleLines.push(line);
444
439
  } else if (currentSection !== null) {
445
- const trimmed = line.trim();
446
- if (trimmed.length > 0) {
447
- sections.get(currentSection).push(line);
448
- }
440
+ sections.get(currentSection).push(line);
449
441
  }
450
442
  }
451
443
 
@@ -460,7 +452,7 @@ function splitSections(markdown) {
460
452
  // ---------------------------------------------------------------------------
461
453
 
462
454
  /**
463
- * Build the minimal {@link ParseResult} returned for a legacy string body —
455
+ * Build the minimal {@link ParseResult} returned for an unstructured body —
464
456
  * markdown that carries no recognised structured section. The goal falls
465
457
  * back to the preamble text (or the whole trimmed input), `depends_on` is
466
458
  * still recovered from the footer, and all section arrays are empty.
@@ -470,13 +462,15 @@ function splitSections(markdown) {
470
462
  * @param {string} footer - Footer block text (from splitSections).
471
463
  * @returns {ParseResult}
472
464
  */
473
- function parseLegacyStringBody(input, preamble, footer) {
465
+ function parseUnstructuredBody(input, preamble, footer) {
474
466
  const warnings = [
475
- 'legacy-string-body: no structured sections found; returning minimal body from preamble text.',
467
+ 'unstructured-body: no structured sections found; returning minimal body from preamble text.',
476
468
  'test-surface-unestimated: estimated_test_files not present.',
477
469
  ];
478
470
  const body = {
479
471
  goal: preamble || input.trim(),
472
+ slicing: '',
473
+ spec: '',
480
474
  changes: [],
481
475
  acceptance: [],
482
476
  verify: [],
@@ -499,7 +493,9 @@ function parseLegacyStringBody(input, preamble, footer) {
499
493
  hasVerifySection: false,
500
494
  hasReferencesSection: false,
501
495
  hasNonGoalsSection: false,
502
- isLegacyStringBody: true,
496
+ hasSlicingSection: false,
497
+ hasSpecSection: false,
498
+ isUnstructuredBody: true,
503
499
  },
504
500
  };
505
501
  }
@@ -518,15 +514,30 @@ function parseGoalSection(lines) {
518
514
  .join(' ');
519
515
  }
520
516
 
517
+ /**
518
+ * Parse a verbatim text-block section (`## Slicing` or `## Spec`) into a
519
+ * newline-joined string. Unlike {@link parseGoalSection}, line breaks are
520
+ * preserved so a bullet list, compact table, or folded Tech Spec survives the
521
+ * round-trip; only blank lines and trailing whitespace are normalized.
522
+ *
523
+ * @param {string[]} lines
524
+ * @returns {string}
525
+ */
526
+ function parseTextBlockSection(lines) {
527
+ return lines
528
+ .map((line) => line.replace(/\s+$/, ''))
529
+ .join('\n')
530
+ .replace(/^\n+|\n+$/g, '');
531
+ }
532
+
521
533
  /**
522
534
  * Parse a `## Changes` / `## References` section into a list of
523
- * `PathEntry | string` entries. List markers are stripped, blank entries are
524
- * dropped, and each surviving entry is normalized via {@link parsePathEntry}
525
- * (which appends `legacy-path-entry` warnings for bare-string bullets).
535
+ * `PathEntry` entries. List markers are stripped, blank entries are
536
+ * dropped, and each surviving entry is normalized via {@link parsePathEntry}.
526
537
  *
527
538
  * @param {string[]} lines - Raw content lines under the heading.
528
539
  * @param {string[]} warnings - Mutable warnings sink.
529
- * @returns {Array<PathEntry|string>}
540
+ * @returns {PathEntry[]}
530
541
  */
531
542
  function parsePathEntrySection(lines, warnings) {
532
543
  const entries = [];
@@ -601,19 +612,28 @@ export function parse(input) {
601
612
  const hasVerifySection = sections.has('verify');
602
613
  const hasReferencesSection = sections.has('references');
603
614
  const hasNonGoalsSection = sections.has('non_goals');
615
+ const hasSlicingSection = sections.has('slicing');
616
+ const hasSpecSection = sections.has('spec');
604
617
 
605
- // If no structured sections found, treat as legacy string body.
606
- const isLegacyStringBody =
618
+ // If no structured sections found, treat as unstructured body.
619
+ const isUnstructuredBody =
607
620
  !hasGoalSection &&
608
621
  !hasChangesSection &&
609
622
  !hasAcceptanceSection &&
610
623
  !hasVerifySection;
611
624
 
612
- if (isLegacyStringBody) {
613
- return parseLegacyStringBody(input, preamble, footer);
625
+ if (isUnstructuredBody) {
626
+ return parseUnstructuredBody(input, preamble, footer);
614
627
  }
615
628
 
616
629
  const goal = parseGoalSection(sections.get('goal') ?? []);
630
+ // Optional v2 intra-Story delivery slice plan (`## Slicing`). Preserved as
631
+ // a verbatim text block — a large Story (what v1 called an Epic) folds its
632
+ // Delivery Slicing here instead of fanning out into sibling Stories; a
633
+ // trivial Story omits it entirely. Parsed as a text block so a bullet list
634
+ // or compact table round-trips.
635
+ const slicing = parseTextBlockSection(sections.get('slicing') ?? []);
636
+ const spec = parseTextBlockSection(sections.get('spec') ?? []);
617
637
  const changes = parsePathEntrySection(
618
638
  sections.get('changes') ?? [],
619
639
  warnings,
@@ -644,6 +664,8 @@ export function parse(input) {
644
664
 
645
665
  const body = {
646
666
  goal,
667
+ slicing,
668
+ spec,
647
669
  changes,
648
670
  acceptance,
649
671
  verify,
@@ -667,7 +689,9 @@ export function parse(input) {
667
689
  hasVerifySection,
668
690
  hasReferencesSection,
669
691
  hasNonGoalsSection,
670
- isLegacyStringBody: false,
692
+ hasSlicingSection,
693
+ hasSpecSection,
694
+ isUnstructuredBody: false,
671
695
  },
672
696
  };
673
697
  }
@@ -685,6 +709,12 @@ function parseStructuredObject(obj) {
685
709
 
686
710
  const goal = typeof obj.goal === 'string' ? obj.goal.trim() : '';
687
711
 
712
+ // slicing — optional v2 intra-Story delivery slice plan (verbatim text).
713
+ const slicing = typeof obj.slicing === 'string' ? obj.slicing.trim() : '';
714
+
715
+ // spec — optional folded Tech Spec (verbatim text).
716
+ const spec = typeof obj.spec === 'string' ? obj.spec.trim() : '';
717
+
688
718
  // changes
689
719
  const rawChanges = Array.isArray(obj.changes) ? obj.changes : [];
690
720
  const changes = [];
@@ -747,6 +777,8 @@ function parseStructuredObject(obj) {
747
777
 
748
778
  const body = {
749
779
  goal,
780
+ slicing,
781
+ spec,
750
782
  changes,
751
783
  acceptance,
752
784
  verify,
@@ -770,7 +802,9 @@ function parseStructuredObject(obj) {
770
802
  hasVerifySection: 'verify' in obj,
771
803
  hasReferencesSection: 'references' in obj,
772
804
  hasNonGoalsSection: 'non_goals' in obj,
773
- isLegacyStringBody: false,
805
+ hasSlicingSection: 'slicing' in obj,
806
+ hasSpecSection: 'spec' in obj,
807
+ isUnstructuredBody: false,
774
808
  },
775
809
  };
776
810
  }
@@ -793,10 +827,10 @@ function serializePathEntry(entry) {
793
827
 
794
828
  /**
795
829
  * Descriptor table for the human-readable Story-body sections, in canonical
796
- * emit order (`## Goal`, `## Changes`, `## Acceptance`, `## Verify`,
797
- * `## References`, `## Non-Goals`). Each descriptor reads one body field and returns the
798
- * section's markdown block when the field is present and non-empty, or `null`
799
- * to omit the section.
830
+ * emit order (`## Goal`, `## Slicing`, `## Spec`, `## Changes`,
831
+ * `## Acceptance`, `## Verify`, `## References`, `## Non-Goals`). Each
832
+ * descriptor reads one body field and returns the section's markdown block
833
+ * when the field is present and non-empty, or `null` to omit the section.
800
834
  *
801
835
  * Standardising the section ladder as a single data table makes adding a new
802
836
  * optional section a one-line edit here rather than a new control-flow branch
@@ -812,6 +846,26 @@ const SERIALIZE_SECTIONS = [
812
846
  ? `## Goal\n${goal.trim()}`
813
847
  : null,
814
848
  },
849
+ {
850
+ // Optional v2 intra-Story delivery slice plan. Single-token `## Slicing`
851
+ // heading (recognized by the `[\w-]+` field-heading regex). Verbatim text
852
+ // block. Render-when-non-empty: an absent/empty `slicing` emits nothing,
853
+ // so every pre-v2 body round-trips byte-identically.
854
+ field: 'slicing',
855
+ render: (slicing) =>
856
+ typeof slicing === 'string' && slicing.trim().length > 0
857
+ ? `## Slicing\n${slicing.trim()}`
858
+ : null,
859
+ },
860
+ {
861
+ // Optional folded Tech Spec. Like `## Slicing`, this is a verbatim text
862
+ // block and emits nothing for absent/empty pre-v2 bodies.
863
+ field: 'spec',
864
+ render: (spec) =>
865
+ typeof spec === 'string' && spec.trim().length > 0
866
+ ? `## Spec\n${spec.trim()}`
867
+ : null,
868
+ },
815
869
  {
816
870
  field: 'changes',
817
871
  render: (changes) =>
@@ -938,8 +992,8 @@ function serializeFooter(body, opts) {
938
992
  * format written to GitHub issue bodies.
939
993
  *
940
994
  * The output matches the section order the spec-renderer uses:
941
- * `## Goal`, `## Changes`, `## Acceptance`, `## Verify`, `## References`,
942
- * `## Non-Goals` (each omitted when empty).
995
+ * `## Goal`, `## Slicing`, `## Spec`, `## Changes`, `## Acceptance`,
996
+ * `## Verify`, `## References`, `## Non-Goals` (each omitted when empty).
943
997
  *
944
998
  * `wide`, `reason_to_exist`, and `estimated_test_files` are emitted as a
945
999
  * fenced `<!-- meta -->` comment block so round-trips preserve them without
@@ -200,7 +200,6 @@ export async function loadBodyTemplate(projectRoot) {
200
200
  export function buildContextEnvelope({
201
201
  seed,
202
202
  refine,
203
- persona,
204
203
  bodyTemplate,
205
204
  duplicateCandidates,
206
205
  techStack = null,
@@ -212,7 +211,6 @@ export function buildContextEnvelope({
212
211
  version: 1,
213
212
  seed,
214
213
  refine,
215
- persona,
216
214
  bodyTemplate,
217
215
  requiredSections: [...REQUIRED_SECTIONS],
218
216
  duplicateCandidates: {
@@ -222,8 +220,8 @@ export function buildContextEnvelope({
222
220
  techStack,
223
221
  corpusContext,
224
222
  deliverContract: {
225
- workflow: '.agents/workflows/helpers/single-story-deliver.md',
226
- requiredLabels: ['type::story', `persona::${persona}`],
223
+ workflow: '.agents/workflows/helpers/deliver-story.md',
224
+ requiredLabels: ['type::story'],
227
225
  forbidden: ['Epic: #N references in the body'],
228
226
  },
229
227
  };
@@ -1,8 +1,9 @@
1
1
  import { LIMITS_DEFAULTS } from '../config/limits.js';
2
2
  import {
3
3
  AUTHORING_ALTITUDE_GUIDANCE,
4
- DEFAULT_TASK_SIZING,
4
+ DEFAULT_MODEL_CAPACITY,
5
5
  DELIVERABLE_GRANULARITY_GUIDANCE,
6
+ resolveCapacityCeilings,
6
7
  } from '../orchestration/ticket-validator-sizing.js';
7
8
 
8
9
  /**
@@ -18,27 +19,16 @@ import {
18
19
  * asks the planner to carry acceptance/verify as top-level ticket arrays.
19
20
  *
20
21
  * **Single source of the prompt body (Story #4162).** This module is the sole
21
- * carrier of the full decomposer system-prompt body. The
22
- * `epic-plan-decompose-author` SKILL no longer embeds a second verbatim copy —
23
- * it references this rendered prompt (delivered to the host LLM in the
24
- * `systemPrompt` field of the authoring context envelope built by
25
- * `epic-plan-decompose/phases/context.js`) instead, so the two surfaces cannot
26
- * drift. A guard test (`tests/ticket-decomposer.test.js`) fails if the SKILL
27
- * re-grows a full copy of the prompt preamble.
28
- *
29
- * **Token-budget sizing input (Story #4162).** `maxTokenBudget` is the real
30
- * one-pass delivery envelope (the task-prompt hydration cap surfaced into the
31
- * authoring envelope by `context.js`, Story #3875). It is threaded into the
32
- * rendered prompt as a sizing input so the planner sizes Stories against the
33
- * envelope a single agent can actually deliver in one pass, rather than leading
34
- * with the file-count proxy alone.
22
+ * carrier of the full decomposer system-prompt body, delivered to the host
23
+ * LLM in the `systemPrompts.decompose` field of the `/plan` context envelope
24
+ * (via `lib/orchestration/planning/decomposer-context.js`), so no second
25
+ * verbatim copy can drift.
35
26
  */
36
27
  export function renderDecomposerSystemPrompt({
37
28
  maxTickets = LIMITS_DEFAULTS.maxTickets,
38
- maxTokenBudget = LIMITS_DEFAULTS.maxTokenBudget,
39
29
  epicId = null,
40
30
  } = {}) {
41
- return render2TierPrompt({ maxTickets, maxTokenBudget, epicId });
31
+ return render2TierPrompt({ maxTickets, epicId });
42
32
  }
43
33
 
44
34
  /**
@@ -47,12 +37,16 @@ export function renderDecomposerSystemPrompt({
47
37
  * on the Story body so the executing agent has everything it needs in one
48
38
  * ticket. Thematic grouping lives as prose in the Epic body / Tech Spec.
49
39
  */
50
- function render2TierPrompt({ maxTickets, maxTokenBudget, epicId = null }) {
51
- // Sizing thresholds are sourced from the single DEFAULT_TASK_SIZING constant
52
- // (ticket-validator-sizing.js) so the prompt and the validator cannot drift.
53
- const { softFiles, hardFiles, softAcceptanceCount } = DEFAULT_TASK_SIZING;
40
+ function render2TierPrompt({ maxTickets, epicId = null }) {
41
+ // v2 Stage 3: default-single emit one Story unless the split policy clears.
42
+ // Capacity thresholds are sourced from the single DEFAULT_MODEL_CAPACITY
43
+ // constant (ticket-validator-sizing.js) so the prompt and the validator
44
+ // cannot drift.
45
+ const { softSessionTokens, hardSessionTokens } = resolveCapacityCeilings(
46
+ DEFAULT_MODEL_CAPACITY,
47
+ );
54
48
  // Deliverable-granularity definition + single-consumer merge rule + the
55
- // soft envelope-floor heuristic are sourced from the single
49
+ // thin-dependent merge heuristic are sourced from the single
56
50
  // DELIVERABLE_GRANULARITY_GUIDANCE constant (ticket-validator-sizing.js) so
57
51
  // the prompt and the authoring SKILL cannot drift (Story #3777; the
58
52
  // envelope-floor sentence added by Story #4313).
@@ -78,17 +72,18 @@ function render2TierPrompt({ maxTickets, maxTokenBudget, epicId = null }) {
78
72
  ? `@epic-${epicId}-ac-1`
79
73
  : '@epic-<id>-ac-N';
80
74
  return `You are an expert Senior Project Manager and Orchestrator.
81
- Your job is to take an Epic (including its inline User Stories) and a Technical Specification and decompose them into a flat list of Story tickets for an AI Agent to execute.
75
+ Your job is to turn a plan seed / Tech Spec into a Story ticket array for an AI Agent to execute.
82
76
 
83
- ### HIERARCHY RULES:
84
- 1. **Stories**: Specific user-facing or architectural user stories (e.g., "Implement JWT Token Exchange").
85
- - Every Story attaches directly to the Epic there is NO Feature tier and NO Task layer in this hierarchy.
86
- - **Story-Level Execution**: Each Story will be executed end-to-end on a single branch by a single agent. Acceptance criteria and verification commands live as top-level \`acceptance[]\` / \`verify[]\` arrays on the Story ticket (see STORY BODY SCHEMA below).
87
- - Thematic grouping is prose in the Epic body / Tech Spec, never a ticket.
77
+ ### HIERARCHY RULES (v2 default-single):
78
+ 1. **Emit exactly one Story by default.** Split into N>1 only when pieces have near-zero overlap or sit across an architectural seam. Coupled work stays one Story — put intra-session checkpoints in \`## Slicing\` and fold the Tech Spec into \`## Spec\`.
79
+ 2. **Stories**: Specific user-facing or architectural capabilities (e.g., "Implement JWT Token Exchange").
80
+ - There is NO Epic parent ticket, NO Feature tier, and NO Task layer.
81
+ - **Story-Level Execution**: Each Story is executed end-to-end on a single branch by a single agent. Acceptance criteria and verification commands live as top-level \`acceptance[]\` / \`verify[]\` arrays on the Story ticket (see STORY BODY SCHEMA below).
82
+ - Thematic grouping is prose in the Story's folded \`## Spec\` / \`## Slicing\`, never sibling tickets for coupled work.
88
83
 
89
84
  ### LABEL CONVENTIONS:
90
85
  - Every ticket must have the \`type::story\` label. No other type label is allowed — the retired Feature and Task tiers have no labels under this hierarchy.
91
- - Every ticket must have a \`persona::[engineer|architect|qa-engineer|security-engineer|etc]\` label indicating WHO should execute it.
86
+ - Do **not** emit \`persona::*\` labels — the behavioral persona concept (and its label axis) was removed in v2.
92
87
 
93
88
  ### OUTPUT FORMAT:
94
89
  You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown blocks.
@@ -102,7 +97,7 @@ You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown
102
97
  "body": <string — see STORY BODY SCHEMA below>,
103
98
  "acceptance": ["<testable, observable criterion>", ...],
104
99
  "verify": ["<exact command or test path> (<tier>)", ...],
105
- "labels": ["type::story", "persona::..."],
100
+ "labels": ["type::story"],
106
101
  "depends_on": ["slug-of-blocking-dependency"] (optional array of Story slugs that block execution)
107
102
  }
108
103
  ]
@@ -112,12 +107,18 @@ You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown
112
107
  ### STORY BODY SCHEMA (REQUIRED FOR EVERY STORY):
113
108
  \`body\` MUST be a **string** — the serialized markdown produced by \`serialize()\` from \`lib/story-body/story-body.js\`. Do NOT emit \`body\` as a JSON object: an object body throws \`StoryBodyParseError\` in the reconciler (Story #3302) and is discarded by the GitHub provider, producing an empty issue body. Stories are consumed by non-interactive sub-agents that must self-verify from the Story ticket alone — so the ticket must carry everything an agent needs to execute and self-verify.
114
109
 
115
- The \`acceptance[]\` and \`verify[]\` arrays live at the **top level** of the Story ticket object (not nested inside \`body\`). The validator reads \`story.acceptance\` and \`story.verify\` directly nesting them inside the body makes them invisible to the validator and the decompose is rejected.
110
+ The \`acceptance[]\` and \`verify[]\` arrays live at the **top level** of the Story ticket object that is the machine contract the validator reads. Persist syncs those arrays into the body's \`## Acceptance\` / \`## Verify\` sections so the GitHub issue stays a complete executable document. Prefer authoring the lists **once at top-level** and omitting those sections from the authored \`body\` string (or mirroring the exact same items). Do **not** invent a second criteria list inside \`## Spec\`, and do not author a separate Acceptance Spec / PRD artifact.
116
111
 
117
112
  The serialized \`body\` string renders these markdown sections (in order):
118
113
 
119
114
  ## Goal
120
- <one sentence — why this Story exists within the Epic>
115
+ <one sentence — why this Story exists>
116
+
117
+ ## Slicing
118
+ <optional ordered intra-session checkpoints — not a second Spec or AC table>
119
+
120
+ ## Spec
121
+ <optional lean technical approach — do NOT restate Goal / Acceptance / Verify>
121
122
 
122
123
  ## Changes
123
124
  - {"path": "<file path>", "assumption": "creates" | "refactors-existing" | "deletes"}
@@ -141,7 +142,9 @@ The serialized \`body\` string renders these markdown sections (in order):
141
142
 
142
143
  #### STORY BODY RULES:
143
144
 
144
- - **goal** (in body string): One sentence stating WHY this story exists within the Epic.
145
+ - **goal** (in body string): One sentence stating WHY this Story exists.
146
+ - **spec** (optional, in body string as \`## Spec\`): Lean technical approach only. If the Spec is large enough to feel like its own document, the Story is probably too big — split it. Persist keeps Specs inline and rejects over-budget Specs (never writes them under \`docs/\`).
147
+ - **slicing** (optional): Ordered intra-session checkpoints for one Story. Not a fan-out table and not a duplicate of Acceptance.
145
148
  - **changes** (in body string): Each entry is an object \`{ path, assumption }\` where \`assumption\` is one of \`creates | refactors-existing | deletes\`. Acceptable path shapes include explicit files (\`src/components/Foo.tsx\`), glob patterns (\`tests/e2e/*.spec.ts\`, \`**/*.astro\`), and module identifiers that resolve to files. Use \`refactors-existing\` for in-place edits to a file already on \`main\`; \`creates\` for net-new files; \`deletes\` for removals.
146
149
  - **acceptance** (top-level array on the ticket object): Items MUST be observable from outside the agent. Acceptable shapes: a specific command exits 0, a file exists at a given path, a snapshot test matches, a \`data-testid\` resolves under a given selector, a row count in a fixture matches. UNACCEPTABLE: "verify by reading the diff", "looks good", "matches the spec" — push these down into a \`verify\` command instead.
147
150
  - **verify** (top-level array on the ticket object): Each entry MUST name a testing tier in parentheses, drawn from \`unit\` / \`contract\` / \`e2e\` / \`validate\`. Example: \`npm run test -- src/x.test.ts (unit)\`, \`npm run validate (validate)\`. Stories with zero verify entries SHOULD fail validation; if a story is genuinely unverifiable in isolation (e.g., a copy edit auditor will eyeball), the literal entry \`manual:<reason>\` is allowed so the absence is intentional, not lazy. Manual entries without a reason are rejected.
@@ -157,37 +160,35 @@ ${newFileContract}
157
160
 
158
161
  ${advisoryCaveat}
159
162
 
160
- #### STORY SIZING — COHESION FIRST (the numeric ceiling is only a backstop):
163
+ #### STORY SIZING — COHESION FIRST (session capacity is only a backstop):
161
164
 
162
165
  **Decompose at deliverable granularity, not module/task level.** ${granularityDefinition}
163
166
 
164
- The primary question is **cohesion, not count**: *is this one coherent change with one reason to exist?* File count cannot tell a trivial ${softFiles}-file rename from a hard 3-file parser+caller+config change — so lead with the change's reason, not its size.
165
-
166
- **Size against the real one-pass delivery envelope.** Each Story is delivered and self-verified by a single agent in one pass, whose context is capped by the delivery token budget \`maxTokenBudget = ${maxTokenBudget}\` tokens (the task-prompt hydration cap). Use that envelope — not the file count alone — as the leading sizing input: a Story is correctly sized when one agent can hold its full change, acceptance, and verification in a single pass within \`maxTokenBudget\`. The numeric file thresholds below are a coarse backstop on top of this envelope, not the primary signal.
167
+ The primary question is **cohesion, not count**: *is this one coherent change with one reason to exist?* File count cannot tell a trivial rename from a hard parser+caller+config change — so lead with the change's reason, not its size. Frontier models one-shot capability-sized work in a single pass — do not fragment a coherent capability into dependent slices just to stay "small."
167
168
 
168
169
  ${envelopeFloor}
169
170
 
170
171
  - **One Story = one coherent change with one reason to exist.** If you cannot state that reason in a sentence, the Story is probably two Stories — or two Stories that should be one. State that sentence explicitly in the Story's \`reason_to_exist\` meta field (see STORY BODY RULES) so the consolidate critic can check it.
171
172
  - ${singleConsumerRule}
172
173
  - **Split independent, parallelizable work** into sibling Stories — but only when the pieces genuinely have separate reasons to exist.
173
- - **Declare \`wide\` with a one-line reason when a change is legitimately broad** (a cohesive cutover that spans many files for one reason). Declaring \`wide\` lifts the hard file-width ceiling — see below.
174
+ - **Declare \`wide\` with a one-line reason when a change is legitimately broad** (a cohesive cutover whose authored ticket mass is high for one reason). Declaring \`wide\` lifts the hard session-mass ceiling — see below.
174
175
 
175
- **Numeric backstop (validator-enforced).** These thresholds are sourced from the single \`DEFAULT_TASK_SIZING\` constant in \`ticket-validator-sizing.js\` — there is no second copy to drift:
176
+ **Capacity backstop (validator-enforced).** Absolute authored-token ceilings from the single \`DEFAULT_MODEL_CAPACITY\` constant in \`ticket-validator-sizing.js\` — not operator-tunable. They catch Spec novels, not capability-sized Stories:
176
177
 
177
- - A Story touching more than **${softFiles} files** (\`softFiles\`) emits an advisory width finding a nudge to check cohesion or declare \`wide\`.
178
- - A Story touching more than **${hardFiles} files** (\`hardFiles\`) is **rejected** unless it declares \`wide\` with a reason.
179
- - Acceptance mass is **advisory only**: more than **${softAcceptanceCount} acceptance items** (\`softAcceptanceCount\`) emits an advisory warning. There is NO hard acceptance ceiling — a long binding contract is a signal to re-check cohesion, never a reason to fragment one coherent capability into dependent slices.
178
+ - Soft advisory (**${softSessionTokens} tokens**): authored session mass above this emits a nudge to check cohesion or declare \`wide\`.
179
+ - Hard ceiling (**${hardSessionTokens} tokens**): authored session mass above this is **rejected** unless the Story declares \`wide\` with a reason.
180
+ - Session mass = **authored tokens only** (goal / reason / Spec / acceptance / verify / slicing / change-path text). File count and AC count do **not** inflate mass — a long binding contract or a broad file footprint is never by itself a reason to fragment one coherent capability into dependent slices.
180
181
 
181
182
  #### DELIVERY-SCHEDULE SIMULATION — the story count must earn itself:
182
183
 
183
184
  Before emitting, simulate the delivery schedule your plan implies, and judge the plan by its schedule — not by how tidy the taxonomy looks:
184
185
 
185
186
  1. **Build the wave schedule.** A Story runs only after every \`depends_on\` completes, and two Stories that name the same file in \`changes[]\` cannot run in the same wave (the scheduler serializes file-overlapping Stories even when no \`depends_on\` edge links them).
186
- 2. **Compute the parallelism yield**: story count ÷ critical-path length in waves. A yield near 1.0 means the plan is a serial chain — N Stories that deliver no faster than one Story while paying N delivery sessions (hydration, branch, PR, review, CI).
187
+ 2. **Compute the parallelism yield**: story count ÷ critical-path length in waves. A yield near 1.0 means the plan is a serial chain — N Stories that deliver no faster than one Story while paying N delivery sessions (branch, PR, review, CI).
187
188
  3. **Every Story must earn its slot** by at least one of:
188
189
  - **(a) parallelism** — it actually runs concurrently with a sibling in the schedule you just built ("logically independent" does not count; *schedule*-independent does);
189
190
  - **(b) risk isolation** — it isolates a consumer-facing behavior change or high-risk cutover into its own reviewable, revertable unit;
190
- - **(c) envelope pressure** — merged into its neighbor it would exceed the one-pass delivery envelope (\`maxTokenBudget\`).
191
+ - **(c) cohesion break** — merged into its neighbor it would no longer be one coherent change with one reason to exist.
191
192
  4. **A dependent link with none of those justifications merges into its consumer.** This generalizes the single-consumer merge rule from pairs to chains.
192
193
  5. **Hot-file rule.** When one file appears in the \`changes[]\` of more than a third of your Stories, the slicing axis cuts across a shared seam — merge the Stories that co-edit it, or re-slice along the seam so each Story owns its files.
193
194
 
@@ -201,7 +202,7 @@ A Story whose footprint is legitimately broad declares \`wide\` carrying a one-l
201
202
  "wide": { "reason": "hard contract cutover: migrate every <X> call site in one PR" }
202
203
  \`\`\`
203
204
 
204
- Declaring \`wide\` with a non-empty reason **lifts the \`hardFiles\` rejection** — no Story is rejected for width when it states why it is broad. Omit \`wide\` for ordinary Stories; a wide footprint with no \`wide\` declaration emits only an advisory nudge (check cohesion or declare \`wide\`), never a rejection on its own.
205
+ Declaring \`wide\` with a non-empty reason **lifts the hard session-mass rejection** — no Story is rejected for width when it states why it is broad. Omit \`wide\` for ordinary Stories; a wide footprint with no \`wide\` declaration emits only an advisory nudge (check cohesion or declare \`wide\`), never a rejection on its own.
205
206
 
206
207
  **Glob entries** in \`changes[]\` (bullets containing \`*\`) mark the Story footprint as \`unknown-width\`: the numeric ceiling cannot bound a glob, so it is skipped. A Story carrying glob changes with no \`wide\` declaration emits an advisory nudge.
207
208