mandrel 1.94.0 → 2.1.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 (560) hide show
  1. package/.agents/README.md +116 -99
  2. package/.agents/agents/acceptance-critic.md +9 -7
  3. package/.agents/agents/story-worker.md +45 -51
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +498 -1287
  6. package/.agents/docs/agentrc-reference.json +185 -80
  7. package/.agents/docs/configuration.md +132 -190
  8. package/.agents/docs/execution-reference.md +51 -25
  9. package/.agents/docs/quality-gates.md +25 -33
  10. package/.agents/docs/workflows.md +8 -8
  11. package/.agents/instructions.md +113 -139
  12. package/.agents/rules/ci-remediation.md +11 -15
  13. package/.agents/rules/git-conventions-reference.md +48 -58
  14. package/.agents/rules/git-conventions.md +16 -22
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  16. package/.agents/schemas/agentrc.schema.json +83 -254
  17. package/.agents/schemas/audit-rules.json +59 -1
  18. package/.agents/schemas/audit-rules.schema.json +33 -1
  19. package/.agents/schemas/lifecycle/README.md +1 -2
  20. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  21. package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
  22. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
  23. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  24. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  25. package/.agents/schemas/signal-event.schema.json +3 -3
  26. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  27. package/.agents/schemas/validation-evidence.schema.json +1 -1
  28. package/.agents/scripts/acceptance-eval.js +22 -66
  29. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  30. package/.agents/scripts/audit-to-stories.js +7 -7
  31. package/.agents/scripts/boot-sweep.js +1 -1
  32. package/.agents/scripts/bootstrap.js +3 -3
  33. package/.agents/scripts/check-dead-exports.js +43 -104
  34. package/.agents/scripts/check-doc-links.js +2 -2
  35. package/.agents/scripts/check-lifecycle-lint.js +7 -10
  36. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  37. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  38. package/.agents/scripts/deliver-recover.js +122 -0
  39. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  40. package/.agents/scripts/evidence-gate.js +20 -50
  41. package/.agents/scripts/generate-skills-index.js +17 -1
  42. package/.agents/scripts/generate-workflows-doc.js +4 -4
  43. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  44. package/.agents/scripts/lib/Logger.js +6 -10
  45. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  46. package/.agents/scripts/lib/audit-suite/selector.js +328 -28
  47. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  48. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  49. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
  50. package/.agents/scripts/lib/baselines/reader.js +1 -6
  51. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  52. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  53. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  54. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  55. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  56. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  57. package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
  58. package/.agents/scripts/lib/checks/index.js +3 -2
  59. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  60. package/.agents/scripts/lib/checks/state.js +17 -248
  61. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
  62. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  63. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  64. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  65. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  66. package/.agents/scripts/lib/cli-args.js +39 -9
  67. package/.agents/scripts/lib/close-validation/gates.js +15 -15
  68. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  69. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  70. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  71. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  72. package/.agents/scripts/lib/config/ci.js +6 -31
  73. package/.agents/scripts/lib/config/delivery-routing.js +52 -35
  74. package/.agents/scripts/lib/config/explain.js +61 -48
  75. package/.agents/scripts/lib/config/github.js +7 -5
  76. package/.agents/scripts/lib/config/limits.js +29 -80
  77. package/.agents/scripts/lib/config/paths.js +0 -2
  78. package/.agents/scripts/lib/config/quality.js +12 -15
  79. package/.agents/scripts/lib/config/runners.js +20 -66
  80. package/.agents/scripts/lib/config/temp-paths.js +30 -63
  81. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  82. package/.agents/scripts/lib/config-resolver.js +2 -7
  83. package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
  84. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
  85. package/.agents/scripts/lib/config-settings-schema.js +100 -60
  86. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  87. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  88. package/.agents/scripts/lib/dependency-parser.js +3 -2
  89. package/.agents/scripts/lib/doc-tiers.js +2 -2
  90. package/.agents/scripts/lib/duplicate-search.js +242 -41
  91. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  92. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  93. package/.agents/scripts/lib/format-generated-json.js +97 -0
  94. package/.agents/scripts/lib/framework-version.js +19 -190
  95. package/.agents/scripts/lib/gh-exec.js +8 -0
  96. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  97. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
  98. package/.agents/scripts/lib/git-utils.js +32 -20
  99. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  100. package/.agents/scripts/lib/json-utils.js +1 -2
  101. package/.agents/scripts/lib/label-constants.js +10 -38
  102. package/.agents/scripts/lib/label-taxonomy.js +10 -55
  103. package/.agents/scripts/lib/observability/active-story-env.js +44 -165
  104. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  105. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  106. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  107. package/.agents/scripts/lib/observability/source-classifier.js +5 -5
  108. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  109. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  110. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  111. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  112. package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
  113. package/.agents/scripts/lib/orchestration/code-review.js +78 -436
  114. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  115. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
  116. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  117. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  118. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  119. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  120. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  121. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  122. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  123. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  124. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  125. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
  126. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  127. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  128. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  129. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
  130. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  131. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  132. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  133. package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
  134. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  135. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  136. package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
  137. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
  138. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
  139. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  140. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  141. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
  142. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
  143. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  144. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
  145. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
  146. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
  147. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  148. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  149. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  150. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
  151. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  152. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
  153. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  154. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  155. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  156. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  157. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  158. package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
  159. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  160. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  161. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  162. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  163. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  164. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  165. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  166. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  167. package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
  168. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
  169. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  170. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  171. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
  172. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  173. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
  174. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  175. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  176. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
  177. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  178. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  179. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
  180. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  181. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  182. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  183. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  184. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  185. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  186. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  187. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
  188. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  189. package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
  190. package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
  191. package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
  192. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  193. package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
  194. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  195. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
  196. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
  197. package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
  198. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
  199. package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
  200. package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
  201. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  202. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  203. package/.agents/scripts/lib/planning-corpus.js +12 -281
  204. package/.agents/scripts/lib/preflight-runner.js +4 -4
  205. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  206. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  207. package/.agents/scripts/lib/signals/index.js +4 -17
  208. package/.agents/scripts/lib/signals/read.js +35 -35
  209. package/.agents/scripts/lib/signals/schema.js +8 -11
  210. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  211. package/.agents/scripts/lib/signals/write.js +0 -1
  212. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  213. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  214. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  215. package/.agents/scripts/lib/story-adjacency.js +17 -19
  216. package/.agents/scripts/lib/story-body/story-body.js +130 -75
  217. package/.agents/scripts/lib/story-plan.js +2 -4
  218. package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
  219. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  220. package/.agents/scripts/lib/test-env.js +14 -1
  221. package/.agents/scripts/lib/test-tiers.js +0 -3
  222. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
  223. package/.agents/scripts/lib/validation-evidence.js +32 -60
  224. package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
  225. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  226. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  227. package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
  228. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  229. package/.agents/scripts/lint-issue-body.js +71 -40
  230. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  231. package/.agents/scripts/notify.js +4 -3
  232. package/.agents/scripts/plan-context.js +102 -80
  233. package/.agents/scripts/plan-persist.js +230 -279
  234. package/.agents/scripts/plan-run-epilogue.js +142 -0
  235. package/.agents/scripts/post-structured-comment.js +0 -38
  236. package/.agents/scripts/pr-watch-with-update.js +43 -22
  237. package/.agents/scripts/providers/github/compose.js +0 -1
  238. package/.agents/scripts/providers/github/errors.js +0 -19
  239. package/.agents/scripts/providers/github/issues.js +13 -39
  240. package/.agents/scripts/providers/github/mappers.js +5 -12
  241. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  242. package/.agents/scripts/providers/github/tickets.js +33 -156
  243. package/.agents/scripts/providers/github.js +17 -6
  244. package/.agents/scripts/resolve-stories.js +236 -0
  245. package/.agents/scripts/run-coverage.js +4 -1
  246. package/.agents/scripts/run-lint.js +2 -2
  247. package/.agents/scripts/run-verify.js +31 -2
  248. package/.agents/scripts/signals-view.js +25 -21
  249. package/.agents/scripts/single-story-close.js +178 -26
  250. package/.agents/scripts/single-story-confirm-merge.js +313 -24
  251. package/.agents/scripts/single-story-init.js +35 -30
  252. package/.agents/scripts/stories-wave-tick.js +85 -10
  253. package/.agents/scripts/story-plan.js +28 -49
  254. package/.agents/scripts/update-ticket-state.js +14 -65
  255. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  256. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  257. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  258. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  259. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  260. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  261. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  262. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  263. package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
  264. package/.agents/skills/core/scope-triage/SKILL.md +31 -172
  265. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  266. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  267. package/.agents/skills/skills.index.json +3 -53
  268. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  269. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  270. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  271. package/.agents/starter-agentrc.json +0 -5
  272. package/.agents/templates/agent-protocol.md +9 -10
  273. package/.agents/workflows/audit-architecture.md +6 -7
  274. package/.agents/workflows/audit-clean-code.md +7 -7
  275. package/.agents/workflows/audit-dependencies.md +3 -3
  276. package/.agents/workflows/audit-devops.md +3 -3
  277. package/.agents/workflows/audit-documentation.md +9 -10
  278. package/.agents/workflows/audit-lighthouse.md +11 -3
  279. package/.agents/workflows/audit-navigability.md +13 -2
  280. package/.agents/workflows/audit-performance.md +5 -6
  281. package/.agents/workflows/audit-privacy.md +3 -3
  282. package/.agents/workflows/audit-quality.md +11 -12
  283. package/.agents/workflows/audit-security.md +4 -5
  284. package/.agents/workflows/audit-seo.md +13 -3
  285. package/.agents/workflows/audit-sre.md +3 -3
  286. package/.agents/workflows/audit-to-stories.md +20 -20
  287. package/.agents/workflows/audit-ux-ui.md +10 -3
  288. package/.agents/workflows/deliver.md +177 -176
  289. package/.agents/workflows/git-cleanup.md +5 -6
  290. package/.agents/workflows/git-deliver.md +1 -1
  291. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  292. package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
  293. package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
  294. package/.agents/workflows/helpers/code-review.md +75 -196
  295. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
  296. package/.agents/workflows/helpers/deliver-story.md +606 -0
  297. package/.agents/workflows/helpers/diagnose.md +10 -10
  298. package/.agents/workflows/helpers/parallel-tooling.md +3 -3
  299. package/.agents/workflows/helpers/signals.md +16 -16
  300. package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
  301. package/.agents/workflows/mandrel-update.md +2 -1
  302. package/.agents/workflows/plan.md +277 -145
  303. package/.agents/workflows/qa-assist.md +27 -33
  304. package/.agents/workflows/qa-explore.md +29 -38
  305. package/.agents/workflows/qa-run.md +2 -6
  306. package/README.md +9 -8
  307. package/bin/mandrel.js +12 -1
  308. package/docs/CHANGELOG.md +70 -0
  309. package/lib/cli/registry.js +262 -19
  310. package/lib/cli/sync-agents.js +157 -0
  311. package/lib/cli/sync-commands.js +115 -6
  312. package/lib/cli/sync.js +168 -6
  313. package/lib/cli/update.js +105 -8
  314. package/lib/cli/version-helpers.js +131 -0
  315. package/lib/migrations/README.md +7 -5
  316. package/lib/migrations/index.js +12 -8
  317. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  318. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  319. package/package.json +2 -2
  320. package/.agents/agents/retro.md +0 -42
  321. package/.agents/personas/architect.md +0 -113
  322. package/.agents/personas/devops-engineer.md +0 -38
  323. package/.agents/personas/engineer.md +0 -33
  324. package/.agents/personas/project-manager.md +0 -114
  325. package/.agents/personas/qa-engineer.md +0 -95
  326. package/.agents/personas/security-engineer.md +0 -111
  327. package/.agents/personas/technical-writer.md +0 -101
  328. package/.agents/schemas/dispatch-manifest.json +0 -232
  329. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  330. package/.agents/schemas/epic-spec.schema.json +0 -153
  331. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  332. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  333. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  334. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  335. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  336. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  337. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  338. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  339. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  340. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  341. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  342. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  343. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  344. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  345. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  346. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  347. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  348. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  349. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  350. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  351. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  352. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  353. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  354. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  355. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  356. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  357. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  358. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  359. package/.agents/schemas/risk-verdict.schema.json +0 -66
  360. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  361. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  362. package/.agents/scripts/analyze-execution.js +0 -444
  363. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  364. package/.agents/scripts/check-prepush-recovery.js +0 -90
  365. package/.agents/scripts/dispatcher.js +0 -295
  366. package/.agents/scripts/epic-audit-prepare.js +0 -497
  367. package/.agents/scripts/epic-audit-recheck.js +0 -274
  368. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  369. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  370. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  371. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  372. package/.agents/scripts/epic-plan-clarity.js +0 -211
  373. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  374. package/.agents/scripts/epic-reconcile.js +0 -625
  375. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  376. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  377. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  378. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  379. package/.agents/scripts/lib/config/preflight.js +0 -58
  380. package/.agents/scripts/lib/config/retro.js +0 -77
  381. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  382. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  383. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  384. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  385. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  386. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
  387. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  388. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  389. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  390. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
  391. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  392. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  393. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  394. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  395. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  396. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  397. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  398. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  399. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  400. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  401. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  402. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  403. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  404. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  405. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  406. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  407. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  408. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
  409. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  410. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  411. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  412. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  413. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  414. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  415. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  416. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  417. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  418. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  419. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  420. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  421. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  422. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  423. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  424. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  425. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  426. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
  427. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  428. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  429. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  430. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  431. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  432. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  433. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  434. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  435. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  436. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  437. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  438. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  439. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  440. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  441. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  442. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  443. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  444. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  445. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  446. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  447. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  448. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  449. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  450. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  451. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  452. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  453. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  454. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  455. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  456. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  457. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  458. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  459. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  460. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  461. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
  462. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  463. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  464. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  465. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
  466. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  467. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  468. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  469. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  470. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  471. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  472. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  473. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  474. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  475. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  476. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  477. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  478. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  479. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  480. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  481. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  482. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  483. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  484. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  485. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  486. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  487. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  488. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  489. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  490. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  491. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  492. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  493. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  494. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  495. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  496. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  497. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  498. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  499. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  500. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  501. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  502. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  503. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  504. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  505. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  506. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  507. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  508. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  509. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  510. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  511. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  512. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  513. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  514. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  515. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  516. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  517. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  518. package/.agents/scripts/lib/spec/index.js +0 -36
  519. package/.agents/scripts/lib/spec/loader.js +0 -425
  520. package/.agents/scripts/lib/spec/state.js +0 -208
  521. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  522. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  523. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  524. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  525. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  526. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  527. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  528. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  529. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  530. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  531. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  532. package/.agents/scripts/lifecycle-emit.js +0 -510
  533. package/.agents/scripts/retro-run.js +0 -218
  534. package/.agents/scripts/slice-phase.js +0 -361
  535. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  536. package/.agents/scripts/story-close.js +0 -294
  537. package/.agents/scripts/story-init.js +0 -599
  538. package/.agents/scripts/story-phase.js +0 -369
  539. package/.agents/scripts/wave-tick.js +0 -464
  540. package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
  541. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  542. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  543. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  544. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  545. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  546. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  547. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  548. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  549. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  550. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  551. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  552. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  553. package/.agents/workflows/helpers/epic-audit.md +0 -189
  554. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  555. package/.agents/workflows/helpers/epic-testing.md +0 -125
  556. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  557. package/.agents/workflows/helpers/plan-epic.md +0 -353
  558. package/.agents/workflows/helpers/plan-story.md +0 -251
  559. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  560. package/.agents/workflows/helpers/single-story-deliver.md +0 -557
