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
@@ -1,359 +0,0 @@
1
- /**
2
- * amend.js — the `--amend` change-request delta path of the collapsed
3
- * persist surface (Epic #4474 PR4, design §2 mode matrix, amend row).
4
- *
5
- * An amend run receives the full ticket set with every ticket carrying an
6
- * `op` field:
7
- *
8
- * - `add` — a new Story; created fresh.
9
- * - `modify` — an existing Story whose contract changed; closed and
10
- * recreated (close-and-recreate is scoped to modify/close
11
- * slugs ONLY — never the whole tree, which is `--force`'s
12
- * semantics).
13
- * - `keep` — an existing Story left byte-untouched; it participates in
14
- * the merged-set DAG validation but no provider mutation
15
- * ever targets it.
16
- * - `close` — an existing Story dropped from the plan; closed.
17
- *
18
- * The DAG (and the full ticket validator) runs over the MERGED set —
19
- * keeps + adds + modifies, closes excluded — so a cycle introduced by an
20
- * add that depends on a kept Story that depends on a modify is caught
21
- * before any GitHub call, and a dependency pointing at a closed slug fails
22
- * the unknown-slug check.
23
- *
24
- * Close ops are destructive, so they are gated behind the same explicit
25
- * confirmation contract as `epic-reconcile.js`: without `--explicit-delete`
26
- * the run stops BEFORE any mutation, prints the dry-run op diff, and exits
27
- * 2 ({@link AmendExplicitCloseError} carries the rendered diff; the CLI
28
- * maps it onto the exit code). Non-interactive callers pass the flag.
29
- *
30
- * Slug → issue resolution: an explicit `id` on the ticket (the authoring
31
- * envelope's open-children listing carries issue numbers) wins; otherwise
32
- * the reconciler state ledger (`.agents/epics/<id>.state.json`) resolves
33
- * the slug. A modify/keep/close slug that resolves nowhere is a hard error
34
- * — the amend never guesses which Story it is about to close.
35
- *
36
- * @module lib/orchestration/plan-persist/amend
37
- */
38
-
39
- import { Logger } from '../../Logger.js';
40
-
41
- /** Valid `op` values on an amend ticket. */
42
- const AMEND_OPS = Object.freeze(['add', 'modify', 'keep', 'close']);
43
-
44
- /**
45
- * Error carrying the rendered dry-run diff for the exit-2 confirmation
46
- * path (mirrors `epic-reconcile.js` EXIT_CODES.EXPLICIT_DELETE_REQUIRED).
47
- */
48
- export class AmendExplicitCloseError extends Error {
49
- /**
50
- * @param {string} message
51
- * @param {{ diff: string }} detail
52
- */
53
- constructor(message, { diff }) {
54
- super(message);
55
- this.name = 'AmendExplicitCloseError';
56
- this.code = 'PLAN_AMEND_EXPLICIT_DELETE_REQUIRED';
57
- this.diff = diff;
58
- }
59
- }
60
-
61
- /**
62
- * Partition an amend ticket set by `op`, validating the op vocabulary and
63
- * slug uniqueness. Every ticket MUST carry an op — a missing op on one
64
- * ticket of an amend payload is an authoring defect, not a default.
65
- *
66
- * @param {Array<{ slug?: string, op?: string }>} tickets
67
- * @returns {{ add: object[], modify: object[], keep: object[], close: object[] }}
68
- */
69
- export function partitionAmendTickets(tickets) {
70
- const partition = { add: [], modify: [], keep: [], close: [] };
71
- const seen = new Set();
72
- for (const ticket of tickets) {
73
- const slug = ticket?.slug;
74
- if (typeof slug !== 'string' || slug.length === 0) {
75
- throw new Error(
76
- '[plan-persist] amend ticket without a slug — every amend ticket ' +
77
- 'must carry both slug and op.',
78
- );
79
- }
80
- if (seen.has(slug)) {
81
- throw new Error(
82
- `[plan-persist] duplicate slug "${slug}" in the amend payload.`,
83
- );
84
- }
85
- seen.add(slug);
86
- const op = ticket?.op;
87
- if (!AMEND_OPS.includes(op)) {
88
- throw new Error(
89
- `[plan-persist] amend ticket "${slug}" carries invalid op ` +
90
- `"${op}" — expected one of ${AMEND_OPS.join(', ')}.`,
91
- );
92
- }
93
- partition[op].push(ticket);
94
- }
95
- return partition;
96
- }
97
-
98
- /**
99
- * Project the MERGED ticket set for validation and spec rendering:
100
- * keeps + adds + modifies in original authoring order, closes excluded,
101
- * with the amend-only `op`/`id` carrier fields stripped so the ticket
102
- * validator and `renderSpec` see the exact fan-out ticket shape.
103
- *
104
- * @param {Array<{ op?: string }>} tickets the full amend payload
105
- * @returns {object[]} merged set, op/id stripped
106
- */
107
- export function buildMergedTicketSet(tickets) {
108
- return tickets
109
- .filter((t) => t?.op !== 'close')
110
- .map(({ op: _op, id: _id, ...rest }) => rest);
111
- }
112
-
113
- /**
114
- * Resolve every modify/keep/close slug to its live issue number and
115
- * hard-error on any ambiguity (the "closing the wrong stories" risk):
116
- *
117
- * - modify/keep/close must resolve via explicit `id` or the state
118
- * ledger mapping — no resolution is a hard error;
119
- * - an add slug must NOT already resolve to an issue (a collision means
120
- * the author meant modify, or picked a stale slug);
121
- * - resolved modify/close targets are fetched and must exist; a target
122
- * already closed on GitHub is surfaced (skipped close, not an error —
123
- * re-running an interrupted amend must stay safe).
124
- *
125
- * @param {{
126
- * partition: ReturnType<typeof partitionAmendTickets>,
127
- * stateMapping: Record<string, { issueNumber?: number }>,
128
- * provider: { getTicket: (id: number) => Promise<object|null> },
129
- * }} args
130
- * @returns {Promise<{
131
- * modify: Array<{ ticket: object, issueNumber: number, alreadyClosed: boolean }>,
132
- * keep: Array<{ ticket: object, issueNumber: number }>,
133
- * close: Array<{ ticket: object, issueNumber: number, alreadyClosed: boolean }>,
134
- * }>}
135
- */
136
- export async function resolveAmendTargets({
137
- partition,
138
- stateMapping,
139
- provider,
140
- }) {
141
- const mapping = stateMapping ?? {};
142
- const resolveSlug = (ticket) => {
143
- if (Number.isInteger(ticket.id)) return ticket.id;
144
- const entry = mapping[ticket.slug];
145
- if (Number.isInteger(entry?.issueNumber)) return entry.issueNumber;
146
- return null;
147
- };
148
-
149
- for (const ticket of partition.add) {
150
- const collision = resolveSlug(ticket);
151
- if (collision !== null) {
152
- throw new Error(
153
- `[plan-persist] amend op "add" for slug "${ticket.slug}" collides ` +
154
- `with existing issue #${collision} — use op "modify" to replace ` +
155
- 'it, or pick a fresh slug.',
156
- );
157
- }
158
- }
159
-
160
- const resolveExisting = async (ticket, op) => {
161
- const issueNumber = resolveSlug(ticket);
162
- if (issueNumber === null) {
163
- throw new Error(
164
- `[plan-persist] amend op "${op}" for slug "${ticket.slug}" resolves ` +
165
- 'to no existing issue (no `id` on the ticket, no state-ledger ' +
166
- 'mapping). Refusing to guess — carry the issue number as `id`.',
167
- );
168
- }
169
- const issue = await provider.getTicket(issueNumber);
170
- if (!issue) {
171
- throw new Error(
172
- `[plan-persist] amend op "${op}" for slug "${ticket.slug}" points ` +
173
- `at issue #${issueNumber}, which does not exist.`,
174
- );
175
- }
176
- return { ticket, issueNumber, alreadyClosed: issue.state === 'closed' };
177
- };
178
-
179
- const modify = [];
180
- for (const t of partition.modify)
181
- modify.push(await resolveExisting(t, 'modify'));
182
- const close = [];
183
- for (const t of partition.close)
184
- close.push(await resolveExisting(t, 'close'));
185
- const keep = [];
186
- for (const t of partition.keep) {
187
- const { ticket, issueNumber } = await resolveExisting(t, 'keep');
188
- keep.push({ ticket, issueNumber });
189
- }
190
- return { modify, keep, close };
191
- }
192
-
193
- /**
194
- * Render the operator-facing dry-run diff of the amend plan — printed on
195
- * the exit-2 confirmation path and logged before an `--explicit-delete`
196
- * apply so the destructive set is always visible.
197
- *
198
- * @param {{
199
- * epicId: number,
200
- * targets: Awaited<ReturnType<typeof resolveAmendTargets>>,
201
- * adds: Array<{ slug: string, title?: string }>,
202
- * }} args
203
- * @returns {string}
204
- */
205
- export function renderAmendPlanDiff({ epicId, targets, adds }) {
206
- const rows = [
207
- ...targets.close.map(
208
- (t) =>
209
- `| close | \`${t.ticket.slug}\` | #${t.issueNumber} | closed${t.alreadyClosed ? ' (already closed)' : ''} |`,
210
- ),
211
- ...targets.modify.map(
212
- (t) =>
213
- `| modify | \`${t.ticket.slug}\` | #${t.issueNumber} | closed + recreated |`,
214
- ),
215
- ...adds.map((t) => `| add | \`${t.slug}\` | — | created |`),
216
- ...targets.keep.map(
217
- (t) => `| keep | \`${t.ticket.slug}\` | #${t.issueNumber} | untouched |`,
218
- ),
219
- ];
220
- return [
221
- `Amend plan for Epic #${epicId} (dry-run):`,
222
- '',
223
- '| Op | Slug | Issue | Effect |',
224
- '| --- | --- | --- | --- |',
225
- ...rows,
226
- ].join('\n');
227
- }
228
-
229
- /**
230
- * Enforce the close-op confirmation gate: when the amend plan carries
231
- * close ops (including the close half of modify) affecting live issues and
232
- * `--explicit-delete` was not passed, throw {@link AmendExplicitCloseError}
233
- * with the rendered diff — BEFORE any mutation. Mirrors the
234
- * `epic-reconcile.js` exit-2 contract.
235
- *
236
- * @param {{
237
- * epicId: number,
238
- * targets: Awaited<ReturnType<typeof resolveAmendTargets>>,
239
- * adds: object[],
240
- * explicitDelete: boolean,
241
- * }} args
242
- */
243
- export function enforceAmendCloseGate({
244
- epicId,
245
- targets,
246
- adds,
247
- explicitDelete,
248
- }) {
249
- const liveCloses = [
250
- ...targets.close.filter((t) => !t.alreadyClosed),
251
- ...targets.modify.filter((t) => !t.alreadyClosed),
252
- ];
253
- if (liveCloses.length === 0 || explicitDelete) return;
254
- const diff = renderAmendPlanDiff({ epicId, targets, adds });
255
- const named = liveCloses
256
- .map((t) => `#${t.issueNumber} (\`${t.ticket.slug}\`)`)
257
- .join(', ');
258
- throw new AmendExplicitCloseError(
259
- `[plan-persist] amend plan would close ${liveCloses.length} live ` +
260
- `issue(s): ${named}. Review the dry-run diff and re-run with ` +
261
- '--explicit-delete to apply.',
262
- { diff },
263
- );
264
- }
265
-
266
- /**
267
- * Apply the amend ops against the provider, in destructive-last order per
268
- * slug class: closes first (their disappearance is what the operator
269
- * confirmed), then modify (close old + create new), then adds. Keeps are
270
- * never touched by construction — no code path here receives them.
271
- *
272
- * @param {{
273
- * epicId: number,
274
- * provider: {
275
- * updateTicket: (id: number, patch: object) => Promise<object>,
276
- * createTicket: (parentId: number, payload: object) => Promise<{ id: number }>,
277
- * },
278
- * targets: Awaited<ReturnType<typeof resolveAmendTargets>>,
279
- * validatedBySlug: Map<string, { slug: string, title: string, body?: string, labels?: string[] }>,
280
- * }} args
281
- * @returns {Promise<{
282
- * closed: Array<{ slug: string, issueNumber: number }>,
283
- * recreated: Array<{ slug: string, oldIssueNumber: number, issueNumber: number }>,
284
- * created: Array<{ slug: string, issueNumber: number }>,
285
- * mapping: Record<string, { entity: 'story', issueNumber: number }>,
286
- * closedSlugs: string[],
287
- * }>}
288
- */
289
- export async function applyAmendOps({
290
- epicId,
291
- provider,
292
- targets,
293
- validatedBySlug,
294
- }) {
295
- const closed = [];
296
- const recreated = [];
297
- const created = [];
298
- const mapping = {};
299
- const closedSlugs = [];
300
-
301
- const createFromValidated = async (slug) => {
302
- const validated = validatedBySlug.get(slug);
303
- if (!validated) {
304
- throw new Error(
305
- `[plan-persist] amend apply: no validated ticket for slug "${slug}".`,
306
- );
307
- }
308
- const result = await provider.createTicket(epicId, {
309
- title: validated.title,
310
- body: validated.body ?? '',
311
- labels: validated.labels ?? [],
312
- });
313
- return result.id;
314
- };
315
-
316
- for (const target of targets.close) {
317
- if (!target.alreadyClosed) {
318
- await provider.updateTicket(target.issueNumber, { state: 'closed' });
319
- } else {
320
- Logger.info(
321
- `[plan-persist] amend close: #${target.issueNumber} ` +
322
- `(${target.ticket.slug}) already closed — skipping.`,
323
- );
324
- }
325
- closed.push({ slug: target.ticket.slug, issueNumber: target.issueNumber });
326
- closedSlugs.push(target.ticket.slug);
327
- }
328
-
329
- for (const target of targets.modify) {
330
- if (!target.alreadyClosed) {
331
- await provider.updateTicket(target.issueNumber, { state: 'closed' });
332
- }
333
- const newId = await createFromValidated(target.ticket.slug);
334
- recreated.push({
335
- slug: target.ticket.slug,
336
- oldIssueNumber: target.issueNumber,
337
- issueNumber: newId,
338
- });
339
- mapping[target.ticket.slug] = { entity: 'story', issueNumber: newId };
340
- }
341
-
342
- for (const [slug] of validatedBySlug) {
343
- const isModify = targets.modify.some((t) => t.ticket.slug === slug);
344
- const isKeep = targets.keep.some((t) => t.ticket.slug === slug);
345
- if (isModify || isKeep) continue;
346
- const newId = await createFromValidated(slug);
347
- created.push({ slug, issueNumber: newId });
348
- mapping[slug] = { entity: 'story', issueNumber: newId };
349
- }
350
-
351
- for (const target of targets.keep) {
352
- mapping[target.ticket.slug] = {
353
- entity: 'story',
354
- issueNumber: target.issueNumber,
355
- };
356
- }
357
-
358
- return { closed, recreated, created, mapping, closedSlugs };
359
- }
@@ -1,127 +0,0 @@
1
- /**
2
- * delivery-mode.js — delivery-shape mode resolution for the collapsed
3
- * persist surface (Epic #4474 PR4, design §2 mode matrix).
4
- *
5
- * The risk verdict's optional `deliveryShape` field ("fan-out" | "single",
6
- * absent → fan-out so every existing verdict stays valid) selects between
7
- * the three persist modes:
8
- *
9
- * - `fan-out` — the full mode: ticket validator + DAG + budget gates,
10
- * Story-tree creation via the structural reconciler.
11
- * - `single` — the spec-only single-delivery mode: NO tickets are
12
- * authored, the ticket validator + DAG are skipped (fenced by
13
- * construction — {@link resolveDeliveryMode} hard-refuses the
14
- * combination of `deliveryShape: "single"` with a tickets payload, so
15
- * the skip branch is unreachable when tickets are present), and the
16
- * persist applies the `delivery::single` routing marker instead of a
17
- * Story tree. Inert until #4475 lands the deliver-side reader.
18
- * - `amend` — the change-request delta path (`--amend`): tickets carry
19
- * `op: add|modify|keep|close` and the persist maps the ops onto the
20
- * existing Story tree (see `plan-persist/amend.js`).
21
- *
22
- * @module lib/orchestration/plan-persist/delivery-mode
23
- */
24
-
25
- import { parseDeliverySlicingTable } from '../consolidation-precondition.js';
26
-
27
- /** Canonical delivery-shape values the risk-verdict schema admits. */
28
- const DELIVERY_SHAPES = Object.freeze(['fan-out', 'single']);
29
-
30
- /**
31
- * Mode-coherence hard error (design §1 step 3 item 3, extended for PR4).
32
- *
33
- * Resolves the persist mode from the risk verdict's `deliveryShape` (absent
34
- * → `fan-out`), the tickets payload, and the `--amend` flag — and refuses
35
- * every incoherent combination loudly instead of silently coercing:
36
- *
37
- * - unknown `deliveryShape` values;
38
- * - `deliveryShape: "single"` WITH a tickets payload (the DAG-skip
39
- * leakage risk — the single mode's validator/DAG skip is only sound
40
- * when there are no tickets to validate);
41
- * - fan-out without a non-empty tickets array;
42
- * - `--amend` combined with `deliveryShape: "single"` (the delta path is
43
- * fan-out-shaped by definition — a single-delivery re-plan is a
44
- * `--force` re-persist);
45
- * - `--amend` without tickets (the delta IS the tickets-with-ops
46
- * payload);
47
- * - `op` fields present without `--amend` (a full persist must never
48
- * silently reinterpret an amend delta as a fresh tree).
49
- *
50
- * @param {{ deliveryShape?: string }} riskVerdict schema-validated verdict
51
- * @param {unknown} tickets parsed tickets payload (null when no file)
52
- * @param {{ amend?: boolean }} [opts]
53
- * @returns {'fan-out'|'single'|'amend'} the resolved persist mode
54
- */
55
- export function resolveDeliveryMode(riskVerdict, tickets, opts = {}) {
56
- const { amend = false } = opts;
57
- const shape = riskVerdict?.deliveryShape ?? 'fan-out';
58
- if (!DELIVERY_SHAPES.includes(shape)) {
59
- throw new Error(
60
- `[plan-persist] unknown deliveryShape "${shape}" — expected one of ` +
61
- `${DELIVERY_SHAPES.join(', ')} (or omit the field for fan-out).`,
62
- );
63
- }
64
- const hasTickets = Array.isArray(tickets) && tickets.length > 0;
65
-
66
- if (amend) {
67
- if (shape === 'single') {
68
- throw new Error(
69
- '[plan-persist] --amend is incoherent with deliveryShape "single" — ' +
70
- 'the amend delta maps ops onto an existing Story tree, and a ' +
71
- 'single-delivery plan has none. Re-author the verdict as fan-out, ' +
72
- 'or re-persist the single plan with --force.',
73
- );
74
- }
75
- if (!hasTickets) {
76
- throw new Error(
77
- '[plan-persist] --amend requires a tickets payload carrying ' +
78
- '`op: add|modify|keep|close` on every ticket — the delta IS the ' +
79
- 'tickets file (--tickets <file>).',
80
- );
81
- }
82
- return 'amend';
83
- }
84
-
85
- if (shape === 'single') {
86
- if (hasTickets) {
87
- throw new Error(
88
- '[plan-persist] mode-coherence: deliveryShape "single" with a ' +
89
- 'tickets payload is contradictory — the single-delivery mode ' +
90
- 'authors NO tickets (the Delivery Slicing table is the audit ' +
91
- 'trail). Remove the tickets file, or re-author the risk verdict ' +
92
- 'as fan-out.',
93
- );
94
- }
95
- return 'single';
96
- }
97
-
98
- if (!hasTickets) {
99
- throw new Error(
100
- '[plan-persist] fan-out persist requires a non-empty tickets array ' +
101
- '(--tickets <file>). A ticket-less spec-only plan must declare ' +
102
- 'deliveryShape: "single" in the risk verdict.',
103
- );
104
- }
105
- if (tickets.some((t) => t && typeof t === 'object' && 'op' in t)) {
106
- throw new Error(
107
- '[plan-persist] tickets carry `op` fields but --amend was not passed ' +
108
- '— refusing to reinterpret an amend delta as a full persist. Pass ' +
109
- '--amend, or strip the op fields for a fresh fan-out.',
110
- );
111
- }
112
- return 'fan-out';
113
- }
114
-
115
- /**
116
- * Count the slices of the authored Tech Spec's `## Delivery Slicing` table
117
- * — the single-mode plan summary's `sliceCount` (design §2: the slicing
118
- * table IS the single mode's audit trail). Returns `null` when the table
119
- * is absent or unparseable (fail-open, mirroring the parser's contract).
120
- *
121
- * @param {string} techSpecContent
122
- * @returns {number|null}
123
- */
124
- export function countDeliverySlices(techSpecContent) {
125
- const rows = parseDeliverySlicingTable(techSpecContent ?? '');
126
- return Array.isArray(rows) ? rows.length : null;
127
- }
@@ -1,205 +0,0 @@
1
- /**
2
- * post-merge-pipeline.js — sequencer for the post-merge phases of
3
- * `story-close`.
4
- *
5
- * After the Story branch is merged into the Epic branch, several best-effort
6
- * cleanup + reporting phases must run:
7
- *
8
- * 1. worktree-reap — remove the per-Story worktree.
9
- * 2. branch-cleanup — delete the Story branch (local + remote).
10
- * 3. ticket-closure — transition the Story to agent::done
11
- * and run cascade completion.
12
- * 4. notification — fire the story-complete webhook.
13
- * 5. dashboard-refresh — regenerate the dispatch manifest.
14
- * 6. temp-cleanup — delete the per-Story manifest pair under
15
- * `temp/epic-<eid>/stories/story-<sid>/manifest.{md,json}`
16
- * (Epic #1030 Story #1040). Falls back to the
17
- * legacy flat `temp/story-manifest-<id>.{md,json}`
18
- * layout when `epicId` is unknown — both paths
19
- * are tried so partial migrations don't leak
20
- * files in either layout.
21
- * 7. detectors — fire rework + retry signal detectors against
22
- * this Story's `traces.ndjson` and persist each
23
- * emission to `signals.ndjson` BEFORE the
24
- * analyzer renders the perf-summary comment.
25
- * 8. perf-summary — shell out to `analyze-execution.js` so the
26
- * analyzer is the single writer of the
27
- * `<!-- structured:story-perf-summary -->`
28
- * comment on the Story ticket.
29
- *
30
- * Each phase is wrapped by `runPhase` so a single failure does not abort
31
- * the rest of the close-out — the same best-effort contract that the
32
- * pre-extraction inline code provided. Phase return values are merged into
33
- * a `state` object whose shape `runStoryClose` consumes to build the final
34
- * structured result.
35
- *
36
- * The phase implementations live under `./post-merge/phases/` (one file
37
- * per phase) — this module is a pure sequencer that imports each phase,
38
- * re-exports them for backwards compatibility, and runs them in order
39
- * via `runPhase`.
40
- */
41
-
42
- import { execFileSync } from 'node:child_process';
43
- import path from 'node:path';
44
- import { Logger } from '../Logger.js';
45
- import { detectorsPhase } from './detectors-phase.js';
46
- import { runPhase } from './phase-runner.js';
47
- import { branchCleanupPhase } from './post-merge/phases/branch-cleanup.js';
48
- import { dashboardRefreshPhase } from './post-merge/phases/dashboard-refresh.js';
49
- import { notificationPhase } from './post-merge/phases/notification.js';
50
- import { tempCleanupPhase } from './post-merge/phases/temp-cleanup.js';
51
- import { ticketClosurePhase } from './post-merge/phases/ticket-closure.js';
52
- import {
53
- createWorktreeReapState,
54
- worktreeReapPhase,
55
- } from './post-merge/phases/worktree-reap.js';
56
-
57
- export {
58
- branchCleanupPhase,
59
- dashboardRefreshPhase,
60
- detectorsPhase,
61
- notificationPhase,
62
- tempCleanupPhase,
63
- ticketClosurePhase,
64
- worktreeReapPhase,
65
- };
66
-
67
- function reapPhaseLogger(progress) {
68
- return progress ?? (() => {});
69
- }
70
-
71
- /**
72
- * perfSummaryPhase — shells out to `analyze-execution.js --story <sid>
73
- * --epic <eid> --phase-timings <path>` so the analyzer is the single
74
- * writer of the `<!-- structured:story-perf-summary -->` comment on the
75
- * Story ticket (Epic #1030 Story #1046). Replaces the legacy
76
- * `<!-- structured:phase-timings -->` post that lived inline in
77
- * `post-merge-close.js`.
78
- *
79
- * Best-effort: any failure (missing analyzer, non-zero exit, no path
80
- * supplied) logs a warning and resolves — the merge has already
81
- * succeeded and we would rather lose the perf summary than roll back
82
- * closure.
83
- *
84
- * @param {{
85
- * storyId: number|string,
86
- * epicId: number|string,
87
- * phaseTimingsPath: string|null|undefined,
88
- * projectRoot?: string,
89
- * progress?: Function,
90
- * logger?: object,
91
- * spawnFn?: typeof execFileSync,
92
- * }} ctx
93
- * @returns {Promise<{ status: 'ok'|'skipped'|'failed', reason?: string }>}
94
- */
95
- export async function perfSummaryPhase(ctx) {
96
- const {
97
- storyId,
98
- epicId,
99
- phaseTimingsPath,
100
- projectRoot,
101
- progress,
102
- logger,
103
- spawnFn = execFileSync,
104
- } = ctx;
105
- const log = reapPhaseLogger(progress);
106
- if (!phaseTimingsPath) {
107
- log('PERF', '⏭️ Skipping perf-summary (no phase-timings path provided)');
108
- return { status: 'skipped', reason: 'no-phase-timings-path' };
109
- }
110
- const root = projectRoot ?? process.cwd();
111
- const analyzerPath = path.join(
112
- root,
113
- '.agents',
114
- 'scripts',
115
- 'analyze-execution.js',
116
- );
117
- const args = [
118
- analyzerPath,
119
- '--story',
120
- String(storyId),
121
- '--epic',
122
- String(epicId),
123
- '--phase-timings',
124
- phaseTimingsPath,
125
- ];
126
- log(
127
- 'PERF',
128
- `Running analyzer: analyze-execution.js --story ${storyId} --epic ${epicId}`,
129
- );
130
- try {
131
- spawnFn(process.execPath, args, {
132
- cwd: root,
133
- stdio: ['ignore', 'pipe', 'pipe'],
134
- });
135
- log('PERF', '✅ story-perf-summary posted');
136
- return { status: 'ok' };
137
- } catch (err) {
138
- const reason = err?.message ?? String(err);
139
- logger?.warn?.(
140
- `[post-merge-pipeline] ⚠️ analyze-execution failed (non-fatal): ${reason}`,
141
- );
142
- return { status: 'failed', reason };
143
- }
144
- }
145
-
146
- export const DEFAULT_POST_MERGE_PHASES = Object.freeze([
147
- {
148
- name: 'worktree-reap',
149
- fn: worktreeReapPhase,
150
- stateKey: 'worktreeReap',
151
- fallback: createWorktreeReapState({
152
- status: 'failed',
153
- reason: 'phase-error',
154
- }),
155
- },
156
- { name: 'branch-cleanup', fn: branchCleanupPhase, stateKey: 'branchCleanup' },
157
- { name: 'ticket-closure', fn: ticketClosurePhase, stateKey: 'ticketClosure' },
158
- { name: 'notification', fn: notificationPhase },
159
- {
160
- name: 'dashboard-refresh',
161
- fn: dashboardRefreshPhase,
162
- stateKey: 'manifestUpdated',
163
- },
164
- { name: 'temp-cleanup', fn: tempCleanupPhase },
165
- // Detectors MUST run before `perf-summary`. The perf phase shells out
166
- // to `analyze-execution.js`, which reads the per-Story signals stream
167
- // to author the `<!-- structured:story-perf-summary -->` comment;
168
- // emitting rework/retry events first ensures the rendered surface
169
- // reflects this Story's signals.
170
- { name: 'detectors', fn: detectorsPhase, stateKey: 'detectors' },
171
- { name: 'perf-summary', fn: perfSummaryPhase, stateKey: 'perfSummary' },
172
- ]);
173
-
174
- /**
175
- * Sequence the post-merge phases of `story-close`. Every phase runs
176
- * under `runPhase` so a single failure logs `[phase=<name>] <err>` and the
177
- * pipeline keeps going. Each phase's return value is recorded under its
178
- * `stateKey` (when defined) on the returned state object.
179
- *
180
- * @param {object} ctx Phase collaborators (provider, notify,
181
- * logger, progress, etc.).
182
- * @param {Array<{name: string, fn: Function, stateKey?: string, fallback?: any}>} [phases]
183
- * Phase descriptors. Defaults to `DEFAULT_POST_MERGE_PHASES`.
184
- * @returns {Promise<object>} Aggregated state from each phase.
185
- */
186
- export async function runPostMergePipeline(
187
- ctx,
188
- phases = DEFAULT_POST_MERGE_PHASES,
189
- ) {
190
- const logger = ctx.logger ?? Logger;
191
- const state = {
192
- worktreeReap: createWorktreeReapState(),
193
- branchCleanup: { localDeleted: false, remoteDeleted: false },
194
- ticketClosure: { closedTickets: [], cascadedTo: [], cascadeFailed: [] },
195
- manifestUpdated: false,
196
- };
197
- for (const phase of phases) {
198
- const value = await runPhase(phase.name, () => phase.fn(ctx, state), {
199
- logger,
200
- fallback: phase.fallback,
201
- });
202
- if (phase.stateKey && value !== undefined) state[phase.stateKey] = value;
203
- }
204
- return state;
205
- }