mandrel 1.93.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 (463) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/acceptance-critic.md +129 -0
  3. package/.agents/agents/story-worker.md +161 -0
  4. package/.agents/docs/SDLC.md +489 -1285
  5. package/.agents/docs/agentrc-reference.json +177 -67
  6. package/.agents/docs/configuration.md +108 -136
  7. package/.agents/docs/execution-reference.md +44 -22
  8. package/.agents/docs/quality-gates.md +13 -19
  9. package/.agents/docs/workflows.md +3 -3
  10. package/.agents/instructions.md +107 -108
  11. package/.agents/rules/ci-remediation.md +8 -12
  12. package/.agents/rules/git-conventions-reference.md +224 -0
  13. package/.agents/rules/git-conventions.md +42 -223
  14. package/.agents/rules/security-baseline.md +5 -0
  15. package/.agents/rules/testing-standards.md +106 -13
  16. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  17. package/.agents/schemas/agentrc.schema.json +71 -201
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  20. package/.agents/schemas/risk-verdict.schema.json +0 -13
  21. package/.agents/scripts/acceptance-eval.js +62 -18
  22. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  23. package/.agents/scripts/analyze-execution.js +1 -1
  24. package/.agents/scripts/audit-to-stories.js +7 -7
  25. package/.agents/scripts/boot-sweep.js +1 -1
  26. package/.agents/scripts/check-context-budget.js +62 -5
  27. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  28. package/.agents/scripts/check-prepush-recovery.js +1 -1
  29. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  30. package/.agents/scripts/diagnose-friction.js +0 -6
  31. package/.agents/scripts/lib/Logger.js +6 -10
  32. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  33. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  34. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  35. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  36. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  37. package/.agents/scripts/lib/baselines/reader.js +1 -6
  38. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  39. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  40. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  41. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  42. package/.agents/scripts/lib/checks/index.js +2 -1
  43. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  44. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  45. package/.agents/scripts/lib/cli-args.js +16 -7
  46. package/.agents/scripts/lib/close-validation/gates.js +160 -22
  47. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  48. package/.agents/scripts/lib/config/ci.js +6 -31
  49. package/.agents/scripts/lib/config/delivery-routing.js +103 -0
  50. package/.agents/scripts/lib/config/explain.js +57 -36
  51. package/.agents/scripts/lib/config/limits.js +17 -58
  52. package/.agents/scripts/lib/config/paths.js +0 -2
  53. package/.agents/scripts/lib/config/quality.js +1 -1
  54. package/.agents/scripts/lib/config/runners.js +17 -50
  55. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  56. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  57. package/.agents/scripts/lib/config-resolver.js +3 -8
  58. package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
  59. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
  60. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  61. package/.agents/scripts/lib/dependency-parser.js +3 -2
  62. package/.agents/scripts/lib/doc-tiers.js +39 -4
  63. package/.agents/scripts/lib/duplicate-search.js +211 -41
  64. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  66. package/.agents/scripts/lib/framework-version.js +2 -3
  67. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  68. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  69. package/.agents/scripts/lib/git-utils.js +32 -6
  70. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  71. package/.agents/scripts/lib/label-constants.js +10 -23
  72. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  73. package/.agents/scripts/lib/observability/active-story-env.js +112 -3
  74. package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
  75. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  76. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  77. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  78. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  79. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  80. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  81. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
  82. package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
  83. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  84. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  85. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  86. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  87. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  88. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  89. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  90. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  91. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  92. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  93. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  94. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  95. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  96. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  97. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  98. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  99. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  100. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  102. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  103. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  104. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  105. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  106. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  107. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  108. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
  109. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  110. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  111. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  112. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  113. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  114. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  115. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  116. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  118. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  119. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  120. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  121. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  122. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  124. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  131. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  132. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  134. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  135. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  136. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  137. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  138. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  139. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  140. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  141. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  142. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  143. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  144. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  145. package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
  146. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  147. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  148. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  149. package/.agents/scripts/lib/planning-corpus.js +16 -11
  150. package/.agents/scripts/lib/preflight-runner.js +2 -2
  151. package/.agents/scripts/lib/provider-factory.js +1 -1
  152. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  153. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  154. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  155. package/.agents/scripts/lib/story-adjacency.js +11 -14
  156. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  157. package/.agents/scripts/lib/story-plan.js +2 -4
  158. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  159. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  160. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  161. package/.agents/scripts/lib/validation-evidence.js +1 -1
  162. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  163. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  164. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  165. package/.agents/scripts/lint-issue-body.js +71 -40
  166. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  167. package/.agents/scripts/notify.js +4 -3
  168. package/.agents/scripts/plan-context.js +64 -74
  169. package/.agents/scripts/plan-persist.js +121 -280
  170. package/.agents/scripts/plan-run-epilogue.js +97 -0
  171. package/.agents/scripts/post-structured-comment.js +38 -0
  172. package/.agents/scripts/providers/github/issues.js +17 -33
  173. package/.agents/scripts/providers/github/mappers.js +0 -12
  174. package/.agents/scripts/providers/github/tickets.js +2 -5
  175. package/.agents/scripts/resolve-plan-run.js +117 -0
  176. package/.agents/scripts/signals-view.js +24 -19
  177. package/.agents/scripts/single-story-close.js +11 -14
  178. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  179. package/.agents/scripts/single-story-init.js +29 -20
  180. package/.agents/scripts/stories-wave-tick.js +6 -6
  181. package/.agents/scripts/story-plan.js +26 -47
  182. package/.agents/scripts/sync-claude-agents.js +165 -0
  183. package/.agents/scripts/update-ticket-state.js +37 -15
  184. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  185. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  186. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  187. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  188. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  189. package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
  190. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  191. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  192. package/.agents/skills/skills.index.json +8 -418
  193. package/.agents/starter-agentrc.json +0 -5
  194. package/.agents/templates/agent-protocol.md +9 -10
  195. package/.agents/workflows/audit-architecture.md +3 -3
  196. package/.agents/workflows/audit-clean-code.md +3 -3
  197. package/.agents/workflows/audit-dependencies.md +3 -3
  198. package/.agents/workflows/audit-devops.md +3 -3
  199. package/.agents/workflows/audit-documentation.md +5 -5
  200. package/.agents/workflows/audit-lighthouse.md +3 -3
  201. package/.agents/workflows/audit-navigability.md +3 -2
  202. package/.agents/workflows/audit-performance.md +3 -3
  203. package/.agents/workflows/audit-privacy.md +3 -3
  204. package/.agents/workflows/audit-quality.md +3 -3
  205. package/.agents/workflows/audit-security.md +3 -3
  206. package/.agents/workflows/audit-seo.md +3 -3
  207. package/.agents/workflows/audit-sre.md +3 -3
  208. package/.agents/workflows/audit-to-stories.md +20 -20
  209. package/.agents/workflows/audit-ux-ui.md +3 -3
  210. package/.agents/workflows/deliver.md +122 -131
  211. package/.agents/workflows/git-cleanup.md +3 -4
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
  214. package/.agents/workflows/helpers/code-review.md +70 -193
  215. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  216. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  217. package/.agents/workflows/helpers/diagnose.md +10 -10
  218. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  219. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  220. package/.agents/workflows/helpers/signals.md +16 -16
  221. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  222. package/.agents/workflows/mandrel-update.md +3 -2
  223. package/.agents/workflows/plan.md +112 -145
  224. package/.agents/workflows/qa-assist.md +24 -30
  225. package/.agents/workflows/qa-explore.md +29 -38
  226. package/.agents/workflows/qa-run.md +2 -2
  227. package/README.md +9 -8
  228. package/docs/CHANGELOG.md +46 -0
  229. package/lib/cli/registry.js +95 -0
  230. package/lib/migrations/index.js +6 -5
  231. package/package.json +5 -3
  232. package/.agents/personas/architect.md +0 -113
  233. package/.agents/personas/devops-engineer.md +0 -38
  234. package/.agents/personas/engineer-mobile.md +0 -120
  235. package/.agents/personas/engineer-web.md +0 -111
  236. package/.agents/personas/engineer.md +0 -119
  237. package/.agents/personas/product.md +0 -94
  238. package/.agents/personas/project-manager.md +0 -114
  239. package/.agents/personas/qa-engineer.md +0 -95
  240. package/.agents/personas/refactorer.md +0 -113
  241. package/.agents/personas/security-engineer.md +0 -112
  242. package/.agents/personas/sre.md +0 -86
  243. package/.agents/personas/technical-writer.md +0 -101
  244. package/.agents/personas/ux-designer.md +0 -95
  245. package/.agents/schemas/dispatch-manifest.json +0 -232
  246. package/.agents/schemas/epic-spec.schema.json +0 -153
  247. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  248. package/.agents/scripts/dispatcher.js +0 -295
  249. package/.agents/scripts/epic-audit-prepare.js +0 -497
  250. package/.agents/scripts/epic-audit-recheck.js +0 -274
  251. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  252. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  253. package/.agents/scripts/epic-deliver-prepare.js +0 -590
  254. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  255. package/.agents/scripts/epic-plan-clarity.js +0 -211
  256. package/.agents/scripts/epic-plan-decompose.js +0 -54
  257. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  258. package/.agents/scripts/epic-plan-spec.js +0 -64
  259. package/.agents/scripts/epic-reconcile.js +0 -625
  260. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  261. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  262. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  263. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  264. package/.agents/scripts/lib/config/preflight.js +0 -58
  265. package/.agents/scripts/lib/config/retro.js +0 -77
  266. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  267. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  268. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  269. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
  270. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  271. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  272. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  273. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  274. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  275. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  276. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  277. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  278. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  279. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  280. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  281. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  282. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  283. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  284. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  285. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  286. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  287. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  288. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
  289. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  290. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  291. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  292. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  293. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  294. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  295. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  296. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  297. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  298. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  299. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  300. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  301. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  302. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  303. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  304. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  305. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  306. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  307. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  308. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  309. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  310. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  311. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  313. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
  314. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  315. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  316. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  317. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
  318. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  319. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  320. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  321. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  322. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  323. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  324. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  325. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  326. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  327. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  328. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  329. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  330. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  331. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  332. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  333. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  334. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  335. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  336. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  337. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  338. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  339. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  340. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  341. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  342. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  343. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  344. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  345. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  346. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  347. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  348. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  349. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  350. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  351. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  352. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  353. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  354. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  355. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  356. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  357. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  358. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  359. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  360. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  361. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
  362. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  363. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  364. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  365. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  366. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  367. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  368. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  369. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  370. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  371. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  372. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  373. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  374. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  375. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  376. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  377. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  378. package/.agents/scripts/lib/spec/index.js +0 -36
  379. package/.agents/scripts/lib/spec/loader.js +0 -425
  380. package/.agents/scripts/lib/spec/state.js +0 -208
  381. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  382. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  383. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  384. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  385. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  386. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  387. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  388. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  389. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  390. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  391. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  392. package/.agents/scripts/lifecycle-emit.js +0 -510
  393. package/.agents/scripts/plan-critics.js +0 -199
  394. package/.agents/scripts/retro-run.js +0 -218
  395. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  396. package/.agents/scripts/story-close.js +0 -294
  397. package/.agents/scripts/story-init.js +0 -599
  398. package/.agents/scripts/story-phase.js +0 -369
  399. package/.agents/scripts/wave-tick.js +0 -335
  400. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  401. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  402. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  403. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  404. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  405. package/.agents/skills/core/context-engineering/examples.md +0 -58
  406. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  407. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  408. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  409. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  410. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  411. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  412. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  413. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
  414. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  415. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  416. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  417. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  418. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  419. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  420. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  421. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  422. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  423. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  424. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  425. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  426. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  427. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  428. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  429. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  430. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  431. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  432. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  433. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  434. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  435. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  436. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  437. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  438. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  439. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  440. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  441. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  442. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  443. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  444. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  445. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  446. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  447. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  448. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  449. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  450. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  451. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  452. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
  453. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
  454. package/.agents/workflows/helpers/deliver-epic.md +0 -955
  455. package/.agents/workflows/helpers/deliver-stories.md +0 -440
  456. package/.agents/workflows/helpers/epic-audit.md +0 -189
  457. package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
  458. package/.agents/workflows/helpers/epic-testing.md +0 -125
  459. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  460. package/.agents/workflows/helpers/plan-epic.md +0 -351
  461. package/.agents/workflows/helpers/plan-story.md +0 -251
  462. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  463. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,72 +0,0 @@