@@ -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,105 +0,0 @@
1
- /**
2
- * phases/risk-verdict.js — read + schema-validate the planner-authored
3
- * risk verdict (Epic #3865).
4
- *
5
- * The `epic-plan-spec-author` Skill writes `risk-verdict.json` as the
6
- * fourth planning artifact; the persist half of `epic-plan-spec.js` loads
7
- * it through this module before deriving the planningRisk envelope. A
8
- * missing, unparseable, or schema-invalid verdict throws — the spec phase
9
- * fails closed rather than mis-routing the review gate.
10
- */
11
-
12
- import { readFileSync } from 'node:fs';
13
- import path from 'node:path';
14
- import { fileURLToPath } from 'node:url';
15
-
16
- import Ajv2020 from 'ajv/dist/2020.js';
17
- import addFormats from 'ajv-formats';
18
-
19
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
-
21
- export const RISK_VERDICT_SCHEMA_PATH = path.resolve(
22
- __dirname,
23
- '..',
24
- '..',
25
- '..',
26
- '..',
27
- '..',
28
- 'schemas',
29
- 'risk-verdict.schema.json',
30
- );
31
-
32
- /** @type {Map<string, import('ajv').ValidateFunction>} */
33
- const validatorCache = new Map();
34
-
35
- /**
36
- * Compile (and cache) the Ajv2020 validator for the risk-verdict schema.
37
- *
38
- * @param {string} schemaPath
39
- * @param {{ readFileSync: typeof readFileSync }} io
40
- * @returns {import('ajv').ValidateFunction}
41
- */
42
- function getRiskVerdictValidator(schemaPath, io) {
43
- const cached = validatorCache.get(schemaPath);
44
- if (cached) return cached;
45
- const ajv = new Ajv2020({ allErrors: true, strict: false });
46
- addFormats(ajv);
47
- const schema = JSON.parse(io.readFileSync(schemaPath, 'utf8'));
48
- const validate = ajv.compile(schema);
49
- validatorCache.set(schemaPath, validate);
50
- return validate;
51
- }
52
-
53
- /**
54
- * Validate a parsed risk verdict against the schema. Throws with the full
55
- * Ajv error detail on any violation so the spec phase never routes the
56
- * review gate off a malformed verdict.
57
- *
58
- * @param {unknown} verdict
59
- * @param {{ schemaPath?: string, io?: { readFileSync: typeof readFileSync } }} [opts]
60
- * @returns {import('../../planning-risk.js').RiskVerdict} The validated verdict (same reference).
61
- */
62
- export function validateRiskVerdict(verdict, opts = {}) {
63
- const validate = getRiskVerdictValidator(
64
- opts.schemaPath ?? RISK_VERDICT_SCHEMA_PATH,
65
- opts.io ?? { readFileSync },
66
- );
67
- if (!validate(verdict)) {
68
- const detail = (validate.errors ?? [])
69
- .map((e) => `${e.instancePath || '/'} ${e.message}`)
70
- .join('; ');
71
- throw new Error(
72
- `[epic-plan-spec] risk verdict failed schema validation: ${detail}`,
73
- );
74
- }
75
- return /** @type {import('../../planning-risk.js').RiskVerdict} */ (verdict);
76
- }
77
-
78
- /**
79
- * Read, parse, and schema-validate the risk-verdict file the
80
- * `epic-plan-spec-author` Skill wrote.
81
- *
82
- * @param {string} verdictPath
83
- * @param {{ schemaPath?: string, io?: { readFileSync: typeof readFileSync } }} [opts]
84
- * @returns {import('../../planning-risk.js').RiskVerdict}
85
- */
86
- export function loadRiskVerdict(verdictPath, opts = {}) {
87
- const io = opts.io ?? { readFileSync };
88
- let raw;
89
- try {
90
- raw = io.readFileSync(verdictPath, 'utf8');
91
- } catch (err) {
92
- throw new Error(
93
- `[epic-plan-spec] cannot read risk verdict at ${verdictPath}: ${err.message}`,
94
- );
95
- }
96
- let parsed;
97
- try {
98
- parsed = JSON.parse(raw);
99
- } catch (err) {
100
- throw new Error(
101
- `[epic-plan-spec] risk verdict at ${verdictPath} is not valid JSON: ${err.message}`,
102
- );
103
- }
104
- return validateRiskVerdict(parsed, opts);
105
- }
@@ -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
- }