mandrel 1.94.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/story-worker.md +12 -13
  3. package/.agents/docs/SDLC.md +489 -1285
  4. package/.agents/docs/agentrc-reference.json +177 -67
  5. package/.agents/docs/configuration.md +104 -138
  6. package/.agents/docs/execution-reference.md +17 -20
  7. package/.agents/docs/quality-gates.md +13 -19
  8. package/.agents/docs/workflows.md +3 -3
  9. package/.agents/instructions.md +70 -81
  10. package/.agents/rules/ci-remediation.md +8 -12
  11. package/.agents/rules/git-conventions-reference.md +6 -7
  12. package/.agents/rules/git-conventions.md +16 -22
  13. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  14. package/.agents/schemas/agentrc.schema.json +54 -214
  15. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  16. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  17. package/.agents/schemas/risk-verdict.schema.json +0 -13
  18. package/.agents/scripts/analyze-execution.js +1 -1
  19. package/.agents/scripts/audit-to-stories.js +7 -7
  20. package/.agents/scripts/boot-sweep.js +1 -1
  21. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  22. package/.agents/scripts/check-prepush-recovery.js +1 -1
  23. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  24. package/.agents/scripts/lib/Logger.js +6 -10
  25. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  26. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  27. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  28. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  29. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  30. package/.agents/scripts/lib/baselines/reader.js +1 -6
  31. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  32. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  33. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  34. package/.agents/scripts/lib/checks/index.js +2 -1
  35. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  36. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  37. package/.agents/scripts/lib/cli-args.js +16 -7
  38. package/.agents/scripts/lib/close-validation/gates.js +2 -2
  39. package/.agents/scripts/lib/config/ci.js +6 -31
  40. package/.agents/scripts/lib/config/delivery-routing.js +45 -29
  41. package/.agents/scripts/lib/config/explain.js +55 -36
  42. package/.agents/scripts/lib/config/limits.js +17 -58
  43. package/.agents/scripts/lib/config/paths.js +0 -2
  44. package/.agents/scripts/lib/config/quality.js +1 -1
  45. package/.agents/scripts/lib/config/runners.js +17 -50
  46. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  47. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  48. package/.agents/scripts/lib/config-resolver.js +2 -7
  49. package/.agents/scripts/lib/config-settings-schema-delivery.js +24 -148
  50. package/.agents/scripts/lib/config-settings-schema-quality.js +8 -14
  51. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  52. package/.agents/scripts/lib/dependency-parser.js +3 -2
  53. package/.agents/scripts/lib/doc-tiers.js +2 -2
  54. package/.agents/scripts/lib/duplicate-search.js +211 -41
  55. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  56. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  57. package/.agents/scripts/lib/framework-version.js +2 -3
  58. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  59. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  60. package/.agents/scripts/lib/git-utils.js +32 -6
  61. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  62. package/.agents/scripts/lib/label-constants.js +10 -23
  63. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  64. package/.agents/scripts/lib/observability/active-story-env.js +1 -1
  65. package/.agents/scripts/lib/observability/hook-heartbeat.js +20 -52
  66. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  67. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  68. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  69. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +8 -5
  70. package/.agents/scripts/lib/orchestration/ceremony-routing.js +83 -20
  71. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  72. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  73. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  74. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  75. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  76. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  77. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  78. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  79. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  80. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  81. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  82. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  83. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  84. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  85. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  86. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  87. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  88. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  89. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  90. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  91. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  92. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  93. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  94. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  95. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +13 -13
  96. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  97. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  98. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  99. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  100. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  101. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  102. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  103. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  104. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  105. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  106. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  107. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  108. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  109. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  110. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  111. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  112. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  113. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  114. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  115. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  116. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  117. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  118. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  119. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  120. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  121. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  122. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  123. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  124. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  125. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  126. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  127. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  128. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  129. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  130. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  131. package/.agents/scripts/lib/orchestration/ticket-validator.js +2 -7
  132. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  133. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  134. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  135. package/.agents/scripts/lib/planning-corpus.js +16 -11
  136. package/.agents/scripts/lib/preflight-runner.js +2 -2
  137. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  138. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  139. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  140. package/.agents/scripts/lib/story-adjacency.js +11 -14
  141. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  142. package/.agents/scripts/lib/story-plan.js +2 -4
  143. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  144. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  145. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  146. package/.agents/scripts/lib/validation-evidence.js +1 -1
  147. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  148. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  149. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  150. package/.agents/scripts/lint-issue-body.js +71 -40
  151. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  152. package/.agents/scripts/notify.js +4 -3
  153. package/.agents/scripts/plan-context.js +64 -74
  154. package/.agents/scripts/plan-persist.js +121 -280
  155. package/.agents/scripts/plan-run-epilogue.js +97 -0
  156. package/.agents/scripts/providers/github/issues.js +17 -33
  157. package/.agents/scripts/providers/github/mappers.js +0 -12
  158. package/.agents/scripts/providers/github/tickets.js +2 -5
  159. package/.agents/scripts/resolve-plan-run.js +117 -0
  160. package/.agents/scripts/signals-view.js +24 -19
  161. package/.agents/scripts/single-story-close.js +11 -14
  162. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  163. package/.agents/scripts/single-story-init.js +29 -20
  164. package/.agents/scripts/stories-wave-tick.js +6 -6
  165. package/.agents/scripts/story-plan.js +26 -47
  166. package/.agents/scripts/update-ticket-state.js +6 -15
  167. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  168. package/.agents/skills/core/idea-refinement/SKILL.md +6 -6
  169. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  170. package/.agents/skills/skills.index.json +3 -43
  171. package/.agents/starter-agentrc.json +0 -5
  172. package/.agents/templates/agent-protocol.md +9 -10
  173. package/.agents/workflows/audit-architecture.md +3 -3
  174. package/.agents/workflows/audit-clean-code.md +3 -3
  175. package/.agents/workflows/audit-dependencies.md +3 -3
  176. package/.agents/workflows/audit-devops.md +3 -3
  177. package/.agents/workflows/audit-documentation.md +5 -5
  178. package/.agents/workflows/audit-lighthouse.md +3 -3
  179. package/.agents/workflows/audit-navigability.md +3 -2
  180. package/.agents/workflows/audit-performance.md +3 -3
  181. package/.agents/workflows/audit-privacy.md +3 -3
  182. package/.agents/workflows/audit-quality.md +3 -3
  183. package/.agents/workflows/audit-security.md +3 -3
  184. package/.agents/workflows/audit-seo.md +3 -3
  185. package/.agents/workflows/audit-sre.md +3 -3
  186. package/.agents/workflows/audit-to-stories.md +20 -20
  187. package/.agents/workflows/audit-ux-ui.md +3 -3
  188. package/.agents/workflows/deliver.md +122 -174
  189. package/.agents/workflows/git-cleanup.md +3 -4
  190. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  191. package/.agents/workflows/helpers/acceptance-self-eval.md +16 -29
  192. package/.agents/workflows/helpers/code-review.md +70 -193
  193. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  194. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  195. package/.agents/workflows/helpers/diagnose.md +10 -10
  196. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  197. package/.agents/workflows/helpers/signals.md +16 -16
  198. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  199. package/.agents/workflows/mandrel-update.md +2 -1
  200. package/.agents/workflows/plan.md +112 -145
  201. package/.agents/workflows/qa-assist.md +24 -30
  202. package/.agents/workflows/qa-explore.md +29 -38
  203. package/.agents/workflows/qa-run.md +2 -2
  204. package/README.md +9 -8
  205. package/docs/CHANGELOG.md +30 -0
  206. package/lib/migrations/index.js +6 -5
  207. package/package.json +2 -2
  208. package/.agents/agents/retro.md +0 -42
  209. package/.agents/personas/architect.md +0 -113
  210. package/.agents/personas/devops-engineer.md +0 -38
  211. package/.agents/personas/engineer.md +0 -33
  212. package/.agents/personas/project-manager.md +0 -114
  213. package/.agents/personas/qa-engineer.md +0 -95
  214. package/.agents/personas/security-engineer.md +0 -111
  215. package/.agents/personas/technical-writer.md +0 -101
  216. package/.agents/schemas/dispatch-manifest.json +0 -232
  217. package/.agents/schemas/epic-spec.schema.json +0 -153
  218. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  219. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  220. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  221. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  222. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  223. package/.agents/scripts/dispatcher.js +0 -295
  224. package/.agents/scripts/epic-audit-prepare.js +0 -497
  225. package/.agents/scripts/epic-audit-recheck.js +0 -274
  226. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  227. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  228. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  229. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  230. package/.agents/scripts/epic-plan-clarity.js +0 -211
  231. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  232. package/.agents/scripts/epic-reconcile.js +0 -625
  233. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  234. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  235. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  236. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  237. package/.agents/scripts/lib/config/preflight.js +0 -58
  238. package/.agents/scripts/lib/config/retro.js +0 -77
  239. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  240. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  241. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  242. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  243. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  244. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  245. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  246. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  247. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  248. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  249. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  250. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  251. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  252. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  253. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  254. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  255. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  256. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  257. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  258. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  259. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  260. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  261. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  262. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  263. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  264. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  265. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  266. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  267. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  268. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  269. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  270. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  271. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  272. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  273. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  274. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  275. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  276. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  277. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  278. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  279. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  280. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  281. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  282. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  283. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  284. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  285. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  286. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  287. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  288. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  289. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  290. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  291. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  292. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  293. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  294. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  295. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  296. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  297. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  298. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  299. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  300. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  301. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  302. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  303. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  304. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  305. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  306. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  307. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  308. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  309. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  310. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  311. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  312. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  313. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  314. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  315. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  316. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  317. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  318. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  319. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  320. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  321. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  322. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  323. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  324. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  325. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  326. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  327. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  328. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  329. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  330. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  331. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  332. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  333. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  334. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  335. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  336. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  337. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  338. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  339. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  340. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  341. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  342. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  343. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  344. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  345. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  346. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  347. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  348. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  349. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  350. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  351. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  352. package/.agents/scripts/lib/spec/index.js +0 -36
  353. package/.agents/scripts/lib/spec/loader.js +0 -425
  354. package/.agents/scripts/lib/spec/state.js +0 -208
  355. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  356. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  357. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  358. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  359. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  360. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  361. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  362. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  363. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  364. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  365. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  366. package/.agents/scripts/lifecycle-emit.js +0 -510
  367. package/.agents/scripts/retro-run.js +0 -218
  368. package/.agents/scripts/slice-phase.js +0 -361
  369. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  370. package/.agents/scripts/story-close.js +0 -294
  371. package/.agents/scripts/story-init.js +0 -599
  372. package/.agents/scripts/story-phase.js +0 -369
  373. package/.agents/scripts/wave-tick.js +0 -464
  374. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  375. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  376. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  377. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  378. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  379. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  380. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  381. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  382. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  383. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  384. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  385. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  386. package/.agents/workflows/helpers/epic-audit.md +0 -189
  387. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  388. package/.agents/workflows/helpers/epic-testing.md +0 -125
  389. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  390. package/.agents/workflows/helpers/plan-epic.md +0 -353
  391. package/.agents/workflows/helpers/plan-story.md +0 -251
  392. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  393. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,310 +0,0 @@
