mandrel 2.0.0 → 2.1.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 (311) hide show
  1. package/.agents/README.md +59 -28
  2. package/.agents/agents/acceptance-critic.md +9 -7
  3. package/.agents/agents/story-worker.md +41 -46
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +51 -44
  6. package/.agents/docs/agentrc-reference.json +8 -13
  7. package/.agents/docs/configuration.md +32 -56
  8. package/.agents/docs/execution-reference.md +39 -10
  9. package/.agents/docs/quality-gates.md +14 -16
  10. package/.agents/docs/workflows.md +6 -6
  11. package/.agents/instructions.md +64 -79
  12. package/.agents/rules/ci-remediation.md +3 -3
  13. package/.agents/rules/git-conventions-reference.md +42 -51
  14. package/.agents/schemas/agentrc.schema.json +34 -45
  15. package/.agents/schemas/audit-rules.json +59 -1
  16. package/.agents/schemas/audit-rules.schema.json +33 -1
  17. package/.agents/schemas/lifecycle/README.md +1 -2
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
  20. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
  21. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  22. package/.agents/schemas/signal-event.schema.json +3 -3
  23. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  24. package/.agents/schemas/validation-evidence.schema.json +1 -1
  25. package/.agents/scripts/acceptance-eval.js +22 -66
  26. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  27. package/.agents/scripts/bootstrap.js +3 -3
  28. package/.agents/scripts/check-dead-exports.js +43 -104
  29. package/.agents/scripts/check-doc-links.js +2 -2
  30. package/.agents/scripts/check-lifecycle-lint.js +1 -1
  31. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  32. package/.agents/scripts/deliver-recover.js +122 -0
  33. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  34. package/.agents/scripts/evidence-gate.js +20 -50
  35. package/.agents/scripts/generate-skills-index.js +17 -1
  36. package/.agents/scripts/generate-workflows-doc.js +4 -4
  37. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  38. package/.agents/scripts/lib/audit-suite/selector.js +323 -23
  39. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
  40. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  41. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  42. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  43. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  44. package/.agents/scripts/lib/checks/core-bare-clean.js +4 -1
  45. package/.agents/scripts/lib/checks/index.js +1 -1
  46. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  47. package/.agents/scripts/lib/checks/state.js +17 -248
  48. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +3 -3
  49. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  50. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  51. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  52. package/.agents/scripts/lib/cli-args.js +23 -2
  53. package/.agents/scripts/lib/close-validation/gates.js +13 -13
  54. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  55. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  56. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  57. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  58. package/.agents/scripts/lib/config/delivery-routing.js +7 -6
  59. package/.agents/scripts/lib/config/explain.js +10 -16
  60. package/.agents/scripts/lib/config/github.js +7 -5
  61. package/.agents/scripts/lib/config/limits.js +15 -25
  62. package/.agents/scripts/lib/config/quality.js +11 -14
  63. package/.agents/scripts/lib/config/runners.js +8 -21
  64. package/.agents/scripts/lib/config/temp-paths.js +18 -56
  65. package/.agents/scripts/lib/config-settings-schema-delivery.js +31 -13
  66. package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
  67. package/.agents/scripts/lib/config-settings-schema.js +48 -22
  68. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  69. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  70. package/.agents/scripts/lib/duplicate-search.js +38 -7
  71. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  72. package/.agents/scripts/lib/format-generated-json.js +97 -0
  73. package/.agents/scripts/lib/framework-version.js +19 -189
  74. package/.agents/scripts/lib/gh-exec.js +8 -0
  75. package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
  76. package/.agents/scripts/lib/git-utils.js +0 -14
  77. package/.agents/scripts/lib/json-utils.js +1 -2
  78. package/.agents/scripts/lib/label-constants.js +0 -15
  79. package/.agents/scripts/lib/label-taxonomy.js +1 -12
  80. package/.agents/scripts/lib/observability/active-story-env.js +42 -163
  81. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  82. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  83. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  84. package/.agents/scripts/lib/observability/source-classifier.js +2 -2
  85. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  86. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  87. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  88. package/.agents/scripts/lib/orchestration/ceremony-routing.js +43 -45
  89. package/.agents/scripts/lib/orchestration/code-review.js +58 -168
  90. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
  91. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  92. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  93. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  94. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  95. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  96. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +9 -11
  97. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  98. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  99. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +7 -3
  100. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  101. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  102. package/.agents/scripts/lib/orchestration/merge-block-class.js +76 -20
  103. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  104. package/.agents/scripts/lib/orchestration/plan-context.js +114 -24
  105. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
  106. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +3 -7
  107. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  108. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
  109. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
  110. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  111. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -75
  112. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
  113. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
  114. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  115. package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
  116. package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  118. package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
  119. package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
  120. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  121. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  122. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  124. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  125. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  126. package/.agents/scripts/lib/orchestration/run-epilogue.js +374 -16
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  130. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +3 -12
  131. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  132. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +72 -30
  133. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  134. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  135. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +12 -8
  136. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  137. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  138. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +264 -43
  139. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  140. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  141. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -32
  142. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  143. package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
  144. package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
  145. package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
  146. package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
  147. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  148. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
  149. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
  150. package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
  151. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
  152. package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
  153. package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
  154. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  155. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  156. package/.agents/scripts/lib/planning-corpus.js +12 -286
  157. package/.agents/scripts/lib/preflight-runner.js +2 -2
  158. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  159. package/.agents/scripts/lib/signals/index.js +4 -17
  160. package/.agents/scripts/lib/signals/read.js +35 -35
  161. package/.agents/scripts/lib/signals/schema.js +8 -11
  162. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  163. package/.agents/scripts/lib/signals/write.js +0 -1
  164. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  165. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  166. package/.agents/scripts/lib/story-adjacency.js +8 -7
  167. package/.agents/scripts/lib/story-body/story-body.js +6 -5
  168. package/.agents/scripts/lib/templates/decomposer-prompts.js +7 -3
  169. package/.agents/scripts/lib/test-env.js +14 -1
  170. package/.agents/scripts/lib/test-tiers.js +0 -3
  171. package/.agents/scripts/lib/ticket-body-sections.js +0 -14
  172. package/.agents/scripts/lib/validation-evidence.js +31 -59
  173. package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
  174. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  175. package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
  176. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  177. package/.agents/scripts/plan-context.js +38 -6
  178. package/.agents/scripts/plan-persist.js +145 -35
  179. package/.agents/scripts/plan-run-epilogue.js +83 -38
  180. package/.agents/scripts/post-structured-comment.js +0 -38
  181. package/.agents/scripts/pr-watch-with-update.js +43 -22
  182. package/.agents/scripts/providers/github/compose.js +0 -1
  183. package/.agents/scripts/providers/github/errors.js +0 -19
  184. package/.agents/scripts/providers/github/issues.js +1 -11
  185. package/.agents/scripts/providers/github/mappers.js +5 -0
  186. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  187. package/.agents/scripts/providers/github/tickets.js +33 -153
  188. package/.agents/scripts/providers/github.js +17 -6
  189. package/.agents/scripts/resolve-stories.js +236 -0
  190. package/.agents/scripts/run-coverage.js +4 -1
  191. package/.agents/scripts/run-lint.js +2 -2
  192. package/.agents/scripts/run-verify.js +31 -2
  193. package/.agents/scripts/signals-view.js +9 -10
  194. package/.agents/scripts/single-story-close.js +173 -18
  195. package/.agents/scripts/single-story-confirm-merge.js +288 -15
  196. package/.agents/scripts/single-story-init.js +6 -10
  197. package/.agents/scripts/stories-wave-tick.js +79 -4
  198. package/.agents/scripts/story-plan.js +3 -3
  199. package/.agents/scripts/update-ticket-state.js +8 -50
  200. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  201. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  202. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  203. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  204. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  205. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  206. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  207. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  208. package/.agents/skills/core/idea-refinement/SKILL.md +3 -3
  209. package/.agents/skills/core/scope-triage/SKILL.md +3 -0
  210. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  211. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  212. package/.agents/skills/skills.index.json +2 -12
  213. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  214. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  215. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  216. package/.agents/workflows/audit-architecture.md +3 -4
  217. package/.agents/workflows/audit-clean-code.md +4 -4
  218. package/.agents/workflows/audit-documentation.md +4 -5
  219. package/.agents/workflows/audit-lighthouse.md +8 -0
  220. package/.agents/workflows/audit-navigability.md +10 -0
  221. package/.agents/workflows/audit-performance.md +2 -3
  222. package/.agents/workflows/audit-quality.md +8 -9
  223. package/.agents/workflows/audit-security.md +1 -2
  224. package/.agents/workflows/audit-seo.md +10 -0
  225. package/.agents/workflows/audit-ux-ui.md +7 -0
  226. package/.agents/workflows/deliver.md +98 -45
  227. package/.agents/workflows/git-cleanup.md +2 -2
  228. package/.agents/workflows/git-deliver.md +1 -1
  229. package/.agents/workflows/helpers/acceptance-self-eval.md +21 -13
  230. package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
  231. package/.agents/workflows/helpers/code-review.md +12 -10
  232. package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
  233. package/.agents/workflows/helpers/deliver-story.md +193 -118
  234. package/.agents/workflows/helpers/parallel-tooling.md +2 -2
  235. package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
  236. package/.agents/workflows/plan.md +184 -19
  237. package/.agents/workflows/qa-assist.md +6 -6
  238. package/.agents/workflows/qa-explore.md +3 -3
  239. package/.agents/workflows/qa-run.md +1 -5
  240. package/bin/mandrel.js +12 -1
  241. package/docs/CHANGELOG.md +40 -0
  242. package/lib/cli/registry.js +262 -19
  243. package/lib/cli/sync-agents.js +157 -0
  244. package/lib/cli/sync-commands.js +115 -6
  245. package/lib/cli/sync.js +168 -6
  246. package/lib/cli/update.js +105 -8
  247. package/lib/cli/version-helpers.js +131 -0
  248. package/lib/migrations/README.md +7 -5
  249. package/lib/migrations/index.js +12 -9
  250. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  251. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  252. package/package.json +1 -1
  253. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  254. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  255. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  256. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  257. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  258. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  259. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  260. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  261. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  262. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  263. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  264. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  265. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  266. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  267. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  268. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  269. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  270. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  271. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  272. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  273. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  274. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  275. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  276. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  277. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  278. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  279. package/.agents/schemas/risk-verdict.schema.json +0 -53
  280. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  281. package/.agents/scripts/analyze-execution.js +0 -444
  282. package/.agents/scripts/check-prepush-recovery.js +0 -90
  283. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  284. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  285. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -187
  286. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  287. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  288. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  289. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +0 -128
  290. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
  291. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  292. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  293. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  294. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  295. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  296. package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
  297. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  298. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  299. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  300. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -21
  301. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  302. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  303. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  304. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -397
  305. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  306. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
  307. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  308. package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
  309. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
  310. package/.agents/scripts/resolve-plan-run.js +0 -117
  311. package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
