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,378 +0,0 @@
1
- // .agents/scripts/lib/orchestration/lifecycle/listeners/index.js
2
- /**
3
- * Default listener-chain builder for the standalone `lifecycle-emit`
4
- * CLI surface (Story #2510, Epic #2501).
5
- *
6
- * This is the SOLE production wiring path for the close-tail listener
7
- * roster. (The in-process `epic-runner/factory.js` that previously
8
- * mirrored this roster for an in-session runner was deleted with the
9
- * dead epic-runner stratum in Story #3908; the host-LLM-drives-CLIs
10
- * model reaches every close-tail listener through the `lifecycle-emit.js`
11
- * CLI shells in `/deliver`'s Phase 6 / 7.5 / 8 markdown invocations,
12
- * which call this builder.)
13
- *
14
- * Canonical roster (registration order):
15
- * 1. LedgerWriter (privileged hooks via `register(bus)`)
16
- * 2. AcceptanceReconciler (epic.close.end → acceptance.reconcile.*)
17
- * 3. Finalizer (acceptance.reconcile.{ok,waived} → pr.created)
18
- * 4. AutomergeArmer (epic.merge.ready → epic.merge.armed)
19
- * 5. AutomergePredicate (epic.watch.end → epic.merge.{ready,blocked})
20
- * 6. BranchCleaner (epic.cleanup.start → branch reap)
21
- * 7. MergeWatcher (epic.merge.armed → epic.merge.confirmed)
22
- * 8. Cleaner (epic.merge.confirmed → epic.cleanup.* / epic.complete)
23
- * 9. LabelTransitioner (epic.complete → Epic ticket flips to agent::done)
24
- * 10. CheckpointPointerWriter (every *.end → checkpoint.json)
25
- *
26
- * The bus contract requires LedgerWriter first: its `onEmitted` hook
27
- * lands the `emitted` ledger record on disk BEFORE any listener body
28
- * executes, so a crash mid-chain leaves a recoverable trail.
29
- *
30
- * Listeners whose constructors require collaborators that are not
31
- * available outside the runner (e.g. AutomergePredicate's `provider`,
32
- * BranchCleaner's `checkpointer`) are SKIPPED with a debug log rather
33
- * than constructed. This matches the factory's defensive guard pattern
34
- * — registration is best-effort; the chain still wires every listener
35
- * whose dependencies are satisfiable.
36
- *
37
- * Signature: `buildDefaultListenerChain({ bus, ledgerPath, repoRoot })`.
38
- * The Tech Spec for Epic #2501 (§ Story 4) fixes the public shape at
39
- * those three keys. `ledgerPath` is decomposed into `tempRoot` and
40
- * `epicId` so the listener constructors receive what they need;
41
- * `repoRoot` threads through as `cwd` for listeners that shell out
42
- * (`Finalizer`, `AutomergeArmer`).
43
- *
44
- * Maintainability exemption (refs #3685): this module is listed under
45
- * `delivery.quality.gates.maintainability.ignoreGlobs` in `.agentrc.json`.
46
- * Its sole content is a linear, low-branching listener-registration
47
- * sequence; the maintainability index mis-gauges that shape (the same
48
- * reason the declarative `config-settings-schema*` files are exempt).
49
- * Splitting the sequence across sibling builder modules purely to clear
50
- * the floor would add indirection without making the wiring easier to
51
- * read, so the debt is carried explicitly here rather than hidden behind
52
- * a blanket low floor.
53
- */
54
-
55
- import path from 'node:path';
56
-
57
- import { createLedgerWriter } from '../ledger-writer.js';
58
- import { AcceptanceReconciler } from './acceptance-reconciler.js';
59
- import { AutomergeArmer } from './automerge-armer.js';
60
- import { AutomergePredicate } from './automerge-predicate.js';
61
- import { BranchCleaner } from './branch-cleaner.js';
62
- import { CheckpointPointerWriter } from './checkpoint-pointer-writer.js';
63
- import { Cleaner } from './cleaner.js';
64
- import { Finalizer } from './finalizer.js';
65
- import { LabelTransitioner } from './label-transitioner.js';
66
- import { MergeWatcher } from './merge-watcher.js';
67
-
68
- /**
69
- * Parse `temp/epic-<id>/lifecycle.ndjson` into `{ tempRoot, epicId }`.
70
- *
71
- * Throws when the input does not match the canonical layout. The
72
- * standalone `lifecycle-emit` CLI is the sole production caller and it
73
- * always feeds the canonical `epicLedgerPath(eid)` value, so a mismatch
74
- * here is a programmer error — surface it loudly.
75
- *
76
- * @param {string} ledgerPath
77
- * @returns {{ tempRoot: string, epicId: number }}
78
- */
79
- export function parseLedgerPath(ledgerPath) {
80
- if (typeof ledgerPath !== 'string' || ledgerPath.length === 0) {
81
- throw new TypeError(
82
- 'buildDefaultListenerChain: ledgerPath must be a non-empty string',
83
- );
84
- }
85
- const epicDir = path.dirname(ledgerPath);
86
- const tempRoot = path.dirname(epicDir);
87
- const epicDirName = path.basename(epicDir);
88
- const m = /^epic-(\d+)$/.exec(epicDirName);
89
- if (!m) {
90
- throw new Error(
91
- `buildDefaultListenerChain: ledgerPath does not match temp/epic-<id>/lifecycle.ndjson layout (got ${ledgerPath})`,
92
- );
93
- }
94
- const epicId = Number.parseInt(m[1], 10);
95
- if (!Number.isInteger(epicId) || epicId < 1) {
96
- throw new Error(
97
- `buildDefaultListenerChain: parsed epicId from ledgerPath is not a positive integer (got ${m[1]})`,
98
- );
99
- }
100
- return { tempRoot, epicId };
101
- }
102
-
103
- /**
104
- * Build and subscribe the canonical default listener chain onto the
105
- * supplied bus.
106
- *
107
- * @param {object} opts
108
- * @param {object} opts.bus Lifecycle bus instance (must expose `on`,
109
- * `emit`, and the privileged `onEmitted` / `onCompleted` / `onFailed`
110
- * hook seam).
111
- * @param {string} opts.ledgerPath Absolute or repo-relative path to the
112
- * Epic's `lifecycle.ndjson`. Decomposed into `{ tempRoot, epicId }`
113
- * for downstream constructors.
114
- * @param {string} opts.repoRoot Absolute path used as `cwd` for
115
- * listeners that shell out (Finalizer, AutomergeArmer, BranchCleaner).
116
- * @param {object} [opts.provider] Ticketing provider. When omitted,
117
- * AutomergePredicate is skipped (the listener constructor throws on
118
- * a missing provider).
119
- * @param {object} [opts.config] Resolved agent config. Forwarded to the
120
- * AcceptanceReconciler.
121
- * @param {object} [opts.checkpointer] Epic-run-state checkpoint reader.
122
- * When omitted, BranchCleaner is skipped.
123
- * @param {object} [opts.logger] Logger surface (`debug`/`warn`/`error`).
124
- * @param {boolean} [opts.headless] Explicit must-land signal (Story
125
- * #4427), threaded straight through to `MergeWatcher`. Defaults to
126
- * `false` (attended-mode behavior unchanged). `lifecycle-emit.js`
127
- * resolves this from its own `--headless` runtime flag — an explicit
128
- * input, never an ambient global.
129
- *
130
- * @returns {Promise<{
131
- * ledgerWriter: object,
132
- * acceptanceReconciler: object,
133
- * finalizer: object,
134
- * automergeArmer: object,
135
- * automergePredicate: object|null,
136
- * branchCleaner: object|null,
137
- * cleaner: object,
138
- * checkpointPointerWriter: object,
139
- * order: string[]
140
- * }>}
141
- */
142
- export async function buildDefaultListenerChain(opts = {}) {
143
- const {
144
- bus,
145
- ledgerPath,
146
- repoRoot,
147
- provider = null,
148
- config = null,
149
- checkpointer = null,
150
- logger = console,
151
- headless = false,
152
- } = opts;
153
- if (
154
- !bus ||
155
- typeof bus.on !== 'function' ||
156
- typeof bus.emit !== 'function' ||
157
- typeof bus.onEmitted !== 'function'
158
- ) {
159
- throw new TypeError(
160
- 'buildDefaultListenerChain: bus must expose on/emit and the privileged onEmitted/onCompleted/onFailed seam',
161
- );
162
- }
163
- if (typeof repoRoot !== 'string' || repoRoot.length === 0) {
164
- throw new TypeError(
165
- 'buildDefaultListenerChain: repoRoot must be a non-empty string',
166
- );
167
- }
168
- const { tempRoot, epicId } = parseLedgerPath(ledgerPath);
169
-
170
- const order = [];
171
-
172
- // 1. LedgerWriter — MUST be first. Uses the privileged hook seam, so
173
- // its registration call is `register(bus)` rather than a regular
174
- // `bus.on()` subscription. The bus contract guarantees `emitted`
175
- // lands on disk before any listener body executes.
176
- const ledgerWriter = createLedgerWriter({ epicId, tempRoot });
177
- ledgerWriter.register(bus);
178
- order.push('LedgerWriter');
179
-
180
- // 2. AcceptanceReconciler — gates Finalize on close-time AC coverage.
181
- const acceptanceReconciler = new AcceptanceReconciler({
182
- bus,
183
- epicId,
184
- cwd: repoRoot,
185
- provider,
186
- config,
187
- logger,
188
- });
189
- acceptanceReconciler.register();
190
- order.push('AcceptanceReconciler');
191
-
192
- // 3. Finalizer — opens the PR on acceptance.reconcile.ok or .waived
193
- // (Story #2893 split waiver out of .skipped) via the bus-owned
194
- // default (`composeBusOwnedFinalize`, Story #2894), which chains
195
- // openOrLocatePr → postHandoffComment and
196
- // emits `epic.merge.ready` on success. The legacy
197
- // `d1-default-no-op` blocker is gone; the listener constructed
198
- // with no `runFinalizeFn` override always runs the real flow.
199
- // The code-review / audit-results graduator steps (Stories
200
- // #2555 / #2615) remain best-effort and are silently skipped
201
- // when `provider` / `currentRepo` are not wired in. `currentRepo`
202
- // is resolved from `config.github.{owner,repo}`; `frameworkRepo`
203
- // from `config.github.frameworkRepo` when distinct, otherwise omitted.
204
- const currentRepo =
205
- config?.github?.owner && config?.github?.repo
206
- ? { owner: config.github.owner, repo: config.github.repo }
207
- : null;
208
- const frameworkRepo =
209
- config?.github?.frameworkRepo?.owner && config?.github?.frameworkRepo?.repo
210
- ? {
211
- owner: config.github.frameworkRepo.owner,
212
- repo: config.github.frameworkRepo.repo,
213
- }
214
- : null;
215
- const finalizer = new Finalizer({
216
- bus,
217
- epicId,
218
- cwd: repoRoot,
219
- provider,
220
- config,
221
- currentRepo,
222
- frameworkRepo,
223
- logger,
224
- });
225
- finalizer.register();
226
- order.push('Finalizer');
227
-
228
- // 4. AutomergeArmer — arms `gh pr merge --auto --squash --delete-branch`
229
- // on epic.merge.ready. Story #4472: `headless` gates the direct-merge
230
- // fallback's terminal escalation (a genuine arm failure emits
231
- // `merge.unlanded` + `epic.blocked` in a `--yes` run instead of
232
- // returning silently); `epicId` scopes the `merge.unlanded` ledger row.
233
- const automergeArmer = new AutomergeArmer({
234
- bus,
235
- epicId,
236
- cwd: repoRoot,
237
- headless,
238
- logger,
239
- });
240
- automergeArmer.register();
241
- order.push('AutomergeArmer');
242
-
243
- // 5. AutomergePredicate — emits epic.merge.{ready,blocked} based on
244
- // the runtime predicate evaluation. Requires a truthy `provider`;
245
- // skip cleanly when the caller omitted one (lifecycle-emit CLI
246
- // has no provider wired in by default). `config` selects the
247
- // `delivery.ci.autoMerge` posture (trust-ci default vs strict) and
248
- // `cwd` (repoRoot) is where the live `gh pr checks --required`
249
- // probe shells out (Story #4361).
250
- let automergePredicate = null;
251
- if (provider) {
252
- automergePredicate = new AutomergePredicate({
253
- bus,
254
- epicId,
255
- provider,
256
- config,
257
- cwd: repoRoot,
258
- headless,
259
- logger,
260
- });
261
- automergePredicate.register();
262
- order.push('AutomergePredicate');
263
- } else {
264
- logger?.debug?.(
265
- '[lifecycle] buildDefaultListenerChain: skipping AutomergePredicate (no provider)',
266
- );
267
- }
268
-
269
- // 6. BranchCleaner — reaps story/epic branches on epic.cleanup.start.
270
- // Requires a checkpointer exposing `read()`; skip cleanly when
271
- // the caller omitted one.
272
- let branchCleaner = null;
273
- if (checkpointer && typeof checkpointer.read === 'function') {
274
- branchCleaner = new BranchCleaner({
275
- bus,
276
- epicId,
277
- checkpointer,
278
- cwd: repoRoot,
279
- logger,
280
- });
281
- branchCleaner.register();
282
- order.push('BranchCleaner');
283
- } else {
284
- logger?.debug?.(
285
- '[lifecycle] buildDefaultListenerChain: skipping BranchCleaner (no checkpointer)',
286
- );
287
- }
288
-
289
- // 7. MergeWatcher (Story #2896, Epic #2880) — polls `gh pr view`
290
- // after `epic.merge.armed` until the PR's mergeCommit is
291
- // non-null, then emits `epic.merge.confirmed`. Cleaner now
292
- // waits on the confirmed event rather than the armed event so
293
- // the Epic only transitions to its terminal state after the
294
- // merge is actually observed on GitHub. Reads `intervalSeconds`
295
- // and `maxBudgetSeconds` from `config.delivery.mergeWatch.*`
296
- // when supplied; otherwise uses the listener's framework
297
- // defaults (30s / 3600s).
298
- const mergeWatchConfig = config?.delivery?.mergeWatch ?? {};
299
- const mergeWatcher = new MergeWatcher({
300
- bus,
301
- epicId,
302
- tempRoot,
303
- cwd: repoRoot,
304
- intervalSeconds: mergeWatchConfig.intervalSeconds,
305
- maxBudgetSeconds: mergeWatchConfig.maxBudgetSeconds,
306
- headless,
307
- logger,
308
- });
309
- mergeWatcher.register();
310
- order.push('MergeWatcher');
311
-
312
- // 8. Cleaner — archives temp/epic-<id>/ and emits the terminal
313
- // epic.cleanup.start → .end → epic.complete sequence. Story
314
- // #2896 rebound this listener from `epic.merge.armed` to
315
- // `epic.merge.confirmed`.
316
- const cleaner = new Cleaner({
317
- bus,
318
- epicId,
319
- tempRoot,
320
- logger,
321
- });
322
- cleaner.register();
323
- order.push('Cleaner');
324
-
325
- // 9. LabelTransitioner — flips the Epic ticket to `agent::done` (and
326
- // closes it as completed, idempotently) on the terminal
327
- // `epic.complete` event. Requires a truthy `provider`; skip
328
- // cleanly when the caller omitted one — the same guard pattern as
329
- // AutomergePredicate. Restores the contract the Cleaner /
330
- // BranchCleaner / MergeWatcher docstrings have referenced since
331
- // the original listener was deleted with the epic-runner stratum
332
- // (#3936): without this registration the flip had NO owner and
333
- // cleanly-merged Epics stranded at `agent::executing`.
334
- let labelTransitioner = null;
335
- if (provider) {
336
- labelTransitioner = new LabelTransitioner({
337
- bus,
338
- epicId,
339
- provider,
340
- logger,
341
- });
342
- labelTransitioner.register();
343
- order.push('LabelTransitioner');
344
- } else {
345
- logger?.debug?.(
346
- '[lifecycle] buildDefaultListenerChain: skipping LabelTransitioner (no provider)',
347
- );
348
- }
349
-
350
- // 10. CheckpointPointerWriter — persists `{ lastCompletedSeqId, phase }`
351
- // on every `*.end` event.
352
- const checkpointPointerWriter = new CheckpointPointerWriter({
353
- bus,
354
- epicId,
355
- tempRoot,
356
- logger,
357
- });
358
- checkpointPointerWriter.register();
359
- order.push('CheckpointPointerWriter');
360
-
361
- logger?.debug?.(
362
- `[lifecycle] buildDefaultListenerChain registered listeners: ${order.join(' → ')}`,
363
- );
364
-
365
- return {
366
- ledgerWriter,
367
- acceptanceReconciler,
368
- finalizer,
369
- automergeArmer,
370
- automergePredicate,
371
- branchCleaner,
372
- mergeWatcher,
373
- cleaner,
374
- labelTransitioner,
375
- checkpointPointerWriter,
376
- order,
377
- };
378
- }
@@ -1,140 +0,0 @@
1
- // .agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js
2
- /**
3
- * InterventionRecorder — lifecycle listener that persists out-of-band
4
- * manual interventions to the `epic-run-state` structured comment.
5
- *
6
- * Subscribes to (per Story #2410 / Task #2416):
7
- * - `intervention.recorded` → calls `appendIntervention` on the
8
- * `epic-run-state-store` so the `manualInterventions` array on the
9
- * epic-run-state checkpoint comment grows by exactly one record.
10
- *
11
- * The lifecycle event is the canonical signal that the host LLM has
12
- * performed an out-of-band recovery (`AskUserQuestion`, manual
13
- * `git restore`, `--no-ff` recovery merge, `story-close --skipValidation`,
14
- * etc.). The auto-merge predicate reads the persisted array and only
15
- * fires when it is empty, so getting one record per emit is load-bearing.
16
- *
17
- * Idempotency contract (listeners/README.md): the listener keeps a
18
- * per-instance `Set<seqId>` of seqIds it has handled. A repeat
19
- * invocation with the same seqId short-circuits without calling the
20
- * store. (`epic-run-state-store.appendIntervention` is NOT idempotent
21
- * on its own — it always appends — so the seqId guard is the only
22
- * thing standing between a bus replay and a duplicated record.)
23
- *
24
- * Side-effect firewall (listeners/README.md):
25
- * - MAY read/write the epic-run-state comment via the injected
26
- * `provider` (through `epic-run-state-store`).
27
- * - MUST NOT `bus.emit()` from inside the handler body — the bus is a
28
- * sequential mediator and cannot re-enter safely.
29
- * - MUST NOT import any module from
30
- * `STATE_MUTATING_MODULES` in `check-lifecycle-lint.js`. The
31
- * epic-run-state-store module is NOT on that blocklist; the lint
32
- * rule treats it as a safe persistence boundary for listeners.
33
- */
34
-
35
- import { appendIntervention } from '../../epic-run-state-store.js';
36
-
37
- export const INTERVENTION_RECORDED_EVENT = 'intervention.recorded';
38
-
39
- export class InterventionRecorder {
40
- /**
41
- * @param {object} opts
42
- * @param {object} opts.provider Ticketing provider threaded through to
43
- * `appendIntervention`.
44
- * @param {number} opts.epicId Target ticket id (the Epic). Used both
45
- * to scope `appendIntervention` and to filter incoming emits — a
46
- * payload whose `epicId` does not match this listener's Epic is
47
- * ignored (defensive; production wiring only ever emits with the
48
- * listener's own epicId).
49
- * @param {{ warn?: Function, debug?: Function }} [opts.logger]
50
- * @param {Function} [opts.appendIntervention] Injected store fn —
51
- * defaults to the canonical import. Tests pass a spy.
52
- */
53
- constructor(opts = {}) {
54
- if (!opts.provider) {
55
- throw new TypeError('InterventionRecorder requires a provider');
56
- }
57
- if (!Number.isInteger(opts.epicId) || opts.epicId < 1) {
58
- throw new TypeError('InterventionRecorder requires a numeric epicId');
59
- }
60
- this.provider = opts.provider;
61
- this.epicId = opts.epicId;
62
- this.logger = opts.logger ?? console;
63
- this._appendIntervention =
64
- typeof opts.appendIntervention === 'function'
65
- ? opts.appendIntervention
66
- : appendIntervention;
67
- /** @type {Set<number>} seqIds we've already handled. */
68
- this._seen = new Set();
69
- this.events = Object.freeze([INTERVENTION_RECORDED_EVENT]);
70
- }
71
-
72
- /**
73
- * Subscribe to `intervention.recorded`. Returns the unsubscribe
74
- * handles so tests / teardown can detach without re-binding through
75
- * the bus's private registry.
76
- */
77
- register(bus) {
78
- if (!bus || typeof bus.on !== 'function') {
79
- throw new TypeError(
80
- 'InterventionRecorder.register requires a bus with on()',
81
- );
82
- }
83
- return this.events.map((event) =>
84
- bus.on(event, async (ctx) => this.handle(ctx)),
85
- );
86
- }
87
-
88
- /**
89
- * Handle one `intervention.recorded` emit. Idempotent on seqId. The
90
- * payload has already been schema-validated by the bus, so `reason`
91
- * is guaranteed to be a non-empty string and `epicId` a positive
92
- * integer.
93
- *
94
- * @param {{ event: string, seqId: number, payload: { epicId: number, reason: string, source?: string, ts?: string } }} ctx
95
- */
96
- async handle({ event, seqId, payload }) {
97
- if (event !== INTERVENTION_RECORDED_EVENT) return;
98
- if (this._seen.has(seqId)) {
99
- this.logger.debug?.(
100
- `[InterventionRecorder] skip duplicate seqId=${seqId} (idempotent)`,
101
- );
102
- return;
103
- }
104
- // Defensive epicId filter — a misrouted emit (e.g., a shared bus in
105
- // tests) should not pollute a different Epic's state comment.
106
- if (payload?.epicId !== this.epicId) {
107
- this.logger.debug?.(
108
- `[InterventionRecorder] skip payload.epicId=${payload?.epicId} (listener bound to #${this.epicId})`,
109
- );
110
- return;
111
- }
112
- this._seen.add(seqId);
113
-
114
- const entry = {
115
- reason: payload.reason,
116
- };
117
- if (typeof payload.source === 'string' && payload.source.length > 0) {
118
- entry.source = payload.source;
119
- }
120
- if (typeof payload.ts === 'string' && payload.ts.length > 0) {
121
- entry.ts = payload.ts;
122
- }
123
- try {
124
- await this._appendIntervention({
125
- provider: this.provider,
126
- epicId: this.epicId,
127
- entry,
128
- });
129
- } catch (err) {
130
- this.logger.warn?.(
131
- `[InterventionRecorder] appendIntervention failed for seqId=${seqId}: ${err?.message ?? err}`,
132
- );
133
- throw err;
134
- }
135
- }
136
-
137
- resetSeen() {
138
- this._seen.clear();
139
- }
140
- }
@@ -1,144 +0,0 @@
1
- // .agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js
2
- /**
3
- * LabelTransitioner — lifecycle listener that owns the terminal Epic
4
- * ticket-state flip: on `epic.complete` it transitions the Epic to
5
- * `agent::done` via the canonical `transitionTicketState` API (which
6
- * also closes the issue with `state_reason: completed` and mirrors the
7
- * Projects-v2 status column).
8
- *
9
- * Subscribes to:
10
- * - `epic.complete` → and ONLY this event.
11
- *
12
- * Why this listener exists (regression history): the original
13
- * LabelTransitioner lived in the in-process epic-runner stratum and was
14
- * deleted with it (Story #3908 / #3936) — but the `lifecycle-emit`
15
- * listener chain never re-registered a replacement, so the Epic
16
- * `agent::done` flip silently had NO owner. Every docstring in
17
- * `cleaner.js` / `branch-cleaner.js` / `merge-watcher.js` that says
18
- * "LabelTransitioner flips the Epic ticket to `agent::done` on
19
- * epic.complete" referenced a ghost. In practice the flip only happened
20
- * when a driving session (or the operator) ran `update-ticket-state.js`
21
- * by hand — observed live on 2026-07-11 when Epics #4405 / #4425 /
22
- * #4429 merged cleanly (Cleaner archived, `epic.complete` on the
23
- * ledger) yet stayed at `agent::executing`. This listener restores the
24
- * documented contract on the SOLE production wiring path
25
- * (`buildDefaultListenerChain`).
26
- *
27
- * Side effects executed inside `handle()`:
28
- * 1. `transitionTicketState(provider, epicId, STATE_LABELS.DONE)` —
29
- * adds `agent::done`, removes every other `agent::*` label, closes
30
- * the issue as completed (idempotent when the GitHub Closes-#N
31
- * linkage already closed it), syncs the board column, and runs the
32
- * upward cascade (a no-op sweep here: story-close already flipped
33
- * every child Story).
34
- *
35
- * Failure posture: a failed transition THROWS (per
36
- * `rules/orchestration-error-handling.md` — throw, never fatal). The
37
- * bus's `onFailed` hook records the failure on the ledger and
38
- * `lifecycle-emit`'s `collectOutcomes` → `emitBlockedSignal` path
39
- * surfaces it loudly, so a provider outage cannot silently strand the
40
- * Epic at `agent::executing` again — the exact failure mode this
41
- * listener exists to close.
42
- *
43
- * Idempotency contract: per-instance `Set<string>` of
44
- * `${event}:${seqId}` keys (the standard bus-replay defence). The
45
- * transition itself is also idempotent at the provider layer (label
46
- * add/remove and a close on an already-closed issue are no-ops), so a
47
- * cross-process replay after a crash re-runs the flip harmlessly.
48
- *
49
- * Side-effect firewall: exactly one provider call per handled event. No
50
- * filesystem writes, no follow-up bus emits, no `gh` shell-outs.
51
- */
52
-
53
- import { STATE_LABELS } from '../../ticketing/reads.js';
54
- import { transitionTicketState } from '../../ticketing/transition.js';
55
-
56
- /**
57
- * The single lifecycle event this listener subscribes to. `epic.complete`
58
- * is the terminal event of a successful Epic run, emitted by Cleaner
59
- * AFTER the MergeWatcher observed a non-null mergeCommit — so the flip
60
- * can never fire for an Epic whose PR did not actually merge.
61
- */
62
- export const SUBSCRIBED_EVENT = 'epic.complete';
63
-
64
- export class LabelTransitioner {
65
- /**
66
- * @param {object} opts
67
- * @param {object} opts.bus Lifecycle bus exposing `on()`.
68
- * @param {number} opts.epicId Epic ticket id.
69
- * @param {import('../../../ITicketingProvider.js').ITicketingProvider} opts.provider
70
- * Ticketing provider. Required — the chain builder skips this
71
- * listener entirely when no provider is wired (parity with
72
- * AutomergePredicate's guard), so construction can demand one.
73
- * @param {{ info?: Function, warn?: Function, debug?: Function }} [opts.logger]
74
- */
75
- constructor(opts = {}) {
76
- if (!opts.bus || typeof opts.bus.on !== 'function') {
77
- throw new TypeError('LabelTransitioner requires a bus with on()');
78
- }
79
- if (!Number.isInteger(opts.epicId) || opts.epicId < 1) {
80
- throw new TypeError('LabelTransitioner requires a numeric epicId');
81
- }
82
- if (!opts.provider) {
83
- // Truthiness-only, parity with AutomergePredicate: the chain
84
- // builder's best-effort registration must not explode on a
85
- // shape-minimal provider — a malformed one fails loudly at
86
- // handle time instead, where the ledger records the outcome.
87
- throw new TypeError('LabelTransitioner requires a provider');
88
- }
89
- this.bus = opts.bus;
90
- this.epicId = opts.epicId;
91
- this.provider = opts.provider;
92
- this.logger = opts.logger ?? console;
93
- /** @type {Set<string>} `${event}:${seqId}` idempotency cache. */
94
- this._seen = new Set();
95
- // Canonical subscription-set shape: the lifecycle doc-drift gate
96
- // (`check-lifecycle-doc-drift.js#extractCodeEvents`) and the
97
- // event-connectivity contract test both resolve this frozen array
98
- // (constant references included) to derive the subscriber table.
99
- this.events = Object.freeze([SUBSCRIBED_EVENT]);
100
- }
101
-
102
- /**
103
- * Register the listener on `epic.complete`. Returns the array of
104
- * unsubscribe callbacks the bus produced (parity with the sibling
105
- * listeners).
106
- */
107
- register() {
108
- return this.events.map((event) =>
109
- this.bus.on(event, async (ctx) => this.handle(ctx)),
110
- );
111
- }
112
-
113
- /**
114
- * Bus listener body. Idempotent on `(event, seqId)`; flips the Epic
115
- * to `agent::done` exactly once per observed `epic.complete`.
116
- */
117
- async handle({ event, seqId }) {
118
- const key = `${event}:${seqId}`;
119
- if (this._seen.has(key)) {
120
- this.logger.debug?.(
121
- `[LabelTransitioner] skip duplicate ${key} (idempotent)`,
122
- );
123
- return;
124
- }
125
- this._seen.add(key);
126
-
127
- this.logger.info?.(
128
- `[LabelTransitioner] epic.complete observed — transitioning Epic #${this.epicId} to ${STATE_LABELS.DONE}.`,
129
- );
130
- // Throws on failure by design: the ledger records the failed
131
- // listener outcome and lifecycle-emit surfaces it (see the failure
132
- // posture note in the module docstring). Swallowing here would
133
- // recreate the silent agent::executing strand this listener fixes.
134
- await transitionTicketState(this.provider, this.epicId, STATE_LABELS.DONE);
135
- }
136
-
137
- /**
138
- * Test-only — clear the idempotency cache so a single instance can
139
- * exercise replay scenarios without re-constructing the listener.
140
- */
141
- resetSeen() {
142
- this._seen.clear();
143
- }
144
- }