1
- /**
2
- * diagnostics.js — partial-failure diagnostics for epic-plan-decompose
3
- * (Story #2466).
4
- *
5
- * `reportPartialFailure({ epicId, provider, err })` is invoked from the
6
- * CLI shell after `runDecomposePhase` throws — typically GitHub
7
- * secondary-RL after dozens of issue creations. The function is
8
- * intentionally defensive: never throws, never eclipses the original
9
- * failure, and always emits the "to resume" hint as the final lines.
10
- *
11
- * @module lib/orchestration/epic-plan-decompose/phases/diagnostics
12
- */
13
-
14
- import { Logger } from '../../../Logger.js';
15
- import { TYPE_LABELS } from '../../../label-constants.js';
16
-
17
- /**
18
- * Count open child tickets under the Epic without distinguishing by
19
- * type. Under the 2-tier hierarchy (Epic → Story), child
20
- * tickets are always Stories.
21
- */
22
- async function emitOpenChildrenDiagnostic(provider, epicId) {
23
- if (typeof provider.getSubTickets !== 'function') return;
24
- // Story #3455 — scope to the Epic's sub-issue graph instead of
25
- // `getTickets`'s repo-wide `state=all` scan. The diagnostic explicitly
26
- // counts `state !== 'closed'`, so the scoped fetch (which still surfaces
27
- // closed children) yields the same open-child count without paging
28
- // every issue in the repo.
29
- const existing = await provider.getSubTickets(epicId);
30
- const childTypes = [TYPE_LABELS.STORY];
31
- const created = (existing || []).filter(
32
- (t) =>
33
- (t.labels || []).some((l) => childTypes.includes(l)) &&
34
- t.state !== 'closed',
35
- ).length;
36
- Logger.error(
37
- `[epic-plan-decompose] Children currently open under Epic: ${created}`,
38
- );
39
- }
40
-
41
- async function emitLifecycleLabelDiagnostic(provider, epicId) {
42
- if (typeof provider.getEpic !== 'function') return;
43
- const epic = await provider.getEpic(epicId);
44
- const lifecycleLabel =
45
- (epic?.labels || []).find((l) => l.startsWith('agent::')) ?? 'unknown';
46
- Logger.error(
47
- `[epic-plan-decompose] Epic #${epicId} current label: ${lifecycleLabel}`,
48
- );
49
- }
50
-
51
- /**
52
- * Best-effort recovery diagnostics. Never throws.
53
- */
54
- export async function reportPartialFailure({ epicId, provider, err }) {
55
- Logger.error('');
56
- Logger.error('[epic-plan-decompose] ❌ Decompose phase aborted.');
57
- Logger.error(`[epic-plan-decompose] Reason: ${err?.message ?? err}`);
58
- try {
59
- await emitLifecycleLabelDiagnostic(provider, epicId);
60
- await emitOpenChildrenDiagnostic(provider, epicId);
61
- } catch (probeErr) {
62
- Logger.error(
63
- `[epic-plan-decompose] (diagnostics probe failed: ${probeErr.message})`,
64
- );
65
- }
66
- Logger.error('');
67
- Logger.error('[epic-plan-decompose] To resume from the partial backlog:');
68
- Logger.error(
69
- `[epic-plan-decompose] node .agents/scripts/epic-plan-decompose.js --epic ${epicId} --tickets <tickets-file> --resume`,
70
- );
71
- Logger.error('');
72
- }
@@ -1,156 +0,0 @@
1
- /**
2
- * persist-helpers.js — pure helpers split out of `persist.js` so the
3
- * orchestrator stays under Story #2466's 200-LOC ceiling.
4
- *
5
- * Exports:
6
- * - `assertDecomposeInputs(epic, epicId, tickets)` — entry guards.
7
- * - `buildEpicSpecInput(epic, epicId)` — projection used by
8
- * `renderSpec`; the Epic body already carries the folded planning
9
- * spec body carries the `## Planning Artifacts` section the
10
- * cascade-close path depends on.
11
- * - `validateTickets(tickets, config)` — runs the cross-link / freshness
12
- * normaliser and the task-body validator in one pass.
13
- * - `seedPlanState(provider, epicId, epic)` — initialise + flip the
14
- * `epic-plan-state` checkpoint to the decomposing phase.
15
- * - `recordCheckpoint(provider, epicId, tickets)` — write the final
16
- * `decompose.completedAt` + `ticketCount` checkpoint after apply.
17
- * - `logCleanupSummary(cleanup, epicId, ticketCount)` — terminal log.
18
- *
19
- * @module lib/orchestration/epic-plan-decompose/phases/persist-helpers
20
- */
21
-
22
- import { hasTechSpecContent } from '../../../epic-body-sections.js';
23
- import { gitSpawn } from '../../../git-utils.js';
24
- import { Logger } from '../../../Logger.js';
25
- import { TYPE_LABELS } from '../../../label-constants.js';
26
- import {
27
- initialize as initializePlanState,
28
- read as readPlanState,
29
- write as writePlanState,
30
- } from '../../epic-plan-state-store.js';
31
- import { validateTaskBodies } from '../../task-body-validator.js';
32
- import { validateAndNormalizeTickets } from '../../ticket-validator.js';
33
- import { resolveConflictPolicy } from './planning-artifacts.js';
34
-
35
- export function assertDecomposeInputs(epic, epicId, tickets) {
36
- if (!epic) {
37
- throw new Error(`[epic-plan-decompose] Epic #${epicId} not found.`);
38
- }
39
- if (!epic.labels?.includes(TYPE_LABELS.EPIC)) {
40
- throw new Error(
41
- `[epic-plan-decompose] Ticket #${epicId} is not a ${TYPE_LABELS.EPIC}.`,
42
- );
43
- }
44
- if (!hasTechSpecContent(epic.body ?? '')) {
45
- throw new Error(
46
- `[epic-plan-decompose] Epic #${epicId} body carries no Tech Spec sections (no ## Delivery Slicing). Run /plan Phase 7 first.`,
47
- );
48
- }
49
- if (!Array.isArray(tickets)) {
50
- throw new Error(
51
- `[epic-plan-decompose] tickets must be an array (got ${typeof tickets}).`,
52
- );
53
- }
54
- }
55
-
56
- export function buildEpicSpecInput(epic, epicId) {
57
- const epicBody = epic.body ?? '';
58
- const epicSpecInput = { id: epicId, title: epic.title };
59
- if (epicBody.length > 0) epicSpecInput.body = epicBody;
60
- return epicSpecInput;
61
- }
62
-
63
- /**
64
- * Default fan-out counter — counts distinct files at `baseBranchRef` that
65
- * reference the basename (without extension) of the deleted path. Uses
66
- * `git grep -l` for a streaming-friendly probe; an empty grep returns
67
- * exit code 1 which we map to a count of 0.
68
- *
69
- * Story #2962. Injected via opts in tests; this default runs in production.
70
- */
71
- export function makeDefaultFanOutCounter({ baseBranchRef, cwd }) {
72
- return ({ path }) => {
73
- const lastSlash = path.lastIndexOf('/');
74
- const base = lastSlash === -1 ? path : path.slice(lastSlash + 1);
75
- const dotIdx = base.lastIndexOf('.');
76
- const stem = dotIdx > 0 ? base.slice(0, dotIdx) : base;
77
- if (stem.length < 3) return 0;
78
- const result = gitSpawn(
79
- cwd ?? process.cwd(),
80
- 'grep',
81
- '-l',
82
- '--fixed-strings',
83
- stem,
84
- baseBranchRef,
85
- );
86
- if (result.status !== 0) return 0;
87
- const lines = result.stdout.split('\n').filter((l) => l.trim().length > 0);
88
- // Exclude the deleted file itself from the call-site count.
89
- return lines.filter((l) => !l.endsWith(`:${path}`)).length;
90
- };
91
- }
92
-
93
- export function validateTickets(tickets, config, opts = {}) {
94
- const baseBranchRef = config?.baseBranch ?? 'main';
95
- const conflictPolicy = resolveConflictPolicy(config);
96
- if (typeof opts.fanOutCounter === 'function') {
97
- conflictPolicy.fanOutCounter = opts.fanOutCounter;
98
- } else if (!conflictPolicy.fanOutCounter) {
99
- conflictPolicy.fanOutCounter = makeDefaultFanOutCounter({
100
- baseBranchRef,
101
- cwd: opts.cwd,
102
- });
103
- }
104
- const validated = validateAndNormalizeTickets(tickets, {
105
- baseBranchRef,
106
- conflictPolicy,
107
- // Thread the repo cwd into the AC-freshness / file-assumption git
108
- // probes (#4474 PR7) — without it they silently ran against
109
- // process.cwd(), which is only the repo root by coincidence.
110
- cwd: opts.cwd,
111
- });
112
- validateTaskBodies(validated);
113
- return validated;
114
- }
115
-
116
- export async function seedPlanState(provider, epicId, epic) {
117
- await initializePlanState({
118
- provider,
119
- epicId,
120
- seed: {
121
- spec: {
122
- techSpecPersisted: hasTechSpecContent(epic.body ?? ''),
123
- completedAt: null,
124
- },
125
- },
126
- });
127
- }
128
-
129
- export async function recordCheckpoint(provider, epicId, tickets) {
130
- const currentState =
131
- (await readPlanState({ provider, epicId })) ??
132
- (await initializePlanState({ provider, epicId }));
133
- return writePlanState({
134
- provider,
135
- epicId,
136
- state: {
137
- ...currentState,
138
- decompose: {
139
- ...currentState.decompose,
140
- ticketCount: tickets.length,
141
- completedAt: new Date().toISOString(),
142
- },
143
- },
144
- });
145
- }
146
-
147
- export function logCleanupSummary(cleanup, epicId, ticketCount) {
148
- Logger.info(
149
- `[epic-plan-decompose] ✅ Decompose phase complete for Epic #${epicId}. ${ticketCount} ticket(s) persisted via reconciler.`,
150
- );
151
- if (cleanup.deleted.length > 0) {
152
- Logger.info(
153
- `[epic-plan-decompose] 🧹 Cleaned up ${cleanup.deleted.length} temp file(s).`,
154
- );
155
- }
156
- }
@@ -1,345 +0,0 @@
1
- /**
2
- * persist.js — Phase 5 of the epic-plan-decompose pipeline (Story #2466).
3
- *
4
- * Owns the reconciler-based persist flow:
5
- * 1. validate + normalise the ticket array
6
- * 2. render the structural spec
7
- * 3. write the YAML spec under `.agents/epics/<epicId>.yaml`
8
- * 4. spawn `epic-reconcile.js --apply --yes`
9
- * 5. run the sub-issue link safety net
10
- * 6. update the `epic-plan-state` checkpoint
11
- * 7. flip the Epic to `agent::ready`
12
- * 8. clean up phase temp files
13
- *
14
- * Pure helpers (input guards, spec input projection, validation, state
15
- * seed/checkpoint, cleanup logging) live in the sibling
16
- * `persist-helpers.js` module so this orchestrator stays under Story
17
- * #2466's 200-LOC ceiling.
18
- *
19
- * @module lib/orchestration/epic-plan-decompose/phases/persist
20
- */
21
-
22
- import { spawnSync as defaultSpawnSync } from 'node:child_process';
23
-
24
- import { runPlanHealthcheck as defaultRunPlanHealthcheck } from '../../../../epic-plan-healthcheck.js';
25
- import { getLimits, PROJECT_ROOT } from '../../../config-resolver.js';
26
- import { Logger } from '../../../Logger.js';
27
- import {
28
- AGENT_LABELS,
29
- PLANNING_HEALTHCHECK_WAIVED,
30
- } from '../../../label-constants.js';
31
- import { cleanupPhaseTempFiles } from '../../../plan-phase-cleanup.js';
32
- import { loadState, writeSpec } from '../../../spec/index.js';
33
- import {
34
- assertNoOpenPlanChildren,
35
- releaseEpicPlanLease,
36
- } from '../../epic-plan-lease-guard.js';
37
- import { renderSpec } from '../../spec-renderer.js';
38
- import { renderHardConflictError } from '../../ticket-validator-conflicts.js';
39
- import {
40
- reconcileSubIssueLinks,
41
- setBlockedByDependencies,
42
- setEpicLabel,
43
- warnTicketCapNearLimit,
44
- } from './creation.js';
45
- import {
46
- assertDecomposeInputs,
47
- buildEpicSpecInput,
48
- logCleanupSummary,
49
- recordCheckpoint,
50
- seedPlanState,
51
- validateTickets,
52
- } from './persist-helpers.js';
53
- import { RECONCILE_CLI, spawnReconcilerApply } from './reconcile-spawn.js';
54
-
55
- /**
56
- * Execute the decompose phase end to end. See module-doc for the 8-step
57
- * flow.
58
- *
59
- * @param {number} epicId
60
- * @param {import('../../../ITicketingProvider.js').ITicketingProvider} provider
61
- * @param {{ tickets: Array<object> }} payload
62
- * @param {object} config
63
- * @param {{ force?: boolean, resume?: boolean, allowOverBudget?: boolean, allowLargeFanOut?: boolean, fanOutCounter?: (arg: { path: string }) => number, spawnSync?: typeof defaultSpawnSync, reconcileCli?: string, writeSpecFn?: typeof writeSpec, renderSpecFn?: typeof renderSpec, loadStateFn?: typeof loadState, cwd?: string, runHealthcheckFn?: typeof defaultRunPlanHealthcheck, skipHealthcheck?: boolean }} [opts]
64
- */
65
- export async function runDecomposePhase(
66
- epicId,
67
- provider,
68
- { tickets },
69
- config = {},
70
- {
71
- force = false,
72
- resume = false,
73
- allowOverBudget = false,
74
- allowLargeFanOut = false,
75
- fanOutCounter = undefined,
76
- spawnSync = defaultSpawnSync,
77
- reconcileCli = RECONCILE_CLI,
78
- writeSpecFn = writeSpec,
79
- renderSpecFn = renderSpec,
80
- loadStateFn = loadState,
81
- cwd = PROJECT_ROOT,
82
- runHealthcheckFn = defaultRunPlanHealthcheck,
83
- skipHealthcheck = false,
84
- } = {},
85
- ) {
86
- if (force && resume) {
87
- throw new Error(
88
- '[epic-plan-decompose] --force and --resume are mutually exclusive.',
89
- );
90
- }
91
- const epic = await provider.getEpic(epicId);
92
- assertDecomposeInputs(epic, epicId, tickets);
93
- const maxTickets = getLimits(config).maxTickets;
94
- // Story #2798 — `maxTickets` is a reviewability budget. Over-budget
95
- // persistence requires an explicit `--allow-over-budget` override so
96
- // an accidental over-budget plan does not silently land.
97
- if (tickets.length > maxTickets && !allowOverBudget) {
98
- throw new Error(
99
- `[epic-plan-decompose] Tickets (${tickets.length}) exceed the reviewability budget (${maxTickets}). ` +
100
- `Re-scope the Epic into a smaller plan, or rerun with --allow-over-budget after confirming the over-budget rationale on the Epic.`,
101
- );
102
- }
103
- warnTicketCapNearLimit(tickets, maxTickets);
104
- if (tickets.length > maxTickets && allowOverBudget) {
105
- Logger.warn(
106
- `[epic-plan-decompose] Persisting an over-budget decomposition: ${tickets.length} tickets vs. budget ${maxTickets} (operator override --allow-over-budget).`,
107
- );
108
- }
109
- // Story #2962 — run cross-validation BEFORE the plan-state mutation so
110
- // the fan-out gate (and any future hard gate) can refuse persist
111
- // without leaving a half-initialised epic-plan-state behind.
112
- Logger.info(
113
- `[epic-plan-decompose] Running cross-validation on ${tickets.length} tickets...`,
114
- );
115
- const validated = validateTickets(tickets, config, { fanOutCounter, cwd });
116
-
117
- // Refuse to persist when any Task declares a deletion whose call-site
118
- // fan-out exceeds the configured threshold, unless the operator has
119
- // passed `--allow-large-fan-out`. The planner cannot reduce call sites
120
- // by re-prompting, so this gate sits at persist time (like
121
- // `--allow-over-budget`) rather than in the auto-redrive loop.
122
- enforceFanOutGate(validated.findings, allowLargeFanOut);
123
-
124
- // Story #3957 — surface soft cross-Story conflict findings on the
125
- // validator's warning channel. `failOnSharedEditors` defaults to `false`,
126
- // so a real shared-editor / implicit-dep hazard lands as `'soft'` and would
127
- // otherwise be invisible during the Phase-8 operator review. Logging each
128
- // soft finding here puts it in the same decompose output the operator reads
129
- // before approving the plan.
130
- surfaceSoftConflictFindings(validated.findings);
131
-
132
- // Workflow-guards (Story #3481): refuse to persist when the Epic already has
133
- // open Feature/Story children unless this is a deliberate re-decompose
134
- // (`--force` closes + recreates the tree; `--resume` continues a partial
135
- // persist). Sits immediately before the first plan-state mutation so a
136
- // refusal never leaves a half-initialised epic-plan-state behind.
137
- await assertNoOpenPlanChildren({
138
- provider,
139
- epicId,
140
- force: force || resume,
141
- });
142
-
143
- await seedPlanState(provider, epicId, epic);
144
-
145
- Logger.info(
146
- `[epic-plan-decompose] Rendering spec for Epic #${epicId} (${validated.length} tickets)...`,
147
- );
148
- const spec = renderSpecFn(validated, {
149
- epic: buildEpicSpecInput(epic, epicId),
150
- });
151
- const specFilePath = writeSpecFn(epicId, spec, { epicsDir: undefined });
152
- Logger.info(`[epic-plan-decompose] Wrote spec → ${specFilePath}`);
153
-
154
- Logger.info(
155
- `[epic-plan-decompose] Spawning epic-reconcile.js --apply --yes for Epic #${epicId}...`,
156
- );
157
- // Story #3905 — a `--force` re-plan with a changed ticket set produces
158
- // a plan carrying close ops for the dropped slugs. `epic-reconcile.js`
159
- // hard-exits 2 on close ops unless `--explicit-delete` is passed, so a
160
- // force re-decompose must thread the flag through or it fails *after*
161
- // the spec was already overwritten and plan-state flipped.
162
- const reconcile = spawnReconcilerApply({
163
- spawnSync,
164
- reconcileCli,
165
- epicId,
166
- cwd,
167
- explicitDelete: force,
168
- });
169
-
170
- // Sub-issue link safety net — Story #2063. The reconciler's apply path
171
- // opportunistically calls `addSubIssue` and swallows transient failures;
172
- // re-establish missing native links before flipping the Epic to ready.
173
- await reconcileSubIssueLinks(epicId, provider);
174
-
175
- // Story #4067 — translate `depends_on` edges into native GitHub "blocked
176
- // by" dependencies so maintainers see blocking relationships in the UI.
177
- // Best-effort and non-fatal: the reconciler has already written the state
178
- // file, so we load it here to get the authoritative slug→issueNumber map.
179
- const postReconcileState = loadStateFn(epicId);
180
- await setBlockedByDependencies(
181
- epicId,
182
- provider,
183
- spec,
184
- postReconcileState.mapping,
185
- );
186
-
187
- const checkpoint = await recordCheckpoint(provider, epicId, tickets);
188
-
189
- // Story #2921 (Epic #2880 F7) — `agent::ready` handoff gate. The
190
- // post-plan readiness healthcheck (`epic-plan-healthcheck.js`) is now
191
- // blocking: a failing healthcheck refuses the `agent::ready` flip
192
- // unless the operator has applied the `planning::healthcheck-waived`
193
- // label. See `.agents/docs/SDLC.md` § "`agent::ready` exit conditions" for
194
- // the full contract. Tests inject `skipHealthcheck: true` to bypass
195
- // the network-bound check; production callers must not set this.
196
- const healthcheck = skipHealthcheck
197
- ? { ok: true, skipped: true }
198
- : await runHealthcheckGate({
199
- epicId,
200
- epic,
201
- runHealthcheckFn,
202
- });
203
-
204
- Logger.info(
205
- `[epic-plan-decompose] Flipping Epic #${epicId} to ${AGENT_LABELS.READY}...`,
206
- );
207
- await setEpicLabel(provider, epicId, AGENT_LABELS.READY);
208
-
209
- const cleanup = await cleanupPhaseTempFiles({ phase: 'decompose', epicId });
210
- logCleanupSummary(cleanup, epicId, tickets.length);
211
-
212
- // Workflow-guards (Story #3481): release the Epic-lease now that Phase 8 has
213
- // persisted the plan. Best-effort — a release failure never fails decompose.
214
- await releaseEpicPlanLease({ provider, epicId, config });
215
-
216
- return {
217
- epicId,
218
- ticketCount: tickets.length,
219
- checkpoint,
220
- cleanup,
221
- reconcile,
222
- specPath: specFilePath,
223
- healthcheck,
224
- };
225
- }
226
-
227
- /**
228
- * Run the post-plan readiness healthcheck and enforce the
229
- * `agent::ready` handoff gate. Returns the healthcheck result on
230
- * success (either `ok: true` or `ok: false` with the waiver label
231
- * applied). Throws when the healthcheck failed and the operator has
232
- * not applied `planning::healthcheck-waived` to the Epic.
233
- *
234
- * Extracted from `runDecomposePhase` so the gate is a single named
235
- * code path the contract tests can target.
236
- *
237
- * @param {object} args
238
- * @param {number} args.epicId
239
- * @param {{ labels?: string[] }} args.epic
240
- * @param {typeof defaultRunPlanHealthcheck} args.runHealthcheckFn
241
- * @returns {Promise<{ ok: boolean, waived?: boolean, reason?: string|null }>}
242
- */
243
- export function enforceFanOutGate(
244
- findings,
245
- allowLargeFanOut,
246
- tag = 'epic-plan-decompose',
247
- ) {
248
- const fanOut = (findings ?? []).filter((f) => f.kind === 'fan-out-warning');
249
- if (fanOut.length === 0) return;
250
- if (allowLargeFanOut) {
251
- for (const f of fanOut) {
252
- Logger.warn(
253
- `[${tag}] Persisting a large-fan-out deletion: ` +
254
- `Task "${f.taskSlug}" deletes "${f.path}" with ${f.callSiteCount} ` +
255
- `call site(s) (threshold ${f.threshold}). Operator override --allow-large-fan-out.`,
256
- );
257
- }
258
- return;
259
- }
260
- const lines = fanOut
261
- .map(
262
- (f) =>
263
- ` - Task "${f.taskSlug}" (Story "${f.storySlug}") deletes "${f.path}" — ${f.callSiteCount} call site(s) (threshold ${f.threshold})`,
264
- )
265
- .join('\n');
266
- throw new Error(
267
- `[${tag}] ${fanOut.length} Task(s) declare large-fan-out deletions:\n${lines}\n\n` +
268
- `Split each deletion into a subsystem-by-subsystem migration across multiple Stories, ` +
269
- `or rerun --allow-large-fan-out after confirming the deletion is intentional.`,
270
- );
271
- }
272
-
273
- /**
274
- * Story #3957 — log every `'soft'` cross-Story conflict finding on the
275
- * validator's warning channel so it is visible during the Phase-8 operator
276
- * review even when its policy flag (e.g. `failOnSharedEditors`) is `false`
277
- * and the finding never reaches the AC-visible `errors[]` path.
278
- *
279
- * `fan-out-warning` findings are excluded: `enforceFanOutGate` already emits
280
- * a dedicated warn/throw line for those, and double-logging would be noise.
281
- * Hard findings are excluded too — they are already rendered into `errors[]`
282
- * and block the decompose, so they need no advisory echo here.
283
- *
284
- * Each line reuses `renderHardConflictError` for the message body (the
285
- * remediation hint is identical regardless of severity) under a `soft
286
- * conflict:` prefix so the operator can tell advisory findings apart from
287
- * blocking ones.
288
- *
289
- * @param {object[]} findings
290
- */
291
- export function surfaceSoftConflictFindings(
292
- findings,
293
- tag = 'epic-plan-decompose',
294
- ) {
295
- const soft = (findings ?? []).filter(
296
- (f) => f?.severity === 'soft' && f?.kind !== 'fan-out-warning',
297
- );
298
- if (soft.length === 0) return;
299
- Logger.warn(
300
- `[${tag}] ${soft.length} soft cross-Story conflict finding(s) — review before approving the plan:`,
301
- );
302
- for (const finding of soft) {
303
- Logger.warn(`[${tag}] soft conflict: ${renderHardConflictError(finding)}`);
304
- }
305
- }
306
-
307
- export async function runHealthcheckGate({
308
- epicId,
309
- epic,
310
- runHealthcheckFn,
311
- tag = 'epic-plan-decompose',
312
- }) {
313
- Logger.info(
314
- `[${tag}] Running post-plan readiness healthcheck for Epic #${epicId}...`,
315
- );
316
- let result;
317
- try {
318
- result = await runHealthcheckFn({ epicId });
319
- } catch (err) {
320
- // A throwing healthcheck is itself a failure — surface it as the
321
- // gate reason rather than letting the throw propagate raw, so the
322
- // operator sees a uniform "handoff refused" diagnostic.
323
- result = { ok: false, reason: `healthcheck threw: ${err.message}` };
324
- }
325
-
326
- if (result?.ok) {
327
- return { ok: true };
328
- }
329
-
330
- const labels = Array.isArray(epic?.labels) ? epic.labels : [];
331
- const waived = labels.includes(PLANNING_HEALTHCHECK_WAIVED);
332
- if (waived) {
333
- Logger.warn(
334
- `[${tag}] Healthcheck failed for Epic #${epicId} but '${PLANNING_HEALTHCHECK_WAIVED}' is applied — proceeding with agent::ready handoff. Reason: ${result?.reason ?? '(no reason reported)'}`,
335
- );
336
- return { ok: false, waived: true, reason: result?.reason ?? null };
337
- }
338
-
339
- throw new Error(
340
- `[${tag}] Refusing agent::ready handoff for Epic #${epicId}: ` +
341
- `post-plan healthcheck failed (${result?.reason ?? '(no reason reported)'}). ` +
342
- `Resolve the failing check(s), or apply the '${PLANNING_HEALTHCHECK_WAIVED}' ` +
343
- `label to the Epic to override and rerun the persist phase.`,
344
- );
345
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * planning-artifacts.js — Phase 1 of the epic-plan-decompose pipeline
3
- * (Story #2466). Owns the cross-Story conflict-policy resolver.
4
- *
5
- * Story #4324 retired the `## Planning Artifacts` body shim
6
- * (`ensurePlanningArtifacts`) with the context-ticket classes — the Epic
7
- * body now carries the planning content itself as managed sections.
8
- *
9
- * @module lib/orchestration/epic-plan-decompose/phases/planning-artifacts
10
- */
11
-
12
- import { resolveListValue } from '../../../config/shared.js';
13
- import { DEFAULT_REGISTRY_PATTERNS } from '../../ticket-validator-conflicts.js';
14
-
15
- /**
16
- * Resolve the cross-Story conflict-finding policy from `_config.planning`.
17
- * Both flags default to `false` so existing repos keep the advisory-only
18
- * behaviour; setting either to `true` upgrades the matching finding class
19
- * to `'hard'`, which routes it through the validator's `errors[]` channel
20
- * and (when called inside the bounded decompose loop) triggers a re-prompt.
21
- */
22
- export function resolveConflictPolicy(cfg) {
23
- const planning = cfg?.planning;
24
- const policy = {
25
- failOnSharedEditors: planning?.failOnSharedEditors === true,
26
- requireExplicitCrossStoryDeps:
27
- planning?.requireExplicitCrossStoryDeps === true,
28
- failOnRegistryConflicts: planning?.failOnRegistryConflicts === true,
29
- failOnLargeFanOut: planning?.failOnLargeFanOut === true,
30
- };
31
- if (Number.isFinite(planning?.largeFanOutThreshold)) {
32
- policy.largeFanOutThreshold = planning.largeFanOutThreshold;
33
- }
34
- if (planning?.crossCuttingRegistries !== undefined) {
35
- policy.registries = resolveListValue(
36
- DEFAULT_REGISTRY_PATTERNS,
37
- planning.crossCuttingRegistries,
38
- );
39
- }
40
- return policy;
41
- }