mandrel 1.57.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 (843) hide show
  1. package/.agents/README.md +954 -0
  2. package/.agents/docs/SDLC.md +1420 -0
  3. package/.agents/docs/agentrc-reference.json +278 -0
  4. package/.agents/docs/configuration.md +1040 -0
  5. package/.agents/docs/workflows.md +59 -0
  6. package/.agents/instructions.md +384 -0
  7. package/.agents/personas/architect.md +107 -0
  8. package/.agents/personas/devops-engineer.md +36 -0
  9. package/.agents/personas/engineer-mobile.md +119 -0
  10. package/.agents/personas/engineer-web.md +110 -0
  11. package/.agents/personas/engineer.md +90 -0
  12. package/.agents/personas/product.md +88 -0
  13. package/.agents/personas/project-manager.md +110 -0
  14. package/.agents/personas/qa-engineer.md +91 -0
  15. package/.agents/personas/refactorer.md +110 -0
  16. package/.agents/personas/security-engineer.md +112 -0
  17. package/.agents/personas/sre.md +86 -0
  18. package/.agents/personas/technical-writer.md +100 -0
  19. package/.agents/personas/ux-designer.md +95 -0
  20. package/.agents/rules/api-conventions.md +75 -0
  21. package/.agents/rules/changelog-style.md +238 -0
  22. package/.agents/rules/gherkin-standards.md +146 -0
  23. package/.agents/rules/git-conventions.md +146 -0
  24. package/.agents/rules/orchestration-error-handling.md +35 -0
  25. package/.agents/rules/security-baseline.md +92 -0
  26. package/.agents/rules/shell-conventions.md +70 -0
  27. package/.agents/rules/test-seams.md +59 -0
  28. package/.agents/rules/testing-standards.md +177 -0
  29. package/.agents/runtime-deps.json +18 -0
  30. package/.agents/schemas/acceptance-eval-verdict.schema.json +93 -0
  31. package/.agents/schemas/agentrc.schema.json +1583 -0
  32. package/.agents/schemas/audit-results.schema.json +69 -0
  33. package/.agents/schemas/audit-rules.json +134 -0
  34. package/.agents/schemas/audit-rules.schema.json +69 -0
  35. package/.agents/schemas/baselines/baseline-envelope.schema.json +44 -0
  36. package/.agents/schemas/baselines/bundle-size.schema.json +47 -0
  37. package/.agents/schemas/baselines/coverage.schema.json +50 -0
  38. package/.agents/schemas/baselines/crap.schema.json +52 -0
  39. package/.agents/schemas/baselines/duplication.schema.json +62 -0
  40. package/.agents/schemas/baselines/lighthouse.schema.json +59 -0
  41. package/.agents/schemas/baselines/lint.schema.json +47 -0
  42. package/.agents/schemas/baselines/maintainability.schema.json +71 -0
  43. package/.agents/schemas/baselines/mutation.schema.json +52 -0
  44. package/.agents/schemas/crap-baseline.schema.json +57 -0
  45. package/.agents/schemas/crap-report.schema.json +102 -0
  46. package/.agents/schemas/dispatch-manifest.json +232 -0
  47. package/.agents/schemas/epic-perf-report.schema.json +89 -0
  48. package/.agents/schemas/epic-spec.schema.json +183 -0
  49. package/.agents/schemas/friction-event.schema.json +56 -0
  50. package/.agents/schemas/lifecycle/README.md +18 -0
  51. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +13 -0
  52. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +13 -0
  53. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +13 -0
  54. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +12 -0
  55. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +13 -0
  56. package/.agents/schemas/lifecycle/checkpoint.written.schema.json +13 -0
  57. package/.agents/schemas/lifecycle/close-validate.end.schema.json +18 -0
  58. package/.agents/schemas/lifecycle/close-validate.start.schema.json +13 -0
  59. package/.agents/schemas/lifecycle/code-review.end.schema.json +30 -0
  60. package/.agents/schemas/lifecycle/code-review.start.schema.json +12 -0
  61. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +14 -0
  62. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +13 -0
  63. package/.agents/schemas/lifecycle/epic.blocked.schema.json +13 -0
  64. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +12 -0
  65. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +12 -0
  66. package/.agents/schemas/lifecycle/epic.close.end.schema.json +12 -0
  67. package/.agents/schemas/lifecycle/epic.complete.schema.json +13 -0
  68. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +13 -0
  69. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +12 -0
  70. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +13 -0
  71. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +14 -0
  72. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +17 -0
  73. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +15 -0
  74. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +18 -0
  75. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +12 -0
  76. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +16 -0
  77. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +12 -0
  78. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +28 -0
  79. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +16 -0
  80. package/.agents/schemas/lifecycle/intervention.recorded.schema.json +15 -0
  81. package/.agents/schemas/lifecycle/ledger-record.schema.json +59 -0
  82. package/.agents/schemas/lifecycle/notification.emitted.schema.json +18 -0
  83. package/.agents/schemas/lifecycle/pr.created.schema.json +14 -0
  84. package/.agents/schemas/lifecycle/retro.end.schema.json +16 -0
  85. package/.agents/schemas/lifecycle/retro.start.schema.json +12 -0
  86. package/.agents/schemas/lifecycle/story.blocked.schema.json +13 -0
  87. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +17 -0
  88. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +15 -0
  89. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +20 -0
  90. package/.agents/schemas/lifecycle/story.merged.schema.json +13 -0
  91. package/.agents/schemas/mi-report.schema.json +58 -0
  92. package/.agents/schemas/model-attribution.schema.json +49 -0
  93. package/.agents/schemas/qa-finding.schema.json +133 -0
  94. package/.agents/schemas/qa-ledger.schema.json +89 -0
  95. package/.agents/schemas/risk-verdict.schema.json +53 -0
  96. package/.agents/schemas/signal-event.schema.json +58 -0
  97. package/.agents/schemas/skill.schema.json +31 -0
  98. package/.agents/schemas/skills-index.schema.json +81 -0
  99. package/.agents/schemas/story-perf-summary.schema.json +73 -0
  100. package/.agents/schemas/validation-evidence.schema.json +78 -0
  101. package/.agents/scripts/README.md +93 -0
  102. package/.agents/scripts/acceptance-eval.js +284 -0
  103. package/.agents/scripts/acceptance-spec-reconciler.js +556 -0
  104. package/.agents/scripts/agents-bootstrap-github.js +634 -0
  105. package/.agents/scripts/analyze-execution.js +369 -0
  106. package/.agents/scripts/assert-branch.js +83 -0
  107. package/.agents/scripts/audit-labels-bootstrap.js +253 -0
  108. package/.agents/scripts/audit-to-stories.js +257 -0
  109. package/.agents/scripts/bootstrap.js +1378 -0
  110. package/.agents/scripts/check-baselines.js +81 -0
  111. package/.agents/scripts/check-dead-exports.js +311 -0
  112. package/.agents/scripts/check-doc-links.js +401 -0
  113. package/.agents/scripts/check-gherkin-placeholders.js +663 -0
  114. package/.agents/scripts/check-lifecycle-doc-drift.js +402 -0
  115. package/.agents/scripts/check-lifecycle-lint.js +379 -0
  116. package/.agents/scripts/check-prepush-recovery.js +90 -0
  117. package/.agents/scripts/check-windows-git-perf.js +138 -0
  118. package/.agents/scripts/cleanup-repo-test-temp.js +67 -0
  119. package/.agents/scripts/coverage-capture.js +112 -0
  120. package/.agents/scripts/detect-merges.js +111 -0
  121. package/.agents/scripts/diagnose-friction.js +257 -0
  122. package/.agents/scripts/diagnose.js +240 -0
  123. package/.agents/scripts/dispatcher.js +295 -0
  124. package/.agents/scripts/drain-pending-cleanup.js +147 -0
  125. package/.agents/scripts/epic-audit-prepare.js +419 -0
  126. package/.agents/scripts/epic-audit-recheck.js +241 -0
  127. package/.agents/scripts/epic-deliver-note-intervention.js +192 -0
  128. package/.agents/scripts/epic-deliver-preflight.js +407 -0
  129. package/.agents/scripts/epic-deliver-prepare.js +383 -0
  130. package/.agents/scripts/epic-execute-record-wave.js +463 -0
  131. package/.agents/scripts/epic-plan-clarity.js +201 -0
  132. package/.agents/scripts/epic-plan-decompose.js +79 -0
  133. package/.agents/scripts/epic-plan-healthcheck.js +363 -0
  134. package/.agents/scripts/epic-plan-spec-validate.js +111 -0
  135. package/.agents/scripts/epic-plan-spec.js +198 -0
  136. package/.agents/scripts/epic-reconcile.js +637 -0
  137. package/.agents/scripts/evidence-gate.js +235 -0
  138. package/.agents/scripts/generate-config-docs.js +516 -0
  139. package/.agents/scripts/generate-lifecycle-docs.js +224 -0
  140. package/.agents/scripts/generate-skills-index.js +252 -0
  141. package/.agents/scripts/generate-workflows-doc.js +168 -0
  142. package/.agents/scripts/git-cleanup.js +124 -0
  143. package/.agents/scripts/git-pr-quality-gate.js +203 -0
  144. package/.agents/scripts/git-rebase-and-resolve.js +234 -0
  145. package/.agents/scripts/hierarchy-gate.js +176 -0
  146. package/.agents/scripts/hydrate-context.js +179 -0
  147. package/.agents/scripts/install-matrix-assert.js +282 -0
  148. package/.agents/scripts/lib/Graph.js +326 -0
  149. package/.agents/scripts/lib/ITicketingProvider.js +349 -0
  150. package/.agents/scripts/lib/Logger.js +194 -0
  151. package/.agents/scripts/lib/audit-suite/cli.js +64 -0
  152. package/.agents/scripts/lib/audit-suite/findings.js +164 -0
  153. package/.agents/scripts/lib/audit-suite/frontmatter-lint.js +32 -0
  154. package/.agents/scripts/lib/audit-suite/frontmatter.js +110 -0
  155. package/.agents/scripts/lib/audit-suite/index.js +22 -0
  156. package/.agents/scripts/lib/audit-suite/runner.js +233 -0
  157. package/.agents/scripts/lib/audit-suite/selector.js +235 -0
  158. package/.agents/scripts/lib/audit-suite/substitutions.js +124 -0
  159. package/.agents/scripts/lib/audit-suite/workflow-loader.js +49 -0
  160. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +130 -0
  161. package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +114 -0
  162. package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +93 -0
  163. package/.agents/scripts/lib/audit-to-stories/group-findings.js +265 -0
  164. package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +246 -0
  165. package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +160 -0
  166. package/.agents/scripts/lib/auto-refresh-baselines.js +308 -0
  167. package/.agents/scripts/lib/baseline-loader.js +0 -0
  168. package/.agents/scripts/lib/baseline-schema-registry.js +69 -0
  169. package/.agents/scripts/lib/baseline-snapshot.js +716 -0
  170. package/.agents/scripts/lib/baselines/component-matcher.js +21 -0
  171. package/.agents/scripts/lib/baselines/components.js +126 -0
  172. package/.agents/scripts/lib/baselines/diff-scope-cli.js +203 -0
  173. package/.agents/scripts/lib/baselines/duplication-scanner.js +220 -0
  174. package/.agents/scripts/lib/baselines/env-overrides.js +129 -0
  175. package/.agents/scripts/lib/baselines/envelope.js +368 -0
  176. package/.agents/scripts/lib/baselines/exit-codes.js +89 -0
  177. package/.agents/scripts/lib/baselines/git-base.js +0 -0
  178. package/.agents/scripts/lib/baselines/kernel.js +111 -0
  179. package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +220 -0
  180. package/.agents/scripts/lib/baselines/kinds/bundle-size.js +157 -0
  181. package/.agents/scripts/lib/baselines/kinds/coverage.js +194 -0
  182. package/.agents/scripts/lib/baselines/kinds/crap.js +555 -0
  183. package/.agents/scripts/lib/baselines/kinds/duplication.js +197 -0
  184. package/.agents/scripts/lib/baselines/kinds/lighthouse.js +185 -0
  185. package/.agents/scripts/lib/baselines/kinds/lint.js +172 -0
  186. package/.agents/scripts/lib/baselines/kinds/maintainability.js +340 -0
  187. package/.agents/scripts/lib/baselines/kinds/mutation.js +153 -0
  188. package/.agents/scripts/lib/baselines/path-canon.js +279 -0
  189. package/.agents/scripts/lib/baselines/preview-gates.js +298 -0
  190. package/.agents/scripts/lib/baselines/reader.js +321 -0
  191. package/.agents/scripts/lib/baselines/refresh-service.js +733 -0
  192. package/.agents/scripts/lib/baselines/scope.js +291 -0
  193. package/.agents/scripts/lib/baselines/writer.js +312 -0
  194. package/.agents/scripts/lib/bdd-runner-detect.js +417 -0
  195. package/.agents/scripts/lib/bdd-scenario-scanner.js +310 -0
  196. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +202 -0
  197. package/.agents/scripts/lib/bootstrap/branch-protection.js +222 -0
  198. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +171 -0
  199. package/.agents/scripts/lib/bootstrap/commit-push.js +146 -0
  200. package/.agents/scripts/lib/bootstrap/gh-list.js +153 -0
  201. package/.agents/scripts/lib/bootstrap/gh-preflight.js +306 -0
  202. package/.agents/scripts/lib/bootstrap/hitl-confirm.js +89 -0
  203. package/.agents/scripts/lib/bootstrap/install-ledger.js +174 -0
  204. package/.agents/scripts/lib/bootstrap/manifest.js +272 -0
  205. package/.agents/scripts/lib/bootstrap/merge-methods.js +108 -0
  206. package/.agents/scripts/lib/bootstrap/preflight.js +195 -0
  207. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +801 -0
  208. package/.agents/scripts/lib/bootstrap/prompt.js +480 -0
  209. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +370 -0
  210. package/.agents/scripts/lib/bootstrap/summary.js +75 -0
  211. package/.agents/scripts/lib/bootstrap/workflow-audit.js +256 -0
  212. package/.agents/scripts/lib/branch-name-guard.js +98 -0
  213. package/.agents/scripts/lib/c8-cli-path.js +21 -0
  214. package/.agents/scripts/lib/changed-files.js +184 -0
  215. package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +104 -0
  216. package/.agents/scripts/lib/checks/core-bare-clean.js +48 -0
  217. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +54 -0
  218. package/.agents/scripts/lib/checks/index.js +288 -0
  219. package/.agents/scripts/lib/checks/push-hook-parity.js +106 -0
  220. package/.agents/scripts/lib/checks/stale-origin-epic.js +49 -0
  221. package/.agents/scripts/lib/checks/state.js +558 -0
  222. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +186 -0
  223. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +182 -0
  224. package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +92 -0
  225. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +81 -0
  226. package/.agents/scripts/lib/checks/worktree-residue-biome.js +55 -0
  227. package/.agents/scripts/lib/cli/parse-numeric.js +60 -0
  228. package/.agents/scripts/lib/cli/standard-args.js +351 -0
  229. package/.agents/scripts/lib/cli-args.js +286 -0
  230. package/.agents/scripts/lib/cli-utils.js +69 -0
  231. package/.agents/scripts/lib/close-validation/projections/head-sha.js +44 -0
  232. package/.agents/scripts/lib/close-validation/projections/inputs.js +86 -0
  233. package/.agents/scripts/lib/close-validation/projections/maintainability.js +286 -0
  234. package/.agents/scripts/lib/close-validation.js +897 -0
  235. package/.agents/scripts/lib/codebase-snapshot.js +513 -0
  236. package/.agents/scripts/lib/command-header.js +33 -0
  237. package/.agents/scripts/lib/config/acceptance-eval.js +95 -0
  238. package/.agents/scripts/lib/config/baselines.js +60 -0
  239. package/.agents/scripts/lib/config/ci.js +30 -0
  240. package/.agents/scripts/lib/config/commands.js +36 -0
  241. package/.agents/scripts/lib/config/defaults.js +119 -0
  242. package/.agents/scripts/lib/config/explain.js +348 -0
  243. package/.agents/scripts/lib/config/gates/bundle-size.schema.js +23 -0
  244. package/.agents/scripts/lib/config/gates/coverage.schema.js +18 -0
  245. package/.agents/scripts/lib/config/gates/crap.schema.js +33 -0
  246. package/.agents/scripts/lib/config/gates/duplication.schema.js +26 -0
  247. package/.agents/scripts/lib/config/gates/index.js +36 -0
  248. package/.agents/scripts/lib/config/gates/lighthouse.schema.js +23 -0
  249. package/.agents/scripts/lib/config/gates/lint.schema.js +9 -0
  250. package/.agents/scripts/lib/config/gates/maintainability.schema.js +20 -0
  251. package/.agents/scripts/lib/config/gates/mutation.schema.js +12 -0
  252. package/.agents/scripts/lib/config/gates/shared.js +117 -0
  253. package/.agents/scripts/lib/config/github.js +122 -0
  254. package/.agents/scripts/lib/config/lifecycle.js +40 -0
  255. package/.agents/scripts/lib/config/limits.js +211 -0
  256. package/.agents/scripts/lib/config/paths.js +73 -0
  257. package/.agents/scripts/lib/config/preflight.js +58 -0
  258. package/.agents/scripts/lib/config/quality.js +665 -0
  259. package/.agents/scripts/lib/config/retro.js +77 -0
  260. package/.agents/scripts/lib/config/runners.js +105 -0
  261. package/.agents/scripts/lib/config/runtime.js +167 -0
  262. package/.agents/scripts/lib/config/shared.js +46 -0
  263. package/.agents/scripts/lib/config/sync-agentrc.js +243 -0
  264. package/.agents/scripts/lib/config/temp-paths.js +373 -0
  265. package/.agents/scripts/lib/config/validate-orchestration.js +81 -0
  266. package/.agents/scripts/lib/config/worktree-isolation.js +80 -0
  267. package/.agents/scripts/lib/config-resolver.js +298 -0
  268. package/.agents/scripts/lib/config-schema-shared.js +32 -0
  269. package/.agents/scripts/lib/config-schema.js +20 -0
  270. package/.agents/scripts/lib/config-settings-schema-delivery.js +332 -0
  271. package/.agents/scripts/lib/config-settings-schema-quality.js +165 -0
  272. package/.agents/scripts/lib/config-settings-schema.js +420 -0
  273. package/.agents/scripts/lib/coverage-baseline.js +352 -0
  274. package/.agents/scripts/lib/coverage-capture.js +195 -0
  275. package/.agents/scripts/lib/coverage-utils.js +239 -0
  276. package/.agents/scripts/lib/cpu-pool.js +223 -0
  277. package/.agents/scripts/lib/crap-engine.js +119 -0
  278. package/.agents/scripts/lib/crap-utils.js +479 -0
  279. package/.agents/scripts/lib/degraded-mode.js +69 -0
  280. package/.agents/scripts/lib/dependency-parser.js +129 -0
  281. package/.agents/scripts/lib/duplicate-search.js +189 -0
  282. package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +70 -0
  283. package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +197 -0
  284. package/.agents/scripts/lib/dynamic-workflow/capability.js +396 -0
  285. package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +80 -0
  286. package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +72 -0
  287. package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +90 -0
  288. package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +43 -0
  289. package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +83 -0
  290. package/.agents/scripts/lib/env-loader.js +52 -0
  291. package/.agents/scripts/lib/epic-merge-lock.js +239 -0
  292. package/.agents/scripts/lib/epic-plan-clarity.js +142 -0
  293. package/.agents/scripts/lib/epic-plan-ideation.js +228 -0
  294. package/.agents/scripts/lib/error-redactor.js +125 -0
  295. package/.agents/scripts/lib/errors/index.js +67 -0
  296. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +230 -0
  297. package/.agents/scripts/lib/feedback-loop/code-review-graduator.js +207 -0
  298. package/.agents/scripts/lib/feedback-loop/graduator-core.js +421 -0
  299. package/.agents/scripts/lib/feedback-loop/memory-freshness.js +480 -0
  300. package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +229 -0
  301. package/.agents/scripts/lib/findings/classify-finding.js +195 -0
  302. package/.agents/scripts/lib/findings/promote-finding.js +353 -0
  303. package/.agents/scripts/lib/findings/route-finding.js +283 -0
  304. package/.agents/scripts/lib/findings/semantic-issue-search.js +179 -0
  305. package/.agents/scripts/lib/findings/severity.js +102 -0
  306. package/.agents/scripts/lib/gates/baseline-store.js +106 -0
  307. package/.agents/scripts/lib/gates/friction.js +43 -0
  308. package/.agents/scripts/lib/gh-exec.js +553 -0
  309. package/.agents/scripts/lib/git/cached-fetch.js +0 -0
  310. package/.agents/scripts/lib/git/sync-from-base.js +162 -0
  311. package/.agents/scripts/lib/git-branch-cleanup.js +213 -0
  312. package/.agents/scripts/lib/git-branch-lifecycle.js +353 -0
  313. package/.agents/scripts/lib/git-merge-orchestrator.js +261 -0
  314. package/.agents/scripts/lib/git-utils.js +363 -0
  315. package/.agents/scripts/lib/github-url.js +29 -0
  316. package/.agents/scripts/lib/install-cmd-parser.js +51 -0
  317. package/.agents/scripts/lib/issue-link-parser.js +74 -0
  318. package/.agents/scripts/lib/json-utils.js +60 -0
  319. package/.agents/scripts/lib/label-constants.js +169 -0
  320. package/.agents/scripts/lib/label-taxonomy.js +200 -0
  321. package/.agents/scripts/lib/maintainability-engine.js +164 -0
  322. package/.agents/scripts/lib/maintainability-utils.js +343 -0
  323. package/.agents/scripts/lib/mandrel-catalog.js +170 -0
  324. package/.agents/scripts/lib/mutation/baseline-snapshot.js +238 -0
  325. package/.agents/scripts/lib/mutation/config-detector.js +119 -0
  326. package/.agents/scripts/lib/mutation/stryker-runner.js +306 -0
  327. package/.agents/scripts/lib/mutation/survivor-report.js +160 -0
  328. package/.agents/scripts/lib/notifications/notifier.js +75 -0
  329. package/.agents/scripts/lib/observability/active-story-env.js +182 -0
  330. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +221 -0
  331. package/.agents/scripts/lib/observability/perf-aggregator.js +887 -0
  332. package/.agents/scripts/lib/observability/perf-report-readers.js +319 -0
  333. package/.agents/scripts/lib/observability/perf-report-render.js +182 -0
  334. package/.agents/scripts/lib/observability/signals-writer.js +296 -0
  335. package/.agents/scripts/lib/observability/source-classifier.js +103 -0
  336. package/.agents/scripts/lib/observability/tool-trace-hook.js +417 -0
  337. package/.agents/scripts/lib/onboard/detect-stack.js +300 -0
  338. package/.agents/scripts/lib/onboard/scaffold-docs.js +128 -0
  339. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +173 -0
  340. package/.agents/scripts/lib/orchestration/cascade-grouping.js +275 -0
  341. package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +131 -0
  342. package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +80 -0
  343. package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +132 -0
  344. package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +142 -0
  345. package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +149 -0
  346. package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +158 -0
  347. package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +56 -0
  348. package/.agents/scripts/lib/orchestration/code-review.js +652 -0
  349. package/.agents/scripts/lib/orchestration/column-sync.js +286 -0
  350. package/.agents/scripts/lib/orchestration/context-envelope.js +280 -0
  351. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +581 -0
  352. package/.agents/scripts/lib/orchestration/dependency-analyzer.js +88 -0
  353. package/.agents/scripts/lib/orchestration/detectors-phase.js +188 -0
  354. package/.agents/scripts/lib/orchestration/dispatch-engine.js +144 -0
  355. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +206 -0
  356. package/.agents/scripts/lib/orchestration/doc-reader.js +94 -0
  357. package/.agents/scripts/lib/orchestration/epic-cleanup.js +473 -0
  358. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +310 -0
  359. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/cli.js +167 -0
  360. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +151 -0
  361. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +74 -0
  362. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +78 -0
  363. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +72 -0
  364. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +155 -0
  365. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +321 -0
  366. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +75 -0
  367. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +86 -0
  368. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +235 -0
  369. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +197 -0
  370. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +48 -0
  371. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +94 -0
  372. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +414 -0
  373. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +55 -0
  374. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +105 -0
  375. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +235 -0
  376. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +120 -0
  377. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +118 -0
  378. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +295 -0
  379. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +186 -0
  380. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +50 -0
  381. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +146 -0
  382. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +110 -0
  383. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +392 -0
  384. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +217 -0
  385. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +235 -0
  386. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter.js +69 -0
  387. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +32 -0
  388. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +291 -0
  389. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +175 -0
  390. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +37 -0
  391. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +127 -0
  392. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +400 -0
  393. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +285 -0
  394. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +66 -0
  395. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +797 -0
  396. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +619 -0
  397. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +335 -0
  398. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +230 -0
  399. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +363 -0
  400. package/.agents/scripts/lib/orchestration/error-journal.js +139 -0
  401. package/.agents/scripts/lib/orchestration/file-assumption-enum.js +31 -0
  402. package/.agents/scripts/lib/orchestration/file-assumptions.js +506 -0
  403. package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +116 -0
  404. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +241 -0
  405. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +489 -0
  406. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +88 -0
  407. package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +219 -0
  408. package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +309 -0
  409. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +99 -0
  410. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +123 -0
  411. package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +57 -0
  412. package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +114 -0
  413. package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +426 -0
  414. package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +84 -0
  415. package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +365 -0
  416. package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +72 -0
  417. package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +69 -0
  418. package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +214 -0
  419. package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +137 -0
  420. package/.agents/scripts/lib/orchestration/label-transitions.js +43 -0
  421. package/.agents/scripts/lib/orchestration/lifecycle/bus.js +309 -0
  422. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +147 -0
  423. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +155 -0
  424. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +226 -0
  425. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +69 -0
  426. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +378 -0
  427. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +248 -0
  428. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +527 -0
  429. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +259 -0
  430. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +278 -0
  431. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +355 -0
  432. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +647 -0
  433. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +331 -0
  434. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +140 -0
  435. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +421 -0
  436. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +168 -0
  437. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +668 -0
  438. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +322 -0
  439. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +114 -0
  440. package/.agents/scripts/lib/orchestration/manifest-builder.js +216 -0
  441. package/.agents/scripts/lib/orchestration/model-attribution.js +390 -0
  442. package/.agents/scripts/lib/orchestration/parked-follow-ons.js +147 -0
  443. package/.agents/scripts/lib/orchestration/phase-runner.js +87 -0
  444. package/.agents/scripts/lib/orchestration/plan-review-routing.js +63 -0
  445. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +86 -0
  446. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +212 -0
  447. package/.agents/scripts/lib/orchestration/planning-context-budget.js +213 -0
  448. package/.agents/scripts/lib/orchestration/planning-risk.js +155 -0
  449. package/.agents/scripts/lib/orchestration/planning-state-manager.js +318 -0
  450. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +56 -0
  451. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +33 -0
  452. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +78 -0
  453. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +68 -0
  454. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +118 -0
  455. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +396 -0
  456. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +205 -0
  457. package/.agents/scripts/lib/orchestration/pr-base-guard.js +47 -0
  458. package/.agents/scripts/lib/orchestration/preflight-cache.js +164 -0
  459. package/.agents/scripts/lib/orchestration/reassert-status-column.js +202 -0
  460. package/.agents/scripts/lib/orchestration/reconciler.js +137 -0
  461. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +152 -0
  462. package/.agents/scripts/lib/orchestration/recut.js +56 -0
  463. package/.agents/scripts/lib/orchestration/resolves-token.js +127 -0
  464. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +94 -0
  465. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +448 -0
  466. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +335 -0
  467. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +133 -0
  468. package/.agents/scripts/lib/orchestration/retro-heuristics.js +57 -0
  469. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +275 -0
  470. package/.agents/scripts/lib/orchestration/retro-proposals.js +395 -0
  471. package/.agents/scripts/lib/orchestration/retro-runner.js +171 -0
  472. package/.agents/scripts/lib/orchestration/review-depth.js +93 -0
  473. package/.agents/scripts/lib/orchestration/review-providers/codex.js +363 -0
  474. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +205 -0
  475. package/.agents/scripts/lib/orchestration/review-providers/native.js +805 -0
  476. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +73 -0
  477. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +396 -0
  478. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +373 -0
  479. package/.agents/scripts/lib/orchestration/review-providers/types.js +89 -0
  480. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +107 -0
  481. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +159 -0
  482. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +194 -0
  483. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +81 -0
  484. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +190 -0
  485. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +70 -0
  486. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +106 -0
  487. package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +42 -0
  488. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +73 -0
  489. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +225 -0
  490. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +315 -0
  491. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +149 -0
  492. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +110 -0
  493. package/.agents/scripts/lib/orchestration/spec-freshness.js +320 -0
  494. package/.agents/scripts/lib/orchestration/spec-renderer.js +456 -0
  495. package/.agents/scripts/lib/orchestration/spec-section-validator.js +80 -0
  496. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +797 -0
  497. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +163 -0
  498. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +152 -0
  499. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +387 -0
  500. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +266 -0
  501. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +48 -0
  502. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +67 -0
  503. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +161 -0
  504. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +117 -0
  505. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +86 -0
  506. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +147 -0
  507. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +142 -0
  508. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +62 -0
  509. package/.agents/scripts/lib/orchestration/story-close/format-autofix-scoped.js +221 -0
  510. package/.agents/scripts/lib/orchestration/story-close/format-autofix-shared.js +123 -0
  511. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +216 -0
  512. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +636 -0
  513. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +198 -0
  514. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +105 -0
  515. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +222 -0
  516. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +220 -0
  517. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +291 -0
  518. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +234 -0
  519. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +110 -0
  520. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +86 -0
  521. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +112 -0
  522. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +157 -0
  523. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +434 -0
  524. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +290 -0
  525. package/.agents/scripts/lib/orchestration/story-close-recovery.js +643 -0
  526. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +67 -0
  527. package/.agents/scripts/lib/orchestration/task-body-validator.js +391 -0
  528. package/.agents/scripts/lib/orchestration/ticket-lease.js +358 -0
  529. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +783 -0
  530. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +367 -0
  531. package/.agents/scripts/lib/orchestration/ticket-validator.js +691 -0
  532. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +723 -0
  533. package/.agents/scripts/lib/orchestration/ticketing/reads.js +474 -0
  534. package/.agents/scripts/lib/orchestration/ticketing/state.js +559 -0
  535. package/.agents/scripts/lib/orchestration/ticketing.js +55 -0
  536. package/.agents/scripts/lib/orchestration/wave-marker.js +28 -0
  537. package/.agents/scripts/lib/orchestration/wave-record-io.js +277 -0
  538. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +189 -0
  539. package/.agents/scripts/lib/orchestration/wave-record-projection.js +423 -0
  540. package/.agents/scripts/lib/path-security.js +25 -0
  541. package/.agents/scripts/lib/plan-phase-cleanup.js +125 -0
  542. package/.agents/scripts/lib/preflight-runner.js +196 -0
  543. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +95 -0
  544. package/.agents/scripts/lib/presentation/manifest-builder.js +245 -0
  545. package/.agents/scripts/lib/presentation/manifest-formatter.js +243 -0
  546. package/.agents/scripts/lib/presentation/manifest-helpers.js +213 -0
  547. package/.agents/scripts/lib/presentation/manifest-persistence.js +262 -0
  548. package/.agents/scripts/lib/presentation/manifest-procedures.js +55 -0
  549. package/.agents/scripts/lib/presentation/manifest-render-waves.js +252 -0
  550. package/.agents/scripts/lib/presentation/manifest-renderer.js +188 -0
  551. package/.agents/scripts/lib/presentation/manifest-story-views.js +119 -0
  552. package/.agents/scripts/lib/provider-factory.js +80 -0
  553. package/.agents/scripts/lib/push-epic-retry.js +209 -0
  554. package/.agents/scripts/lib/qa/console-allowlist.js +151 -0
  555. package/.agents/scripts/lib/qa/coverage-report.js +181 -0
  556. package/.agents/scripts/lib/qa/coverage-verdict.js +296 -0
  557. package/.agents/scripts/lib/qa/propose-missing-test.js +95 -0
  558. package/.agents/scripts/lib/qa/qa-context-hydrator.js +296 -0
  559. package/.agents/scripts/lib/qa/qa-session.js +197 -0
  560. package/.agents/scripts/lib/qa/redact-evidence.js +245 -0
  561. package/.agents/scripts/lib/qa/resolve-qa-contract.js +190 -0
  562. package/.agents/scripts/lib/qa/resolve-selection.js +373 -0
  563. package/.agents/scripts/lib/runtime-deps/ensure-installed.js +100 -0
  564. package/.agents/scripts/lib/runtime-deps/manifest.js +96 -0
  565. package/.agents/scripts/lib/runtime-deps/preflight.js +78 -0
  566. package/.agents/scripts/lib/runtime-deps/scan-imports.js +202 -0
  567. package/.agents/scripts/lib/signals/detectors/common.js +36 -0
  568. package/.agents/scripts/lib/signals/detectors/hotspot.js +298 -0
  569. package/.agents/scripts/lib/signals/detectors/index.js +14 -0
  570. package/.agents/scripts/lib/signals/detectors/retry.js +289 -0
  571. package/.agents/scripts/lib/signals/detectors/rework.js +204 -0
  572. package/.agents/scripts/lib/signals/index.js +39 -0
  573. package/.agents/scripts/lib/signals/read.js +268 -0
  574. package/.agents/scripts/lib/signals/schema.js +225 -0
  575. package/.agents/scripts/lib/signals/span-tree.js +290 -0
  576. package/.agents/scripts/lib/signals/write.js +19 -0
  577. package/.agents/scripts/lib/single-story/confirm-merge.js +201 -0
  578. package/.agents/scripts/lib/single-story/story-merged-notify.js +126 -0
  579. package/.agents/scripts/lib/single-story-sweep/protection.js +274 -0
  580. package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +169 -0
  581. package/.agents/scripts/lib/single-story-sweep.js +329 -0
  582. package/.agents/scripts/lib/skills/parse-skill.js +202 -0
  583. package/.agents/scripts/lib/skills/walk-skill-files.js +56 -0
  584. package/.agents/scripts/lib/spec/index.js +36 -0
  585. package/.agents/scripts/lib/spec/loader.js +425 -0
  586. package/.agents/scripts/lib/spec/state.js +217 -0
  587. package/.agents/scripts/lib/story-body/story-body.js +743 -0
  588. package/.agents/scripts/lib/story-init/blocker-validator.js +68 -0
  589. package/.agents/scripts/lib/story-init/branch-initializer.js +422 -0
  590. package/.agents/scripts/lib/story-init/context-resolver.js +92 -0
  591. package/.agents/scripts/lib/story-init/donor-precheck.js +207 -0
  592. package/.agents/scripts/lib/story-init/hierarchy-tracer.js +36 -0
  593. package/.agents/scripts/lib/story-init/state-transitioner.js +80 -0
  594. package/.agents/scripts/lib/story-init/task-graph-builder.js +114 -0
  595. package/.agents/scripts/lib/story-init/transition-summary.js +34 -0
  596. package/.agents/scripts/lib/story-lifecycle.js +186 -0
  597. package/.agents/scripts/lib/story-plan.js +246 -0
  598. package/.agents/scripts/lib/task-utils.js +26 -0
  599. package/.agents/scripts/lib/templates/decomposer-prompts.js +168 -0
  600. package/.agents/scripts/lib/test-env.js +30 -0
  601. package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +52 -0
  602. package/.agents/scripts/lib/test-isolate/list-files.js +90 -0
  603. package/.agents/scripts/lib/test-isolate/parse-tap.js +75 -0
  604. package/.agents/scripts/lib/test-isolate/runner.js +483 -0
  605. package/.agents/scripts/lib/test-profile/parse-tap.js +136 -0
  606. package/.agents/scripts/lib/test-profile/render-report.js +45 -0
  607. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +35 -0
  608. package/.agents/scripts/lib/test-tiers.js +94 -0
  609. package/.agents/scripts/lib/util/concurrent-map.js +59 -0
  610. package/.agents/scripts/lib/util/phase-timer-state.js +72 -0
  611. package/.agents/scripts/lib/util/phase-timer.js +163 -0
  612. package/.agents/scripts/lib/util/poll-loop.js +86 -0
  613. package/.agents/scripts/lib/util/with-timeout.js +32 -0
  614. package/.agents/scripts/lib/validation-evidence.js +323 -0
  615. package/.agents/scripts/lib/wave-runner/tick.js +665 -0
  616. package/.agents/scripts/lib/wave-runner/wave-checkpoint.js +91 -0
  617. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +19 -0
  618. package/.agents/scripts/lib/workers/crap-worker.js +197 -0
  619. package/.agents/scripts/lib/workers/maintainability-report-worker.js +137 -0
  620. package/.agents/scripts/lib/workers/maintainability-worker.js +79 -0
  621. package/.agents/scripts/lib/workspace-provisioner.js +189 -0
  622. package/.agents/scripts/lib/worktree/bootstrapper.js +48 -0
  623. package/.agents/scripts/lib/worktree/inspector.js +140 -0
  624. package/.agents/scripts/lib/worktree/lifecycle/creation.js +118 -0
  625. package/.agents/scripts/lib/worktree/lifecycle/drift-detection.js +62 -0
  626. package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +276 -0
  627. package/.agents/scripts/lib/worktree/lifecycle/gc.js +49 -0
  628. package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +178 -0
  629. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +264 -0
  630. package/.agents/scripts/lib/worktree/lifecycle/precheck.js +100 -0
  631. package/.agents/scripts/lib/worktree/lifecycle/reap.js +588 -0
  632. package/.agents/scripts/lib/worktree/lifecycle/registry-sync.js +124 -0
  633. package/.agents/scripts/lib/worktree/lifecycle/shared.js +26 -0
  634. package/.agents/scripts/lib/worktree/lifecycle-manager.js +40 -0
  635. package/.agents/scripts/lib/worktree/node-modules-strategy.js +349 -0
  636. package/.agents/scripts/lib/worktree-manager.js +243 -0
  637. package/.agents/scripts/lifecycle-diff.js +206 -0
  638. package/.agents/scripts/lifecycle-emit-story-dispatch.js +194 -0
  639. package/.agents/scripts/lifecycle-emit.js +479 -0
  640. package/.agents/scripts/lint-baseline.js +507 -0
  641. package/.agents/scripts/lint-label-vocabulary.js +237 -0
  642. package/.agents/scripts/loc-delta.js +205 -0
  643. package/.agents/scripts/notify.js +307 -0
  644. package/.agents/scripts/package.json +3 -0
  645. package/.agents/scripts/post-structured-comment.js +127 -0
  646. package/.agents/scripts/pr-watch-with-update.js +152 -0
  647. package/.agents/scripts/providers/github/auth.js +65 -0
  648. package/.agents/scripts/providers/github/board-add.js +63 -0
  649. package/.agents/scripts/providers/github/branch-protection.js +186 -0
  650. package/.agents/scripts/providers/github/cache.js +72 -0
  651. package/.agents/scripts/providers/github/comments.js +131 -0
  652. package/.agents/scripts/providers/github/compose.js +111 -0
  653. package/.agents/scripts/providers/github/errors.js +242 -0
  654. package/.agents/scripts/providers/github/issues.js +242 -0
  655. package/.agents/scripts/providers/github/labels.js +179 -0
  656. package/.agents/scripts/providers/github/mappers.js +126 -0
  657. package/.agents/scripts/providers/github/merge-methods.js +82 -0
  658. package/.agents/scripts/providers/github/project-board.js +47 -0
  659. package/.agents/scripts/providers/github/projects-v2-graphql.js +472 -0
  660. package/.agents/scripts/providers/github/prs.js +103 -0
  661. package/.agents/scripts/providers/github/request-helpers.js +110 -0
  662. package/.agents/scripts/providers/github/sub-issues.js +369 -0
  663. package/.agents/scripts/providers/github/tickets.js +381 -0
  664. package/.agents/scripts/providers/github/transient-retry.js +62 -0
  665. package/.agents/scripts/providers/github.js +157 -0
  666. package/.agents/scripts/quality-preview.js +327 -0
  667. package/.agents/scripts/quality-watch.js +223 -0
  668. package/.agents/scripts/render-manifest.js +143 -0
  669. package/.agents/scripts/resync-status-column.js +176 -0
  670. package/.agents/scripts/retro-run.js +167 -0
  671. package/.agents/scripts/run-audit-suite.js +97 -0
  672. package/.agents/scripts/run-coverage.js +103 -0
  673. package/.agents/scripts/run-lint.js +94 -0
  674. package/.agents/scripts/run-test-profile.js +126 -0
  675. package/.agents/scripts/run-tests.js +185 -0
  676. package/.agents/scripts/run-verify.js +56 -0
  677. package/.agents/scripts/select-audits.js +155 -0
  678. package/.agents/scripts/signals-view.js +294 -0
  679. package/.agents/scripts/single-story-close.js +83 -0
  680. package/.agents/scripts/single-story-confirm-merge.js +183 -0
  681. package/.agents/scripts/single-story-init.js +692 -0
  682. package/.agents/scripts/stories-wave-tick.js +415 -0
  683. package/.agents/scripts/story-close.js +246 -0
  684. package/.agents/scripts/story-deliver-prepare.js +267 -0
  685. package/.agents/scripts/story-init.js +516 -0
  686. package/.agents/scripts/story-phase.js +327 -0
  687. package/.agents/scripts/story-plan.js +284 -0
  688. package/.agents/scripts/sync-agentrc.js +71 -0
  689. package/.agents/scripts/sync-branch-from-base.js +138 -0
  690. package/.agents/scripts/sync-claude-commands.js +151 -0
  691. package/.agents/scripts/test-isolate.js +222 -0
  692. package/.agents/scripts/test-wrapper.js +108 -0
  693. package/.agents/scripts/update-coverage-baseline.js +129 -0
  694. package/.agents/scripts/update-crap-baseline.js +177 -0
  695. package/.agents/scripts/update-duplication-baseline.js +134 -0
  696. package/.agents/scripts/update-maintainability-baseline.js +183 -0
  697. package/.agents/scripts/update-mutation-baseline.js +189 -0
  698. package/.agents/scripts/update-ticket-state.js +107 -0
  699. package/.agents/scripts/validate-docs-freshness.js +259 -0
  700. package/.agents/scripts/validate-skills.js +278 -0
  701. package/.agents/scripts/wave-tick.js +335 -0
  702. package/.agents/skills/core/analyze-execution/SKILL.md +98 -0
  703. package/.agents/skills/core/api-and-interface-design/SKILL.md +327 -0
  704. package/.agents/skills/core/baseline-refresh/SKILL.md +181 -0
  705. package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +352 -0
  706. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +274 -0
  707. package/.agents/skills/core/ci-cd-and-automation/examples.md +211 -0
  708. package/.agents/skills/core/code-review-and-quality/SKILL.md +421 -0
  709. package/.agents/skills/core/code-simplification/SKILL.md +389 -0
  710. package/.agents/skills/core/context-engineering/SKILL.md +309 -0
  711. package/.agents/skills/core/context-engineering/examples.md +58 -0
  712. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +338 -0
  713. package/.agents/skills/core/deprecation-and-migration/SKILL.md +250 -0
  714. package/.agents/skills/core/diagnose-friction/SKILL.md +79 -0
  715. package/.agents/skills/core/documentation-and-adrs/SKILL.md +323 -0
  716. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +145 -0
  717. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +425 -0
  718. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +393 -0
  719. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +357 -0
  720. package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +352 -0
  721. package/.agents/skills/core/hydrate-context/SKILL.md +118 -0
  722. package/.agents/skills/core/idea-refinement/SKILL.md +317 -0
  723. package/.agents/skills/core/idea-refinement/examples.md +437 -0
  724. package/.agents/skills/core/idea-refinement/frameworks.md +135 -0
  725. package/.agents/skills/core/idea-refinement/refinement-criteria.md +155 -0
  726. package/.agents/skills/core/idea-refinement/scripts/idea-refine.sh +15 -0
  727. package/.agents/skills/core/incremental-implementation/SKILL.md +271 -0
  728. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +213 -0
  729. package/.agents/skills/core/knowledge-transfer/SKILL.md +175 -0
  730. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +117 -0
  731. package/.agents/skills/core/performance-optimization/SKILL.md +314 -0
  732. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +277 -0
  733. package/.agents/skills/core/property-based-testing/SKILL.md +148 -0
  734. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +105 -0
  735. package/.agents/skills/core/refactoring-discipline/SKILL.md +111 -0
  736. package/.agents/skills/core/scope-triage/SKILL.md +127 -0
  737. package/.agents/skills/core/security-and-hardening/SKILL.md +400 -0
  738. package/.agents/skills/core/shipping-and-launch/SKILL.md +328 -0
  739. package/.agents/skills/core/spec-driven-development/SKILL.md +252 -0
  740. package/.agents/skills/core/test-driven-development/SKILL.md +475 -0
  741. package/.agents/skills/core/using-agent-skills/SKILL.md +232 -0
  742. package/.agents/skills/skills.index.json +596 -0
  743. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +31 -0
  744. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +51 -0
  745. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +48 -0
  746. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +31 -0
  747. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +33 -0
  748. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +31 -0
  749. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +51 -0
  750. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +54 -0
  751. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +29 -0
  752. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +30 -0
  753. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +57 -0
  754. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +9 -0
  755. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +48 -0
  756. package/.agents/skills/stack/frontend/astro/SKILL.md +62 -0
  757. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +30 -0
  758. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +29 -0
  759. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +50 -0
  760. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +58 -0
  761. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +34 -0
  762. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +51 -0
  763. package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +257 -0
  764. package/.agents/skills/stack/qa/gherkin-authoring/examples/invoice-issue.feature +41 -0
  765. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +199 -0
  766. package/.agents/skills/stack/qa/playwright/SKILL.md +50 -0
  767. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +188 -0
  768. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +142 -0
  769. package/.agents/skills/stack/qa/qa-harness/SKILL.md +220 -0
  770. package/.agents/skills/stack/qa/vitest/SKILL.md +51 -0
  771. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +68 -0
  772. package/.agents/starter-agentrc.json +22 -0
  773. package/.agents/templates/agent-protocol.md +72 -0
  774. package/.agents/templates/docs/architecture.md +30 -0
  775. package/.agents/templates/docs/decisions.md +24 -0
  776. package/.agents/templates/epic-from-idea.md +21 -0
  777. package/.agents/templates/single-story-body.md +17 -0
  778. package/.agents/workflows/agents-update.md +415 -0
  779. package/.agents/workflows/audit-architecture.md +312 -0
  780. package/.agents/workflows/audit-clean-code.md +179 -0
  781. package/.agents/workflows/audit-dependencies.md +91 -0
  782. package/.agents/workflows/audit-devops.md +110 -0
  783. package/.agents/workflows/audit-lighthouse.md +260 -0
  784. package/.agents/workflows/audit-performance.md +161 -0
  785. package/.agents/workflows/audit-privacy.md +104 -0
  786. package/.agents/workflows/audit-quality.md +191 -0
  787. package/.agents/workflows/audit-security.md +156 -0
  788. package/.agents/workflows/audit-seo.md +118 -0
  789. package/.agents/workflows/audit-sre.md +139 -0
  790. package/.agents/workflows/audit-to-stories.md +257 -0
  791. package/.agents/workflows/audit-ux-ui.md +102 -0
  792. package/.agents/workflows/epic-deliver.md +864 -0
  793. package/.agents/workflows/epic-plan.md +998 -0
  794. package/.agents/workflows/explain.md +118 -0
  795. package/.agents/workflows/git-cleanup.md +250 -0
  796. package/.agents/workflows/git-commit-all.md +15 -0
  797. package/.agents/workflows/git-merge-pr.md +377 -0
  798. package/.agents/workflows/git-pr-all.md +278 -0
  799. package/.agents/workflows/git-push.md +60 -0
  800. package/.agents/workflows/helpers/_merge-conflict-template.md +54 -0
  801. package/.agents/workflows/helpers/acceptance-self-eval.md +74 -0
  802. package/.agents/workflows/helpers/agents-sync-config.md +129 -0
  803. package/.agents/workflows/helpers/code-quality-guardrails.md +101 -0
  804. package/.agents/workflows/helpers/code-review.md +370 -0
  805. package/.agents/workflows/helpers/diagnose.md +117 -0
  806. package/.agents/workflows/helpers/epic-audit.md +295 -0
  807. package/.agents/workflows/helpers/epic-deliver-story.md +370 -0
  808. package/.agents/workflows/helpers/epic-plan-decompose.md +199 -0
  809. package/.agents/workflows/helpers/epic-plan-spec.md +184 -0
  810. package/.agents/workflows/helpers/epic-testing.md +125 -0
  811. package/.agents/workflows/helpers/parallel-tooling.md +88 -0
  812. package/.agents/workflows/helpers/signals.md +112 -0
  813. package/.agents/workflows/helpers/single-story-deliver.md +636 -0
  814. package/.agents/workflows/helpers/worktree-lifecycle.md +317 -0
  815. package/.agents/workflows/onboard.md +207 -0
  816. package/.agents/workflows/qa-assist.md +293 -0
  817. package/.agents/workflows/qa-explore.md +350 -0
  818. package/.agents/workflows/qa-run-harness.md +288 -0
  819. package/.agents/workflows/story-deliver.md +327 -0
  820. package/.agents/workflows/story-plan.md +233 -0
  821. package/LICENSE +21 -0
  822. package/README.md +193 -0
  823. package/bin/mandrel.js +56 -0
  824. package/bin/postinstall.js +195 -0
  825. package/lib/cli/__tests__/migrate.test.js +268 -0
  826. package/lib/cli/__tests__/sync-local-zone.test.js +247 -0
  827. package/lib/cli/__tests__/sync.test.js +372 -0
  828. package/lib/cli/__tests__/update-major.test.js +217 -0
  829. package/lib/cli/__tests__/update.test.js +696 -0
  830. package/lib/cli/__tests__/version-check.test.js +398 -0
  831. package/lib/cli/doctor.js +124 -0
  832. package/lib/cli/explain.js +107 -0
  833. package/lib/cli/migrate.js +260 -0
  834. package/lib/cli/registry.js +830 -0
  835. package/lib/cli/sync-commands.js +50 -0
  836. package/lib/cli/sync.js +200 -0
  837. package/lib/cli/uninstall.js +795 -0
  838. package/lib/cli/update.js +854 -0
  839. package/lib/cli/version-check.js +206 -0
  840. package/lib/migrations/README.md +69 -0
  841. package/lib/migrations/__tests__/index.test.js +216 -0
  842. package/lib/migrations/index.js +164 -0
  843. package/package.json +105 -0