@@ -22,8 +22,7 @@
22
22
  * catches an over-deep fan-out. The self-healing surface is preserved — it is
23
23
  * re-scoped, not removed.
24
24
  *
25
- * Scope: 'epic-deliver', 'retro'. Surfaces as a blocker at preflight for
26
- * `epic-deliver` (the fan-out site) and as audit signal at retro.
25
+ * Scope: 'retro'. Surfaces as audit signal at retro.
27
26
  *
28
27
  * The check is `refuse-and-print` — auto-rewriting a workflow's declared
29
28
  * depth or tool list would silently change runtime behavior in ways the
@@ -208,7 +207,7 @@ const FIX_COMMAND = [
208
207
  export default {
209
208
  id: 'subagent-agent-tool-required',
210
209
  severity: 'blocker',
211
- scope: ['epic-deliver', 'retro'],
210
+ scope: ['retro'],
212
211
  autoCorrect: 'refuse-and-print',
213
212
 
214
213
  detect(state) {
@@ -249,7 +248,7 @@ export default {
249
248
  return {
250
249
  id: 'subagent-agent-tool-required',
251
250
  severity: 'blocker',
252
- scope: state?.scope ?? 'epic-deliver',
251
+ scope: state?.scope ?? 'retro',
253
252
  summary: `${offences.length} sub-agent workflow(s) declare an Agent fan-out deeper than the supported nesting ceiling (${ceiling})`,
254
253
  detail,
255
254
  fixCommand: FIX_COMMAND,
@@ -8,7 +8,7 @@
8
8
  * tests that read environment variables silently take a different code
9
9
  * path.
10
10
  *
11
- * Surface: `epic-deliver` preflight and the `/diagnose` CLI. Surfaced as a
11
+ * Surface: the `/diagnose` CLI. Surfaced as a
12
12
  * warning rather than a blocker — the missing file may be a deliberate
13
13
  * choice (e.g. a worktree that doesn't need MCP), but the operator should
14
14
  * see the divergence from the main checkout.
@@ -28,7 +28,7 @@ const ID = 'worktree-bootstrap-env';
28
28
  export default {
29
29
  id: ID,
30
30
  severity: 'warning',
31
- scope: ['epic-deliver', 'diagnose'],
31
+ scope: ['diagnose'],
32
32
  autoCorrect: 'refuse-and-print',
33
33
  detect(state) {
34
34
  const status = state?.fs?.worktreeBootstrapStatus ?? {};
@@ -6,8 +6,8 @@
6
6
  * root `npm run lint` walks into the orphan tree, hits the nested config,
7
7
  * and fails. The close-time biome block is the canonical symptom.
8
8
  *
9
- * Surface: `epic-deliver` preflight, `story-close` preflight, and the
10
- * `/diagnose` CLI. Surfaced as a blocker so the operator clears the residue
9
+ * Surface: `story-close` preflight, the `/diagnose` CLI, and retro.
10
+ * Surfaced as a blocker so the operator clears the residue
11
11
  * with `rm -rf` before close re-runs the validation chain.
12
12
  *
13
13
  * AutoCorrect is `refuse-and-print`. Recursive deletion under `.worktrees/`
@@ -21,7 +21,7 @@ const ID = 'worktree-residue-biome';
21
21
  export default {
22
22
  id: ID,
23
23
  severity: 'blocker',
24
- scope: ['epic-deliver', 'story-close', 'diagnose', 'retro'],
24
+ scope: ['story-close', 'diagnose', 'retro'],
25
25
  autoCorrect: 'refuse-and-print',
26
26
  detect(state) {
27
27
  const orphans = state?.fs?.worktreeBiomeOrphans ?? [];
@@ -46,6 +46,22 @@ function optionalBooleanFlag(value) {
46
46
  return coerceBooleanFlag(value);
47
47
  }
48
48
 
49
+ /**
50
+ * Parse a positive-integer flag, preserving `undefined` when the flag is
51
+ * absent so a caller can distinguish "not supplied" (fall back to config)
52
+ * from an explicit value. A non-numeric or non-positive value is treated as
53
+ * absent rather than coerced to 0 — a `--max-wait-seconds=abc` typo must not
54
+ * silently become a zero-second wait.
55
+ *
56
+ * @param {unknown} value
57
+ * @returns {number|undefined}
58
+ */
59
+ function parsePositiveInt(value) {
60
+ if (value === undefined || value === null) return undefined;
61
+ const parsed = Number.parseInt(String(value), 10);
62
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
63
+ }
64
+
49
65
  /**
50
66
  * Standardized CLI argument parser for sprint scripts.
51
67
  * Supports options like --epic, --story, --dry-run, --skip-dashboard.
@@ -63,10 +79,12 @@ export function parseSprintArgs(args = process.argv) {
63
79
  'skip-validation': { type: 'boolean', default: false },
64
80
  'skip-sync': { type: 'boolean', default: false },
65
81
  'no-auto-merge': { type: 'boolean', default: false },
66
- 'no-full-scope-crap': { type: 'boolean', default: false },
67
82
  // No default — absent means "use delivery.routing.closeAndLand".
68
83
  'wait-merge': { type: 'boolean' },
69
84
  'no-wait-merge': { type: 'boolean', default: false },
85
+ // Story #4543 — per-run override of `delivery.mergeWatch.maxWaitSeconds`
86
+ // (the merge wait's per-invocation bound). Absent means "use the config".
87
+ 'max-wait-seconds': { type: 'string' },
70
88
  executor: { type: 'string' },
71
89
  cwd: { type: 'string' },
72
90
  'recut-of': { type: 'string' },
@@ -87,13 +105,16 @@ export function parseSprintArgs(args = process.argv) {
87
105
  skipValidation: coerceBooleanFlag(values['skip-validation']),
88
106
  skipSync: coerceBooleanFlag(values['skip-sync']),
89
107
  noAutoMerge: coerceBooleanFlag(values['no-auto-merge']),
90
- noFullScopeCrap: coerceBooleanFlag(values['no-full-scope-crap']),
91
108
  // Close-and-land: `--wait-merge` forces land-in-close; `--no-wait-merge`
92
109
  // opts out. When neither flag is present (`undefined`),
93
110
  // `parseCloseOptions` applies `delivery.routing.closeAndLand` (default
94
111
  // true) so attended and headless delivers share the same happy path.
95
112
  waitForMerge: optionalBooleanFlag(values['wait-merge']),
96
113
  noWaitForMerge: coerceBooleanFlag(values['no-wait-merge']),
114
+ // Story #4543 — raise the merge wait's per-invocation bound for a
115
+ // headless caller with no host tool-invocation ceiling, so it lands in
116
+ // one block instead of returning `pending` at the default 300s.
117
+ maxWaitSeconds: parsePositiveInt(values['max-wait-seconds']),
97
118
  executor: values.executor ?? null,
98
119
  // Resolve worktree cwd from flag or env. Empty string/whitespace → null.
99
120
  cwd:
@@ -54,22 +54,22 @@ function buildChangedFileScope(baseRef) {
54
54
  *
55
55
  * The baselines gate resolves its compare ref through `resolveScope`,
56
56
  * whose environment layer reads `BASELINE_REF`. Threading
57
- * `origin/<epicBranch>` here makes the gate diff head against the epic
57
+ * `origin/<baseBranch>` here makes the gate diff head against the epic
58
58
  * integration branch instead of the framework-default `origin/main`, so
59
59
  * drift that already landed on `main` but is outside the Story's own diff
60
60
  * does not surface as a phantom regression. The same convention
61
- * (`origin/<epicBranch>`) is used by the baseline-attribution and
61
+ * (`origin/<baseBranch>`) is used by the baseline-attribution and
62
62
  * auto-refresh paths, keeping read/compare bases aligned.
63
63
  *
64
64
  * Returns `null` when no integration branch is supplied (the gate then
65
65
  * keeps its existing default-ref / consumer-config behaviour untouched).
66
66
  *
67
- * @param {string|undefined|null} epicBranch
67
+ * @param {string|undefined|null} baseBranch
68
68
  * @returns {{ BASELINE_REF: string } | null}
69
69
  */
70
- function buildBaselinesGateEnv(epicBranch) {
71
- if (typeof epicBranch !== 'string' || epicBranch.length === 0) return null;
72
- return { BASELINE_REF: `origin/${epicBranch}` };
70
+ function buildBaselinesGateEnv(baseBranch) {
71
+ if (typeof baseBranch !== 'string' || baseBranch.length === 0) return null;
72
+ return { BASELINE_REF: `origin/${baseBranch}` };
73
73
  }
74
74
 
75
75
  /**
@@ -240,11 +240,11 @@ function probeBaselinesGate({ config, cwd, presentBaselines } = {}) {
240
240
  * shared in-process runner. The unified `check-baselines` gate is now the
241
241
  * single source of truth for per-kind regression enforcement
242
242
  * (attribution-wired floor + tolerance + schema).
243
- * The `epicBranch` parameter threads the close run's integration branch
243
+ * The `baseBranch` parameter threads the close run's integration branch
244
244
  * into two gates: the `format` gate's `changedFileScope` (existing) and —
245
245
  * since Story #3890 — the `check-baselines` gate's `BASELINE_REF` env, so
246
246
  * the baselines regression compare diffs head against the epic integration
247
- * branch (`origin/<epicBranch>`) rather than the framework-default
247
+ * branch (`origin/<baseBranch>`) rather than the framework-default
248
248
  * `origin/main`. Without this, every child Story on an `epic/<id>` branch
249
249
  * re-discovered inherited main-vs-epic drift in untouched files as phantom
250
250
  * regressions and worked around it by hand-setting `BASELINE_REF`.
@@ -268,10 +268,10 @@ function probeBaselinesGate({ config, cwd, presentBaselines } = {}) {
268
268
  * none are required, the gate is skipped with a logged reason (via `log`)
269
269
  * instead of a blocking failure.
270
270
  *
271
- * @param {{ config?: object, epicBranch?: string, cwd?: string, packageScripts?: Record<string, string>, presentBaselines?: string[]|Set<string>, log?: (message: string) => void }} [opts]
271
+ * @param {{ config?: object, baseBranch?: string, cwd?: string, packageScripts?: Record<string, string>, presentBaselines?: string[]|Set<string>, log?: (message: string) => void }} [opts]
272
272
  * `config` is the canonical resolved config (`{ project, delivery, ... }`);
273
273
  * gate commands resolve from `project.commands` and the CRAP toggle from
274
- * `delivery.quality.gates.crap.enabled`. `epicBranch` is the close run's
274
+ * `delivery.quality.gates.crap.enabled`. `baseBranch` is the close run's
275
275
  * integration branch (`epic/<id>` for Epic-attached Stories, the base
276
276
  * branch for standalone Stories). `cwd` is where the `package.json`
277
277
  * coverage-script probe and the `baselines/<kind>.json` presence probe
@@ -285,7 +285,7 @@ function probeBaselinesGate({ config, cwd, presentBaselines } = {}) {
285
285
  */
286
286
  export function buildDefaultGates({
287
287
  config,
288
- epicBranch,
288
+ baseBranch,
289
289
  cwd,
290
290
  packageScripts,
291
291
  presentBaselines,
@@ -305,9 +305,9 @@ export function buildDefaultGates({
305
305
  const formatWriteString = resolveFormatWriteCommand(config);
306
306
  const formatChangedFileScope =
307
307
  formatCheckString === FORMAT_CHECK_FALLBACK
308
- ? buildChangedFileScope(epicBranch)
308
+ ? buildChangedFileScope(baseBranch)
309
309
  : null;
310
- const baselinesGateEnv = buildBaselinesGateEnv(epicBranch);
310
+ const baselinesGateEnv = buildBaselinesGateEnv(baseBranch);
311
311
  const baselinesDecision = probeBaselinesGate({
312
312
  config,
313
313
  cwd,
@@ -3,7 +3,7 @@
3
3
  * inputs.js — shared input validator for close-validation projection helpers.
4
4
  *
5
5
  * Used by `projections/maintainability.js` (and any future projection that
6
- * shares the same `{ cwd, epicBranch, storyBranch, baselinePath }` argument
6
+ * shares the same `{ cwd, baseBranch, storyBranch, baselinePath }` argument
7
7
  * shape) to collapse the inline guard cascade into a single predicate that
8
8
  * returns a typed `reason` on failure.
9
9
  *
@@ -16,7 +16,7 @@
16
16
  /**
17
17
  * @typedef {Object} ProjectionInputs
18
18
  * @property {string} [cwd]
19
- * @property {string} [epicBranch]
19
+ * @property {string} [baseBranch]
20
20
  * @property {string} [storyBranch]
21
21
  * @property {string} [baselinePath]
22
22
  */
@@ -32,7 +32,7 @@
32
32
  /**
33
33
  * @typedef {Object} ValidationFail
34
34
  * @property {false} ok
35
- * @property {'missing-cwd'|'missing-epic-branch'|'missing-story-branch'|'missing-baseline-path'|'no-baseline'} reason
35
+ * @property {'missing-cwd'|'missing-base-branch'|'missing-story-branch'|'missing-baseline-path'|'no-baseline'} reason
36
36
  */
37
37
 
38
38
  /**
@@ -40,7 +40,7 @@
40
40
  *
41
41
  * Reason branches (in order):
42
42
  * - `missing-cwd` — cwd is falsy
43
- * - `missing-epic-branch` — epicBranch is falsy
43
+ * - `missing-base-branch` — baseBranch is falsy
44
44
  * - `missing-story-branch` — storyBranch is falsy
45
45
  * - `missing-baseline-path` — baselinePath is falsy
46
46
  * - `no-baseline` — loadBaseline returned null/undefined/empty
@@ -54,9 +54,9 @@
54
54
  * @returns {ValidationOk | ValidationFail}
55
55
  */
56
56
  export function validateProjectionInputs(inputs, opts = {}) {
57
- const { cwd, epicBranch, storyBranch, baselinePath } = inputs ?? {};
57
+ const { cwd, baseBranch, storyBranch, baselinePath } = inputs ?? {};
58
58
  if (!cwd) return { ok: false, reason: 'missing-cwd' };
59
- if (!epicBranch) return { ok: false, reason: 'missing-epic-branch' };
59
+ if (!baseBranch) return { ok: false, reason: 'missing-base-branch' };
60
60
  if (!storyBranch) return { ok: false, reason: 'missing-story-branch' };
61
61
  if (!baselinePath) return { ok: false, reason: 'missing-baseline-path' };
62
62
 
@@ -80,7 +80,7 @@ export function validateProjectionInputs(inputs, opts = {}) {
80
80
  */
81
81
  export const MISSING_ARG_REASONS = new Set([
82
82
  'missing-cwd',
83
- 'missing-epic-branch',
83
+ 'missing-base-branch',
84
84
  'missing-story-branch',
85
85
  'missing-baseline-path',
86
86
  ]);
@@ -41,18 +41,18 @@ function normaliseSkipReason(reason) {
41
41
  }
42
42
 
43
43
  /**
44
- * Refresh `origin/<epicBranch>` so the diff range resolves even when the
44
+ * Refresh `origin/<baseBranch>` so the diff range resolves even when the
45
45
  * close script hasn't reached its own pull/rebase step yet. Routed through
46
46
  * the shared `(cwd, ref, windowMs)` cache so a story-init fetch in the same
47
47
  * wave satisfies the projection without re-hitting origin.
48
48
  *
49
49
  * @param {string} cwd
50
- * @param {string} epicBranch
50
+ * @param {string} baseBranch
51
51
  * @param {{ gitSpawn: typeof defaultGitSpawn }} git
52
52
  * @returns {{ ok: true } | { ok: false, detail: string }}
53
53
  */
54
- function refreshEpicRef(cwd, epicBranch, git) {
55
- const fetchRes = cachedGitFetchSync(cwd, epicBranch, {
54
+ function refreshEpicRef(cwd, baseBranch, git) {
55
+ const fetchRes = cachedGitFetchSync(cwd, baseBranch, {
56
56
  gitSpawn: git.gitSpawn,
57
57
  });
58
58
  if (fetchRes.status !== 0) {
@@ -69,13 +69,13 @@ function refreshEpicRef(cwd, epicBranch, git) {
69
69
  * the changed-files list. Normalises Windows-style backslash paths to
70
70
  * forward slashes so the baseline lookup is platform-agnostic.
71
71
  *
72
- * @param {{ cwd: string, epicBranch: string, storyBranch: string, git: { gitSpawn: typeof defaultGitSpawn } }} opts
72
+ * @param {{ cwd: string, baseBranch: string, storyBranch: string, git: { gitSpawn: typeof defaultGitSpawn } }} opts
73
73
  * @returns {{ ok: true, files: string[] } | { ok: false, detail: string }}
74
74
  */
75
- function diffChangedFiles({ cwd, epicBranch, storyBranch, git }) {
75
+ function diffChangedFiles({ cwd, baseBranch, storyBranch, git }) {
76
76
  try {
77
77
  const files = diffNameOnly({
78
- range: `origin/${epicBranch}...${storyBranch}`,
78
+ range: `origin/${baseBranch}...${storyBranch}`,
79
79
  cwd,
80
80
  gitSpawn: git.gitSpawn,
81
81
  });
@@ -190,7 +190,7 @@ function collectRegressions({
190
190
  *
191
191
  * @param {{
192
192
  * cwd: string,
193
- * epicBranch: string,
193
+ * baseBranch: string,
194
194
  * storyBranch: string,
195
195
  * baselinePath: string,
196
196
  * tolerance?: number,
@@ -207,7 +207,7 @@ function collectRegressions({
207
207
  */
208
208
  export function projectMaintainabilityRegressions({
209
209
  cwd,
210
- epicBranch,
210
+ baseBranch,
211
211
  storyBranch,
212
212
  baselinePath,
213
213
  tolerance = DEFAULT_MI_TOLERANCE,
@@ -216,7 +216,7 @@ export function projectMaintainabilityRegressions({
216
216
  loadBaseline = getBaseline,
217
217
  } = {}) {
218
218
  const validation = validateProjectionInputs(
219
- { cwd, epicBranch, storyBranch, baselinePath },
219
+ { cwd, baseBranch, storyBranch, baselinePath },
220
220
  { loadBaseline },
221
221
  );
222
222
  if (!validation.ok) {
@@ -227,7 +227,7 @@ export function projectMaintainabilityRegressions({
227
227
  };
228
228
  }
229
229
 
230
- const fetchOutcome = refreshEpicRef(cwd, epicBranch, git);
230
+ const fetchOutcome = refreshEpicRef(cwd, baseBranch, git);
231
231
  if (!fetchOutcome.ok) {
232
232
  return {
233
233
  ok: true,
@@ -237,7 +237,7 @@ export function projectMaintainabilityRegressions({
237
237
  };
238
238
  }
239
239
 
240
- const diffOutcome = diffChangedFiles({ cwd, epicBranch, storyBranch, git });
240
+ const diffOutcome = diffChangedFiles({ cwd, baseBranch, storyBranch, git });
241
241
  if (!diffOutcome.ok) {
242
242
  return {
243
243
  ok: true,
@@ -72,21 +72,19 @@ function applyChangedFileScope({ gate, spawnCwd, log }) {
72
72
  * Worktree locality (Story #1120): when `worktreePath` is supplied, every
73
73
  * gate runner is spawned with `cwd: worktreePath` so the gate sees the
74
74
  * Story branch's post-rebase tree. Evidence reads/writes still key against
75
- * `cwd` (the main checkout) because the per-Epic temp tree lives under
76
- * the main `.git/`. Failure messages name the worktree path.
75
+ * `cwd` (the main checkout) because the temp tree lives under the main
76
+ * `.git/`. Failure messages name the worktree path.
77
77
  *
78
- * Evidence-aware: when `storyId` is provided alongside either `epicId` or
79
- * `standalone: true`, and `useEvidence !== false`, each gate consults
78
+ * Evidence-aware: when `storyId` is provided alongside `standalone: true`,
79
+ * and `useEvidence !== false`, each gate consults
80
80
  * `validation-evidence.shouldSkip()` against current HEAD + the gate's
81
81
  * command-config hash. A matching record skips the gate; a successful run
82
82
  * is recorded so the next caller in the local hot path can skip in turn.
83
83
  *
84
- * Standalone keyspace (Story #4250): the standalone path has no parent
85
- * Epic, so it passes `standalone: true` (and leaves `epicId` null) to route
86
- * the evidence file to the storyId-anchored
84
+ * Standalone keyspace (Story #4250): `standalone: true` routes the evidence
85
+ * file to the storyId-anchored
87
86
  * `<tempRoot>/standalone/stories/story-<id>/validation-evidence.json`
88
- * keyspace instead of feeding a null `epicId` into the Epic-keyed path
89
- * (which structurally disabled the cache before).
87
+ * keyspace. v2.0.0 removed the Epic tier and its Epic-keyed keyspace.
90
88
  *
91
89
  * `onGateStart` is invoked immediately before each gate's runner spawn.
92
90
  * story-close uses it to drive `phaseTimer.mark(...)` for per-gate
@@ -100,7 +98,6 @@ function applyChangedFileScope({ gate, spawnCwd, log }) {
100
98
  * log?: (m: string) => void,
101
99
  * onGateStart?: (gate: Gate) => void,
102
100
  * storyId?: number|null,
103
- * epicId?: number|null,
104
101
  * standalone?: boolean,
105
102
  * useEvidence?: boolean,
106
103
  * evidenceClock?: () => number,
@@ -118,7 +115,6 @@ export async function runCloseValidation({
118
115
  log = () => {},
119
116
  onGateStart,
120
117
  storyId = null,
121
- epicId = null,
122
118
  standalone = false,
123
119
  useEvidence = true,
124
120
  evidenceClock = () => Date.now(),
@@ -129,16 +125,12 @@ export async function runCloseValidation({
129
125
  const failed = [];
130
126
  const skipped = [];
131
127
  // Evidence is active when a Story id is present AND there is a keyspace to
132
- // anchor on: either a real Epic id (Epic path) or `standalone: true`
133
- // (Story #4250 standalone storyId-anchored keyspace). A bare `epicId:
134
- // null` without `standalone` keeps the cache off, as before.
135
- const evidenceActive =
136
- useEvidence && storyId != null && (epicId != null || standalone);
137
- // The evidence-store opts: `standalone` routes to the storyId-anchored
138
- // keyspace; otherwise the Epic-keyed path resolves under `epicId`.
139
- const evidenceStoreOpts = { cwd, epicId, standalone };
140
- // Evidence keys against the main checkout's HEAD because the per-Epic
141
- // evidence file lives under the main `.git/`. Gate spawn, in contrast,
128
+ // anchor on (`standalone: true` — Story #4250's storyId-anchored
129
+ // keyspace, now the only one).
130
+ const evidenceActive = useEvidence && storyId != null && standalone;
131
+ const evidenceStoreOpts = { cwd, standalone };
132
+ // Evidence keys against the main checkout's HEAD because the evidence
133
+ // file lives under the main `.git/`. Gate spawn, in contrast,
142
134
  // runs in the worktree when one is supplied — that's the whole point of
143
135
  // Story #1120.
144
136
  const spawnCwd = worktreePath ?? cwd;
@@ -3,19 +3,25 @@
3
3
  */
4
4
 
5
5
  import { writeFile as defaultWriteFile } from 'node:fs/promises';
6
- import { storyArtifactPath } from '../config/temp-paths.js';
6
+ import path from 'node:path';
7
+ import { storyTempDir } from '../config/temp-paths.js';
7
8
  import { getSpawnCount as defaultGetSpawnCount } from '../gh-exec.js';
8
9
 
9
10
  /**
10
11
  * Throw-away ghSpawnCount emitter (Story #1795 / Epic #1788).
11
12
  *
12
13
  * Writes the current `gh-exec` spawn counter to
13
- * `temp/epic-<eid>/stories/story-<sid>/gh-spawn-count.json` so the
14
- * `analyze-execution.js` child process can read it and emit a
15
- * `ghSpawnCount` field on the `story-perf-summary` payload. The Story-
16
- * close orchestrator calls this inside `runPostMergeClose` right before
17
- * the perf-summary phase, capturing every `gh` invocation from preflight
18
- * through the merge in one counter snapshot.
14
+ * `temp/run-<id>/stories/story-<sid>/gh-spawn-count.json`.
15
+ *
16
+ * Story #4545 its reader is gone: `analyze-execution.js` consumed this file
17
+ * to emit a `ghSpawnCount` field on the `story-perf-summary` payload, and both
18
+ * that CLI and that payload were deleted with the execution-analysis surface.
19
+ * The writer itself already had no production caller before that (the
20
+ * `runPostMergeClose` orchestrator named below went in the v2.0.0 cutover), so
21
+ * this module is production-dead and kept alive only by its own test — the
22
+ * test-importer blind spot the dead-exports ratchet cannot see. It is left in
23
+ * place rather than deleted because reviving spawn telemetry against the live
24
+ * close path is a decision, not a sweep.
19
25
  *
20
26
  * @param {object} opts
21
27
  * @param {number|string} opts.epicId
@@ -50,7 +56,10 @@ export async function emitGhSpawnCount({
50
56
  );
51
57
  return { status: 'failed', reason: 'counter-read-failed' };
52
58
  }
53
- const targetPath = storyArtifactPath(eid, sid, 'gh-spawn-count.json', config);
59
+ const targetPath = path.join(
60
+ storyTempDir(eid, sid, config),
61
+ 'gh-spawn-count.json',
62
+ );
54
63
  const payload = {
55
64
  kind: 'gh-spawn-count',
56
65
  epicId: eid,
@@ -18,12 +18,13 @@
18
18
  * full-closure agent that ran before M7-B.
19
19
  *
20
20
  * `delivery.routing.freshCriticSampleRate` is the **maker-checker sampling
21
- * floor** (Epic #4478, M7-B, Part 2). Risk-routed ceremony sends a low-risk
22
- * acceptance cluster down the contract-identical *inline* critic path, but a
23
- * fraction of low-risk clusters are still forced through a *fresh-context*
24
- * critic so "low risk" never degrades to zero independent checking. The rate is
25
- * clamped into `[0, 1]`; `0` disables the floor (pure risk routing), `1` forces
26
- * every cluster fresh. The default is `0.2`. See `resolveCeremonyForRisk` in
21
+ * floor** (Epic #4478, M7-B, Part 2). Ceremony routing sends the acceptance
22
+ * clusters of a change set that touches no sensitive path down the
23
+ * contract-identical *inline* critic path, but a fraction of them are still
24
+ * forced through a *fresh-context* critic so a low derived level never degrades
25
+ * to zero independent checking. The rate is clamped into `[0, 1]`; `0` disables
26
+ * the floor (pure level routing), `1` forces every cluster fresh. The default is
27
+ * `0.2`. See `resolveCeremonyForRisk` in
27
28
  * `lib/orchestration/ceremony-routing.js`.
28
29
  *
29
30
  * Framework-defaults pattern mirrors `lib/config/ci.js#getCiDelivery`.
@@ -63,13 +63,13 @@ const SECRET_SEGMENT_PATTERNS = Object.freeze([
63
63
  const KEY_MEANINGS = Object.freeze({
64
64
  // project.*
65
65
  'project.baseBranch':
66
- 'Default base branch Epics and Stories branch from and merge back into.',
66
+ 'Default base branch Stories branch from and merge back into.',
67
67
  'project.paths.agentRoot':
68
68
  'Directory holding the distributed agent bundle (instructions, skills, scripts).',
69
69
  'project.paths.docsRoot':
70
70
  'Directory the mandatory docs-context reads resolve against.',
71
71
  'project.paths.tempRoot':
72
- 'Root for gitignored scratch output (per-Epic run state, mirrors, logs).',
72
+ 'Root for gitignored scratch output (per-run state, mirrors, logs).',
73
73
  'project.docsContextFiles':
74
74
  'Authoritative files an agent must read before starting any task.',
75
75
  'project.commands.lintBaseline':
@@ -114,10 +114,6 @@ const KEY_MEANINGS = Object.freeze({
114
114
  'Allowlist of events that fire a webhook notification.',
115
115
 
116
116
  // planning.*
117
- 'planning.context.maxBytes':
118
- 'Byte budget for the planning-context payload before summary mode kicks in.',
119
- 'planning.context.summaryMode':
120
- 'When the planner switches to a summarized context representation.',
121
117
  'planning.codebaseSnapshot.tier':
122
118
  'Depth of the structural codebase view threaded into spec authoring.',
123
119
  'planning.codebaseSnapshot.include':
@@ -149,7 +145,7 @@ const KEY_MEANINGS = Object.freeze({
149
145
  'delivery.execution.timeoutMs':
150
146
  'Per-execution timeout for orchestrated delivery steps.',
151
147
  'delivery.lease.ttlMs':
152
- 'Time-to-live for the Epic lease before a stale claim is reclaimable.',
148
+ 'Time-to-live for the delivery lease before a stale claim is reclaimable.',
153
149
  'delivery.ci.watch.pollIntervalMs':
154
150
  'Poll cadence (ms) for the merge/CI watch loop.',
155
151
  'delivery.ci.watch.maxPolls':
@@ -161,9 +157,7 @@ const KEY_MEANINGS = Object.freeze({
161
157
  'delivery.docsFreshness.paths':
162
158
  'Docs whose freshness is checked at delivery time.',
163
159
  'delivery.deliverRunner.concurrencyCap':
164
- 'Maximum Stories dispatched in parallel within one wave. Default 3 — conservative by design to keep host-quota consumption predictable. Operators running wide-wave Epics with adequate parallel-agent quota should raise this to reduce wall-clock time proportionally.',
165
- 'delivery.deliverRunner.verifyConcurrencyCap':
166
- 'Maximum verify steps run in parallel.',
160
+ 'Maximum Stories dispatched in parallel within one wave. Default 3 — conservative by design to keep host-quota consumption predictable. Operators running wide waves with adequate parallel-agent quota should raise this to reduce wall-clock time proportionally.',
167
161
  'delivery.worktreeIsolation.enabled':
168
162
  'Whether each Story runs in its own git worktree.',
169
163
  'delivery.worktreeIsolation.root':
@@ -179,9 +173,9 @@ const KEY_MEANINGS = Object.freeze({
179
173
  'delivery.worktreeIsolation.bootstrapFiles':
180
174
  'Files copied into each new worktree (e.g. .env, .mcp.json, local overrides).',
181
175
  'delivery.mergeWatch.intervalSeconds':
182
- 'Poll cadence (seconds) for MergeWatcher after epic.merge.armed.',
176
+ 'Poll cadence (seconds) for the close-and-land merge wait after the arm.',
183
177
  'delivery.mergeWatch.maxBudgetSeconds':
184
- 'Wall-clock budget (seconds) before MergeWatcher surfaces budget-exceeded.',
178
+ 'Cumulative wall-clock budget (seconds) across resumes before the merge wait gives up and blocks.',
185
179
  'delivery.codeReview.providers':
186
180
  'Ordered provider chain the code-review phase consults.',
187
181
  'delivery.codeReview.maxFixAttempts':
@@ -195,7 +189,7 @@ const KEY_MEANINGS = Object.freeze({
195
189
  'delivery.routing.freshCriticSampleRate':
196
190
  'Fraction of low-risk acceptance clusters forced through a fresh-context critic (maker-checker floor).',
197
191
  'delivery.routing.ceremonyProfile':
198
- 'Acceptance-ceremony depth: minimal (always inline), standard (risk-routed), or strict (always fresh).',
192
+ 'Acceptance-ceremony depth: minimal (always inline), standard (derived-level routed), or strict (always fresh).',
199
193
  'delivery.routing.closeAndLand':
200
194
  'When true, single-story-close lands through merge in one close (opt out with --no-wait-merge).',
201
195
  'delivery.feedbackLoop.auditResultsAutoFile':
@@ -217,7 +211,7 @@ const KEY_MEANINGS = Object.freeze({
217
211
  'delivery.acceptanceEval.maxRounds':
218
212
  'Redraft rounds the per-Story acceptance self-eval loop runs before escalating to agent::blocked (default 2; clamped to a hard ceiling that cannot be disabled).',
219
213
  'delivery.acceptanceEval.clusterCeiling':
220
- 'Max acceptance criteria one single-delivery acceptance critic scores per fresh-context pass; the Epic ACs are split into ceil(totalACs / clusterCeiling) maker-blind critic clusters (default 4; clamped to [1, 8]).',
214
+ 'Max acceptance criteria one single-delivery acceptance critic scores per fresh-context pass; the Story ACs are split into ceil(totalACs / clusterCeiling) maker-blind critic clusters (default 4; clamped to [1, 8]).',
221
215
 
222
216
  // qa.*
223
217
  'qa.featureRoot': 'Root directory holding the QA harness .feature files.',
@@ -252,7 +246,7 @@ const PREFIX_MEANINGS = Object.freeze([
252
246
  ],
253
247
  ['delivery.quality', 'Delivery-time quality configuration.'],
254
248
  ['delivery.signals', 'Threshold for a delivery friction/telemetry signal.'],
255
- ['delivery.mergeWatch', 'MergeWatcher poll cadence and wall-clock budget.'],
249
+ ['delivery.mergeWatch', 'Merge-wait poll cadence and wall-clock budget.'],
256
250
  [
257
251
  'delivery.feedbackLoop',
258
252
  'Opt-out toggles for auto-filing non-blocking findings.',
@@ -282,7 +276,7 @@ const PREFIX_MEANINGS = Object.freeze([
282
276
  const BLOCK_MEANINGS = Object.freeze({
283
277
  project: 'Project identity, paths, and command configuration.',
284
278
  github: 'GitHub provider identity and merge/notification policy.',
285
- planning: 'Inputs and guardrails for /epic-plan.',
279
+ planning: 'Inputs and guardrails for /plan.',
286
280
  delivery: 'Execution, isolation, quality, and CI settings for delivery.',
287
281
  qa: 'Agent-driven QA harness contract.',
288
282
  });
@@ -55,11 +55,13 @@ export const NOTIFICATIONS_DEFAULTS = Object.freeze({
55
55
  'operator-message',
56
56
  ]),
57
57
  webhookEvents: Object.freeze([
58
- 'epic-started',
59
- 'epic-progress',
60
- 'epic-blocked',
61
- 'epic-unblocked',
62
- 'epic-complete',
58
+ 'state-transition',
59
+ 'story-merged',
60
+ 'story-closing',
61
+ 'operator-message',
62
+ 'merge.unlanded',
63
+ 'merge.flip-failed',
64
+ 'loop.tick',
63
65
  ]),
64
66
  });
65
67