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,236 +0,0 @@
1
- /**
2
- * phases/plan-epic.js — Tech Spec / Acceptance Table persistence phase.
3
- *
4
- * Story #4324: the `context::tech-spec` / `context::acceptance-spec` ticket
5
- * classes are retired. The Epic body is the single planning document: this
6
- * phase upserts the authored Tech Spec (opening with `## Delivery Slicing`)
7
- * and the Acceptance Spec's AC-ID table (`## Acceptance Table`) as
8
- * marker-delimited managed sections of the Epic body — see
9
- * `lib/epic-body-sections.js`. Each write is **section-scoped**: only the
10
- * managed region is replaced; the rest of the body is byte-preserved.
11
- *
12
- * Idempotent against partial state: when the Epic body already carries all
13
- * requested sections, the phase short-circuits with `already-planned`.
14
- * Pass `force: true` to re-plan: the managed sections are overwritten in
15
- * place and a one-line regeneration audit comment lands on the Epic.
16
- *
17
- * The retired machine-managed `## Planning Artifacts` checklist (which
18
- * linked the old context tickets) is stripped on every persist so a
19
- * re-planned historical Epic stops advertising stale ticket links; the
20
- * legacy tickets themselves are ignored (forward-only cutover — no
21
- * backfill, no fetch).
22
- */
23
-
24
- import {
25
- hasEpicSection,
26
- stripEpicSection,
27
- stripPlanningArtifactsSection,
28
- upsertEpicSection,
29
- } from '../../../epic-body-sections.js';
30
- import { Logger } from '../../../Logger.js';
31
- import { ACCEPTANCE_NA } from '../../../label-constants.js';
32
-
33
- /**
34
- * Resolve whether Phase 7 should persist an acceptance-table section or
35
- * apply the `acceptance::n-a` waiver, from the planningRisk envelope derived
36
- * off the planner-authored risk verdict (`deriveRiskEnvelope`, Epic #3865).
37
- *
38
- * @param {import('../../planning-risk.js').PlanningRiskEnvelope|null} planningRisk
39
- * Derived envelope; `null` (direct invocations without a verdict) never
40
- * applies the waiver.
41
- * @param {string|null} acceptanceSpecContent
42
- * @returns {{ planningRisk: import('../../planning-risk.js').PlanningRiskEnvelope|null, wantsAcceptanceSpec: boolean, applyAcceptanceWaiver: boolean }}
43
- */
44
- export function resolveAcceptancePersistence(
45
- planningRisk,
46
- acceptanceSpecContent,
47
- ) {
48
- const hasAcceptanceContent =
49
- typeof acceptanceSpecContent === 'string' &&
50
- acceptanceSpecContent.trim() !== '';
51
-
52
- if (planningRisk?.acceptanceDisposition === 'not-applicable') {
53
- return {
54
- planningRisk,
55
- wantsAcceptanceSpec: false,
56
- applyAcceptanceWaiver: true,
57
- };
58
- }
59
-
60
- return {
61
- planningRisk: planningRisk ?? null,
62
- wantsAcceptanceSpec: hasAcceptanceContent,
63
- applyAcceptanceWaiver: false,
64
- };
65
- }
66
-
67
- export function validatePlanEpicInputs({
68
- techSpecContent,
69
- acceptanceSpecContent,
70
- }) {
71
- if (typeof techSpecContent !== 'string' || techSpecContent.trim() === '') {
72
- throw new Error(
73
- '[Epic Planner] techSpecContent is required and must be non-empty.',
74
- );
75
- }
76
- if (
77
- acceptanceSpecContent !== null &&
78
- (typeof acceptanceSpecContent !== 'string' ||
79
- acceptanceSpecContent.trim() === '')
80
- ) {
81
- throw new Error(
82
- '[Epic Planner] acceptanceSpecContent, when provided, must be a non-empty string.',
83
- );
84
- }
85
- }
86
-
87
- /**
88
- * Snapshot which managed planning sections the Epic body already carries.
89
- *
90
- * @param {{ body?: string }} epic
91
- * @returns {{ techSpec: boolean, acceptanceTable: boolean }}
92
- */
93
- export function getExistingSections(epic) {
94
- const body = epic?.body ?? '';
95
- return {
96
- techSpec: hasEpicSection(body, 'techSpec'),
97
- acceptanceTable: hasEpicSection(body, 'acceptanceTable'),
98
- };
99
- }
100
-
101
- export function hasAllRequestedSections({ existing, wantsAcceptanceSpec }) {
102
- return Boolean(
103
- existing.techSpec &&
104
- (wantsAcceptanceSpec ? existing.acceptanceTable : true),
105
- );
106
- }
107
-
108
- /**
109
- * Persist the host-authored Tech Spec (and optional Acceptance Table) as
110
- * managed sections of the Epic body.
111
- *
112
- * @returns {Promise<{
113
- * persisted: boolean,
114
- * reason: 'already-planned'|'persisted'|'force-replan',
115
- * techSpecPersisted: boolean,
116
- * acceptanceTable: 'persisted'|'waived'|'none',
117
- * }>}
118
- */
119
- export async function planEpic(
120
- epicId,
121
- provider,
122
- { techSpecContent, acceptanceSpecContent = null },
123
- _settings = {},
124
- { force = false, planningRisk = null } = {},
125
- ) {
126
- validatePlanEpicInputs({
127
- techSpecContent,
128
- acceptanceSpecContent,
129
- });
130
-
131
- Logger.info(`[Epic Planner] Fetching Epic #${epicId}...`);
132
- const epic = await provider.getEpic(epicId);
133
-
134
- if (!epic) {
135
- throw new Error(`Epic #${epicId} not found.`);
136
- }
137
-
138
- const { wantsAcceptanceSpec, applyAcceptanceWaiver } =
139
- resolveAcceptancePersistence(planningRisk, acceptanceSpecContent);
140
-
141
- Logger.info(
142
- `[Epic Planner] Acceptance disposition: ${planningRisk?.acceptanceDisposition ?? 'unspecified'}` +
143
- (applyAcceptanceWaiver
144
- ? ` — applying ${ACCEPTANCE_NA} waiver (no acceptance-table section).`
145
- : wantsAcceptanceSpec
146
- ? ' — persisting the ## Acceptance Table section.'
147
- : ' — no acceptance-spec content supplied.'),
148
- );
149
-
150
- const existing = getExistingSections(epic);
151
- if (!force && hasAllRequestedSections({ existing, wantsAcceptanceSpec })) {
152
- Logger.warn(
153
- `[Epic Planner] Epic #${epicId} body already carries all requested planning sections. Aborting to prevent an unintended overwrite. Use --force to re-plan.`,
154
- );
155
- return {
156
- persisted: false,
157
- reason: 'already-planned',
158
- techSpecPersisted: existing.techSpec,
159
- acceptanceTable: existing.acceptanceTable ? 'persisted' : 'none',
160
- };
161
- }
162
-
163
- // Section-scoped writes: each upsert replaces only its own managed
164
- // region; the ideation sections and any operator-authored prose are
165
- // byte-preserved. The retired `## Planning Artifacts` checklist is
166
- // stripped so re-planned historical Epics stop advertising the old
167
- // context-ticket links (the legacy tickets themselves are ignored).
168
- let newBody = stripPlanningArtifactsSection(epic.body ?? '');
169
- newBody = upsertEpicSection(newBody, 'techSpec', techSpecContent);
170
-
171
- let acceptanceTable = 'none';
172
- if (wantsAcceptanceSpec) {
173
- newBody = upsertEpicSection(
174
- newBody,
175
- 'acceptanceTable',
176
- acceptanceSpecContent,
177
- );
178
- acceptanceTable = 'persisted';
179
- } else if (applyAcceptanceWaiver) {
180
- // Acceptance transition: was present, now waived (acceptance::n-a).
181
- // Strip the stale table so the close-time reconciler cannot read a
182
- // section the planner no longer stands behind.
183
- if (existing.acceptanceTable) {
184
- Logger.info(
185
- `[Epic Planner] Acceptance disposition now waived — removing the stale ## Acceptance Table section from Epic #${epicId}.`,
186
- );
187
- newBody = stripEpicSection(newBody, 'acceptanceTable');
188
- }
189
- acceptanceTable = 'waived';
190
- }
191
-
192
- /** @type {{ add?: string[], remove?: string[] }} */
193
- const labelMutations = {};
194
- if (applyAcceptanceWaiver) {
195
- labelMutations.add = [ACCEPTANCE_NA];
196
- } else if (
197
- wantsAcceptanceSpec &&
198
- (epic.labels ?? []).includes(ACCEPTANCE_NA)
199
- ) {
200
- labelMutations.remove = [ACCEPTANCE_NA];
201
- }
202
-
203
- Logger.info(
204
- `[Epic Planner] Updating Epic #${epicId} body with the planning sections...`,
205
- );
206
- await provider.updateTicket(epicId, {
207
- body: newBody,
208
- ...(labelMutations.add || labelMutations.remove
209
- ? { labels: labelMutations }
210
- : {}),
211
- });
212
-
213
- if (force) {
214
- // Preserve the regeneration audit trail the retired per-ticket
215
- // overwrite used to leave. Best-effort — never fail the persist on a
216
- // comment post error.
217
- try {
218
- await provider.postComment(epicId, {
219
- type: 'notification',
220
- body: '♻️ **Regeneration Audit**: the Tech Spec / Acceptance Table sections of this Epic body were regenerated in place by a `/plan --force` re-plan. Content outside the managed sections was preserved.',
221
- });
222
- } catch (_err) {
223
- // Swallow: audit comment is advisory.
224
- }
225
- }
226
-
227
- Logger.info(`[Epic Planner] Epic #${epicId} updated successfully.`);
228
- Logger.info(`[Epic Planner] Planning pipeline complete!`);
229
-
230
- return {
231
- persisted: true,
232
- reason: force ? 'force-replan' : 'persisted',
233
- techSpecPersisted: true,
234
- acceptanceTable,
235
- };
236
- }
@@ -1,307 +0,0 @@
1
- /**
2
- * phases/run-spec-phase.js — orchestrator for Phase 7 (spec).
3
- *
4
- * Wires the planEpic persist phase, the Tech Spec freshness advisory, the
5
- * `agent::review-spec` label flip, the planning-state checkpoint upsert, and
6
- * the temp-file cleanup into a single sequential flow.
7
- */
8
-
9
- import path from 'node:path';
10
- import { verifyBddRunnerPendingTag } from '../../../bdd-runner-detect.js';
11
- import { Logger } from '../../../Logger.js';
12
- import { AGENT_LABELS, TYPE_LABELS } from '../../../label-constants.js';
13
- import { cleanupPhaseTempFiles } from '../../../plan-phase-cleanup.js';
14
- import { PROJECT_ROOT } from '../../../project-root.js';
15
- import { acquireEpicPlanLease } from '../../epic-plan-lease-guard.js';
16
- import {
17
- initialize as initializePlanState,
18
- read as readPlanState,
19
- write as writePlanState,
20
- } from '../../epic-plan-state-store.js';
21
- import { resolveReviewRouting } from '../../plan-review-routing.js';
22
- import { deriveRiskEnvelope } from '../../planning-risk.js';
23
- import {
24
- formatMissingSectionMessage,
25
- validateSpecSections,
26
- } from '../../spec-section-validator.js';
27
- import { upsertStructuredComment } from '../../ticketing.js';
28
- import { planEpic } from './plan-epic.js';
29
- import { runSpecFreshnessCheck } from './spec-freshness.js';
30
-
31
- /**
32
- * Render the `risk-verdict` structured-comment body: a reviewer-readable
33
- * axis table plus the canonical fenced-JSON record (verdict + derived
34
- * envelope) downstream tooling parses.
35
- *
36
- * @param {{ epicId: number, riskVerdict: import('../../planning-risk.js').RiskVerdict, planningRisk: import('../../planning-risk.js').PlanningRiskEnvelope }} input
37
- * @returns {string}
38
- */
39
- function buildRiskVerdictCommentBody({ epicId, riskVerdict, planningRisk }) {
40
- const axisRows = planningRisk.axes.map(
41
- (entry) => `| ${entry.axis} | ${entry.level} | ${entry.rationale} |`,
42
- );
43
- const axisTable =
44
- axisRows.length > 0
45
- ? ['| Axis | Level | Rationale |', '| --- | --- | --- |', ...axisRows]
46
- : ['_No risk axes apply (planner-asserted)._'];
47
- const record = {
48
- kind: 'risk-verdict',
49
- epicId,
50
- verdict: riskVerdict,
51
- planningRisk,
52
- };
53
- // Story #4145 — when the disposition was forced to not-applicable because
54
- // no BDD runner exists, make the waiver operator-visible in the rendered
55
- // comment (not just the fenced JSON record) so a reviewer sees why an
56
- // otherwise-required AC table was waived.
57
- const waiverNote = planningRisk.acceptanceWaivedReason
58
- ? ['', `> ⚠️ **Acceptance waived** — ${planningRisk.acceptanceWaivedReason}`]
59
- : [];
60
- return [
61
- `### 🧭 Planning Risk Verdict — ${planningRisk.overallLevel} · ${planningRisk.gateDecision}`,
62
- '',
63
- riskVerdict.summary,
64
- '',
65
- ...axisTable,
66
- ...waiverNote,
67
- '',
68
- '```json',
69
- JSON.stringify(record, null, 2),
70
- '```',
71
- ].join('\n');
72
- }
73
-
74
- async function setEpicLabel(provider, epicId, targetLabel) {
75
- const planningLabels = [AGENT_LABELS.REVIEW_SPEC, AGENT_LABELS.READY];
76
- await provider.updateTicket(epicId, {
77
- labels: {
78
- add: [targetLabel],
79
- remove: planningLabels.filter((l) => l !== targetLabel),
80
- },
81
- });
82
- }
83
-
84
- /**
85
- * Execute the spec phase end to end.
86
- *
87
- * @param {number} epicId
88
- * @param {import('../../../ITicketingProvider.js').ITicketingProvider} provider
89
- * @param {{ techSpecContent: string, acceptanceSpecContent?: string|null }} artifacts
90
- * @param {object} settings
91
- * @param {{ force?: boolean, forceReview?: boolean, steal?: boolean, config?: object, riskVerdict?: import('../../planning-risk.js').RiskVerdict }} [opts]
92
- * @returns {Promise<{ epicId: number, techSpecPersisted: boolean, acceptanceTable: 'persisted'|'waived'|'none', checkpoint: object, planningRisk: import('../../planning-risk.js').PlanningRiskEnvelope, reviewRouting: import('../../plan-review-routing.js').ReviewRoutingEnvelope }>}
93
- */
94
- export async function runSpecPhase(
95
- epicId,
96
- provider,
97
- { techSpecContent, acceptanceSpecContent = null },
98
- settings = {},
99
- {
100
- force = false,
101
- forceReview = false,
102
- steal = false,
103
- config,
104
- riskVerdict,
105
- } = {},
106
- ) {
107
- // Hard cutover (Epic #3865): the planner-authored risk verdict is the
108
- // sole risk source. Derive the envelope up front so a missing verdict
109
- // fails closed before any GitHub mutation.
110
- if (!riskVerdict || !Array.isArray(riskVerdict.axes)) {
111
- throw new Error(
112
- '[epic-plan-spec] risk verdict is required — author risk-verdict.json via the epic-plan-spec-author Skill and pass it with --risk-verdict.',
113
- );
114
- }
115
-
116
- // Story #4403 (Finding 3): the "## Delivery Slicing" presence gate — the
117
- // Phase 8-side anchor the Holistic Consolidation pass reconciles against —
118
- // is validated here, against the in-memory authored content, before any
119
- // GitHub mutation (lease acquisition, Epic body write, structured
120
- // comments). This replaces the retired standalone `epic-plan-spec-validate.js`
121
- // CLI / Phase 7.5 workflow step, whose documented ordering ran the check
122
- // AFTER the persist path had already written to GitHub and deleted the
123
- // temp file it read — so the "blocking gate" could never actually block.
124
- const sectionCheck = validateSpecSections({ body: techSpecContent });
125
- if (!sectionCheck.ok) {
126
- throw new Error(
127
- formatMissingSectionMessage({
128
- techspecPath: `Epic #${epicId} authored Tech Spec`,
129
- missing: sectionCheck.missing,
130
- }),
131
- );
132
- }
133
-
134
- // Story #4145 — probe the project's BDD runner. When none is detected
135
- // (`fallback === true`, e.g. a node:test repo with no tests/features/**),
136
- // the acceptance disposition is forced to not-applicable inside
137
- // deriveRiskEnvelope: an authored AC table could never be reconciled by
138
- // `@epic-<id>-ac-*` feature tags, so /deliver finalize would otherwise
139
- // abort and require a manual `acceptance::n-a`. The probe is static and
140
- // best-effort — a detection failure degrades to "runner present" (no
141
- // forced waiver), preserving the BDD-repo path, and never blocks Phase 7.
142
- let bddRunner = null;
143
- try {
144
- bddRunner = await verifyBddRunnerPendingTag({ cwd: PROJECT_ROOT });
145
- } catch (err) {
146
- Logger.warn(
147
- `[epic-plan-spec] BDD runner probe skipped (${err.message}); acceptance disposition derived from risk axes only.`,
148
- );
149
- }
150
- const planningRisk = deriveRiskEnvelope(riskVerdict, { bddRunner });
151
- if (planningRisk.acceptanceWaivedReason) {
152
- Logger.info(
153
- `[epic-plan-spec] Acceptance disposition forced to not-applicable for Epic #${epicId}: ${planningRisk.acceptanceWaivedReason}`,
154
- );
155
- }
156
-
157
- const epic = await provider.getEpic(epicId);
158
- if (!epic) {
159
- throw new Error(`[epic-plan-spec] Epic #${epicId} not found.`);
160
- }
161
- if (!epic.labels?.includes(TYPE_LABELS.EPIC)) {
162
- throw new Error(
163
- `[epic-plan-spec] Ticket #${epicId} is not a ${TYPE_LABELS.EPIC}.`,
164
- );
165
- }
166
-
167
- // Workflow-guards (Story #3481): acquire the Epic-lease before any Phase 7
168
- // mutation so two concurrent /plan runs cannot both drive this Epic. The
169
- // guard fails closed (audit #3513) — any foreign assignee refuses here and
170
- // the CLI exits non-zero naming the owner, unless `--steal` transfers it.
171
- await acquireEpicPlanLease({ provider, epicId, config, steal });
172
-
173
- await initializePlanState({ provider, epicId });
174
-
175
- const planResult = await planEpic(
176
- epicId,
177
- provider,
178
- { techSpecContent, acceptanceSpecContent },
179
- settings,
180
- {
181
- force,
182
- planningRisk,
183
- },
184
- );
185
- const specChanged = planResult?.persisted !== false;
186
-
187
- const afterPlan = await provider.getEpic(epicId);
188
-
189
- // Story #2635 — cross-validate the authored Tech Spec body against the
190
- // base branch and surface any stale path-shaped references. Story #4324:
191
- // with the Tech Spec folded into the Epic body, the advisory comment
192
- // lands on the Epic itself. Non-blocking: a missing base ref, an
193
- // unreadable temp directory, or a provider failure downgrades to a
194
- // warning so Phase 7 never fails on the advisory check.
195
- const baseBranchRef = settings?.baseBranch ?? 'main';
196
- const tempRoot = path.resolve(
197
- PROJECT_ROOT,
198
- settings?.paths?.tempRoot ?? 'temp',
199
- );
200
- const freshness = await runSpecFreshnessCheck({
201
- epicId,
202
- techSpecContent,
203
- baseBranchRef,
204
- tempRoot,
205
- provider,
206
- });
207
-
208
- // Story #1585 (Epic #1471): the baseline-snapshot fork was previously
209
- // performed here at plan-time. It now runs at first-story-init time
210
- // inside `lib/story-init/branch-initializer.js#bootstrapWorktree` so
211
- // `/plan` remains git-state-free. `forkAndCommitEpicSnapshot` and
212
- // `forkMainToEpic` remain exported for that caller.
213
-
214
- const reviewRouting = resolveReviewRouting({ planningRisk, forceReview });
215
-
216
- // Record the planner-authored verdict as a structured artifact — the
217
- // audit trail the retired regex classifier never produced (Epic #3865).
218
- await upsertStructuredComment(
219
- provider,
220
- epicId,
221
- 'risk-verdict',
222
- buildRiskVerdictCommentBody({ epicId, riskVerdict, planningRisk }),
223
- );
224
-
225
- const currentState =
226
- (await readPlanState({ provider, epicId })) ??
227
- (await initializePlanState({ provider, epicId }));
228
- const checkpoint = await writePlanState({
229
- provider,
230
- epicId,
231
- state: {
232
- ...currentState,
233
- planningRisk,
234
- riskVerdict,
235
- reviewRouting: {
236
- decision: reviewRouting.decision,
237
- requiresStop: reviewRouting.requiresStop,
238
- forceReviewApplied: reviewRouting.forceReviewApplied,
239
- },
240
- spec: {
241
- ...currentState.spec,
242
- techSpecPersisted: planResult?.techSpecPersisted === true,
243
- acceptanceTable: planResult?.acceptanceTable ?? 'none',
244
- completedAt: new Date().toISOString(),
245
- },
246
- },
247
- });
248
-
249
- Logger.info(`[epic-plan-spec] Review routing: ${reviewRouting.decision}.`);
250
- Logger.info(`[epic-plan-spec] ${reviewRouting.operatorMessage}`);
251
-
252
- // Story #4019 (refining #3905): a spec-phase rerun that changed nothing
253
- // (planEpic short-circuited on `already-planned`) MUST NOT demote a
254
- // fully-decomposed `agent::ready` Epic back to `agent::review-spec` —
255
- // there is no new spec content to review. The demotion fires only when
256
- // the spec actually persisted/changed, or when the Epic is not at
257
- // `agent::ready` (where the flip is the normal forward transition).
258
- const epicLabels = afterPlan.labels ?? [];
259
- const skipDemotion = !specChanged && epicLabels.includes(AGENT_LABELS.READY);
260
- let labelTransition;
261
- if (skipDemotion) {
262
- labelTransition = 'kept-ready';
263
- Logger.info(
264
- `[epic-plan-spec] Spec unchanged (${planResult?.reason ?? 'already-planned'}) and Epic #${epicId} is ${AGENT_LABELS.READY} — keeping ${AGENT_LABELS.READY} (no demotion to ${AGENT_LABELS.REVIEW_SPEC}).`,
265
- );
266
- } else {
267
- labelTransition = 'review-spec';
268
- Logger.info(
269
- `[epic-plan-spec] Flipping Epic #${epicId} to ${AGENT_LABELS.REVIEW_SPEC}...`,
270
- );
271
- await setEpicLabel(provider, epicId, AGENT_LABELS.REVIEW_SPEC);
272
- }
273
-
274
- const cleanup = await cleanupPhaseTempFiles({ phase: 'spec', epicId });
275
-
276
- const acceptanceSummary =
277
- planResult?.acceptanceTable === 'persisted'
278
- ? ' + ## Acceptance Table section'
279
- : planResult?.acceptanceTable === 'waived'
280
- ? ' (acceptance waived)'
281
- : '';
282
- const freshnessSummary =
283
- freshness.stale > 0 || freshness.ambiguous > 0
284
- ? ` ⚠️ Spec freshness: ${freshness.stale} stale / ${freshness.ambiguous} ambiguous reference(s) — see ${freshness.reportPath ?? 'report'}.`
285
- : '';
286
- Logger.info(
287
- `[epic-plan-spec] ✅ Spec phase complete for Epic #${epicId}. Tech Spec sections folded into the Epic body${acceptanceSummary}.${freshnessSummary}`,
288
- );
289
- if (cleanup.deleted.length > 0) {
290
- Logger.info(
291
- `[epic-plan-spec] 🧹 Cleaned up ${cleanup.deleted.length} temp file(s).`,
292
- );
293
- }
294
-
295
- return {
296
- epicId,
297
- techSpecPersisted: planResult?.techSpecPersisted === true,
298
- acceptanceTable: planResult?.acceptanceTable ?? 'none',
299
- checkpoint,
300
- cleanup,
301
- freshness,
302
- planningRisk,
303
- reviewRouting,
304
- specChanged,
305
- labelTransition,
306
- };
307
- }
@@ -1,117 +0,0 @@
1
- /**
2
- * phases/spec-freshness.js — Tech Spec freshness check phase.
3
- *
4
- * Cross-validates the authored Tech Spec body against the base branch and
5
- * surfaces any stale path-shaped references on the Epic (Story #4324: the
6
- * Tech Spec is folded into the Epic body, so the Epic is the comment
7
- * target). Two side effects, both best-effort and non-blocking:
8
- *
9
- * 1. Write the full `{ stale, fresh, ambiguous }` report to
10
- * `<tempRoot>/epic-<id>-spec-freshness.json` so downstream tooling
11
- * (the `--code-freshness` health check on the roadmap, or an
12
- * operator inspecting the run) can read it without re-probing git.
13
- * 2. When `stale.length > 0`, upsert a `spec-freshness` structured
14
- * comment on the Epic listing each suspect citation.
15
- * The comment is upserted, so re-running spec re-renders the same
16
- * comment in place rather than spamming the issue.
17
- *
18
- * Caller signals are aggressive in containment — any error in this path
19
- * is downgraded to a warning. Phase 7 must not fail because a doc-author
20
- * cited a path the validator can't probe (e.g. shallow clone, base ref
21
- * not fetched). The non-blocking contract is the load-bearing AC.
22
- */
23
-
24
- import { mkdir, writeFile } from 'node:fs/promises';
25
- import path from 'node:path';
26
- import { Logger } from '../../../Logger.js';
27
- import {
28
- renderSpecFreshnessComment,
29
- validateSpecFreshness,
30
- } from '../../spec-freshness.js';
31
- import { upsertStructuredComment } from '../../ticketing.js';
32
-
33
- /**
34
- * @param {object} opts
35
- * @param {number} opts.epicId
36
- * @param {string} opts.techSpecContent
37
- * @param {string} opts.baseBranchRef
38
- * @param {string} opts.tempRoot
39
- * @param {import('../../../ITicketingProvider.js').ITicketingProvider} opts.provider
40
- * @param {Function} [opts.validator] - Testing seam (defaults to validateSpecFreshness).
41
- * @param {Function} [opts.commentUpserter] - Testing seam (defaults to upsertStructuredComment).
42
- * @param {Function} [opts.fileWriter] - Testing seam (defaults to fs writeFile/mkdir wrapper).
43
- * @returns {Promise<{ stale: number, ambiguous: number, fresh: number, reportPath: string|null, commentPosted: boolean }>}
44
- */
45
- export async function runSpecFreshnessCheck({
46
- epicId,
47
- techSpecContent,
48
- baseBranchRef,
49
- tempRoot,
50
- provider,
51
- validator = validateSpecFreshness,
52
- commentUpserter = upsertStructuredComment,
53
- fileWriter = async (filePath, body) => {
54
- await mkdir(path.dirname(filePath), { recursive: true });
55
- await writeFile(filePath, body, 'utf8');
56
- },
57
- }) {
58
- try {
59
- const report = validator(techSpecContent, { baseBranchRef });
60
- const reportPath = path.join(
61
- tempRoot,
62
- `epic-${epicId}-spec-freshness.json`,
63
- );
64
- const payload = {
65
- epicId,
66
- baseBranchRef,
67
- generatedAt: new Date().toISOString(),
68
- summary: {
69
- stale: report.stale.length,
70
- ambiguous: report.ambiguous.length,
71
- fresh: report.fresh.length,
72
- },
73
- ...report,
74
- };
75
- await fileWriter(reportPath, `${JSON.stringify(payload, null, 2)}\n`);
76
-
77
- let commentPosted = false;
78
- if (report.stale.length > 0 && Number.isFinite(epicId)) {
79
- const body = renderSpecFreshnessComment(report, {
80
- baseBranchRef,
81
- epicId,
82
- });
83
- await commentUpserter(provider, epicId, 'spec-freshness', body);
84
- commentPosted = true;
85
- }
86
-
87
- if (report.stale.length > 0 || report.ambiguous.length > 0) {
88
- Logger.warn(
89
- `[epic-plan-spec] Tech Spec freshness: ${report.stale.length} stale, ${report.ambiguous.length} ambiguous, ${report.fresh.length} fresh against ${baseBranchRef}. Report: ${reportPath}.`,
90
- );
91
- } else {
92
- Logger.info(
93
- `[epic-plan-spec] Tech Spec freshness: ${report.fresh.length} fresh references against ${baseBranchRef}. No drift detected.`,
94
- );
95
- }
96
-
97
- return {
98
- stale: report.stale.length,
99
- ambiguous: report.ambiguous.length,
100
- fresh: report.fresh.length,
101
- reportPath,
102
- commentPosted,
103
- };
104
- } catch (err) {
105
- Logger.warn(
106
- `[epic-plan-spec] Tech Spec freshness check skipped: ${err.message}`,
107
- );
108
- return {
109
- stale: 0,
110
- ambiguous: 0,
111
- fresh: 0,
112
- reportPath: null,
113
- commentPosted: false,
114
- error: err.message,
115
- };
116
- }
117
- }