@@ -0,0 +1,665 @@
1
+ /**
2
+ * `tick({ epic, collaborators })` — single callable entry point for
3
+ * "advance this wave one step." Stateless planner: rebuilds wave state
4
+ * from the `epic-run-state` checkpoint plus fresh Story labels on every
5
+ * call, then returns a `WaveTickResult` describing the next action.
6
+ *
7
+ * Contract (Story #1430): stateless; caller owns concurrency,
8
+ * worktrees, and checkpointing. Expected failures (blocked stories,
9
+ * gate failures) flow back through result fields; unexpected failures
10
+ * (GH 5xx, malformed checkpoint) throw `WaveRunnerError`.
11
+ *
12
+ * @module lib/wave-runner/tick
13
+ */
14
+
15
+ import { existsSync, readFileSync } from 'node:fs';
16
+
17
+ import { epicLedgerPath } from '../config/temp-paths.js';
18
+ import { AGENT_LABELS } from '../label-constants.js';
19
+ import { appendEpicSignal } from '../observability/signals-writer.js';
20
+ import * as epicRunStateStoreModule from '../orchestration/epic-run-state-store.js';
21
+ import { detectRecurringFailures } from '../orchestration/recurring-failure-detector.js';
22
+ import { upsertStructuredComment as defaultUpsertStructuredComment } from '../orchestration/ticketing.js';
23
+
24
+ import { collectHaltedStoryIds } from './wave-checkpoint.js';
25
+ import { WaveRunnerError } from './wave-runner-error.js';
26
+
27
+ /**
28
+ * Advance the wave loop one step. Returns a `WaveTickResult`:
29
+ *
30
+ * nextAction: { kind: 'dispatch', stories: [{ id, title?, worktree? }, ...] }
31
+ * | { kind: 'observe', waitingOn: number[] }
32
+ * | { kind: 'wave-complete', index: number }
33
+ * | { kind: 'epic-complete' }
34
+ * blockedStories: [{ storyId, reason, detail? }, ...]
35
+ * gateFailures: [{ storyId, gate, detail? }, ...]
36
+ * currentWave: number
37
+ * totalWaves: number
38
+ *
39
+ * When `spec` is omitted, the planner falls back to the checkpoint's
40
+ * `state.plan` (the GH-derived dependency-DAG grouping originally seeded
41
+ * by /epic-plan) — behaviour is byte-identical to the pre-spec path.
42
+ * When `spec` is supplied, wave grouping is driven by `spec.stories[].wave`
43
+ * (the declarative SSOT from `.agents/epics/<epic-id>.yaml`) and slugs are
44
+ * resolved to GH issue numbers via the sibling `<epic-id>.state.json`
45
+ * mapping; the checkpoint is still consulted for `currentWave`,
46
+ * `totalWaves`, and `waves[]` history but its `plan[]` is overridden.
47
+ *
48
+ * @typedef {object} WaveTickArgs
49
+ * @property {number | { id: number }} epic
50
+ * @property {object} [spec] Parsed epic-spec (see lib/spec/loader.js). When
51
+ * provided, wave grouping comes from `spec.stories[].wave`.
52
+ * @property {object} [state] Parsed epic-state (see lib/spec/loader.js).
53
+ * When `spec` is provided, this must be supplied so slugs can resolve to
54
+ * issue numbers via `state.mapping[slug].issueNumber`.
55
+ * @property {{
56
+ * provider?: object,
57
+ * epicRunStateStore?: { read: () => Promise<object|null> },
58
+ * signalEmit?: (signal: object) => Promise<unknown>,
59
+ * inFlightReader?: () => Promise<number[]>,
60
+ * recurringFailureReporter?: () => Promise<void>,
61
+ * }} [collaborators]
62
+ * @property {{ provider?: object, config?: object }} [ctx]
63
+ *
64
+ * @param {WaveTickArgs} args
65
+ */
66
+ export async function tick(args = {}) {
67
+ const epicId = resolveEpicId(args.epic);
68
+ const {
69
+ provider: collabProvider,
70
+ epicRunStateStore: collabStore,
71
+ signalEmit,
72
+ inFlightReader: collabInFlightReader,
73
+ recurringFailureReporter: collabRecurringFailureReporter,
74
+ } = args.collaborators ?? {};
75
+ const ctx = args.ctx ?? {};
76
+ const provider = collabProvider ?? ctx.provider;
77
+ const spec = args.spec ?? null;
78
+ const specState = args.state ?? null;
79
+ if (!provider) {
80
+ throw new WaveRunnerError('invalid-input', 'provider is required');
81
+ }
82
+ // Story #2409 — the wave-runner tick is stateless. When the caller
83
+ // does not supply a collaborator shim, we read the `epic-run-state`
84
+ // structured comment directly via the function-based store, mirroring
85
+ // the pre-migration `.read()` shape exactly.
86
+ const epicRunStateStore = collabStore ?? {
87
+ read: () => epicRunStateStoreModule.read({ provider, epicId }),
88
+ };
89
+ const emit = signalEmit ?? defaultSignalEmit(epicId, ctx);
90
+ const inFlightReader =
91
+ collabInFlightReader ?? (() => defaultInFlightReader(epicId, ctx?.config));
92
+
93
+ let state;
94
+ try {
95
+ state = await epicRunStateStore.read();
96
+ } catch (err) {
97
+ throw new WaveRunnerError('checkpoint-read', err);
98
+ }
99
+ if (!state || typeof state !== 'object') {
100
+ throw new WaveRunnerError(
101
+ 'checkpoint-missing',
102
+ `no epic-run-state comment on Epic #${epicId}`,
103
+ );
104
+ }
105
+
106
+ const currentWave = positiveIntOrZero(state.currentWave);
107
+ const { plan, totalWaves } = resolvePlan(state, spec, specState);
108
+ const history = Array.isArray(state.waves) ? state.waves : [];
109
+
110
+ if (totalWaves === 0 || currentWave >= totalWaves) {
111
+ return tickResult({
112
+ nextAction: { kind: 'epic-complete' },
113
+ currentWave,
114
+ totalWaves,
115
+ });
116
+ }
117
+
118
+ const wavePlan = Array.isArray(plan[currentWave]) ? plan[currentWave] : [];
119
+ if (wavePlan.length === 0) {
120
+ await emit({
121
+ kind: 'wave-complete',
122
+ index: currentWave,
123
+ totalWaves,
124
+ empty: true,
125
+ });
126
+ return tickResult({
127
+ nextAction: { kind: 'wave-complete', index: currentWave },
128
+ currentWave,
129
+ totalWaves,
130
+ });
131
+ }
132
+
133
+ // Story #3026 — match the iterate-waves resume-check cache strategy:
134
+ // only Stories that the checkpoint marks as halted on a prior wave
135
+ // are force-refreshed. Every other Story serves the tick fetch from
136
+ // the provider's in-process cache, eliminating the per-wave
137
+ // `fresh: true` round-trip we historically issued for every Story.
138
+ const haltedStoryIds = collectHaltedStoryIds(state);
139
+ let waveStates;
140
+ try {
141
+ waveStates = await Promise.all(
142
+ wavePlan.map(async (s) => {
143
+ const id = storyIdOf(s);
144
+ const opts = haltedStoryIds.has(id) ? { fresh: true } : {};
145
+ const ticket = await provider.getTicket(id, opts);
146
+ return {
147
+ id,
148
+ title: s.title ?? ticket?.title,
149
+ worktree: s.worktree,
150
+ labels: Array.isArray(ticket?.labels) ? ticket.labels : [],
151
+ state: ticket?.state,
152
+ };
153
+ }),
154
+ );
155
+ } catch (err) {
156
+ throw new WaveRunnerError('story-fetch', err);
157
+ }
158
+
159
+ // Story #2891 — compute in-flight Stories from the lifecycle ledger.
160
+ // A Story is "in-flight" when the ledger carries a
161
+ // `story.dispatch.start` record for it without a matching
162
+ // `story.dispatch.end`. The reconciliation is purely additive on the
163
+ // result envelope so callers can surface dispatched-but-uncompleted
164
+ // Stories that the per-Wave label state alone cannot reveal.
165
+ //
166
+ // Story #3907 — the in-flight set is read **before** the dispatch
167
+ // classification so it can be subtracted from the dispatchable set below.
168
+ const inFlight = await safeReadInFlight(inFlightReader);
169
+ const inFlightSet = new Set(inFlight);
170
+
171
+ // Story #3907 — a Story is "done" when it carries `agent::done` OR its
172
+ // GitHub issue is `state === 'closed'`. Reading the closed state (not just
173
+ // the label) means a Story closed manually through the GitHub UI — which
174
+ // closes the issue but does not flip the `agent::*` label — is recognised
175
+ // as done and is never re-dispatched.
176
+ const done = waveStates.filter(isStoryDone);
177
+ const blocked = waveStates.filter((s) =>
178
+ s.labels.includes(AGENT_LABELS.BLOCKED),
179
+ );
180
+ const executing = waveStates.filter((s) =>
181
+ s.labels.includes(AGENT_LABELS.EXECUTING),
182
+ );
183
+ // Undispatched = no terminal/in-progress label AND not closed. The closed
184
+ // check rides on `isStoryDone` via the negation in `isUndispatched`.
185
+ const undispatchedByLabel = waveStates.filter(isUndispatched);
186
+
187
+ // Story #3907 — subtract ledger in-flight Stories from the dispatch set.
188
+ // A Story whose `story.dispatch.start` has been recorded but whose label
189
+ // has not yet flipped to `agent::executing` (the child is mid-`story-init`,
190
+ // or the host crashed after the dispatch-ledger write but before the label
191
+ // flip) still looks "undispatched" by label alone. Re-dispatching it would
192
+ // put a second agent on the same `story-<id>` branch — the worst failure
193
+ // mode in the system. The ledger in-flight signal is the authoritative
194
+ // "already dispatched" record, so it overrides the label view here.
195
+ const dispatchable = undispatchedByLabel.filter(
196
+ (s) => !inFlightSet.has(s.id),
197
+ );
198
+
199
+ const blockedStories = blocked.map((s) => ({
200
+ storyId: s.id,
201
+ reason: 'agent::blocked',
202
+ detail: s.title,
203
+ }));
204
+ const gateFailures = readGateFailures(history, currentWave);
205
+
206
+ // Story #3062 — scan the per-Epic lifecycle ledger for recurring
207
+ // failure classes (≥2 distinct Stories sharing the same
208
+ // `close-validate.end` failedGate) and upsert a
209
+ // `recurring-failure-class` structured comment on the Epic when
210
+ // findings are returned. Idempotent across re-ticks: the upsert path
211
+ // diffs body bytes, so a tick that produces the same findings does not
212
+ // duplicate the comment. Best-effort — a reporter throw must not crash
213
+ // the planner.
214
+ const recurringFailureReporter =
215
+ collabRecurringFailureReporter ??
216
+ defaultRecurringFailureReporter({ provider, epicId, config: ctx?.config });
217
+ await safeReportRecurringFailures(recurringFailureReporter);
218
+
219
+ // 6. Decide nextAction.
220
+ let nextAction;
221
+
222
+ // Stories that are label-undispatched but recorded in-flight on the ledger
223
+ // (subtracted out of `dispatchable`) must be observed, not re-dispatched —
224
+ // see the in-flight subtraction above.
225
+ const inFlightUndispatched = undispatchedByLabel.filter((s) =>
226
+ inFlightSet.has(s.id),
227
+ );
228
+
229
+ if (blockedStories.length) {
230
+ nextAction = { kind: 'observe', waitingOn: blocked.map((s) => s.id) };
231
+ } else if (dispatchable.length) {
232
+ // First dispatch of this wave fires `wave-start` exactly once — the
233
+ // perf-aggregator (`waveParallelism` report) brackets each wave's
234
+ // wall-clock from `wave-start` → `wave-complete`. The ledger in-flight
235
+ // set is consulted alongside the label view so a dispatched-but-not-yet-
236
+ // executing Story does not re-fire `wave-start`.
237
+ if (
238
+ executing.length === 0 &&
239
+ done.length === 0 &&
240
+ inFlightUndispatched.length === 0
241
+ ) {
242
+ await emit({
243
+ kind: 'wave-start',
244
+ index: currentWave,
245
+ totalWaves,
246
+ stories: wavePlan.map((s) => ({ id: storyIdOf(s), title: s.title })),
247
+ });
248
+ }
249
+ nextAction = {
250
+ kind: 'dispatch',
251
+ stories: dispatchable.map((s) => ({
252
+ id: s.id,
253
+ title: s.title,
254
+ worktree: s.worktree,
255
+ })),
256
+ };
257
+ } else if (executing.length || inFlightUndispatched.length) {
258
+ // Either a Story is `agent::executing`, or the ledger shows a
259
+ // dispatched-but-unflipped Story we just declined to re-dispatch. Both
260
+ // are in-flight — observe rather than collapse the wave.
261
+ const waitingOn = [
262
+ ...executing.map((s) => s.id),
263
+ ...inFlightUndispatched.map((s) => s.id),
264
+ ].sort((a, b) => a - b);
265
+ nextAction = { kind: 'observe', waitingOn };
266
+ } else if (currentWave + 1 >= totalWaves) {
267
+ nextAction = { kind: 'epic-complete' };
268
+ } else {
269
+ // Closes the wave window for the perf-aggregator's wall-clock bracket.
270
+ await emit({ kind: 'wave-complete', index: currentWave, totalWaves });
271
+ nextAction = { kind: 'wave-complete', index: currentWave };
272
+ }
273
+
274
+ // Story #2891 — attach the in-flight ledger reconciliation to the
275
+ // nextAction envelope. Always emit the field (empty array when the
276
+ // ledger is silent) so downstream consumers can pattern-match on
277
+ // presence without an existence check.
278
+ nextAction['in-flight'] = inFlight;
279
+
280
+ return tickResult({
281
+ nextAction,
282
+ blockedStories,
283
+ gateFailures,
284
+ currentWave,
285
+ totalWaves,
286
+ });
287
+ }
288
+
289
+ /**
290
+ * Wrap the configured `inFlightReader` with a defensive guard so an
291
+ * unreadable ledger never crashes the tick. The default reader already
292
+ * returns `[]` on missing files; this catches any other shape of
293
+ * accidental throw and degrades to an empty list so the planner can
294
+ * still make a decision.
295
+ *
296
+ * @param {() => Promise<number[]>} reader
297
+ * @returns {Promise<number[]>}
298
+ */
299
+ async function safeReadInFlight(reader) {
300
+ try {
301
+ const raw = await reader();
302
+ return Array.isArray(raw) ? raw.filter((n) => Number.isInteger(n)) : [];
303
+ } catch {
304
+ return [];
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Default `recurringFailureReporter` collaborator — reads the per-Epic
310
+ * lifecycle ledger via `detectRecurringFailures`, and when at least one
311
+ * recurring-failure-class finding is returned, upserts a
312
+ * `recurring-failure-class` structured comment on the Epic ticket.
313
+ *
314
+ * The body carries the findings array verbatim in a JSON fence plus a
315
+ * compact human-readable bullet list keyed by gate. Idempotent across
316
+ * re-ticks: `upsertStructuredComment` diffs body bytes, so a tick that
317
+ * produces the same findings does not generate a new comment.
318
+ *
319
+ * Story #3062 (Epic #3051).
320
+ *
321
+ * @param {object} args
322
+ * @param {object} args.provider Ticketing provider passed to upsert.
323
+ * @param {number} args.epicId
324
+ * @param {object} [args.config]
325
+ * @returns {() => Promise<void>}
326
+ */
327
+ function defaultRecurringFailureReporter({ provider, epicId, config }) {
328
+ return async () => {
329
+ const ledgerPath = epicLedgerPath(epicId, config);
330
+ const findings = detectRecurringFailures(epicId, { ledgerPath });
331
+ if (findings.length === 0) return;
332
+ const body = renderRecurringFailureBody(findings);
333
+ await defaultUpsertStructuredComment(
334
+ provider,
335
+ epicId,
336
+ 'recurring-failure-class',
337
+ body,
338
+ );
339
+ };
340
+ }
341
+
342
+ /**
343
+ * Render the comment body the recurring-failure-class reporter upserts.
344
+ * The body is deterministic given a deterministic findings array (the
345
+ * detector sorts findings by gate and storyIds ascending), which is what
346
+ * makes the upsert idempotent across re-ticks.
347
+ *
348
+ * @param {Array<{gate: string, storyIds: number[], firstSeenAt: string, lastSeenAt: string}>} findings
349
+ * @returns {string}
350
+ */
351
+ export function renderRecurringFailureBody(findings) {
352
+ const lines = ['### 🔁 Recurring failure classes detected', ''];
353
+ for (const f of findings) {
354
+ const storiesList = f.storyIds.map((id) => `#${id}`).join(', ');
355
+ lines.push(
356
+ `- **\`${f.gate}\`** — ${f.storyIds.length} stories (${storiesList}); first \`${f.firstSeenAt}\`, last \`${f.lastSeenAt}\``,
357
+ );
358
+ }
359
+ lines.push('');
360
+ lines.push('```json');
361
+ lines.push(
362
+ JSON.stringify({ kind: 'recurring-failure-class', findings }, null, 2),
363
+ );
364
+ lines.push('```');
365
+ return lines.join('\n');
366
+ }
367
+
368
+ /**
369
+ * Wrap the reporter so a throw (e.g. transient provider error, malformed
370
+ * ledger) never crashes the stateless tick. Best-effort — the next tick
371
+ * will retry.
372
+ *
373
+ * @param {() => Promise<void>} reporter
374
+ */
375
+ async function safeReportRecurringFailures(reporter) {
376
+ try {
377
+ await reporter();
378
+ } catch {
379
+ // best-effort
380
+ }
381
+ }
382
+
383
+ /**
384
+ * Default `inFlightReader` — parses `temp/epic-<id>/lifecycle.ndjson`
385
+ * and returns the Story IDs that have a `story.dispatch.start`
386
+ * `emitted` record without a matching `story.dispatch.end` `emitted`
387
+ * record. The check is order-insensitive (the wave-runner records the
388
+ * pair on the same Bus, so the start always lands first, but we don't
389
+ * depend on that here).
390
+ *
391
+ * Returns `[]` when the ledger file does not yet exist or is empty —
392
+ * the tick is stateless and must not throw when nothing has been
393
+ * dispatched on this Epic yet.
394
+ *
395
+ * @param {number} epicId
396
+ * @param {object|undefined} config Resolved config (forwarded to
397
+ * `epicLedgerPath` so `project.paths.tempRoot` overrides apply).
398
+ * @returns {Promise<number[]>}
399
+ */
400
+ async function defaultInFlightReader(epicId, config) {
401
+ const ledgerPath = epicLedgerPath(epicId, config);
402
+ if (!existsSync(ledgerPath)) return [];
403
+ let raw;
404
+ try {
405
+ raw = readFileSync(ledgerPath, 'utf8');
406
+ } catch {
407
+ return [];
408
+ }
409
+ if (!raw) return [];
410
+ const started = new Set();
411
+ const ended = new Set();
412
+ for (const line of raw.split(/\r?\n/)) {
413
+ if (!line) continue;
414
+ let record;
415
+ try {
416
+ record = JSON.parse(line);
417
+ } catch {
418
+ continue;
419
+ }
420
+ if (!record || record.kind !== 'emitted') continue;
421
+ const storyId = record.payload?.storyId;
422
+ if (!Number.isInteger(storyId) || storyId <= 0) continue;
423
+ if (record.event === 'story.dispatch.start') started.add(storyId);
424
+ else if (record.event === 'story.dispatch.end') ended.add(storyId);
425
+ }
426
+ const inFlight = [];
427
+ for (const id of started) {
428
+ if (!ended.has(id)) inFlight.push(id);
429
+ }
430
+ return inFlight;
431
+ }
432
+
433
+ function tickResult({
434
+ nextAction,
435
+ blockedStories = [],
436
+ gateFailures = [],
437
+ currentWave,
438
+ totalWaves,
439
+ }) {
440
+ return { nextAction, blockedStories, gateFailures, currentWave, totalWaves };
441
+ }
442
+
443
+ function resolveEpicId(epic) {
444
+ const id = typeof epic === 'number' ? epic : epic?.id;
445
+ if (Number.isInteger(id) && id > 0) return id;
446
+ throw new WaveRunnerError(
447
+ 'invalid-input',
448
+ `epic must be a positive integer or { id: positiveInt }; got ${
449
+ epic === null ? 'null' : typeof epic
450
+ }`,
451
+ );
452
+ }
453
+
454
+ function positiveIntOrZero(v) {
455
+ return Number.isInteger(v) && v >= 0 ? v : 0;
456
+ }
457
+
458
+ function storyIdOf(s) {
459
+ if (typeof s === 'number') return s;
460
+ return s.id ?? s.storyId ?? s.number;
461
+ }
462
+
463
+ /**
464
+ * Walk `spec.features[].stories[]` and bucket entries by their `wave`
465
+ * value, mapping slugs → GH issue numbers via the sibling state file.
466
+ * Returns `Story[][]` indexed by wave number; missing waves between 0 and
467
+ * the highest declared wave are emitted as empty arrays so wave N is
468
+ * always reachable as `plan[N]`.
469
+ *
470
+ * Each emitted entry is shaped to match the checkpoint plan's
471
+ * `{ id, title }` contract that the rest of `tick()` already consumes:
472
+ *
473
+ * - `id` is the GH issue number resolved from `state.mapping[slug].issueNumber`
474
+ * so the same provider.getTicket(id) path used by the spec-less plan
475
+ * keeps working unchanged.
476
+ * - `title` is carried through from `story.title` so the wave-start
477
+ * signal can include the Story's human-readable name without an
478
+ * extra provider round-trip.
479
+ * - `slug` is preserved on the entry so observability + future
480
+ * re-resolution paths can re-key against the spec.
481
+ *
482
+ * When a Story slug has no resolved `issueNumber` in `state.mapping`
483
+ * (a fresh spec entry the reconciler has not materialised yet), the entry
484
+ * is skipped — un-materialised Stories cannot be dispatched anyway, and
485
+ * including them with a `null` id would surface as a `story-fetch`
486
+ * failure inside `tick()`. The reconciler will close the loop on the
487
+ * next apply; until then, an empty wave is a faithful reflection of
488
+ * GitHub state.
489
+ *
490
+ * Pure function — does not read disk, does not call GH. Callers are
491
+ * expected to compose it with `loadSpec` + `loadState` from
492
+ * `lib/spec/loader.js`.
493
+ *
494
+ * @param {object} spec Parsed epic-spec (see lib/spec/loader.js).
495
+ * @param {{mapping?: Record<string, {issueNumber?: number}>}|null} [state]
496
+ * Parsed epic-state. May be omitted; if missing, no entries can be
497
+ * resolved and `groupByWave` returns `[]`.
498
+ * @returns {Array<Array<{id: number, title?: string, slug: string}>>}
499
+ */
500
+ export function groupByWave(spec, state = null) {
501
+ const mapping =
502
+ state && typeof state.mapping === 'object' && state.mapping !== null
503
+ ? state.mapping
504
+ : {};
505
+ const entries = extractValidStoryEntries(spec, mapping);
506
+ if (entries.length === 0) return [];
507
+ const byWave = new Map();
508
+ let maxWave = -1;
509
+ for (const { wave, entry } of entries) {
510
+ if (!byWave.has(wave)) byWave.set(wave, []);
511
+ byWave.get(wave).push(entry);
512
+ if (wave > maxWave) maxWave = wave;
513
+ }
514
+ if (maxWave < 0) return [];
515
+ const out = [];
516
+ for (let i = 0; i <= maxWave; i += 1) {
517
+ out.push(byWave.get(i) ?? []);
518
+ }
519
+ return out;
520
+ }
521
+
522
+ /**
523
+ * Walk every feature/story pair in `spec` and emit only the entries that
524
+ * survive the spec-validity cascade: the story must be a non-null object,
525
+ * declare a non-negative integer `wave`, declare a string `slug`, and
526
+ * resolve to a numeric `issueNumber` in `mapping`. Each surviving entry
527
+ * is returned as `{ wave, entry }` where `entry` carries the same shape
528
+ * (`{ id, title, slug }`) that `groupByWave` previously pushed into its
529
+ * per-wave bucket.
530
+ *
531
+ * Extracted from `groupByWave` so the bucketing transform stays
532
+ * straight-line; this predicate owns the entire defensive guard cascade
533
+ * and is the right place to add new validation rules going forward.
534
+ *
535
+ * @param {object|null|undefined} spec Parsed epic-spec.
536
+ * @param {Record<string, {issueNumber?: number}>} mapping
537
+ * Slug → issue-number lookup from the sibling state file.
538
+ * @returns {Array<{wave: number, entry: {id: number, title?: string, slug: string}}>}
539
+ */
540
+ export function extractValidStoryEntries(spec, mapping) {
541
+ const out = [];
542
+ const features = Array.isArray(spec?.features) ? spec.features : [];
543
+ for (const feature of features) {
544
+ const stories = Array.isArray(feature?.stories) ? feature.stories : [];
545
+ for (const story of stories) {
546
+ const resolved = resolveStoryEntry(story, mapping);
547
+ if (resolved) out.push(resolved);
548
+ }
549
+ }
550
+ return out;
551
+ }
552
+
553
+ /**
554
+ * Validate a single `story` against the spec-validity cascade and return
555
+ * `{ wave, entry }` when every guard passes, or `null` when any guard
556
+ * trips. Splitting the per-story cascade out keeps both
557
+ * `extractValidStoryEntries` (which owns iteration) and `resolveStoryEntry`
558
+ * (which owns validation) below CRAP 5 even when none of the branches are
559
+ * exercised at runtime — the predicate's cyclomatic footprint is small
560
+ * enough that uncovered branches do not blow the baseline budget.
561
+ *
562
+ * @param {*} story Candidate story from `spec.features[].stories[]`.
563
+ * @param {Record<string, {issueNumber?: number}>} mapping Slug → issue lookup.
564
+ * @returns {{wave: number, entry: {id: number, title?: string, slug: string}} | null}
565
+ */
566
+ function resolveStoryEntry(story, mapping) {
567
+ if (!story || typeof story !== 'object') return null;
568
+ if (!Number.isInteger(story.wave) || story.wave < 0) return null;
569
+ if (typeof story.slug !== 'string' || !story.slug) return null;
570
+ const mapped = mapping[story.slug];
571
+ if (!mapped || typeof mapped.issueNumber !== 'number') return null;
572
+ return {
573
+ wave: story.wave,
574
+ entry: { id: mapped.issueNumber, title: story.title, slug: story.slug },
575
+ };
576
+ }
577
+
578
+ /**
579
+ * Resolve which plan + totalWaves drive this tick. When `spec` is
580
+ * supplied, the spec-derived grouping wins (and totalWaves comes from
581
+ * the spec since the checkpoint may lag); otherwise the checkpoint's
582
+ * plan is used unchanged. Extracted so `tick()`'s cyclomatic complexity
583
+ * stays inside its baseline budget — the route choice is now a single
584
+ * call, not three ternaries inline.
585
+ *
586
+ * @param {object} state Checkpoint state (already validated as object).
587
+ * @param {object|null} spec Parsed epic-spec or `null` when omitted.
588
+ * @param {object|null} specState Parsed epic-state for slug mapping.
589
+ * @returns {{plan: Array<Array<object>>, totalWaves: number}}
590
+ */
591
+ function resolvePlan(state, spec, specState) {
592
+ if (spec) {
593
+ const specPlan = groupByWave(spec, specState);
594
+ return { plan: specPlan, totalWaves: specPlan.length };
595
+ }
596
+ const plan = Array.isArray(state.plan) ? state.plan : [];
597
+ return { plan, totalWaves: positiveIntOrZero(state.totalWaves) };
598
+ }
599
+
600
+ /**
601
+ * A Story is "done" when it carries `agent::done` OR its GitHub issue is
602
+ * `state === 'closed'`. The closed-state arm (Story #3907) is what aligns the
603
+ * wave planner with the other done-predicates in the codebase
604
+ * (`reconciler.isDone`, `verifySingleResult`) so a Story closed manually
605
+ * through the GitHub UI — which closes the issue without flipping the
606
+ * `agent::*` label — is recognised as done and never re-dispatched.
607
+ *
608
+ * @param {{ labels: string[], state?: string }} s
609
+ * @returns {boolean}
610
+ */
611
+ export function isStoryDone(s) {
612
+ const labels = Array.isArray(s?.labels) ? s.labels : [];
613
+ return labels.includes(AGENT_LABELS.DONE) || s?.state === 'closed';
614
+ }
615
+
616
+ /**
617
+ * A wave member is "undispatched" when it carries none of the terminal /
618
+ * in-progress labels AND is not a closed issue. The closed check (Story
619
+ * #3907) prevents a manually-closed Story (issue closed, label not flipped)
620
+ * from being re-dispatched.
621
+ *
622
+ * @param {{ labels: string[], state?: string }} s
623
+ * @returns {boolean}
624
+ */
625
+ function isUndispatched(s) {
626
+ const labels = Array.isArray(s?.labels) ? s.labels : [];
627
+ return (
628
+ !isStoryDone(s) &&
629
+ !labels.includes(AGENT_LABELS.BLOCKED) &&
630
+ !labels.includes(AGENT_LABELS.EXECUTING)
631
+ );
632
+ }
633
+
634
+ function readGateFailures(history, currentWave) {
635
+ const prior = history[currentWave - 1];
636
+ if (!prior || !Array.isArray(prior.stories)) return [];
637
+ return prior.stories
638
+ .filter((s) => s.status === 'failed' && typeof s.detail === 'string')
639
+ .map((s) => ({
640
+ storyId: s.storyId,
641
+ gate: s.gate ?? 'unspecified',
642
+ detail: s.detail,
643
+ }));
644
+ }
645
+
646
+ /**
647
+ * Default emitter — appends to per-Epic `signals.ndjson`. Best-effort;
648
+ * never throws. Tests override via `collaborators.signalEmit`.
649
+ *
650
+ * Story #3909 — the planner now emits only the two wave events that have a
651
+ * live consumer: `wave-start` and `wave-complete`, which the perf-aggregator
652
+ * (`waveParallelism` report) brackets into per-wave wall-clock. The
653
+ * write-only `wave-tick` (per-call telemetry) and `epic-complete` (no reader)
654
+ * emits were dropped — they duplicated the `epic-run-state` checkpoint and the
655
+ * `epic-run-progress` rollup and nothing consumed them.
656
+ */
657
+ function defaultSignalEmit(epicId, ctx) {
658
+ return async (signal) => {
659
+ await appendEpicSignal({
660
+ epicId,
661
+ signal: { ts: new Date().toISOString(), epic: epicId, ...signal },
662
+ config: ctx?.config,
663
+ });
664
+ };
665
+ }