1
- /**
2
- * epic-deliver-lease-guard.js — preflight guards for `/deliver`
3
- * (Story #3482, Epic #3457).
4
- *
5
- * `/deliver`'s prepare phase used to checkout `epic/<id>` over whatever
6
- * the operator had checked out, yanking HEAD and resetting baselines under a
7
- * live working session (the documented "epic-deliver shares the main checkout"
8
- * footgun). This module supplies the two preflight guards the Tech Spec
9
- * (#3476) wires into `epic-deliver-prepare.js` *before* any mutating git work:
10
- *
11
- * 1. **Epic-lease preflight.** Acquire the assignee-as-lease on the Epic
12
- * ticket via `ticket-lease.acquireLease`. On a live foreign claim the
13
- * guard **fails closed** — it throws a clear, operator-facing error that
14
- * names the current owner (the `critical-workflow` risk axis demands
15
- * refuse-and-exit, never warn-and-continue). `--steal` is the only
16
- * override.
17
- * 2. **Checkout-safety preflight.** Refuse to start when the working tree is
18
- * dirty or HEAD is on a branch other than the expected one, instead of
19
- * checking `epic/<id>` out over the operator's work.
20
- *
21
- * Both guards are pure over injected seams (a `git` shim with
22
- * `statusPorcelain` / `currentBranch`, and the lease provider) so the unit
23
- * suite exercises them without standing up a real repo or hitting GitHub.
24
- * Liveness is threaded in via `heartbeatAt` exactly as `ticket-lease.js`
25
- * documents — this module does not read the lifecycle ledger itself.
26
- *
27
- * Per `.agents/rules/orchestration-error-handling.md`, the composed guard
28
- * surfaces unrecoverable failures with `throw new Error(...)` (mapped to
29
- * `process.exit(1)` by the `runAsCli` boundary), never `Logger.fatal`.
30
- */
31
-
32
- import {
33
- acquireLeaseFailClosed,
34
- resolveOperatorFromCandidates,
35
- } from './lease-guard-shared.js';
36
-
37
- /**
38
- * Resolve the acquiring operator's identity. Precedence (Tech Spec #3476):
39
- * 1. An explicit `--as <handle>` flag.
40
- * 2. `github.operatorHandle` in `.agentrc.json`.
41
- * 3. The local `git config user.email`.
42
- *
43
- * The `@`-prefix some operators carry on `operatorHandle` is stripped (via
44
- * the shared lease-guard kernel) so the value matches the bare login written
45
- * to a ticket's `assignees`. This surface's missing-handle policy is `'null'`
46
- * — `runPrepareGuards` fails closed on a null operator with deliver-specific
47
- * wording after the (cheap, local) checkout-safety guard has run.
48
- *
49
- * @param {object} args
50
- * @param {string} [args.asFlag] Explicit `--as` value.
51
- * @param {object} [args.config] Resolved config (reads github.operatorHandle).
52
- * @param {string} [args.gitUserEmail] Fallback `git config user.email`.
53
- * @returns {string|null} The resolved operator handle, or null when none could
54
- * be determined.
55
- */
56
- export function resolveOperator({ asFlag, config, gitUserEmail } = {}) {
57
- return resolveOperatorFromCandidates({
58
- candidates: [asFlag, config?.github?.operatorHandle, gitUserEmail],
59
- });
60
- }
61
-
62
- /**
63
- * Normalise the expected-branch argument into a non-empty list. `/deliver`
64
- * may legitimately start from either the Epic integration branch (`epic/<id>`,
65
- * on a resume) or the project base branch (`main`, on a fresh run), so the
66
- * guard accepts a set rather than a single name.
67
- *
68
- * @param {string|string[]} expectedBranch
69
- * @returns {string[]}
70
- */
71
- function normaliseExpectedBranches(expectedBranch) {
72
- const list = (
73
- Array.isArray(expectedBranch) ? expectedBranch : [expectedBranch]
74
- ).filter((b) => typeof b === 'string' && b.length > 0);
75
- if (list.length === 0) {
76
- throw new Error('checkCheckoutSafety: expectedBranch is required');
77
- }
78
- return list;
79
- }
80
-
81
- /**
82
- * Pure checkout-safety classifier. The working tree must be clean and HEAD
83
- * must sit on one of `expectedBranch` before prepare moves anything.
84
- *
85
- * @param {object} args
86
- * @param {object} args.git Injected git shim.
87
- * @param {() => { dirty: boolean, entries?: string }} args.git.statusPorcelain
88
- * Returns whether the tree has uncommitted/untracked changes.
89
- * @param {() => string|null} args.git.currentBranch Returns HEAD's branch (or
90
- * null in detached-HEAD state).
91
- * @param {string|string[]} args.expectedBranch The branch (or branches)
92
- * prepare expects HEAD on (typically `epic/<id>` or the project base branch).
93
- * @returns {{
94
- * safe: boolean,
95
- * reason: 'clean'|'dirty'|'wrong-branch'|'detached-head',
96
- * currentBranch: string|null,
97
- * expectedBranches: string[],
98
- * dirtyEntries?: string,
99
- * }}
100
- */
101
- export function checkCheckoutSafety({ git, expectedBranch }) {
102
- if (!git || typeof git.statusPorcelain !== 'function') {
103
- throw new Error(
104
- 'checkCheckoutSafety: git shim with statusPorcelain/currentBranch is required',
105
- );
106
- }
107
- const expectedBranches = normaliseExpectedBranches(expectedBranch);
108
-
109
- const status = git.statusPorcelain();
110
- if (status?.dirty) {
111
- return {
112
- safe: false,
113
- reason: 'dirty',
114
- currentBranch: git.currentBranch(),
115
- expectedBranches,
116
- dirtyEntries: status.entries,
117
- };
118
- }
119
-
120
- const branch = git.currentBranch();
121
- if (branch === null || branch === undefined || branch === '') {
122
- return {
123
- safe: false,
124
- reason: 'detached-head',
125
- currentBranch: null,
126
- expectedBranches,
127
- };
128
- }
129
- if (!expectedBranches.includes(branch)) {
130
- return {
131
- safe: false,
132
- reason: 'wrong-branch',
133
- currentBranch: branch,
134
- expectedBranches,
135
- };
136
- }
137
- return {
138
- safe: true,
139
- reason: 'clean',
140
- currentBranch: branch,
141
- expectedBranches,
142
- };
143
- }
144
-
145
- /**
146
- * Render the operator-facing message for a failed checkout-safety guard.
147
- *
148
- * @param {ReturnType<typeof checkCheckoutSafety>} result
149
- * @returns {string}
150
- */
151
- export function renderCheckoutRefusal(result) {
152
- const expected = result.expectedBranches.map((b) => `'${b}'`).join(' or ');
153
- if (result.reason === 'dirty') {
154
- return (
155
- `[epic-deliver] Refusing to start: the working tree is dirty. ` +
156
- `/deliver will not check out ${expected} over uncommitted ` +
157
- `or untracked changes — commit, stash, or clean them, then re-run.\n` +
158
- `--- dirty entries ---\n${result.dirtyEntries ?? '(unavailable)'}`
159
- );
160
- }
161
- if (result.reason === 'detached-head') {
162
- return (
163
- `[epic-deliver] Refusing to start: HEAD is detached. /deliver ` +
164
- `expects HEAD on ${expected}. Check one out before re-running.`
165
- );
166
- }
167
- return (
168
- `[epic-deliver] Refusing to start: HEAD is on '${result.currentBranch}', ` +
169
- `not the expected ${expected}. /deliver will not yank HEAD ` +
170
- `away from your branch — switch to ${expected} yourself before re-running.`
171
- );
172
- }
173
-
174
- /**
175
- * Render the operator-facing message for a refused (live foreign) lease.
176
- *
177
- * @param {{ owner: string|null }} lease
178
- * @param {number} epicId
179
- * @returns {string}
180
- */
181
- export function renderLeaseRefusal(lease, epicId) {
182
- return (
183
- `[epic-deliver] Refusing to start: Epic #${epicId} is already claimed by ` +
184
- `'${lease.owner}' with a live lease (recent heartbeat within the TTL). ` +
185
- `Another /deliver run is driving this Epic. Wait for it to finish, ` +
186
- `or pass --steal to forcibly transfer the claim.`
187
- );
188
- }
189
-
190
- /**
191
- * Acquire the Epic lease for `operator`, failing closed on a live foreign
192
- * claim. Returns the `acquireLease` result on success.
193
- *
194
- * @param {object} args
195
- * @param {object} args.provider Ticketing provider.
196
- * @param {number} args.epicId Epic ticket id.
197
- * @param {string} args.operator Resolved operator handle.
198
- * @param {number|null} [args.heartbeatAt] Current owner's last heartbeat (epoch ms).
199
- * @param {boolean} [args.steal=false] Transfer a live foreign claim.
200
- * @param {object} [args.config] Resolved config (TTL default).
201
- * @param {number} [args.now] Injectable clock.
202
- * @returns {Promise<{ acquired: boolean, owner: string, previousOwner: string|null, reason: string }>}
203
- * @throws {Error} when the Epic carries a live foreign claim and `steal` is false.
204
- */
205
- export async function acquireEpicLease({
206
- provider,
207
- epicId,
208
- operator,
209
- heartbeatAt = null,
210
- steal = false,
211
- config,
212
- now,
213
- }) {
214
- return acquireLeaseFailClosed({
215
- provider,
216
- ticketId: epicId,
217
- operator,
218
- heartbeatAt,
219
- steal,
220
- config,
221
- now,
222
- renderRefusal: renderLeaseRefusal,
223
- });
224
- }
225
-
226
- /**
227
- * Compose the two preflight guards in the order prepare needs them: the
228
- * checkout-safety check first (cheap, local, no network), then the Epic-lease
229
- * acquisition (a GitHub round-trip). Both fail closed by throwing.
230
- *
231
- * The checkout-safety guard runs first (cheap, local) and always executes. The
232
- * Epic-lease step then **fails closed**: when `operator` cannot be resolved
233
- * (null — `--as`, `github.operatorHandle`, and `git user.email` all empty, with
234
- * the shipped `@[USERNAME]` placeholder normalised to null), this throws rather
235
- * than running an ownerless, unguarded delivery. The lease is the cross-clone
236
- * coordination layer; without an identity it cannot serialise concurrent runs,
237
- * so silently skipping it would defeat the guard.
238
- *
239
- * @param {object} args
240
- * @param {number} args.epicId
241
- * @param {string|string[]} args.expectedBranch Branch(es) prepare expects HEAD on.
242
- * @param {object} args.git Injected git shim (statusPorcelain/currentBranch).
243
- * @param {object} args.provider Ticketing provider for the lease.
244
- * @param {string|null} args.operator Resolved operator handle (null fails closed → throw).
245
- * @param {number|null} [args.heartbeatAt] Current owner's last heartbeat (epoch ms).
246
- * @param {boolean} [args.steal=false] Transfer a live foreign claim.
247
- * @param {object} [args.config] Resolved config.
248
- * @param {number} [args.now] Injectable clock.
249
- * @param {object} [args.logger] Logger with info/warn.
250
- * @returns {Promise<{
251
- * checkout: ReturnType<typeof checkCheckoutSafety>,
252
- * lease: { acquired: boolean, owner: string, reason: string },
253
- * }>}
254
- * @throws {Error} on a dirty/wrong-branch tree, an unresolvable operator
255
- * identity, or a refused live foreign lease.
256
- */
257
- export async function runPrepareGuards({
258
- epicId,
259
- expectedBranch,
260
- git,
261
- provider,
262
- operator,
263
- heartbeatAt = null,
264
- steal = false,
265
- config,
266
- now,
267
- logger,
268
- }) {
269
- const log = logger ?? { info: () => {}, warn: () => {} };
270
-
271
- const checkout = checkCheckoutSafety({ git, expectedBranch });
272
- if (!checkout.safe) {
273
- throw new Error(renderCheckoutRefusal(checkout));
274
- }
275
- log.info?.(
276
- `[epic-deliver] ✅ Checkout-safety guard passed (clean tree on '${checkout.currentBranch}').`,
277
- );
278
-
279
- if (!operator) {
280
- throw new Error(
281
- '[epic-deliver] Refusing to start: no operator identity could be ' +
282
- 'resolved. --as, github.operatorHandle (unset or still the shipped ' +
283
- '`@[USERNAME]` placeholder), and git user.email are all empty, so the ' +
284
- 'Epic-lease has no owner and concurrent /deliver runs cannot be ' +
285
- 'serialised. Set your own handle in .agentrc.local.json (e.g. ' +
286
- '{ "github": { "operatorHandle": "@your-login" } }), pass --as <handle>, ' +
287
- 'or configure git user.email, then re-run.',
288
- );
289
- }
290
-
291
- const lease = await acquireEpicLease({
292
- provider,
293
- epicId,
294
- operator,
295
- heartbeatAt,
296
- steal,
297
- config,
298
- now,
299
- });
300
- if (lease.reason === 'stolen') {
301
- log.warn?.(
302
- `[epic-deliver] ⚠️ Stole the Epic #${epicId} lease from '${lease.previousOwner}' via --steal (live claim forcibly transferred).`,
303
- );
304
- } else {
305
- log.info?.(
306
- `[epic-deliver] ✅ Acquired Epic #${epicId} lease for '${operator}' (reason=${lease.reason}).`,
307
- );
308
- }
309
- return { checkout, lease };
310
- }
@@ -1,163 +0,0 @@
1
- /**
2
- * context.js — Phase 3 of the epic-plan-decompose pipeline (Story #2466).
3
- *
4
- * Builds the authoring context (the Epic body — which carries the folded
5
- * Tech Spec sections and Acceptance Table per Story #4324 — plus
6
- * heuristics, system prompt, ticket cap) the host LLM /
7
- * `epic-plan-decompose-author` Skill consumes when producing the ticket
8
- * JSON array.
9
- *
10
- * Extracted verbatim from `epic-plan-decompose.js`; both
11
- * `buildDecomposerSystemPrompt` and `buildDecompositionContext` retain
12
- * their public-export contract for the existing unit tests.
13
- *
14
- * @module lib/orchestration/epic-plan-decompose/phases/context
15
- */
16
-
17
- import {
18
- getLimits,
19
- resolvePreflightCeilings,
20
- } from '../../../config-resolver.js';
21
- import { hasTechSpecContent } from '../../../epic-body-sections.js';
22
- import { renderDecomposerSystemPrompt } from '../../../templates/decomposer-prompts.js';
23
- import { read as readPlanState } from '../../epic-plan-state-store.js';
24
- import { applyBudget } from '../../planning-context-budget.js';
25
-
26
- export function buildDecomposerSystemPrompt(
27
- heuristics = [],
28
- { maxTickets, maxTokenBudget, epicId } = {},
29
- ) {
30
- const base = renderDecomposerSystemPrompt({
31
- maxTickets,
32
- maxTokenBudget,
33
- epicId,
34
- });
35
- const heuristicsStr =
36
- heuristics.length > 0
37
- ? `### RISK HEURISTICS (planning metadata if any apply):\n- ${heuristics.join('\n- ')}`
38
- : '';
39
- return `${base}${heuristicsStr ? `\n\n${heuristicsStr}` : ''}`;
40
- }
41
-
42
- function resolveHeuristics(config) {
43
- if (Array.isArray(config.planning?.riskHeuristics)) {
44
- return config.planning.riskHeuristics;
45
- }
46
- return config.agentSettings?.planning?.riskHeuristics || [];
47
- }
48
-
49
- function projectBudgetedEntry(item, ticket, mode) {
50
- if (mode === 'full') return { id: ticket.id, body: ticket.body };
51
- return { id: ticket.id, body: null, bodySummary: item };
52
- }
53
-
54
- /**
55
- * Read the persisted planning decision for the Epic so the decomposition
56
- * authoring step (Phase 8) can cite the same risk classification the
57
- * gate routing used in Phase 7. The decision lives in the `epic-plan-state`
58
- * structured comment written by `epic-plan-spec.js`.
59
- *
60
- * Returns `{ planningRisk: null, reviewRouting: null }` when the comment
61
- * is missing (older plans planned before Story #2801 landed) or when the
62
- * payload predates the fields. The null sentinels are part of the
63
- * decomposition context contract — callers MUST be able to JSON.stringify
64
- * the result without losing the keys.
65
- *
66
- * @param {import('../../../ITicketingProvider.js').ITicketingProvider} provider
67
- * @param {number} epicId
68
- * @returns {Promise<{ planningRisk: object | null, reviewRouting: object | null }>}
69
- */
70
- async function readPlanningDecision(provider, epicId) {
71
- let state = null;
72
- try {
73
- state = await readPlanState({ provider, epicId });
74
- } catch (_err) {
75
- // `read` already swallows JSON parse errors; a thrown error here
76
- // means the provider couldn't fetch comments. Treat as null state —
77
- // the decomposer can still author tickets without the risk envelope.
78
- state = null;
79
- }
80
- if (!state || typeof state !== 'object') {
81
- return { planningRisk: null, reviewRouting: null };
82
- }
83
- return {
84
- planningRisk: state.planningRisk ?? null,
85
- reviewRouting: state.reviewRouting ?? null,
86
- };
87
- }
88
-
89
- async function fetchPlanningEpic(provider, epicId) {
90
- const epic = await provider.getEpic(epicId);
91
- if (!epic || !hasTechSpecContent(epic.body ?? '')) {
92
- throw new Error(
93
- `[Decomposer] Epic #${epicId} body carries no Tech Spec sections (no ## Delivery Slicing). Run the Epic Planner (Phase 7) first.`,
94
- );
95
- }
96
- return { epic };
97
- }
98
-
99
- /**
100
- * Build the authoring context the host LLM (or the
101
- * `epic-plan-decompose-author` Skill) needs to produce the ticket JSON.
102
- *
103
- * The Epic body (ideation sections + folded Tech Spec sections +
104
- * Acceptance Table — the AC-ID source for wave-0 BDD scaffold tags) is
105
- * bounded by the planning-context budget (Epic #817 Story 9). Pass
106
- * `{ fullContext: true }` (CLI: `--full-context`) to restore the
107
- * unbounded full body.
108
- */
109
- export async function buildDecompositionContext(
110
- epicId,
111
- provider,
112
- config = {},
113
- opts = {},
114
- ) {
115
- const { epic } = await fetchPlanningEpic(provider, epicId);
116
- const { planningRisk, reviewRouting } = await readPlanningDecision(
117
- provider,
118
- epicId,
119
- );
120
- const heuristics = resolveHeuristics(config);
121
- const limits = getLimits(config);
122
- const maxTickets = limits.maxTickets;
123
- const maxTokenBudget = limits.maxTokenBudget;
124
- const planningLimits = limits.planningContext;
125
- const { fullContext = false } = opts;
126
- const systemPrompt = buildDecomposerSystemPrompt(heuristics, {
127
- maxTickets,
128
- maxTokenBudget,
129
- epicId,
130
- });
131
-
132
- const budgeted = applyBudget(
133
- [{ path: `epic-${epic.id}.md`, content: epic.body ?? '' }],
134
- planningLimits,
135
- { fullContext },
136
- );
137
- const [epicItem] = budgeted.items;
138
- return {
139
- epic: { id: epic.id, title: epic.title },
140
- // Story #4324 — the Epic body is the single planning document: it
141
- // carries the ideation sections, the folded Tech Spec sections
142
- // (## Delivery Slicing first), and the ## Acceptance Table the wave-0
143
- // BDD scaffold reads its AC IDs from.
144
- epicBody: projectBudgetedEntry(epicItem, epic, budgeted.mode),
145
- heuristics,
146
- systemPrompt,
147
- maxTickets,
148
- // Story #3875 — surface the real delivery envelope to the decomposer
149
- // so Stories are sized against the hydration budget and the
150
- // configured preflight ceilings rather than guessed. Story #4162 also
151
- // threads this value into the rendered systemPrompt above as a sizing
152
- // input so the prompt itself names the budget.
153
- maxTokenBudget,
154
- preflightCeilings: resolvePreflightCeilings(config),
155
- contextMode: budgeted.mode,
156
- // Story #2801 — surface the Phase 7 planning decision so the
157
- // decomposition authoring step can cite the same risk
158
- // classification used by gate routing. Both fields are `null`
159
- // when the Epic was planned before the decision contract existed.
160
- planningRisk,
161
- reviewRouting,
162
- };
163
- }
@@ -1,140 +0,0 @@
1
- /**
2
- * creation.js — sub-issue link reconciliation, Epic label transitions,
3
- * the advisory ticket-cap warning, and the blocked-by dependency wiring
4
- * used by the reconciler-based persist flow (`persist.js`).
5
- *
6
- * Exports: `reconcileSubIssueLinks`, `setBlockedByDependencies`,
7
- * `setEpicLabel`, `warnTicketCapNearLimit`.
8
- *
9
- * @module lib/orchestration/epic-plan-decompose/phases/creation
10
- */
11
-
12
- import { applyBlockedByDependencies } from '../../../../providers/github/blocked-by-add.js';
13
- import { Logger } from '../../../Logger.js';
14
- import { AGENT_LABELS } from '../../../label-constants.js';
15
-
16
- export async function reconcileSubIssueLinks(epicId, provider) {
17
- if (typeof provider.reconcileSubIssueLinks !== 'function') return;
18
- Logger.info(
19
- `[Decomposer] Reconciling sub-issue API links for Epic #${epicId}...`,
20
- );
21
- const result = await provider.reconcileSubIssueLinks(epicId);
22
- const { totalExpected, alreadyLinked, reconciled, failed, failures } = result;
23
- if (failed === 0) {
24
- const reconciledNote = reconciled > 0 ? ` (${reconciled} reconciled)` : '';
25
- Logger.info(
26
- `[Decomposer] linked ${alreadyLinked + reconciled}/${totalExpected} sub-issues${reconciledNote}`,
27
- );
28
- return;
29
- }
30
- for (const failure of failures) {
31
- Logger.error(
32
- `[Decomposer] sub-issue link gap: parent #${failure.parentId} ← child #${failure.childId}: ${failure.reason}`,
33
- );
34
- }
35
- throw new Error(
36
- `[Decomposer] Sub-issue reconciliation incomplete: ${failed}/${totalExpected} links could not be established (linked=${alreadyLinked}, reconciled=${reconciled}). See log for per-child reasons.`,
37
- );
38
- }
39
-
40
- /**
41
- * Translate each Story's `dependsOn` slug list into native GitHub "blocked
42
- * by" dependency edges. Best-effort and non-fatal: individual edge failures
43
- * are logged as warnings and do not abort the decompose phase.
44
- *
45
- * Requires the provider to expose `owner`, `repo`, `_gh`, and `getTicket`.
46
- * No-ops silently when any required surface is absent so callers remain
47
- * safe across provider stubs.
48
- *
49
- * @param {number} epicId
50
- * @param {import('../../../ITicketingProvider.js').ITicketingProvider} provider
51
- * @param {object} spec — the parsed YAML spec (has `.stories[*].dependsOn`).
52
- * @param {object} stateMapping — slug → `{ issueNumber }` from the reconciler state.
53
- */
54
- export async function setBlockedByDependencies(
55
- epicId,
56
- provider,
57
- spec,
58
- stateMapping,
59
- ) {
60
- const stories = Array.isArray(spec?.stories) ? spec.stories : [];
61
- const hasDeps = stories.some(
62
- (s) => Array.isArray(s.dependsOn) && s.dependsOn.length > 0,
63
- );
64
- if (!hasDeps) return;
65
-
66
- if (
67
- !provider?.owner ||
68
- !provider?.repo ||
69
- !provider?._gh ||
70
- typeof provider.getTicket !== 'function'
71
- ) {
72
- Logger.warn(
73
- `[Decomposer] setBlockedByDependencies: provider missing required surface (owner/repo/_gh/getTicket); skipping.`,
74
- );
75
- return;
76
- }
77
-
78
- Logger.info(
79
- `[Decomposer] Setting native blocked-by dependency edges for Epic #${epicId}...`,
80
- );
81
-
82
- // Build a slug → issueNumber map from the reconciler state mapping.
83
- const slugToIssueNumber = {};
84
- for (const [slug, entry] of Object.entries(stateMapping ?? {})) {
85
- if (typeof entry?.issueNumber === 'number') {
86
- slugToIssueNumber[slug] = entry.issueNumber;
87
- }
88
- }
89
-
90
- const result = await applyBlockedByDependencies({
91
- stories,
92
- slugToIssueNumber,
93
- getTicket: (n) => provider.getTicket(n),
94
- owner: provider.owner,
95
- repo: provider.repo,
96
- gh: provider._gh,
97
- });
98
-
99
- const { edgesAdded, edgesSkipped, edgesFailed, storiesProcessed } = result;
100
- Logger.info(
101
- `[Decomposer] blocked-by edges: ${edgesAdded} added, ${edgesSkipped} already present, ${edgesFailed} failed (${storiesProcessed} stories with deps processed).`,
102
- );
103
- }
104
-
105
- export async function setEpicLabel(provider, epicId, targetLabel) {
106
- const planningLabels = [AGENT_LABELS.REVIEW_SPEC, AGENT_LABELS.READY];
107
- await provider.updateTicket(epicId, {
108
- labels: {
109
- add: [targetLabel],
110
- remove: planningLabels.filter((l) => l !== targetLabel),
111
- },
112
- });
113
- }
114
-
115
- /**
116
- * Advisory-only ticket-count check (Story #2798).
117
- *
118
- * `maxTickets` is a **reviewability budget**, not a hard authoring cap.
119
- * This helper emits a non-destructive warning when a decomposition meets
120
- * or exceeds the budget so the operator can spot over-budget plans early
121
- * in the persist flow. It never blocks — the hard gate lives in the
122
- * `runDecomposePhase` over-budget check, which requires an explicit
123
- * `allowOverBudget` (CLI: `--allow-over-budget`) override.
124
- *
125
- * @param {Array} tickets
126
- * @param {number} maxTickets — the reviewability budget
127
- * @param {string} [tag] — log prefix
128
- * @param {{ logger?: Pick<typeof Logger, 'warn'> }} [opts]
129
- */
130
- export function warnTicketCapNearLimit(
131
- tickets,
132
- maxTickets,
133
- tag = 'epic-plan-decompose',
134
- { logger = Logger } = {},
135
- ) {
136
- if (tickets.length < maxTickets) return;
137
- logger.warn(
138
- `[${tag}] ⚠️ Received ${tickets.length} tickets against a reviewability budget of ${maxTickets}. Review the Story decomposition before persisting; over-budget persistence requires --allow-over-budget.`,
139
- );
140
- }
@@ -1,64 +0,0 @@
1
- /**
2
- * dag.js — Phase 2 of the epic-plan-decompose pipeline (Story #2466).
3
- *
4
- * Owns the deterministic DAG helpers used by the reconciler pipeline:
5
- * - `resolveDependencies(ticket, slugMap)`
6
- * - `orderTicketsForCreation(validated)` (topological sort of the
7
- * Story set so dependency producers are created before consumers)
8
- *
9
- * Extracted verbatim from `epic-plan-decompose.js` so the named exports
10
- * (`resolveDependencies`, `orderTicketsForCreation`) that the
11
- * `tests/ticket-decomposer.test.js` suite imports keep their contract.
12
- *
13
- * @module lib/orchestration/epic-plan-decompose/phases/dag
14
- */
15
-
16
- export function resolveDependencies(ticket, slugMap) {
17
- const resolved = [];
18
- for (const dep of ticket.depends_on || []) {
19
- const depId = slugMap.get(dep);
20
- if (depId === undefined) {
21
- // Unreachable through normal flow: validateAndNormalizeTickets
22
- // already rejects unknown slugs and the topological sort guarantees
23
- // creation order. A throw here turns a future regression (e.g.
24
- // someone bypassing the validator) into a loud failure instead of a
25
- // silently-dropped DAG edge.
26
- throw new Error(
27
- `[Decomposer] ${ticket.type.toUpperCase()} "${ticket.title}" (${ticket.slug}) depends on unresolved slug "${dep}". This indicates a planner bug or out-of-order ticket creation.`,
28
- );
29
- }
30
- resolved.push(depId);
31
- }
32
- return resolved;
33
- }
34
-
35
- function topoSortGroup(group) {
36
- const slugToTicket = new Map(group.map((t) => [t.slug, t]));
37
- const visited = new Set();
38
- const sorted = [];
39
-
40
- function visit(t) {
41
- if (visited.has(t.slug)) return;
42
- visited.add(t.slug);
43
- for (const dep of t.depends_on ?? []) {
44
- const depTicket = slugToTicket.get(dep);
45
- if (depTicket) visit(depTicket);
46
- }
47
- sorted.push(t);
48
- }
49
-
50
- for (const t of group) visit(t);
51
- return sorted;
52
- }
53
-
54
- /**
55
- * Topologically sort the Story set so intra-set dep chains resolve
56
- * before their dependents are created. The 2-tier hierarchy has a
57
- * single ticket type (story) attached directly to the Epic, so there
58
- * is no parent-type ordering to interleave.
59
- */
60
- export function orderTicketsForCreation(validated) {
61
- const result = [];
62
- for (const t of topoSortGroup([...validated])) result.push(t);
63
- return result;
64
- }