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,426 @@
1
+ /**
2
+ * run-epilogue.js — real per-run closeout for `/deliver --run`.
3
+ *
4
+ * After the last Story in a multi-Story plan-run lands, this module:
5
+ * 1. Selects the cross-Story audit lens roster over the combined landed
6
+ * tip vs base (deterministic `selectAudits` — host walks lenses).
7
+ * 2. Rolls up friction follow-ups across every Story in the run and
8
+ * files/posts them on the primary Story.
9
+ * 3. Checks sibling Spec/acceptance coherence across Story bodies.
10
+ *
11
+ * There is no inert planner-only path: `planRunEpilogue` enumerates steps
12
+ * and `runPlanRunEpilogue` executes them. Single-Story runs skip the
13
+ * epilogue (`applicable: false`).
14
+ *
15
+ * @module lib/orchestration/run-epilogue
16
+ */
17
+
18
+ import { selectAudits } from '../audit-suite/index.js';
19
+ import { graduateRetroProposals } from '../feedback-loop/retro-proposals-graduator.js';
20
+ import { gitSpawn } from '../git-utils.js';
21
+ import { Logger } from '../Logger.js';
22
+ import { forEachLine } from '../observability/signals-writer.js';
23
+ import { composeRoutedProposals } from './retro-proposals.js';
24
+ import {
25
+ buildFollowUpsCommentBody,
26
+ resolveFollowUpRepos,
27
+ } from './story-follow-ups.js';
28
+ import { upsertStructuredComment } from './ticketing.js';
29
+
30
+ /**
31
+ * Canonical epilogue step kinds, in execution order.
32
+ * @type {readonly ['audit-roster', 'follow-up-rollup', 'sibling-coherence']}
33
+ */
34
+ export const RUN_EPILOGUE_STEP_KINDS = Object.freeze([
35
+ 'audit-roster',
36
+ 'follow-up-rollup',
37
+ 'sibling-coherence',
38
+ ]);
39
+
40
+ /**
41
+ * @param {string|number|{ id?: string|number, slug?: string }} entry
42
+ * @returns {string|null}
43
+ */
44
+ function normalizeStoryId(entry) {
45
+ if (typeof entry === 'string') return entry.trim() || null;
46
+ if (typeof entry === 'number' && Number.isInteger(entry)) {
47
+ return String(entry);
48
+ }
49
+ if (!entry || typeof entry !== 'object') return null;
50
+ if (typeof entry.id === 'string' || Number.isInteger(entry.id)) {
51
+ return String(entry.id).trim() || null;
52
+ }
53
+ return typeof entry.slug === 'string' ? entry.slug.trim() || null : null;
54
+ }
55
+
56
+ /**
57
+ * @param {Array<string|number|{ id?: string|number, slug?: string }>} stories
58
+ * @returns {string[]}
59
+ */
60
+ function normalizeStoryIds(stories) {
61
+ const list = Array.isArray(stories) ? stories : [];
62
+ const seen = new Set();
63
+ const ids = [];
64
+ for (const entry of list) {
65
+ const id = normalizeStoryId(entry);
66
+ if (!id || seen.has(id)) continue;
67
+ seen.add(id);
68
+ ids.push(id);
69
+ }
70
+ return ids;
71
+ }
72
+
73
+ /**
74
+ * Enumerate the ordered epilogue steps for a completed run.
75
+ *
76
+ * @param {object} args
77
+ * @param {string} args.planRunId
78
+ * @param {Array<string|number|{ id?: string|number, slug?: string }>} args.stories
79
+ * @returns {object}
80
+ */
81
+ export function planRunEpilogue({ planRunId, stories } = {}) {
82
+ const ids = normalizeStoryIds(stories);
83
+ const runId =
84
+ typeof planRunId === 'string' && planRunId.trim() !== ''
85
+ ? planRunId.trim()
86
+ : null;
87
+
88
+ if (ids.length <= 1) {
89
+ return {
90
+ applicable: false,
91
+ planRunId: runId,
92
+ stories: ids,
93
+ steps: [],
94
+ reason:
95
+ ids.length === 0
96
+ ? 'no Stories in run'
97
+ : 'single-Story run — per-Story close is the end; no run-scoped epilogue',
98
+ };
99
+ }
100
+
101
+ // Positional `/deliver 101 102` has no plan-run label. Synthesize a
102
+ // stable adhoc id from the sorted Story set so the epilogue still
103
+ // anchors comments / audit roster without requiring `--run`.
104
+ const effectiveRunId =
105
+ runId ??
106
+ `adhoc-${[...ids].sort((a, b) => Number(a) - Number(b)).join('-')}`;
107
+
108
+ const steps = [
109
+ {
110
+ kind: 'audit-roster',
111
+ description: `Select cross-Story audit lenses for run ${effectiveRunId}`,
112
+ stories: ids,
113
+ },
114
+ {
115
+ kind: 'follow-up-rollup',
116
+ description: `Friction follow-up roll-up for run ${effectiveRunId}`,
117
+ stories: ids,
118
+ },
119
+ {
120
+ kind: 'sibling-coherence',
121
+ description: `Sibling-coherence check across the ${ids.length} Story specs of run ${effectiveRunId}`,
122
+ stories: ids,
123
+ },
124
+ ];
125
+
126
+ return {
127
+ applicable: true,
128
+ planRunId: effectiveRunId,
129
+ stories: ids,
130
+ steps,
131
+ };
132
+ }
133
+
134
+ async function listChangedFiles(cwd, baseRef = 'origin/main') {
135
+ try {
136
+ const result = gitSpawn(cwd, 'diff', '--name-only', `${baseRef}...HEAD`);
137
+ if (result.status !== 0) return [];
138
+ return String(result.stdout ?? '')
139
+ .split('\n')
140
+ .map((line) => line.trim())
141
+ .filter(Boolean);
142
+ } catch {
143
+ return [];
144
+ }
145
+ }
146
+
147
+ async function executeAuditRoster({ planRunId, stories, cwd, provider }) {
148
+ const primaryId = Number(stories[0]);
149
+ const changedFiles = await listChangedFiles(cwd);
150
+ let selectedAudits = [];
151
+ if (Number.isInteger(primaryId) && primaryId > 0) {
152
+ const selected = await selectAudits({
153
+ ticketId: primaryId,
154
+ gate: 'gate3',
155
+ provider,
156
+ baseBranch: 'main',
157
+ headRef: 'HEAD',
158
+ });
159
+ selectedAudits = Array.isArray(selected?.selectedAudits)
160
+ ? selected.selectedAudits
161
+ : Array.isArray(selected)
162
+ ? selected
163
+ : [];
164
+ }
165
+ const body = [
166
+ '### plan-run-audit-roster',
167
+ '',
168
+ `Cross-Story audit roster for plan-run \`${planRunId}\`.`,
169
+ '',
170
+ `Changed files considered: ${changedFiles.length}.`,
171
+ '',
172
+ '**Selected lenses** (host MUST walk each against the combined landed diff):',
173
+ ...(selectedAudits.length > 0
174
+ ? selectedAudits.map((lens) => `- \`${lens}\``)
175
+ : ['- _(none — docs-only or no matching change-set lenses)_']),
176
+ '',
177
+ '```json',
178
+ JSON.stringify(
179
+ {
180
+ planRunId,
181
+ stories: stories.map(Number),
182
+ changedFiles,
183
+ selectedAudits,
184
+ },
185
+ null,
186
+ 2,
187
+ ),
188
+ '```',
189
+ ].join('\n');
190
+ if (Number.isInteger(primaryId) && primaryId > 0) {
191
+ await upsertStructuredComment(
192
+ provider,
193
+ primaryId,
194
+ 'plan-run-audit-roster',
195
+ body,
196
+ );
197
+ }
198
+ return {
199
+ kind: 'audit-roster',
200
+ selectedAudits,
201
+ changedFileCount: changedFiles.length,
202
+ };
203
+ }
204
+
205
+ async function executeFollowUpRollup({
206
+ planRunId,
207
+ stories,
208
+ provider,
209
+ config,
210
+ cwd,
211
+ }) {
212
+ const signals = [];
213
+ for (const raw of stories) {
214
+ const sid = Number(raw);
215
+ if (!Number.isInteger(sid) || sid <= 0) continue;
216
+ await forEachLine(
217
+ null,
218
+ sid,
219
+ (parsed) => {
220
+ if (!parsed || typeof parsed !== 'object') return;
221
+ const category =
222
+ typeof parsed.category === 'string' ? parsed.category.trim() : '';
223
+ if (!category) return;
224
+ const source = parsed.source === 'framework' ? 'framework' : 'consumer';
225
+ signals.push({ category, source });
226
+ },
227
+ config,
228
+ );
229
+ }
230
+ const repos = resolveFollowUpRepos(config);
231
+ const primaryId = Number(stories[0]);
232
+ const proposals = composeRoutedProposals({
233
+ anchorId: Number.isInteger(primaryId) ? primaryId : 1,
234
+ anchorKind: 'run',
235
+ frameworkRepo: repos.frameworkRepo,
236
+ consumerRepo: repos.consumerRepo,
237
+ signals,
238
+ unresolvedBlockedEvents: [],
239
+ });
240
+ // Patch titles to mention the plan-run token (anchorKind run uses numeric id).
241
+ for (const item of [...proposals.framework, ...proposals.consumer]) {
242
+ item.title = item.title.replace(/plan-run \d+/, `plan-run ${planRunId}`);
243
+ item.body = item.body.replace(/plan-run \d+/g, `plan-run ${planRunId}`);
244
+ }
245
+ const graduated = await graduateRetroProposals({
246
+ epicId: primaryId,
247
+ provider,
248
+ config,
249
+ currentRepo: repos.currentRepo,
250
+ frameworkRepo: (() => {
251
+ const [owner, repo] = repos.frameworkRepo.split('/');
252
+ return { owner, repo };
253
+ })(),
254
+ routedProposals: proposals,
255
+ cwd,
256
+ });
257
+ if (Number.isInteger(primaryId) && primaryId > 0) {
258
+ const body = buildFollowUpsCommentBody({
259
+ storyId: primaryId,
260
+ proposals,
261
+ graduated,
262
+ }).replace(
263
+ `from Story #${primaryId}`,
264
+ `from plan-run \`${planRunId}\` (primary Story #${primaryId})`,
265
+ );
266
+ await upsertStructuredComment(provider, primaryId, 'follow-ups', body);
267
+ }
268
+ return {
269
+ kind: 'follow-up-rollup',
270
+ signalCount: signals.length,
271
+ filed: graduated.filed?.length ?? 0,
272
+ };
273
+ }
274
+
275
+ function extractSection(body, heading) {
276
+ if (typeof body !== 'string') return '';
277
+ const re = new RegExp(
278
+ `(?:^|\\n)## ${heading}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`,
279
+ 'i',
280
+ );
281
+ const match = body.match(re);
282
+ return match ? match[1].trim() : '';
283
+ }
284
+
285
+ async function executeSiblingCoherence({ planRunId, stories, provider }) {
286
+ const findings = [];
287
+ const bodies = [];
288
+ for (const raw of stories) {
289
+ const sid = Number(raw);
290
+ if (!Number.isInteger(sid) || sid <= 0) continue;
291
+ const ticket = await provider.getTicket(sid);
292
+ bodies.push({
293
+ id: sid,
294
+ title: ticket?.title ?? '',
295
+ acceptance: extractSection(ticket?.body ?? '', 'Acceptance'),
296
+ spec: extractSection(ticket?.body ?? '', 'Spec'),
297
+ });
298
+ }
299
+ const withAcceptance = bodies.filter((b) => b.acceptance.length > 0);
300
+ if (withAcceptance.length > 0 && withAcceptance.length < bodies.length) {
301
+ const missing = bodies
302
+ .filter((b) => b.acceptance.length === 0)
303
+ .map((b) => `#${b.id}`);
304
+ findings.push(
305
+ `Stories missing ## Acceptance while siblings declare ACs: ${missing.join(', ')}`,
306
+ );
307
+ }
308
+ // Detect identical non-empty Spec blobs (likely copy-paste drift).
309
+ const specMap = new Map();
310
+ for (const b of bodies) {
311
+ if (!b.spec) continue;
312
+ const key = b.spec.replace(/\s+/g, ' ').slice(0, 400);
313
+ if (!specMap.has(key)) specMap.set(key, []);
314
+ specMap.get(key).push(b.id);
315
+ }
316
+ for (const ids of specMap.values()) {
317
+ if (ids.length > 1) {
318
+ findings.push(
319
+ `Duplicate ## Spec prose across Stories ${ids.map((id) => `#${id}`).join(', ')} — split or dedupe.`,
320
+ );
321
+ }
322
+ }
323
+ const primaryId = Number(stories[0]);
324
+ const body = [
325
+ '### plan-run-sibling-coherence',
326
+ '',
327
+ `Sibling-coherence check for plan-run \`${planRunId}\`.`,
328
+ '',
329
+ findings.length === 0
330
+ ? '_No coherence findings._'
331
+ : findings.map((f) => `- ${f}`).join('\n'),
332
+ '',
333
+ '```json',
334
+ JSON.stringify(
335
+ { planRunId, stories: stories.map(Number), findings },
336
+ null,
337
+ 2,
338
+ ),
339
+ '```',
340
+ ].join('\n');
341
+ if (Number.isInteger(primaryId) && primaryId > 0) {
342
+ await upsertStructuredComment(
343
+ provider,
344
+ primaryId,
345
+ 'plan-run-sibling-coherence',
346
+ body,
347
+ );
348
+ }
349
+ return { kind: 'sibling-coherence', findings };
350
+ }
351
+
352
+ /**
353
+ * Execute the per-run epilogue. Throws only on programmer misuse; step
354
+ * failures are collected into `errors[]`.
355
+ *
356
+ * @param {object} args
357
+ * @param {string} args.planRunId
358
+ * @param {Array<string|number>} args.stories
359
+ * @param {object} args.provider
360
+ * @param {object} [args.config]
361
+ * @param {string} [args.cwd]
362
+ * @returns {Promise<object>}
363
+ */
364
+ export async function runPlanRunEpilogue({
365
+ planRunId,
366
+ stories,
367
+ provider,
368
+ config,
369
+ cwd = process.cwd(),
370
+ } = {}) {
371
+ const plan = planRunEpilogue({ planRunId, stories });
372
+ if (!plan.applicable) {
373
+ return { ...plan, results: [], errors: [] };
374
+ }
375
+ if (!provider || typeof provider.getTicket !== 'function') {
376
+ throw new TypeError('runPlanRunEpilogue requires a ticketing provider');
377
+ }
378
+
379
+ const results = [];
380
+ const errors = [];
381
+ for (const step of plan.steps) {
382
+ try {
383
+ if (step.kind === 'audit-roster') {
384
+ results.push(
385
+ await executeAuditRoster({
386
+ planRunId: plan.planRunId,
387
+ stories: plan.stories,
388
+ cwd,
389
+ provider,
390
+ }),
391
+ );
392
+ } else if (step.kind === 'follow-up-rollup') {
393
+ results.push(
394
+ await executeFollowUpRollup({
395
+ planRunId: plan.planRunId,
396
+ stories: plan.stories,
397
+ provider,
398
+ config,
399
+ cwd,
400
+ }),
401
+ );
402
+ } else if (step.kind === 'sibling-coherence') {
403
+ results.push(
404
+ await executeSiblingCoherence({
405
+ planRunId: plan.planRunId,
406
+ stories: plan.stories,
407
+ provider,
408
+ }),
409
+ );
410
+ }
411
+ } catch (err) {
412
+ const message = err?.message ?? String(err);
413
+ Logger.warn(`[run-epilogue] step ${step.kind} failed: ${message}`);
414
+ errors.push({ kind: step.kind, message });
415
+ }
416
+ }
417
+
418
+ return {
419
+ applicable: true,
420
+ planRunId: plan.planRunId,
421
+ stories: plan.stories,
422
+ steps: plan.steps,
423
+ results,
424
+ errors,
425
+ };
426
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * phases/auto-merge.js — enable GitHub native auto-merge on the PR.
3
3
  *
4
- * Mirrors the epic-deliver finalize call shape: squash strategy, delete
4
+ * Mirrors the v2 `single-story-close.js` finalize call shape: squash strategy, delete
5
5
  * the branch on merge. Non-fatal — returns `{ enabled: false, reason }`
6
6
  * on any failure so the caller can fall back to the operator-merges-button
7
7
  * path.
@@ -21,13 +21,14 @@
21
21
  * the caller raises that to a thrown error so auto-merge is not enabled.
22
22
  *
23
23
  * Delegates the `runCodeReview` invocation to `runStoryReviewCore`
24
- * (exported from `story-close/phases/code-review.js`) so both the
25
- * Epic-attached and standalone close paths share a single invocation
26
- * pattern (Story #3653).
24
+ * (exported from `story-close/phases/code-review.js`) so the close path
25
+ * shares a single invocation pattern (Story #3653). When `planningRisk`
26
+ * is omitted, loads it from the Story's `story-plan-state` checkpoint.
27
27
  */
28
28
 
29
29
  import { parsePrNumberFromUrl } from '../../../github-url.js';
30
30
  import { runStoryReviewCore } from '../../story-close/phases/code-review.js';
31
+ import { resolveStoryPlanningRisk } from '../../story-plan-state.js';
31
32
  import { postStructuredComment } from '../../ticketing/state.js';
32
33
 
33
34
  /**
@@ -71,6 +72,79 @@ export function buildStoryReviewCrossRefBody({
71
72
  );
72
73
  }
73
74
 
75
+ async function invokeStoryReviewCore({
76
+ storyId,
77
+ storyBranch,
78
+ baseBranch,
79
+ prNumber,
80
+ provider,
81
+ planningRisk,
82
+ runCodeReviewFn,
83
+ runLocalLensReviewFn,
84
+ progress,
85
+ }) {
86
+ return runStoryReviewCore({
87
+ storyId,
88
+ baseRef: baseBranch,
89
+ headRef: storyBranch,
90
+ commentTargetId: prNumber,
91
+ provider,
92
+ planningRisk: await resolveStoryPlanningRisk({
93
+ provider,
94
+ storyId,
95
+ planningRisk,
96
+ }),
97
+ progress,
98
+ progressTag: 'REVIEW',
99
+ runCodeReviewFn,
100
+ // Forward the seam only when the caller injects it; otherwise
101
+ // `runStoryReviewCore` uses its default local-lens pass. `undefined`
102
+ // deep-merges to the default via the destructuring default there.
103
+ ...(runLocalLensReviewFn ? { runLocalLensReviewFn } : {}),
104
+ });
105
+ }
106
+
107
+ async function postStoryReviewCrossRef({
108
+ provider,
109
+ storyId,
110
+ prUrl,
111
+ prNumber,
112
+ result,
113
+ severity,
114
+ progress,
115
+ }) {
116
+ if (result.posted && Number.isInteger(result.postedCommentId)) {
117
+ const commentUrl = `${prUrl}#issuecomment-${result.postedCommentId}`;
118
+ const body = buildStoryReviewCrossRefBody({
119
+ prUrl,
120
+ prNumber,
121
+ commentUrl,
122
+ severity,
123
+ });
124
+ try {
125
+ await postStructuredComment(provider, storyId, 'notification', body);
126
+ progress(
127
+ 'REVIEW',
128
+ `📝 Cross-reference comment posted on Story #${storyId} → ${commentUrl}`,
129
+ );
130
+ return true;
131
+ } catch (err) {
132
+ progress(
133
+ 'REVIEW',
134
+ `⚠️ Failed to post Story cross-reference comment: ${err?.message ?? err}`,
135
+ );
136
+ return false;
137
+ }
138
+ }
139
+ if (!result.posted) {
140
+ progress(
141
+ 'REVIEW',
142
+ '⚠️ Skipping Story cross-reference comment: PR-side review comment did not post.',
143
+ );
144
+ }
145
+ return false;
146
+ }
147
+
74
148
  /**
75
149
  * Run the Story-scope code review against `main`, post the structured
76
150
  * findings comment to the PR, and add a one-line cross-reference comment
@@ -93,6 +167,7 @@ export function buildStoryReviewCrossRefBody({
93
167
  * prUrl: string,
94
168
  * prNumber: number|null,
95
169
  * provider: object,
170
+ * planningRisk?: object|null, // omit to load from story-plan-state
96
171
  * runCodeReviewFn: Function,
97
172
  * runLocalLensReviewFn?: Function,
98
173
  * progress: (tag: string, msg: string) => void,
@@ -115,6 +190,7 @@ export async function runStoryScopeReview({
115
190
  prUrl,
116
191
  prNumber,
117
192
  provider,
193
+ planningRisk,
118
194
  runCodeReviewFn,
119
195
  runLocalLensReviewFn,
120
196
  progress,
@@ -132,19 +208,16 @@ export async function runStoryScopeReview({
132
208
  `Running Story-scope code review for Story #${storyId} (${baseBranch}...${storyBranch}) → PR #${prNumber}...`,
133
209
  );
134
210
 
135
- const result = await runStoryReviewCore({
211
+ const result = await invokeStoryReviewCore({
136
212
  storyId,
137
- baseRef: baseBranch,
138
- headRef: storyBranch,
139
- commentTargetId: prNumber,
213
+ storyBranch,
214
+ baseBranch,
215
+ prNumber,
140
216
  provider,
141
- progress,
142
- progressTag: 'REVIEW',
217
+ planningRisk,
143
218
  runCodeReviewFn,
144
- // Forward the seam only when the caller injects it; otherwise
145
- // `runStoryReviewCore` uses its default local-lens pass. `undefined`
146
- // deep-merges to the default via the destructuring default there.
147
- ...(runLocalLensReviewFn ? { runLocalLensReviewFn } : {}),
219
+ runLocalLensReviewFn,
220
+ progress,
148
221
  });
149
222
 
150
223
  const sev = result.severity ?? {
@@ -158,34 +231,15 @@ export async function runStoryScopeReview({
158
231
  `Findings — critical:${sev.critical} high:${sev.high} medium:${sev.medium} suggestion:${sev.suggestion}. Posted to PR #${prNumber}: ${result.posted}.`,
159
232
  );
160
233
 
161
- let crossRefPosted = false;
162
- if (result.posted && Number.isInteger(result.postedCommentId)) {
163
- const commentUrl = `${prUrl}#issuecomment-${result.postedCommentId}`;
164
- const body = buildStoryReviewCrossRefBody({
165
- prUrl,
166
- prNumber,
167
- commentUrl,
168
- severity: sev,
169
- });
170
- try {
171
- await postStructuredComment(provider, storyId, 'notification', body);
172
- crossRefPosted = true;
173
- progress(
174
- 'REVIEW',
175
- `📝 Cross-reference comment posted on Story #${storyId} → ${commentUrl}`,
176
- );
177
- } catch (err) {
178
- progress(
179
- 'REVIEW',
180
- `⚠️ Failed to post Story cross-reference comment: ${err?.message ?? err}`,
181
- );
182
- }
183
- } else if (!result.posted) {
184
- progress(
185
- 'REVIEW',
186
- '⚠️ Skipping Story cross-reference comment: PR-side review comment did not post.',
187
- );
188
- }
234
+ const crossRefPosted = await postStoryReviewCrossRef({
235
+ provider,
236
+ storyId,
237
+ prUrl,
238
+ prNumber,
239
+ result,
240
+ severity: sev,
241
+ progress,
242
+ });
189
243
 
190
244
  return {
191
245
  halted: !!result.halted,
@@ -10,6 +10,7 @@
10
10
 
11
11
  import path from 'node:path';
12
12
  import { parseSprintArgs } from '../../../cli-args.js';
13
+ import { getDeliveryRouting } from '../../../config/delivery-routing.js';
13
14
  import { PROJECT_ROOT } from '../../../project-root.js';
14
15
 
15
16
  /**
@@ -27,11 +28,12 @@ function resolveFlag(paramValue, parsedValue, defaultValue) {
27
28
  }
28
29
 
29
30
  /**
30
- * Resolve the `waitForMerge` option: an explicit `--no-wait-merge` opt-out
31
- * always wins (preserves the pre-Story-#4428 exit shape even if a future
32
- * headless wrapper defaults to waiting); otherwise the explicit
33
- * `--wait-merge` / injected value governs, defaulting to `false` so
34
- * attended (non-headless) invocations are byte-identical to before.
31
+ * Resolve the `waitForMerge` option:
32
+ * 1. `--no-wait-merge` / injected opt-out always wins (stop at
33
+ * `agent::closing`).
34
+ * 2. Explicit `--wait-merge` / injected true forces land-in-close.
35
+ * 3. Otherwise default from `delivery.routing.closeAndLand` (true) so
36
+ * attended and headless delivers share the close-and-land happy path.
35
37
  *
36
38
  * @param {{ waitForMergeParam, noWaitForMergeParam, parsed }} raw
37
39
  * @returns {boolean}
@@ -41,13 +43,12 @@ function resolveWaitForMerge({
41
43
  noWaitForMergeParam,
42
44
  parsed,
43
45
  }) {
44
- const optedOut = resolveFlag(
45
- noWaitForMergeParam,
46
- parsed.noWaitForMerge,
47
- false,
48
- );
49
- if (optedOut) return false;
50
- return resolveFlag(waitForMergeParam, parsed.waitForMerge, false);
46
+ if (resolveFlag(noWaitForMergeParam, parsed.noWaitForMerge, false)) {
47
+ return false;
48
+ }
49
+ const explicit = waitForMergeParam ?? parsed.waitForMerge;
50
+ if (typeof explicit === 'boolean') return explicit;
51
+ return getDeliveryRouting().closeAndLand;
51
52
  }
52
53
 
53
54
  /**
@@ -75,7 +76,9 @@ export function parseCloseOptions({
75
76
  skipSync: !!skipSyncParam,
76
77
  noAutoMerge: !!noAutoMergeParam,
77
78
  noFullScopeCrap: !!noFullScopeCrapParam,
78
- waitForMerge: !!waitForMergeParam,
79
+ // Preserve undefined so resolveWaitForMerge can apply the
80
+ // closeAndLand config default when neither flag was injected.
81
+ waitForMerge: waitForMergeParam,
79
82
  noWaitForMerge: !!noWaitForMergeParam,
80
83
  }
81
84
  : parseSprintArgs();