mandrel 1.93.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 (463) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/acceptance-critic.md +129 -0
  3. package/.agents/agents/story-worker.md +161 -0
  4. package/.agents/docs/SDLC.md +489 -1285
  5. package/.agents/docs/agentrc-reference.json +177 -67
  6. package/.agents/docs/configuration.md +108 -136
  7. package/.agents/docs/execution-reference.md +44 -22
  8. package/.agents/docs/quality-gates.md +13 -19
  9. package/.agents/docs/workflows.md +3 -3
  10. package/.agents/instructions.md +107 -108
  11. package/.agents/rules/ci-remediation.md +8 -12
  12. package/.agents/rules/git-conventions-reference.md +224 -0
  13. package/.agents/rules/git-conventions.md +42 -223
  14. package/.agents/rules/security-baseline.md +5 -0
  15. package/.agents/rules/testing-standards.md +106 -13
  16. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  17. package/.agents/schemas/agentrc.schema.json +71 -201
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  20. package/.agents/schemas/risk-verdict.schema.json +0 -13
  21. package/.agents/scripts/acceptance-eval.js +62 -18
  22. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  23. package/.agents/scripts/analyze-execution.js +1 -1
  24. package/.agents/scripts/audit-to-stories.js +7 -7
  25. package/.agents/scripts/boot-sweep.js +1 -1
  26. package/.agents/scripts/check-context-budget.js +62 -5
  27. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  28. package/.agents/scripts/check-prepush-recovery.js +1 -1
  29. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  30. package/.agents/scripts/diagnose-friction.js +0 -6
  31. package/.agents/scripts/lib/Logger.js +6 -10
  32. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  33. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  34. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  35. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  36. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  37. package/.agents/scripts/lib/baselines/reader.js +1 -6
  38. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  39. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  40. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  41. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  42. package/.agents/scripts/lib/checks/index.js +2 -1
  43. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  44. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  45. package/.agents/scripts/lib/cli-args.js +16 -7
  46. package/.agents/scripts/lib/close-validation/gates.js +160 -22
  47. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  48. package/.agents/scripts/lib/config/ci.js +6 -31
  49. package/.agents/scripts/lib/config/delivery-routing.js +103 -0
  50. package/.agents/scripts/lib/config/explain.js +57 -36
  51. package/.agents/scripts/lib/config/limits.js +17 -58
  52. package/.agents/scripts/lib/config/paths.js +0 -2
  53. package/.agents/scripts/lib/config/quality.js +1 -1
  54. package/.agents/scripts/lib/config/runners.js +17 -50
  55. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  56. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  57. package/.agents/scripts/lib/config-resolver.js +3 -8
  58. package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
  59. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
  60. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  61. package/.agents/scripts/lib/dependency-parser.js +3 -2
  62. package/.agents/scripts/lib/doc-tiers.js +39 -4
  63. package/.agents/scripts/lib/duplicate-search.js +211 -41
  64. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  66. package/.agents/scripts/lib/framework-version.js +2 -3
  67. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  68. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  69. package/.agents/scripts/lib/git-utils.js +32 -6
  70. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  71. package/.agents/scripts/lib/label-constants.js +10 -23
  72. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  73. package/.agents/scripts/lib/observability/active-story-env.js +112 -3
  74. package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
  75. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  76. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  77. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  78. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  79. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  80. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  81. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
  82. package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
  83. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  84. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  85. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  86. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  87. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  88. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  89. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  90. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  91. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  92. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  93. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  94. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  95. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  96. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  97. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  98. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  99. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  100. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  102. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  103. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  104. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  105. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  106. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  107. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  108. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
  109. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  110. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  111. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  112. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  113. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  114. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  115. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  116. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  118. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  119. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  120. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  121. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  122. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  124. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  131. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  132. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  134. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  135. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  136. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  137. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  138. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  139. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  140. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  141. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  142. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  143. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  144. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  145. package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
  146. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  147. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  148. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  149. package/.agents/scripts/lib/planning-corpus.js +16 -11
  150. package/.agents/scripts/lib/preflight-runner.js +2 -2
  151. package/.agents/scripts/lib/provider-factory.js +1 -1
  152. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  153. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  154. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  155. package/.agents/scripts/lib/story-adjacency.js +11 -14
  156. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  157. package/.agents/scripts/lib/story-plan.js +2 -4
  158. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  159. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  160. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  161. package/.agents/scripts/lib/validation-evidence.js +1 -1
  162. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  163. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  164. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  165. package/.agents/scripts/lint-issue-body.js +71 -40
  166. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  167. package/.agents/scripts/notify.js +4 -3
  168. package/.agents/scripts/plan-context.js +64 -74
  169. package/.agents/scripts/plan-persist.js +121 -280
  170. package/.agents/scripts/plan-run-epilogue.js +97 -0
  171. package/.agents/scripts/post-structured-comment.js +38 -0
  172. package/.agents/scripts/providers/github/issues.js +17 -33
  173. package/.agents/scripts/providers/github/mappers.js +0 -12
  174. package/.agents/scripts/providers/github/tickets.js +2 -5
  175. package/.agents/scripts/resolve-plan-run.js +117 -0
  176. package/.agents/scripts/signals-view.js +24 -19
  177. package/.agents/scripts/single-story-close.js +11 -14
  178. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  179. package/.agents/scripts/single-story-init.js +29 -20
  180. package/.agents/scripts/stories-wave-tick.js +6 -6
  181. package/.agents/scripts/story-plan.js +26 -47
  182. package/.agents/scripts/sync-claude-agents.js +165 -0
  183. package/.agents/scripts/update-ticket-state.js +37 -15
  184. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  185. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  186. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  187. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  188. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  189. package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
  190. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  191. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  192. package/.agents/skills/skills.index.json +8 -418
  193. package/.agents/starter-agentrc.json +0 -5
  194. package/.agents/templates/agent-protocol.md +9 -10
  195. package/.agents/workflows/audit-architecture.md +3 -3
  196. package/.agents/workflows/audit-clean-code.md +3 -3
  197. package/.agents/workflows/audit-dependencies.md +3 -3
  198. package/.agents/workflows/audit-devops.md +3 -3
  199. package/.agents/workflows/audit-documentation.md +5 -5
  200. package/.agents/workflows/audit-lighthouse.md +3 -3
  201. package/.agents/workflows/audit-navigability.md +3 -2
  202. package/.agents/workflows/audit-performance.md +3 -3
  203. package/.agents/workflows/audit-privacy.md +3 -3
  204. package/.agents/workflows/audit-quality.md +3 -3
  205. package/.agents/workflows/audit-security.md +3 -3
  206. package/.agents/workflows/audit-seo.md +3 -3
  207. package/.agents/workflows/audit-sre.md +3 -3
  208. package/.agents/workflows/audit-to-stories.md +20 -20
  209. package/.agents/workflows/audit-ux-ui.md +3 -3
  210. package/.agents/workflows/deliver.md +122 -131
  211. package/.agents/workflows/git-cleanup.md +3 -4
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
  214. package/.agents/workflows/helpers/code-review.md +70 -193
  215. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  216. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  217. package/.agents/workflows/helpers/diagnose.md +10 -10
  218. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  219. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  220. package/.agents/workflows/helpers/signals.md +16 -16
  221. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  222. package/.agents/workflows/mandrel-update.md +3 -2
  223. package/.agents/workflows/plan.md +112 -145
  224. package/.agents/workflows/qa-assist.md +24 -30
  225. package/.agents/workflows/qa-explore.md +29 -38
  226. package/.agents/workflows/qa-run.md +2 -2
  227. package/README.md +9 -8
  228. package/docs/CHANGELOG.md +46 -0
  229. package/lib/cli/registry.js +95 -0
  230. package/lib/migrations/index.js +6 -5
  231. package/package.json +5 -3
  232. package/.agents/personas/architect.md +0 -113
  233. package/.agents/personas/devops-engineer.md +0 -38
  234. package/.agents/personas/engineer-mobile.md +0 -120
  235. package/.agents/personas/engineer-web.md +0 -111
  236. package/.agents/personas/engineer.md +0 -119
  237. package/.agents/personas/product.md +0 -94
  238. package/.agents/personas/project-manager.md +0 -114
  239. package/.agents/personas/qa-engineer.md +0 -95
  240. package/.agents/personas/refactorer.md +0 -113
  241. package/.agents/personas/security-engineer.md +0 -112
  242. package/.agents/personas/sre.md +0 -86
  243. package/.agents/personas/technical-writer.md +0 -101
  244. package/.agents/personas/ux-designer.md +0 -95
  245. package/.agents/schemas/dispatch-manifest.json +0 -232
  246. package/.agents/schemas/epic-spec.schema.json +0 -153
  247. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  248. package/.agents/scripts/dispatcher.js +0 -295
  249. package/.agents/scripts/epic-audit-prepare.js +0 -497
  250. package/.agents/scripts/epic-audit-recheck.js +0 -274
  251. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  252. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  253. package/.agents/scripts/epic-deliver-prepare.js +0 -590
  254. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  255. package/.agents/scripts/epic-plan-clarity.js +0 -211
  256. package/.agents/scripts/epic-plan-decompose.js +0 -54
  257. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  258. package/.agents/scripts/epic-plan-spec.js +0 -64
  259. package/.agents/scripts/epic-reconcile.js +0 -625
  260. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  261. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  262. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  263. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  264. package/.agents/scripts/lib/config/preflight.js +0 -58
  265. package/.agents/scripts/lib/config/retro.js +0 -77
  266. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  267. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  268. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  269. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
  270. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  271. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  272. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  273. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  274. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  275. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  276. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  277. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  278. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  279. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  280. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  281. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  282. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  283. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  284. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  285. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  286. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  287. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  288. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
  289. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  290. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  291. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  292. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  293. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  294. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  295. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  296. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  297. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  298. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  299. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  300. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  301. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  302. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  303. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  304. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  305. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  306. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  307. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  308. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  309. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  310. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  311. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  313. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
  314. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  315. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  316. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  317. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
  318. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  319. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  320. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  321. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  322. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  323. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  324. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  325. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  326. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  327. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  328. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  329. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  330. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  331. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  332. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  333. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  334. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  335. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  336. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  337. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  338. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  339. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  340. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  341. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  342. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  343. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  344. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  345. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  346. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  347. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  348. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  349. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  350. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  351. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  352. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  353. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  354. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  355. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  356. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  357. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  358. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  359. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  360. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  361. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
  362. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  363. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  364. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  365. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  366. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  367. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  368. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  369. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  370. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  371. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  372. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  373. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  374. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  375. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  376. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  377. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  378. package/.agents/scripts/lib/spec/index.js +0 -36
  379. package/.agents/scripts/lib/spec/loader.js +0 -425
  380. package/.agents/scripts/lib/spec/state.js +0 -208
  381. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  382. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  383. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  384. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  385. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  386. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  387. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  388. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  389. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  390. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  391. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  392. package/.agents/scripts/lifecycle-emit.js +0 -510
  393. package/.agents/scripts/plan-critics.js +0 -199
  394. package/.agents/scripts/retro-run.js +0 -218
  395. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  396. package/.agents/scripts/story-close.js +0 -294
  397. package/.agents/scripts/story-init.js +0 -599
  398. package/.agents/scripts/story-phase.js +0 -369
  399. package/.agents/scripts/wave-tick.js +0 -335
  400. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  401. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  402. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  403. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  404. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  405. package/.agents/skills/core/context-engineering/examples.md +0 -58
  406. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  407. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  408. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  409. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  410. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  411. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  412. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  413. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
  414. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  415. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  416. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  417. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  418. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  419. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  420. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  421. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  422. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  423. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  424. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  425. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  426. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  427. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  428. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  429. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  430. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  431. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  432. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  433. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  434. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  435. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  436. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  437. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  438. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  439. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  440. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  441. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  442. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  443. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  444. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  445. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  446. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  447. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  448. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  449. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  450. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  451. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  452. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
  453. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
  454. package/.agents/workflows/helpers/deliver-epic.md +0 -955
  455. package/.agents/workflows/helpers/deliver-stories.md +0 -440
  456. package/.agents/workflows/helpers/epic-audit.md +0 -189
  457. package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
  458. package/.agents/workflows/helpers/epic-testing.md +0 -125
  459. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  460. package/.agents/workflows/helpers/plan-epic.md +0 -351
  461. package/.agents/workflows/helpers/plan-story.md +0 -251
  462. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  463. /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|engineer-web|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