mandrel 1.93.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/acceptance-critic.md +129 -0
  3. package/.agents/agents/story-worker.md +161 -0
  4. package/.agents/docs/SDLC.md +489 -1285
  5. package/.agents/docs/agentrc-reference.json +177 -67
  6. package/.agents/docs/configuration.md +108 -136
  7. package/.agents/docs/execution-reference.md +44 -22
  8. package/.agents/docs/quality-gates.md +13 -19
  9. package/.agents/docs/workflows.md +3 -3
  10. package/.agents/instructions.md +107 -108
  11. package/.agents/rules/ci-remediation.md +8 -12
  12. package/.agents/rules/git-conventions-reference.md +224 -0
  13. package/.agents/rules/git-conventions.md +42 -223
  14. package/.agents/rules/security-baseline.md +5 -0
  15. package/.agents/rules/testing-standards.md +106 -13
  16. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  17. package/.agents/schemas/agentrc.schema.json +71 -201
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  20. package/.agents/schemas/risk-verdict.schema.json +0 -13
  21. package/.agents/scripts/acceptance-eval.js +62 -18
  22. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  23. package/.agents/scripts/analyze-execution.js +1 -1
  24. package/.agents/scripts/audit-to-stories.js +7 -7
  25. package/.agents/scripts/boot-sweep.js +1 -1
  26. package/.agents/scripts/check-context-budget.js +62 -5
  27. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  28. package/.agents/scripts/check-prepush-recovery.js +1 -1
  29. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  30. package/.agents/scripts/diagnose-friction.js +0 -6
  31. package/.agents/scripts/lib/Logger.js +6 -10
  32. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  33. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  34. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  35. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  36. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  37. package/.agents/scripts/lib/baselines/reader.js +1 -6
  38. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  39. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  40. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  41. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  42. package/.agents/scripts/lib/checks/index.js +2 -1
  43. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  44. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  45. package/.agents/scripts/lib/cli-args.js +16 -7
  46. package/.agents/scripts/lib/close-validation/gates.js +160 -22
  47. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  48. package/.agents/scripts/lib/config/ci.js +6 -31
  49. package/.agents/scripts/lib/config/delivery-routing.js +103 -0
  50. package/.agents/scripts/lib/config/explain.js +57 -36
  51. package/.agents/scripts/lib/config/limits.js +17 -58
  52. package/.agents/scripts/lib/config/paths.js +0 -2
  53. package/.agents/scripts/lib/config/quality.js +1 -1
  54. package/.agents/scripts/lib/config/runners.js +17 -50
  55. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  56. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  57. package/.agents/scripts/lib/config-resolver.js +3 -8
  58. package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
  59. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
  60. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  61. package/.agents/scripts/lib/dependency-parser.js +3 -2
  62. package/.agents/scripts/lib/doc-tiers.js +39 -4
  63. package/.agents/scripts/lib/duplicate-search.js +211 -41
  64. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  66. package/.agents/scripts/lib/framework-version.js +2 -3
  67. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  68. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  69. package/.agents/scripts/lib/git-utils.js +32 -6
  70. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  71. package/.agents/scripts/lib/label-constants.js +10 -23
  72. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  73. package/.agents/scripts/lib/observability/active-story-env.js +112 -3
  74. package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
  75. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  76. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  77. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  78. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  79. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  80. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  81. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
  82. package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
  83. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  84. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  85. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  86. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  87. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  88. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  89. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  90. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  91. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  92. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  93. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  94. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  95. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  96. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  97. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  98. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  99. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  100. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  102. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  103. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  104. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  105. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  106. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  107. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  108. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
  109. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  110. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  111. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  112. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  113. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  114. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  115. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  116. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  118. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  119. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  120. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  121. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  122. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  124. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  131. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  132. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  134. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  135. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  136. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  137. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  138. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  139. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  140. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  141. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  142. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  143. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  144. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  145. package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
  146. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  147. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  148. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  149. package/.agents/scripts/lib/planning-corpus.js +16 -11
  150. package/.agents/scripts/lib/preflight-runner.js +2 -2
  151. package/.agents/scripts/lib/provider-factory.js +1 -1
  152. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  153. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  154. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  155. package/.agents/scripts/lib/story-adjacency.js +11 -14
  156. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  157. package/.agents/scripts/lib/story-plan.js +2 -4
  158. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  159. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  160. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  161. package/.agents/scripts/lib/validation-evidence.js +1 -1
  162. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  163. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  164. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  165. package/.agents/scripts/lint-issue-body.js +71 -40
  166. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  167. package/.agents/scripts/notify.js +4 -3
  168. package/.agents/scripts/plan-context.js +64 -74
  169. package/.agents/scripts/plan-persist.js +121 -280
  170. package/.agents/scripts/plan-run-epilogue.js +97 -0
  171. package/.agents/scripts/post-structured-comment.js +38 -0
  172. package/.agents/scripts/providers/github/issues.js +17 -33
  173. package/.agents/scripts/providers/github/mappers.js +0 -12
  174. package/.agents/scripts/providers/github/tickets.js +2 -5
  175. package/.agents/scripts/resolve-plan-run.js +117 -0
  176. package/.agents/scripts/signals-view.js +24 -19
  177. package/.agents/scripts/single-story-close.js +11 -14
  178. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  179. package/.agents/scripts/single-story-init.js +29 -20
  180. package/.agents/scripts/stories-wave-tick.js +6 -6
  181. package/.agents/scripts/story-plan.js +26 -47
  182. package/.agents/scripts/sync-claude-agents.js +165 -0
  183. package/.agents/scripts/update-ticket-state.js +37 -15
  184. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  185. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  186. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  187. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  188. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  189. package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
  190. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  191. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  192. package/.agents/skills/skills.index.json +8 -418
  193. package/.agents/starter-agentrc.json +0 -5
  194. package/.agents/templates/agent-protocol.md +9 -10
  195. package/.agents/workflows/audit-architecture.md +3 -3
  196. package/.agents/workflows/audit-clean-code.md +3 -3
  197. package/.agents/workflows/audit-dependencies.md +3 -3
  198. package/.agents/workflows/audit-devops.md +3 -3
  199. package/.agents/workflows/audit-documentation.md +5 -5
  200. package/.agents/workflows/audit-lighthouse.md +3 -3
  201. package/.agents/workflows/audit-navigability.md +3 -2
  202. package/.agents/workflows/audit-performance.md +3 -3
  203. package/.agents/workflows/audit-privacy.md +3 -3
  204. package/.agents/workflows/audit-quality.md +3 -3
  205. package/.agents/workflows/audit-security.md +3 -3
  206. package/.agents/workflows/audit-seo.md +3 -3
  207. package/.agents/workflows/audit-sre.md +3 -3
  208. package/.agents/workflows/audit-to-stories.md +20 -20
  209. package/.agents/workflows/audit-ux-ui.md +3 -3
  210. package/.agents/workflows/deliver.md +122 -131
  211. package/.agents/workflows/git-cleanup.md +3 -4
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
  214. package/.agents/workflows/helpers/code-review.md +70 -193
  215. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  216. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  217. package/.agents/workflows/helpers/diagnose.md +10 -10
  218. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  219. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  220. package/.agents/workflows/helpers/signals.md +16 -16
  221. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  222. package/.agents/workflows/mandrel-update.md +3 -2
  223. package/.agents/workflows/plan.md +112 -145
  224. package/.agents/workflows/qa-assist.md +24 -30
  225. package/.agents/workflows/qa-explore.md +29 -38
  226. package/.agents/workflows/qa-run.md +2 -2
  227. package/README.md +9 -8
  228. package/docs/CHANGELOG.md +46 -0
  229. package/lib/cli/registry.js +95 -0
  230. package/lib/migrations/index.js +6 -5
  231. package/package.json +5 -3
  232. package/.agents/personas/architect.md +0 -113
  233. package/.agents/personas/devops-engineer.md +0 -38
  234. package/.agents/personas/engineer-mobile.md +0 -120
  235. package/.agents/personas/engineer-web.md +0 -111
  236. package/.agents/personas/engineer.md +0 -119
  237. package/.agents/personas/product.md +0 -94
  238. package/.agents/personas/project-manager.md +0 -114
  239. package/.agents/personas/qa-engineer.md +0 -95
  240. package/.agents/personas/refactorer.md +0 -113
  241. package/.agents/personas/security-engineer.md +0 -112
  242. package/.agents/personas/sre.md +0 -86
  243. package/.agents/personas/technical-writer.md +0 -101
  244. package/.agents/personas/ux-designer.md +0 -95
  245. package/.agents/schemas/dispatch-manifest.json +0 -232
  246. package/.agents/schemas/epic-spec.schema.json +0 -153
  247. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  248. package/.agents/scripts/dispatcher.js +0 -295
  249. package/.agents/scripts/epic-audit-prepare.js +0 -497
  250. package/.agents/scripts/epic-audit-recheck.js +0 -274
  251. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  252. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  253. package/.agents/scripts/epic-deliver-prepare.js +0 -590
  254. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  255. package/.agents/scripts/epic-plan-clarity.js +0 -211
  256. package/.agents/scripts/epic-plan-decompose.js +0 -54
  257. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  258. package/.agents/scripts/epic-plan-spec.js +0 -64
  259. package/.agents/scripts/epic-reconcile.js +0 -625
  260. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  261. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  262. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  263. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  264. package/.agents/scripts/lib/config/preflight.js +0 -58
  265. package/.agents/scripts/lib/config/retro.js +0 -77
  266. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  267. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  268. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  269. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
  270. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  271. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  272. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  273. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  274. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  275. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  276. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  277. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  278. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  279. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  280. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  281. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  282. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  283. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  284. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  285. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  286. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  287. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  288. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
  289. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  290. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  291. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  292. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  293. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  294. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  295. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  296. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  297. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  298. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  299. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  300. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  301. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  302. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  303. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  304. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  305. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  306. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  307. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  308. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  309. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  310. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  311. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  313. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
  314. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  315. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  316. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  317. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
  318. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  319. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  320. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  321. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  322. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  323. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  324. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  325. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  326. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  327. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  328. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  329. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  330. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  331. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  332. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  333. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  334. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  335. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  336. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  337. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  338. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  339. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  340. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  341. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  342. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  343. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  344. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  345. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  346. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  347. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  348. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  349. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  350. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  351. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  352. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  353. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  354. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  355. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  356. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  357. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  358. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  359. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  360. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  361. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
  362. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  363. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  364. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  365. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  366. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  367. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  368. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  369. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  370. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  371. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  372. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  373. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  374. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  375. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  376. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  377. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  378. package/.agents/scripts/lib/spec/index.js +0 -36
  379. package/.agents/scripts/lib/spec/loader.js +0 -425
  380. package/.agents/scripts/lib/spec/state.js +0 -208
  381. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  382. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  383. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  384. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  385. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  386. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  387. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  388. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  389. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  390. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  391. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  392. package/.agents/scripts/lifecycle-emit.js +0 -510
  393. package/.agents/scripts/plan-critics.js +0 -199
  394. package/.agents/scripts/retro-run.js +0 -218
  395. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  396. package/.agents/scripts/story-close.js +0 -294
  397. package/.agents/scripts/story-init.js +0 -599
  398. package/.agents/scripts/story-phase.js +0 -369
  399. package/.agents/scripts/wave-tick.js +0 -335
  400. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  401. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  402. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  403. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  404. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  405. package/.agents/skills/core/context-engineering/examples.md +0 -58
  406. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  407. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  408. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  409. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  410. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  411. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  412. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  413. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
  414. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  415. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  416. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  417. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  418. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  419. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  420. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  421. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  422. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  423. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  424. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  425. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  426. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  427. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  428. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  429. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  430. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  431. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  432. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  433. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  434. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  435. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  436. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  437. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  438. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  439. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  440. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  441. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  442. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  443. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  444. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  445. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  446. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  447. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  448. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  449. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  450. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  451. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  452. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
  453. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
  454. package/.agents/workflows/helpers/deliver-epic.md +0 -955
  455. package/.agents/workflows/helpers/deliver-stories.md +0 -440
  456. package/.agents/workflows/helpers/epic-audit.md +0 -189
  457. package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
  458. package/.agents/workflows/helpers/epic-testing.md +0 -125
  459. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  460. package/.agents/workflows/helpers/plan-epic.md +0 -351
  461. package/.agents/workflows/helpers/plan-story.md +0 -251
  462. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  463. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,147 +0,0 @@
