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
@@ -0,0 +1,361 @@
1
+ /**
2
+ * story-ops.js — flat Story creation for v2 plan-persist (Stage 3).
3
+ *
4
+ * Under the Story collapse (`docs/roadmap.md` § Stage 3), `/plan` persists
5
+ * zero-or-more Story issues directly — no Epic parent, no reconciler tree,
6
+ * no `deliveryShape` mode matrix. Default is **one Story**; N>1 is gated by
7
+ * the Stage-1 split-policy validator (`assertAcceptancePartition`).
8
+ *
9
+ * Each Story body is the single executable document: Tech Spec stays inline
10
+ * under `## Spec`. Over-budget Specs fail closed (split / tighten) — never
11
+ * spill to `docs/`. Top-level `acceptance[]` / `verify[]` are the machine
12
+ * contract and are synced into the body so the GitHub issue stays complete
13
+ * without requiring the LLM to dual-author the same lists.
14
+ *
15
+ * @module lib/orchestration/plan-persist/story-ops
16
+ */
17
+
18
+ import { randomBytes } from 'node:crypto';
19
+
20
+ import { AGENT_LABELS, TYPE_LABELS } from '../../label-constants.js';
21
+ import {
22
+ parse as parseStoryBody,
23
+ serialize as serializeStoryBody,
24
+ } from '../../story-body/story-body.js';
25
+ import { assertSpecWithinBudget } from '../spec-spill.js';
26
+ import { assertAcceptancePartition } from '../split-policy-validator.js';
27
+
28
+ /** Label prefix grouping sibling Stories from one plan run (N>1). */
29
+ export const PLAN_RUN_LABEL_PREFIX = 'plan-run::';
30
+
31
+ /**
32
+ * Normalize a caller-supplied plan-run token. Persistence and resolution
33
+ * share this helper so human-readable ids map to one canonical label.
34
+ *
35
+ * @param {string} id
36
+ * @returns {string}
37
+ */
38
+ export function normalizePlanRunId(id) {
39
+ const token = String(id ?? '')
40
+ .trim()
41
+ .toLowerCase()
42
+ .replace(/^plan-run::/, '')
43
+ .replace(/[^a-z0-9._-]+/g, '-');
44
+ if (!token) {
45
+ throw new Error('plan-run id requires a non-empty planRunId');
46
+ }
47
+ return token;
48
+ }
49
+
50
+ /**
51
+ * Build a `plan-run::<id>` label. When `id` is omitted, generates a short
52
+ * random hex token (8 chars) suitable for a rare multi-Story plan.
53
+ *
54
+ * @param {string} [id]
55
+ * @returns {string}
56
+ */
57
+ export function planRunLabel(id) {
58
+ const token =
59
+ typeof id === 'string' && id.trim() !== ''
60
+ ? normalizePlanRunId(id)
61
+ : randomBytes(4).toString('hex');
62
+ return `${PLAN_RUN_LABEL_PREFIX}${token}`;
63
+ }
64
+
65
+ function bodyObjectFromTicket(ticket) {
66
+ if (typeof ticket.body === 'string') {
67
+ return parseStoryBody(ticket.body).body;
68
+ }
69
+ if (ticket.body && typeof ticket.body === 'object') {
70
+ return parseStoryBody(ticket.body).body;
71
+ }
72
+
73
+ // Allow top-level structured fields (goal/changes/…) without a `body` key.
74
+ return parseStoryBody({
75
+ goal: ticket.goal ?? '',
76
+ slicing: ticket.slicing ?? '',
77
+ spec: ticket.spec ?? '',
78
+ changes: ticket.changes ?? [],
79
+ acceptance: ticket.acceptance ?? [],
80
+ verify: ticket.verify ?? [],
81
+ references: ticket.references ?? [],
82
+ non_goals: ticket.non_goals ?? [],
83
+ wide: ticket.wide ?? null,
84
+ reason_to_exist: ticket.reason_to_exist ?? null,
85
+ depends_on: ticket.depends_on ?? [],
86
+ estimated_test_files: ticket.estimated_test_files ?? null,
87
+ }).body;
88
+ }
89
+
90
+ function normalizeDependsOn(ticket, bodyObject) {
91
+ if (Array.isArray(ticket.depends_on)) {
92
+ return ticket.depends_on.filter((d) => typeof d === 'string');
93
+ }
94
+ return Array.isArray(bodyObject.depends_on) ? bodyObject.depends_on : [];
95
+ }
96
+
97
+ function arraysEqual(a, b) {
98
+ return a.length === b.length && a.every((value, index) => value === b[index]);
99
+ }
100
+
101
+ /**
102
+ * Top-level `acceptance[]` / `verify[]` are the machine contract (validator
103
+ * SSOT). Sync them into the body so the persisted GitHub issue is complete.
104
+ * When the body already lists the same items, keep them; when the body is
105
+ * empty, fill from top-level; when both disagree, fail closed.
106
+ *
107
+ * @param {object} ticket
108
+ * @param {object} bodyObject
109
+ * @param {'acceptance'|'verify'} field
110
+ */
111
+ function syncContractFieldFromTopLevel(ticket, bodyObject, field) {
112
+ if (!Array.isArray(ticket[field])) return;
113
+ const topLevel = ticket[field].map(String);
114
+ const bodyValue = Array.isArray(bodyObject[field])
115
+ ? bodyObject[field].map(String)
116
+ : [];
117
+ if (bodyValue.length > 0 && !arraysEqual(topLevel, bodyValue)) {
118
+ throw new Error(
119
+ `[plan-persist] Story "${ticket.slug ?? ticket.title ?? 'unknown'}" has mismatched top-level and body ${field} arrays`,
120
+ );
121
+ }
122
+ bodyObject[field] = topLevel;
123
+ }
124
+
125
+ /**
126
+ * Normalize a plan Story ticket into `{ slug, title, bodyObject }`.
127
+ * Accepts either a serialized markdown `body` string or a structured body.
128
+ *
129
+ * @param {object} ticket
130
+ * @returns {{ slug: string, title: string, bodyObject: object, depends_on: string[] }}
131
+ */
132
+ export function normalizeStoryTicket(ticket) {
133
+ if (!ticket || typeof ticket !== 'object') {
134
+ throw new Error('[plan-persist] each story ticket must be an object');
135
+ }
136
+ const slug =
137
+ typeof ticket.slug === 'string' && ticket.slug.trim() !== ''
138
+ ? ticket.slug.trim()
139
+ : null;
140
+ if (!slug) {
141
+ throw new Error(
142
+ '[plan-persist] each story ticket requires a non-empty slug',
143
+ );
144
+ }
145
+ const title =
146
+ typeof ticket.title === 'string' && ticket.title.trim() !== ''
147
+ ? ticket.title.trim()
148
+ : `Story ${slug}`;
149
+ const bodyObject = bodyObjectFromTicket(ticket);
150
+ syncContractFieldFromTopLevel(ticket, bodyObject, 'acceptance');
151
+ syncContractFieldFromTopLevel(ticket, bodyObject, 'verify');
152
+ const depends_on = normalizeDependsOn(ticket, bodyObject);
153
+
154
+ return { slug, title, bodyObject, depends_on };
155
+ }
156
+
157
+ /**
158
+ * Fold optional shared Tech Spec prose into a Story body when the Story has
159
+ * no inline Spec. Specs stay inline; over-budget Specs throw.
160
+ *
161
+ * Precedence: per-Story `body.spec` wins; otherwise `sharedSpec` is used
162
+ * (N===1 convenience only — callers must not share one Spec across N>1).
163
+ *
164
+ * @param {object} bodyObject
165
+ * @param {string} slug
166
+ * @param {object} [opts]
167
+ * @param {string|null} [opts.sharedSpec]
168
+ * @returns {{ bodyObject: object }}
169
+ */
170
+ export function foldSpecIntoStoryBody(bodyObject, slug, opts = {}) {
171
+ const { sharedSpec = null } = opts;
172
+
173
+ const next = {
174
+ ...bodyObject,
175
+ references: Array.isArray(bodyObject.references)
176
+ ? [...bodyObject.references]
177
+ : [],
178
+ };
179
+
180
+ const inline =
181
+ typeof next.spec === 'string' && next.spec.trim() !== ''
182
+ ? next.spec.trim()
183
+ : typeof sharedSpec === 'string' && sharedSpec.trim() !== ''
184
+ ? sharedSpec.trim()
185
+ : '';
186
+
187
+ if (inline === '') {
188
+ return { bodyObject: next };
189
+ }
190
+
191
+ const { content } = assertSpecWithinBudget({ storyId: slug, spec: inline });
192
+ next.spec = content;
193
+ return { bodyObject: next };
194
+ }
195
+
196
+ function assembleOnePlanStory(ticket, opts) {
197
+ const { slug, title, bodyObject, depends_on } = normalizeStoryTicket(ticket);
198
+ const { bodyObject: folded } = foldSpecIntoStoryBody(bodyObject, slug, {
199
+ sharedSpec: opts.sharedSpec ?? null,
200
+ });
201
+ const body = serializeStoryBody({ ...folded, depends_on });
202
+ return {
203
+ story: {
204
+ slug,
205
+ title,
206
+ body,
207
+ bodyObject: { ...folded, depends_on },
208
+ acceptance: Array.isArray(folded.acceptance) ? folded.acceptance : [],
209
+ depends_on,
210
+ },
211
+ };
212
+ }
213
+
214
+ /**
215
+ * Shared techspec.md is an N===1 convenience only — folding one Spec into
216
+ * every sibling duplicates approach prose and breaks Story-as-SSOT.
217
+ *
218
+ * @param {object[]} tickets
219
+ * @param {string|null|undefined} sharedSpec
220
+ */
221
+ function assertSharedSpecAllowed(tickets, sharedSpec) {
222
+ if (tickets.length <= 1) return;
223
+ if (typeof sharedSpec !== 'string' || sharedSpec.trim() === '') return;
224
+ throw new Error(
225
+ '[plan-persist] a shared techspec.md cannot be folded into N>1 Stories — ' +
226
+ "put each Story's approach in its own ## Spec so every Story stays a " +
227
+ 'complete executable document.',
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Assemble markdown bodies for every Story: normalize → fold spec →
233
+ * assertAcceptancePartition → serialize.
234
+ *
235
+ * @param {object[]} tickets
236
+ * @param {object} [opts]
237
+ * @param {string|null} [opts.sharedSpec]
238
+ * @param {string[]} [opts.planAcceptance]
239
+ * @returns {{ stories: Array<{ slug: string, title: string, body: string, acceptance: string[], depends_on: string[] }> }}
240
+ */
241
+ export function assemblePlanStories(tickets, opts = {}) {
242
+ if (!Array.isArray(tickets) || tickets.length === 0) {
243
+ throw new Error(
244
+ '[plan-persist] stories payload must be a non-empty array — author at least one Story (default-single).',
245
+ );
246
+ }
247
+
248
+ assertSharedSpecAllowed(tickets, opts.sharedSpec);
249
+
250
+ const stories = tickets.map(
251
+ (ticket) => assembleOnePlanStory(ticket, opts).story,
252
+ );
253
+
254
+ assertAcceptancePartition(stories, {
255
+ planAcceptance: opts.planAcceptance,
256
+ });
257
+
258
+ return { stories };
259
+ }
260
+
261
+ function orderStoriesByDependencies(stories) {
262
+ const list = Array.isArray(stories) ? stories : [];
263
+ const known = new Set(list.map((story) => story.slug));
264
+ for (const story of list) {
265
+ const unknown = story.depends_on.filter((slug) => !known.has(slug));
266
+ if (unknown.length > 0) {
267
+ throw new Error(
268
+ `[plan-persist] Story "${story.slug}" depends on unknown sibling(s): ${unknown.join(', ')}`,
269
+ );
270
+ }
271
+ }
272
+ const ordered = [];
273
+ const scheduled = new Set();
274
+ const pending = [...list];
275
+ while (pending.length > 0) {
276
+ const index = pending.findIndex((story) =>
277
+ story.depends_on.every((slug) => scheduled.has(slug)),
278
+ );
279
+ if (index === -1) {
280
+ throw new Error(
281
+ `[plan-persist] dependency cycle prevents Story creation: ${pending.map((story) => story.slug).join(', ')}`,
282
+ );
283
+ }
284
+ const [story] = pending.splice(index, 1);
285
+ ordered.push(story);
286
+ scheduled.add(story.slug);
287
+ }
288
+ return ordered;
289
+ }
290
+
291
+ /**
292
+ * Create Story issues via `provider.createIssue`. Applies `type::story`,
293
+ * `agent::ready`, and — when N>1 — a shared plan-run label.
294
+ *
295
+ * @param {object} args
296
+ * @param {object} args.provider
297
+ * @param {ReturnType<typeof assemblePlanStories>['stories']} args.stories
298
+ * @param {object} [args.opts]
299
+ * @param {string} [args.opts.planRunId]
300
+ * @param {boolean} [args.opts.dryRun=false]
301
+ * @returns {Promise<{ created: Array<{ slug: string, id: number, url?: string, title: string }>, planRunLabel: string|null }>}
302
+ */
303
+ export async function createStoryIssues({ provider, stories, opts = {} }) {
304
+ if (typeof provider?.createIssue !== 'function') {
305
+ throw new Error(
306
+ '[plan-persist] provider does not expose createIssue; cannot persist Stories.',
307
+ );
308
+ }
309
+
310
+ const list = Array.isArray(stories) ? stories : [];
311
+ const planLabel = list.length > 1 ? planRunLabel(opts.planRunId) : null;
312
+ const labels = [TYPE_LABELS.STORY, AGENT_LABELS.READY];
313
+ if (planLabel) labels.push(planLabel);
314
+
315
+ if (opts.dryRun) {
316
+ return {
317
+ created: list.map((s, i) => ({
318
+ slug: s.slug,
319
+ id: -(i + 1),
320
+ title: s.title,
321
+ url: undefined,
322
+ })),
323
+ planRunLabel: planLabel,
324
+ };
325
+ }
326
+
327
+ const created = [];
328
+ const createdBySlug = new Map();
329
+ for (const story of orderStoriesByDependencies(list)) {
330
+ const dependencyRefs = story.depends_on.map(
331
+ (slug) => `#${createdBySlug.get(slug)}`,
332
+ );
333
+ const body =
334
+ dependencyRefs.length === 0
335
+ ? story.body
336
+ : serializeStoryBody(
337
+ { ...story.bodyObject, depends_on: dependencyRefs },
338
+ { includeFooter: true },
339
+ );
340
+ const result = await provider.createIssue({
341
+ title: story.title,
342
+ body,
343
+ labels: [...labels],
344
+ });
345
+ const id = result?.id ?? result?.number;
346
+ if (!Number.isInteger(id)) {
347
+ throw new Error(
348
+ `[plan-persist] createIssue for slug "${story.slug}" did not return a numeric id`,
349
+ );
350
+ }
351
+ created.push({
352
+ slug: story.slug,
353
+ id,
354
+ title: story.title,
355
+ url: result.url,
356
+ });
357
+ createdBySlug.set(story.slug, id);
358
+ }
359
+
360
+ return { created, planRunLabel: planLabel };
361
+ }
@@ -1,21 +1,9 @@
1
1
  /**
2
- * summary.js — plan-persist terminal summary (Epic #4474, PR3).
2
+ * summary.js — plan-persist terminal summary (v2 Stage 3).
3
3
  *
4
- * Owns the single `plan-summary` structured comment the collapsed persist
5
- * surface upserts at terminal success, closing with the dry-run wave table.
6
- * This replaces two retired round-trips of the 12-phase pipeline:
7
- *
8
- * - the Phase 9 plan-time `dispatch-manifest` comment, whose claimed
9
- * consumer ("Wave Completeness Gate, /deliver Step 0.5") does not exist
10
- * — the live manifest is written at deliver time by `wave-record-io.js`
11
- * (#4474 design §3: DROP, keep the wave table as summary text only);
12
- * - the Phase 12 notify round-trip ("informational — no webhook for
13
- * planning").
14
- *
15
- * The wave table is computed from the validated ticket set's `depends_on`
16
- * slug edges via the same `computeStoryWaves` layering the deliver-time
17
- * dispatch pipeline uses, so the preview matches what `/deliver` will
18
- * actually fan out (barring later manual ticket edits).
4
+ * Upserts a single `plan-summary` structured comment on the primary Story
5
+ * at terminal success. Carries risk / routing receipts and the dry-run
6
+ * `depends_on` ordering table for the rare N>1 plan.
19
7
  *
20
8
  * @module lib/orchestration/plan-persist/summary
21
9
  */
@@ -23,23 +11,15 @@
23
11
  import { computeStoryWaves } from '../dependency-analyzer.js';
24
12
 
25
13
  /**
26
- * Structured-comment type for the persist summary. Registered in
27
- * `ticketing/reads.js` `STRUCTURED_COMMENT_TYPES`; upsert-idempotent so a
28
- * `--force`/`--resume` re-persist replaces the prior summary in place.
14
+ * Structured-comment type for the persist summary.
29
15
  */
30
16
  export const PLAN_SUMMARY_COMMENT_TYPE = 'plan-summary';
31
17
 
32
18
  /**
33
19
  * Compute the dry-run wave assignment for a validated ticket set.
34
20
  *
35
- * Adapts the slug-keyed ticket shape onto `computeStoryWaves`' storyGroups
36
- * contract (slug → { storyId, tasks: [] }; explicit deps from `depends_on`).
37
- * Under the 2-tier hierarchy Stories carry no tasks, so all edges are
38
- * explicit.
39
- *
40
21
  * @param {Array<{ slug: string, title?: string, depends_on?: string[] }>} tickets
41
22
  * @returns {Array<{ wave: number, stories: Array<{ slug: string, title: string }> }>}
42
- * Waves in execution order.
43
23
  */
44
24
  export function buildWaveTable(tickets) {
45
25
  const list = Array.isArray(tickets) ? tickets : [];
@@ -66,53 +46,24 @@ export function buildWaveTable(tickets) {
66
46
  }
67
47
 
68
48
  /**
69
- * Render the dry-run wave table as GitHub-flavoured markdown.
70
- *
71
49
  * @param {ReturnType<typeof buildWaveTable>} waveTable
72
- * @returns {string[]} markdown lines
50
+ * @returns {string[]}
73
51
  */
74
52
  function renderWaveTableLines(waveTable) {
75
53
  if (!Array.isArray(waveTable) || waveTable.length === 0) {
76
- return ['_No stories to wave (empty plan)._'];
54
+ return ['_No stories to sequence (empty plan)._'];
77
55
  }
78
56
  const rows = waveTable.map(
79
57
  ({ wave, stories }) =>
80
58
  `| ${wave + 1} | ${stories.map((s) => `\`${s.slug}\``).join(', ')} |`,
81
59
  );
82
- return ['| Wave | Stories |', '| --- | --- |', ...rows];
60
+ return ['| Order | Stories |', '| --- | --- |', ...rows];
83
61
  }
84
62
 
85
63
  /**
86
- * Build the `plan-summary` structured-comment body: risk + routing +
87
- * freshness + healthcheck receipts, closing with the mode-specific tail —
88
- * the dry-run wave table for fan-out/amend, or the single-delivery routing
89
- * record `{ deliveryShape, sliceCount, routingReasons }` (Epic #4474 PR4)
90
- * for the spec-only mode.
91
- *
92
- * Every auto-waiver the persist derived is printed WITH its reason
93
- * (#4496 fix 2) — e.g. the no-BDD-runner acceptance-disposition waiver
94
- * (`planningRisk.acceptanceWaivedReason`) — so the summary is
95
- * self-explanatory and a headless reader never has to re-derive a persist
96
- * outcome from framework source.
64
+ * Build the `plan-summary` structured-comment body.
97
65
  *
98
- * @param {{
99
- * epicId: number,
100
- * ticketCount: number,
101
- * planningRisk: { overallLevel?: string, gateDecision?: string, acceptanceDisposition?: string, acceptanceWaivedReason?: string },
102
- * reviewRouting: { decision?: string },
103
- * freshness?: { stale?: number, ambiguous?: number },
104
- * healthcheck?: { ok?: boolean, waived?: boolean, skipped?: boolean },
105
- * waveTable: ReturnType<typeof buildWaveTable>,
106
- * mode?: 'fan-out'|'single'|'amend',
107
- * planMetricsLine?: string|null,
108
- * single?: { deliveryShape: 'single', sliceCount: number|null, routingReasons: string[] }|null,
109
- * amend?: {
110
- * closed: Array<{ slug: string, issueNumber: number }>,
111
- * recreated: Array<{ slug: string, oldIssueNumber: number, issueNumber: number }>,
112
- * created: Array<{ slug: string, issueNumber: number }>,
113
- * keptCount: number,
114
- * }|null,
115
- * }} input
66
+ * @param {object} input
116
67
  * @returns {string}
117
68
  */
118
69
  export function buildPlanSummaryCommentBody({
@@ -123,84 +74,60 @@ export function buildPlanSummaryCommentBody({
123
74
  freshness,
124
75
  healthcheck,
125
76
  waveTable,
126
- mode = 'fan-out',
77
+ mode = 'stories',
127
78
  planMetricsLine = null,
79
+ stories = null,
80
+ planRunLabel = null,
81
+ // legacy unused knobs kept so older test call sites don't crash mid-migration
128
82
  single = null,
129
83
  amend = null,
130
84
  }) {
85
+ void mode;
86
+ void single;
87
+ void amend;
88
+
131
89
  const freshnessLine =
132
90
  (freshness?.stale ?? 0) > 0 || (freshness?.ambiguous ?? 0) > 0
133
- ? `- ⚠️ Spec freshness: ${freshness.stale} stale / ${freshness.ambiguous} ambiguous reference(s) — see the spec-freshness comment.`
91
+ ? `- ⚠️ Spec freshness: ${freshness.stale} stale / ${freshness.ambiguous} ambiguous reference(s).`
134
92
  : '- Spec freshness: clean.';
135
93
  const healthcheckLine = healthcheck?.skipped
136
- ? '- Healthcheck: skipped (test seam).'
94
+ ? '- Healthcheck: skipped (v2 flat Story persist — ticket validators are the gate).'
137
95
  : healthcheck?.ok
138
96
  ? '- Healthcheck: passed.'
139
97
  : `- Healthcheck: failed, waived by operator label.`;
140
98
 
141
- const headLine =
142
- mode === 'single'
143
- ? `- Single-delivery plan (\`delivery::single\`): no Story tree — the Delivery Slicing table is the audit trail.`
144
- : `- ${ticketCount} Story ticket(s) persisted across ${waveTable.length} wave(s).`;
99
+ const storyList =
100
+ Array.isArray(stories) && stories.length > 0
101
+ ? stories.map((s) => `#${s.id} (\`${s.slug}\`)`).join(', ')
102
+ : `${ticketCount} Story(ies)`;
145
103
 
146
- // Auto-waivers always ship with their reason (#4496 fix 2): the summary
147
- // is authoritative, so the line must be self-explanatory on its own.
148
104
  const waiverLines = planningRisk?.acceptanceWaivedReason
149
105
  ? [
150
106
  `- ⚠️ Acceptance disposition auto-waived to \`not-applicable\` — ${planningRisk.acceptanceWaivedReason}`,
151
107
  ]
152
108
  : [];
153
109
 
154
- const amendLines = amend
155
- ? [
156
- `- Amend delta: ${amend.created.length} added, ${amend.recreated.length} modified (closed + recreated), ${amend.closed.length} closed, ${amend.keptCount} kept untouched.`,
157
- ]
158
- : [];
159
-
160
- const tail =
161
- mode === 'single'
162
- ? [
163
- '#### Delivery routing record',
164
- '',
165
- '```json',
166
- JSON.stringify(
167
- {
168
- deliveryShape: 'single',
169
- sliceCount: single?.sliceCount ?? null,
170
- routingReasons: single?.routingReasons ?? [],
171
- },
172
- null,
173
- 2,
174
- ),
175
- '```',
176
- '',
177
- '_Marker is inert until #4475 lands the deliver-side reader — `/deliver` still treats this Epic as fan-out until then._',
178
- ]
179
- : [
180
- '#### Dry-run wave table',
181
- '',
182
- ...renderWaveTableLines(waveTable),
183
- '',
184
- '_Preview only — the authoritative dispatch manifest is written at deliver time (`wave-record-io.js`)._',
185
- ];
110
+ const runLine = planRunLabel
111
+ ? `- Plan-run label: \`${planRunLabel}\` (N>1 — deliver with \`/deliver --run <planRunId>\`).`
112
+ : '- Plan-run: single Story (default).';
186
113
 
187
114
  return [
188
- `### 📋 Plan Summary — Epic #${epicId} is \`agent::ready\``,
115
+ `### 📋 Plan Summary — Story #${epicId} is \`agent::ready\``,
189
116
  '',
190
- headLine,
191
- ...amendLines,
117
+ `- ${ticketCount} Story ticket(s) persisted: ${storyList}.`,
118
+ runLine,
192
119
  `- Risk: ${planningRisk?.overallLevel ?? 'unknown'} · ${planningRisk?.gateDecision ?? 'unknown'} (review routing: ${reviewRouting?.decision ?? 'unknown'}).`,
193
120
  ...waiverLines,
194
121
  freshnessLine,
195
122
  healthcheckLine,
196
- // G2 measurement receipt (Epic #4474 PR1/PR7): the plan-CLI invocation
197
- // ledger roll-up (turns-per-plan proxy, per-mode counts, critic skips)
198
- // rides the summary comment so the cohort reader never has to pull the
199
- // temp ledger off the runner's disk. Omitted when the ledger is empty.
200
123
  ...(typeof planMetricsLine === 'string' && planMetricsLine.length > 0
201
124
  ? [`- ${planMetricsLine}`]
202
125
  : []),
203
126
  '',
204
- ...tail,
127
+ '#### Delivery order (`depends_on`)',
128
+ '',
129
+ ...renderWaveTableLines(waveTable),
130
+ '',
131
+ '_Deliver with `/deliver <storyId>` (N=1) or `/deliver --run <planRunId>` (N>1)._',
205
132
  ].join('\n');
206
133
  }
@@ -3,13 +3,11 @@
3
3
  * the persist surface (Epic #4474 PR6, design §4: the 8.4 reachability
4
4
  * critic demoted from a fresh-context sub-agent to a persist-side scan).
5
5
  *
6
- * Mirrors the mechanics of the existing `--paranoid` F7 healthcheck
7
- * (`epic-plan-healthcheck.js#checkReachability`) route-glob scan of the
8
- * paths a Story declares vs the `planning.navigation.navRegistry` token
9
- * list but runs it over the **draft** ticket set inside `plan-persist.js`
10
- * step 4.5, before any provider call, so an orphaned surface is caught
11
- * while a one-line targeted amend is still free (nothing has been written
12
- * to GitHub yet).
6
+ * Route-glob scan of the paths a Story declares vs the
7
+ * `planning.navigation.navRegistry` token list, run over the **draft**
8
+ * ticket set inside `plan-persist.js` step 4.5, before any provider call,
9
+ * so an orphaned surface is caught while a one-line targeted amend is
10
+ * still free (nothing has been written to GitHub yet).
13
11
  *
14
12
  * Plan-level coverage semantics (the convergence contract): a route-adding
15
13
  * story that never references the nav registry produces orphan surfaces —
@@ -20,9 +18,8 @@
20
18
  * registry) in one targeted amend, and the re-run persist passes.
21
19
  *
22
20
  * Silent no-op when `planning.navigation` is unconfigured (`routeGlobs`
23
- * empty) — same opt-in contract as F7 / AC-13 reported as
24
- * `status: 'skipped'` so the caller can append the audit record to the
25
- * plan-metrics ledger.
21
+ * empty) — reported as `status: 'skipped'` so the caller can append the
22
+ * audit record to the plan-metrics ledger.
26
23
  *
27
24
  * Pure over its inputs (tickets + resolved config), no I/O.
28
25
  */
@@ -31,12 +28,10 @@ import {
31
28
  extractStoryPaths,
32
29
  globToRegExp,
33
30
  resolveNavConfig,
34
- } from '../../epic-plan-healthcheck.js';
31
+ } from './plan-navigation.js';
35
32
 