1
- /**
2
- * emit-story-dispatch-end.js — Story #3900.
3
- *
4
- * Programmatic helper that appends a single `story.dispatch.end` NDJSON
5
- * record to `temp/epic-<id>/lifecycle.ndjson` for one recorded Story.
6
- *
7
- * Why this exists:
8
- * The `wave-tick.js` in-flight reconciler (and the `--check-idle`
9
- * watchdog) compute "in-flight" Stories as those carrying a
10
- * `story.dispatch.start` record WITHOUT a matching `story.dispatch.end`.
11
- * Before this Story the only producer of `story.dispatch.end` was
12
- * `lib/orchestration/wave-session.js`, which nothing imports outside
13
- * tests — so every dispatched Story stayed "in-flight" forever and the
14
- * idle watchdog flagged completed Stories as stalled. The host-LLM driven
15
- * `/deliver` path closes a wave through `epic-execute-record-wave.js`,
16
- * so that CLI is the correct place to emit the matching dispatch-end per
17
- * recorded Story.
18
- *
19
- * The emit mirrors the thin direct-append shape of
20
- * `lifecycle-emit-story-dispatch.js` (start) and `emit-story-heartbeat.js`:
21
- * one schema-validated `emitted`-kind record, no full listener chain. It is
22
- * best-effort at the call site — a failed append must not block the wave
23
- * loop, so callers wrap it and log.
24
- *
25
- * Schema contract (story.dispatch.end.schema.json):
26
- * { storyId, outcome: done|blocked|failed|skipped, durationMs }
27
- */
28
-
29
- import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
30
- import path from 'node:path';
31
- import { fileURLToPath } from 'node:url';
32
-
33
- import Ajv2020 from 'ajv/dist/2020.js';
34
- import addFormats from 'ajv-formats';
35
-
36
- import { epicLedgerPath } from '../../config/temp-paths.js';
37
-
38
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
39
- const SCHEMA_PATH = path.resolve(
40
- __dirname,
41
- '..',
42
- '..',
43
- '..',
44
- '..',
45
- 'schemas',
46
- 'lifecycle',
47
- 'story.dispatch.end.schema.json',
48
- );
49
-
50
- const VALID_OUTCOMES = new Set(['done', 'blocked', 'failed', 'skipped']);
51
-
52
- let _validator;
53
-
54
- function getValidator() {
55
- if (_validator) return _validator;
56
- const schema = JSON.parse(readFileSync(SCHEMA_PATH, 'utf8'));
57
- const ajv = new Ajv2020({ allErrors: true, strict: false });
58
- addFormats(ajv);
59
- _validator = ajv.compile(schema);
60
- return _validator;
61
- }
62
-
63
- /**
64
- * Append exactly one `story.dispatch.end` NDJSON record to the Epic ledger.
65
- *
66
- * @param {object} opts
67
- * @param {number} opts.epicId Parent Epic — required for the ledger path.
68
- * @param {number} opts.storyId Story whose dispatch settled.
69
- * @param {string} opts.outcome One of done|blocked|failed|skipped.
70
- * @param {number} [opts.durationMs=0] Wall-clock dispatch duration in ms.
71
- * Defaults to 0 when the host loop does
72
- * not track per-Story timing.
73
- * @param {string} [opts.timestamp] ISO-8601 wall clock. Defaults to now().
74
- * @param {object} [opts.config] Optional resolved config for tempRoot.
75
- * @param {string} [opts.ledgerPath] Override for tests.
76
- * @returns {{ ledgerPath: string, record: object }}
77
- */
78
- export function emitStoryDispatchEnd(opts) {
79
- const {
80
- epicId,
81
- storyId,
82
- outcome,
83
- durationMs = 0,
84
- timestamp = new Date().toISOString(),
85
- config,
86
- ledgerPath: ledgerPathOverride,
87
- } = opts ?? {};
88
-
89
- if (!Number.isInteger(epicId) || epicId < 1) {
90
- throw new Error('emitStoryDispatchEnd: epicId must be a positive integer');
91
- }
92
- if (!Number.isInteger(storyId) || storyId < 1) {
93
- throw new Error('emitStoryDispatchEnd: storyId must be a positive integer');
94
- }
95
- if (!VALID_OUTCOMES.has(outcome)) {
96
- throw new Error(
97
- `emitStoryDispatchEnd: outcome "${outcome}" must be one of: ${[...VALID_OUTCOMES].join(', ')}`,
98
- );
99
- }
100
- if (!Number.isInteger(durationMs) || durationMs < 0) {
101
- throw new Error(
102
- 'emitStoryDispatchEnd: durationMs must be a non-negative integer',
103
- );
104
- }
105
-
106
- const payload = { storyId, outcome, durationMs };
107
-
108
- const validator = getValidator();
109
- if (!validator(payload)) {
110
- const detail = (validator.errors ?? [])
111
- .map((e) => `${e.instancePath || '/'} ${e.message}`)
112
- .join('; ');
113
- throw new Error(
114
- `emitStoryDispatchEnd: payload failed schema validation: ${detail}`,
115
- );
116
- }
117
-
118
- const ledgerPath = ledgerPathOverride ?? epicLedgerPath(epicId, config);
119
- mkdirSync(path.dirname(ledgerPath), { recursive: true });
120
- const record = {
121
- kind: 'emitted',
122
- ts: timestamp,
123
- event: 'story.dispatch.end',
124
- payload,
125
- };
126
- appendFileSync(ledgerPath, `${JSON.stringify(record)}\n`, 'utf8');
127
- return { ledgerPath, record };
128
- }
129
-
130
- /**
131
- * Map a recorded Story status (`done`/`blocked`/`failed`) to the
132
- * `story.dispatch.end` outcome enum. The status taxonomy is a strict subset
133
- * of the outcome enum, so the mapping is identity for the three values the
134
- * record-wave projection produces. Unknown values throw rather than emit a
135
- * schema-invalid record.
136
- *
137
- * @param {string} status
138
- * @returns {string}
139
- */
140
- export function storyStatusToDispatchOutcome(status) {
141
- if (!VALID_OUTCOMES.has(status)) {
142
- throw new Error(
143
- `storyStatusToDispatchOutcome: unknown story status "${status}"`,
144
- );
145
- }
146
- return status;
147
- }
@@ -1,384 +0,0 @@
1
- // .agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js
2
- /**
3
- * AcceptanceReconciler — lifecycle listener that gates Finalize on the
4
- * close-time acceptance-spec reconciliation. Story #2253 (Epic #2172):
5
- * the reconciliation moves *ahead* of the push + `gh pr create` call so
6
- * that AC coverage gaps block PR creation (review High-2).
7
- *
8
- * Subscribes to:
9
- * - `epic.close.end` → emit `acceptance.reconcile.start`, run the
10
- * `reconcileAcceptanceSpec` helper, emit one of
11
- * `acceptance.reconcile.ok | .waived | .skipped | .failed`, and on
12
- * `.failed` also emit `epic.blocked` so the LabelTransitioner /
13
- * StructuredCommentPoster / NotifyDispatcher trio fire the blocker
14
- * side effects exactly as a `story.blocked` cascade would.
15
- *
16
- * The Finalizer listener subscribes ONLY to `acceptance.reconcile.ok`,
17
- * so this listener is the authoritative safety gate ahead of any push
18
- * or PR-create work. The legacy `epic-deliver-finalize.js` shim still
19
- * exists for backwards compatibility, but its in-line reconciliation
20
- * call is replaced by the event-driven path.
21
- *
22
- * Idempotency contract (Acceptance Spec AC-10):
23
- * - Per-instance `Set<string>` of `${event}:${seqId}` keys. A repeat
24
- * `(event, seqId)` short-circuits without re-running reconciliation
25
- * and emits no events.
26
- * - The reconciler helper's only write is the section-scoped
27
- * disposition record inside the Epic body's ## Acceptance Table
28
- * region (Story #4324) — itself idempotent — so the seqId guard is
29
- * the only defence the listener needs.
30
- *
31
- * Side-effect firewall: the listener owns the reconciliation call and
32
- * the four outcome emits. It does NOT mutate labels, post comments, or
33
- * call `notify` directly — those are downstream listener concerns.
34
- */
35
-
36
- import { reconcileAcceptanceSpec as defaultReconcileAcceptanceSpec } from '../../../../acceptance-spec-reconciler.js';
37
-
38
- /**
39
- * Classify a `reconcileAcceptanceSpec` result envelope into the typed
40
- * outcome event the listener should emit. Pure function — exported so
41
- * unit tests can drive every branch without a bus instance.
42
- *
43
- * The reconciler exposes a four-value `status` discriminant:
44
- * - `'waived'` → the Epic carries `acceptance::n-a` (or no linked
45
- * spec under `--skip-when-waived`). Emit
46
- * `acceptance.reconcile.waived` with reason
47
- * `'waiver'`. Story #2893 split this out from
48
- * `.skipped` so the Finalizer can subscribe to
49
- * `.waived` and route waived Epics through to PR
50
- * creation, while empty-spec Epics still
51
- * terminate without a PR via `.skipped`.
52
- * - `'empty-spec'` → the linked spec exists but declares zero AC IDs.
53
- * Treated as "no work to do"; emit `.skipped` with
54
- * reason `'empty-spec'` so operators see the
55
- * outcome explicitly (no silent skip).
56
- * - `'ok'` → the spec has AC IDs and every one is covered by
57
- * a non-pending scenario. Emit `.ok`.
58
- * - `'gap'` → at least one AC is pending or missing. Emit
59
- * `.failed` carrying a compact reason summary;
60
- * the listener then emits `epic.blocked` to flip
61
- * the Epic ticket.
62
- *
63
- * @param {object|undefined|null} result reconciler envelope.
64
- * @returns {{ outcome: 'ok'|'waived'|'skipped'|'failed', reason?: string }}
65
- */
66
- export function classifyReconcileResult(result) {
67
- if (!result || typeof result !== 'object') {
68
- return { outcome: 'failed', reason: 'reconciler-no-result' };
69
- }
70
- const status = result.status;
71
- if (status === 'waived') {
72
- return { outcome: 'waived', reason: 'waiver' };
73
- }
74
- if (status === 'empty-spec') {
75
- return { outcome: 'skipped', reason: 'empty-spec' };
76
- }
77
- if (status === 'ok') {
78
- return { outcome: 'ok' };
79
- }
80
- if (status === 'gap') {
81
- const missing = Array.isArray(result.missing) ? result.missing : [];
82
- const pending = Array.isArray(result.pending) ? result.pending : [];
83
- const parts = [];
84
- if (missing.length > 0) parts.push(`missing=${missing.join(',')}`);
85
- if (pending.length > 0) parts.push(`pending=${pending.join(',')}`);
86
- const reason =
87
- parts.length > 0 ? `gap:${parts.join(';')}` : 'gap:unspecified';
88
- return { outcome: 'failed', reason };
89
- }
90
- // Unknown status — fail closed so the operator sees the surprise.
91
- return { outcome: 'failed', reason: `unknown-status:${String(status)}` };
92
- }
93
-
94
- /**
95
- * AcceptanceReconciler — instantiate one per Epic run and call
96
- * `register()` to wire it onto the bus. Stateless w.r.t. the system
97
- * under orchestration; per-run state is the `(event, seqId)`
98
- * idempotency cache + the classification log.
99
- */
100
- export class AcceptanceReconciler {
101
- /**
102
- * @param {object} opts
103
- * @param {object} opts.bus Lifecycle bus instance (must expose
104
- * `on()` and `emit()`).
105
- * @param {number} opts.epicId Epic ticket id.
106
- * @param {string} [opts.cwd] Working directory passed through to the
107
- * reconciler helper. Defaults to `process.cwd()`.
108
- * @param {object} [opts.provider] Ticketing provider — injected into
109
- * the reconciler call so the lifecycle bus does not need to
110
- * construct one itself.
111
- * @param {object} [opts.config] Resolved orchestration config —
112
- * injected for the same reason.
113
- * @param {Function} [opts.reconcileAcceptanceSpecFn] Override of the
114
- * helper for tests; defaults to the production export.
115
- * @param {{ info?: Function, warn?: Function, debug?: Function }} [opts.logger]
116
- */
117
- constructor(opts = {}) {
118
- if (
119
- !opts.bus ||
120
- typeof opts.bus.on !== 'function' ||
121
- typeof opts.bus.emit !== 'function'
122
- ) {
123
- throw new TypeError(
124
- 'AcceptanceReconciler requires a bus with on() and emit()',
125
- );
126
- }
127
- if (!Number.isInteger(opts.epicId) || opts.epicId < 1) {
128
- throw new TypeError('AcceptanceReconciler requires a numeric epicId');
129
- }
130
- this.bus = opts.bus;
131
- this.epicId = opts.epicId;
132
- this.cwd = opts.cwd ?? process.cwd();
133
- this.provider = opts.provider ?? null;
134
- this.config = opts.config ?? null;
135
- this.reconcileAcceptanceSpecFn =
136
- opts.reconcileAcceptanceSpecFn ?? defaultReconcileAcceptanceSpec;
137
- this.logger = opts.logger ?? console;
138
- /** @type {Set<string>} `${event}:${seqId}` keys we've handled. */
139
- this._seen = new Set();
140
- /**
141
- * Classification log — mirrors the BlockerHandler "no silent skip"
142
- * surface so tests can confirm every `epic.close.end` we observed
143
- * was classified into exactly one outcome.
144
- *
145
- * @type {Array<{ event: string, seqId: number, outcome: string, reason?: string }>}
146
- */
147
- this.classifications = [];
148
- this.events = Object.freeze(['epic.close.end']);
149
- }
150
-
151
- /**
152
- * Register this listener on the bus. Returns an array of unsubscribe
153
- * functions (one per event) for test teardown.
154
- */
155
- register() {
156
- return this.events.map((event) =>
157
- this.bus.on(event, async (ctx) => this.handle(ctx)),
158
- );
159
- }
160
-
161
- /**
162
- * Bus listener body. The bus passes `{ event, seqId, payload }`. The
163
- * listener:
164
- * 1. Idempotently short-circuits a repeat `(event, seqId)`.
165
- * 2. Emits `acceptance.reconcile.start`.
166
- * 3. Runs `reconcileAcceptanceSpec` with injected provider/config.
167
- * 4. Emits exactly one of `.ok` / `.skipped` / `.failed`.
168
- * 5. On `.failed`, additionally emits `epic.blocked` so the
169
- * downstream listener trio (label flip + structured comment +
170
- * notify) fires the operator-visible blocker side effects.
171
- *
172
- * The listener does NOT throw on reconciler failures: the bus's
173
- * `onFailed` boundary already persists the originating
174
- * `epic.close.end` record; surfacing a throw here would short-circuit
175
- * other `epic.close.end` listeners (e.g. trace logger) and is not
176
- * needed for correctness — the `acceptance.reconcile.failed` +
177
- * `epic.blocked` emits are the cascade contract.
178
- *
179
- * @param {{ event: string, seqId: number, payload: object }} ctx
180
- */
181
- async handle({ event, seqId, payload }) {
182
- const key = `${event}:${seqId}`;
183
- if (this._seen.has(key)) {
184
- this.classifications.push({
185
- event,
186
- seqId,
187
- outcome: 'skipped',
188
- reason: 'duplicate-seqId',
189
- });
190
- this.logger.debug?.(
191
- `[AcceptanceReconciler] skip duplicate ${key} (idempotent)`,
192
- );
193
- return;
194
- }
195
- this._seen.add(key);
196
-
197
- const epicIdFromPayload = Number(payload?.epicId);
198
- const epicId = Number.isInteger(epicIdFromPayload)
199
- ? epicIdFromPayload
200
- : this.epicId;
201
-
202
- // 1. Start emit. The downstream ledger-diff `reconcile-ordering`
203
- // assert checks for `acceptance.reconcile.ok` before `pr.created`,
204
- // but operators want to see the `.start` marker in the trace too.
205
- try {
206
- await this.bus.emit('acceptance.reconcile.start', { epicId });
207
- } catch (err) {
208
- // Schema validation against a known-good payload should never
209
- // throw; if it does, surface and bail — there's no point running
210
- // the reconciler when we cannot announce its outcome.
211
- this.classifications.push({
212
- event,
213
- seqId,
214
- outcome: 'failed',
215
- reason: `start-emit-failed:${err?.message ?? err}`,
216
- });
217
- this.logger.warn?.(
218
- `[AcceptanceReconciler] acceptance.reconcile.start emit failed: ${err?.message ?? err}`,
219
- );
220
- return;
221
- }
222
-
223
- // 2. Run the reconciler. The helper itself throws on hard errors
224
- // (no linked spec + no waiver, etc.); convert those into
225
- // `.failed` emits rather than re-propagating, so the cascade
226
- // contract holds even when the spec is malformed.
227
- let result;
228
- let thrown = null;
229
- try {
230
- result = await this.reconcileAcceptanceSpecFn({
231
- epicId,
232
- cwd: this.cwd,
233
- injectedProvider: this.provider ?? undefined,
234
- injectedConfig: this.config ?? undefined,
235
- loggerImpl: this.logger,
236
- // Honour `acceptance::n-a` — the helper already returns
237
- // `status: 'waived'` for that label, but `skipWhenWaived: true`
238
- // additionally tolerates a missing acceptance-table section under
239
- // the waiver (we want the same forgiving stance the inline
240
- // finalize call had).
241
- skipWhenWaived: true,
242
- // Close time is the one place the verification outcome is
243
- // recorded into the Epic body's ## Acceptance Table section
244
- // (section-scoped write, Story #4324).
245
- writeDispositions: true,
246
- });
247
- } catch (err) {
248
- thrown = err;
249
- }
250
-
251
- const baseRead = thrown == null && result != null;
252
-
253
- if (thrown != null) {
254
- const reason = `reconcile-threw:${thrown?.message ?? thrown}`;
255
- await this._emitFailure({ event, seqId, baseRead, reason });
256
- return;
257
- }
258
-
259
- const classification = classifyReconcileResult(result);
260
- if (classification.outcome === 'ok') {
261
- await this._emitOk({ event, seqId, baseRead });
262
- return;
263
- }
264
- if (classification.outcome === 'waived') {
265
- await this._emitWaived({
266
- event,
267
- seqId,
268
- baseRead,
269
- reason: classification.reason ?? 'waiver',
270
- });
271
- return;
272
- }
273
- if (classification.outcome === 'skipped') {
274
- await this._emitSkipped({
275
- event,
276
- seqId,
277
- baseRead,
278
- reason: classification.reason ?? 'skipped',
279
- });
280
- return;
281
- }
282
- await this._emitFailure({
283
- event,
284
- seqId,
285
- baseRead,
286
- reason: classification.reason ?? 'gap',
287
- });
288
- }
289
-
290
- /**
291
- * Emit `acceptance.reconcile.ok` and record the classification.
292
- * Helper carved out so each branch in `handle()` reads as a single
293
- * decision.
294
- */
295
- async _emitOk({ event, seqId, baseRead }) {
296
- this.classifications.push({ event, seqId, outcome: 'ok' });
297
- try {
298
- await this.bus.emit('acceptance.reconcile.ok', { baseRead });
299
- } catch (err) {
300
- this.logger.warn?.(
301
- `[AcceptanceReconciler] acceptance.reconcile.ok emit failed (swallowed): ${err?.message ?? err}`,
302
- );
303
- }
304
- }
305
-
306
- /**
307
- * Emit `acceptance.reconcile.waived` for the `acceptance::n-a` path.
308
- * Story #2893 split this out of `.skipped` so the Finalizer can
309
- * subscribe to `.waived` and route waived Epics through to PR
310
- * creation. The schema pins `reason` to `'waiver'`.
311
- */
312
- async _emitWaived({ event, seqId, baseRead, reason }) {
313
- this.classifications.push({ event, seqId, outcome: 'waived', reason });
314
- try {
315
- await this.bus.emit('acceptance.reconcile.waived', {
316
- baseRead,
317
- reason,
318
- });
319
- } catch (err) {
320
- this.logger.warn?.(
321
- `[AcceptanceReconciler] acceptance.reconcile.waived emit failed (swallowed): ${err?.message ?? err}`,
322
- );
323
- }
324
- }
325
-
326
- /**
327
- * Emit `acceptance.reconcile.skipped` carrying a typed `reason`. The
328
- * schema requires `reason` to be non-empty so callers always pass one
329
- * (no silent skip).
330
- */
331
- async _emitSkipped({ event, seqId, baseRead, reason }) {
332
- this.classifications.push({ event, seqId, outcome: 'skipped', reason });
333
- try {
334
- await this.bus.emit('acceptance.reconcile.skipped', {
335
- baseRead,
336
- reason,
337
- });
338
- } catch (err) {
339
- this.logger.warn?.(
340
- `[AcceptanceReconciler] acceptance.reconcile.skipped emit failed (swallowed): ${err?.message ?? err}`,
341
- );
342
- }
343
- }
344
-
345
- /**
346
- * Emit `acceptance.reconcile.failed` and then `epic.blocked`, in that
347
- * order. The `epic.blocked` emit drives the LabelTransitioner /
348
- * StructuredCommentPoster / NotifyDispatcher trio so the operator
349
- * sees the blocker label flip + structured comment + webhook,
350
- * exactly as a `story.blocked` cascade would.
351
- *
352
- * Failures inside the `epic.blocked` emit are swallowed (the
353
- * `.failed` record is already on the ledger; double-throwing here
354
- * would mask the original reason).
355
- */
356
- async _emitFailure({ event, seqId, baseRead, reason }) {
357
- this.classifications.push({ event, seqId, outcome: 'failed', reason });
358
- try {
359
- await this.bus.emit('acceptance.reconcile.failed', {
360
- baseRead,
361
- reason,
362
- });
363
- } catch (err) {
364
- this.logger.warn?.(
365
- `[AcceptanceReconciler] acceptance.reconcile.failed emit failed (swallowed): ${err?.message ?? err}`,
366
- );
367
- }
368
- try {
369
- await this.bus.emit('epic.blocked', {
370
- reason: `acceptance-reconcile:${reason}`,
371
- });
372
- } catch (err) {
373
- this.logger.warn?.(
374
- `[AcceptanceReconciler] epic.blocked emit failed (swallowed): ${err?.message ?? err}`,
375
- );
376
- }
377
- }
378
-
379
- /** Test helper — wipe the idempotency cache. */
380
- reset() {
381
- this._seen.clear();
382
- this.classifications = [];
383
- }
384
- }