36
33
  /**
37
- * Fallback tokens when `navRegistry` is unconfigured but `routeGlobs` is
38
- * identical to the F7 healthcheck's fallback, so the two checks agree on
39
- * what counts as a registry reference.
34
+ * Fallback tokens when `navRegistry` is unconfigured but `routeGlobs` is.
40
35
  */
41
36
  const FALLBACK_REGISTRY_TOKENS = ['nav registry', 'navigation'];
42
37
 
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * The `--force` flag is intentional. By the time a Story is `agent::done`
11
11
  * its branch has already been merged into the Epic branch (via
12
- * `story-close.js`), so any residue left in the worktree — dirty
12
+ * `single-story-close.js`), so any residue left in the worktree — dirty
13
13
  * build artifacts, an interrupted rebase, a stray Windows lock — is noise.
14
14
  * The safety rails in `WorktreeManager.reap` exist for the _active_ close
15
15
  * path; at plan time we already know the Story is done and want the
@@ -12,17 +12,17 @@ import path from 'node:path';
12
12
  import {
13
13
  resolveFeatureRoots,
14
14
  verifyBddRunnerPendingTag,
15
- } from '../../../bdd-runner-detect.js';
16
- import { scanBddScenarios } from '../../../bdd-scenario-scanner.js';
17
- import { buildCodebaseSnapshot } from '../../../codebase-snapshot.js';
18
- import { getLimits, getPaths, PROJECT_ROOT } from '../../../config-resolver.js';
19
- import { hasEpicSection } from '../../../epic-body-sections.js';
20
- import { scanMemoryFreshness } from '../../../feedback-loop/memory-freshness.js';
21
- import { fetchPriorFeedback } from '../../../feedback-loop/prior-feedback-fetcher.js';
22
- import { Logger } from '../../../Logger.js';
23
- import { ensureDocsDigest } from '../../docs-digest.js';
24
- import { applyBudget } from '../../planning-context-budget.js';
25
- import { collectReferences, hasNewFileCue } from '../../spec-freshness.js';
15
+ } from '../../bdd-runner-detect.js';
16
+ import { scanBddScenarios } from '../../bdd-scenario-scanner.js';
17
+ import { buildCodebaseSnapshot } from '../../codebase-snapshot.js';
18
+ import { getLimits, getPaths, PROJECT_ROOT } from '../../config-resolver.js';
19
+ import { scanMemoryFreshness } from '../../feedback-loop/memory-freshness.js';
20
+ import { fetchPriorFeedback } from '../../feedback-loop/prior-feedback-fetcher.js';
21
+ import { Logger } from '../../Logger.js';
22
+ import { hasTicketSection } from '../../ticket-body-sections.js';
23
+ import { ensureDocsDigest } from '../docs-digest.js';
24
+ import { applyBudget } from '../planning-context-budget.js';
25
+ import { collectReferences, hasNewFileCue } from '../spec-freshness.js';
26
26
  import { buildAuthoringGrounding } from './spec-authoring-grounding.js';
27
27
 
28
28
  /**
@@ -256,8 +256,8 @@ export async function buildAuthoringContext(
256
256
  // inside `body` (managed sections), which is how the author keeps
257
257
  // AC IDs stable across re-plans.
258
258
  planningSections: {
259
- techSpec: hasEpicSection(epic.body ?? '', 'techSpec'),
260
- acceptanceTable: hasEpicSection(epic.body ?? '', 'acceptanceTable'),
259
+ techSpec: hasTicketSection(epic.body ?? '', 'techSpec'),
260
+ acceptanceTable: hasTicketSection(epic.body ?? '', 'acceptanceTable'),
261
261
  },
262
262
  },
263
263
  docsContext,