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
@@ -5,7 +5,6 @@
5
5
  * Post-reshape, the surviving operator-configurable keys are split across
6
6
  * `planning.*` and `delivery.*`:
7
7
  *
8
- * - `planning.context.{maxBytes, summaryMode}` (planning-context budget)
9
8
  * - `delivery.execution.timeoutMs` (per-process execution timeout)
10
9
  * - `delivery.lease.ttlMs` (assignee-as-lease staleness window — Story #3480)
11
10
  * - `delivery.signals.{rework, retry}` (performance-signal detector
@@ -17,7 +16,12 @@
17
16
  * Dropped entirely: `maxInstructionSteps`, `friction.*`, `executionMaxBuffer`,
18
17
  * `signals.{churn, idle}`, `delivery.preflight`, `delivery.maxTokenBudget`
19
18
  * (planning no longer sizes against a token-budget envelope; session-mass
20
- * ceilings are absolute in `DEFAULT_MODEL_CAPACITY`).
19
+ * ceilings are absolute in `DEFAULT_MODEL_CAPACITY`), and
20
+ * `planning.context.{maxBytes, summaryMode}` (Story #4541 — the `applyBudget`
21
+ * pass they fed lost its last caller in the v2 cutover, and it bounded a field
22
+ * the envelope builders discarded; the live bound on planner-context size is
23
+ * the fixed `PLAN_CONTEXT_ENVELOPE_BYTE_CEILING` in
24
+ * `lib/orchestration/plan-context.js`).
21
25
  *
22
26
  * The historic combined accessor `getLimits(config)` is preserved as a
23
27
  * compatibility surface: it returns a wrapper carrying the surviving
@@ -37,10 +41,14 @@ export const SIGNALS_DEFAULTS = Object.freeze({
37
41
 
38
42
  /**
39
43
  * Default TTL for the assignee-as-lease primitive (Story #3480). A claim
40
- * whose owner has not emitted a `story.heartbeat` within this window is
41
- * considered stale and may be reclaimed by another operator. 15 minutes
42
- * gives a healthy run comfortable headroom over the §2e idle watchdog's
43
- * 10-minute re-tick while still releasing a genuinely dead claim promptly.
44
+ * whose owner's last heartbeat is older than this window is considered stale
45
+ * and may be reclaimed by another operator.
46
+ *
47
+ * Note: no shipped caller supplies a real heartbeat the emitter was inert
48
+ * and was deleted (A22), so the guards anchor liveness to `now` and every
49
+ * foreign claim reads live (fail-closed; clear a stranded claim with
50
+ * `--steal`). This value is therefore only consulted by a caller that threads
51
+ * its own `heartbeatAt`, and is kept as the documented default for that seam.
44
52
  */
45
53
  export const LEASE_TTL_MS_DEFAULT = 900000;
46
54
 
@@ -51,10 +59,6 @@ export const LIMITS_DEFAULTS = Object.freeze({
51
59
  maxTickets: 80,
52
60
  executionTimeoutMs: 600000,
53
61
  leaseTtlMs: LEASE_TTL_MS_DEFAULT,
54
- planningContext: Object.freeze({
55
- maxBytes: 50000,
56
- summaryMode: 'auto',
57
- }),
58
62
  signals: SIGNALS_DEFAULTS,
59
63
  });
60
64
 
@@ -83,8 +87,7 @@ function mergeSignals(userSignals) {
83
87
  /**
84
88
  * Resolve the surviving limits surface against a `.agentrc.json` shape
85
89
  * (post-reshape). `maxTickets` is a framework constant (never read from
86
- * config); pulls `planningContext` from `planning.*`, pulls
87
- * `executionTimeoutMs` from `delivery.*`, pulls signals from
90
+ * config); pulls `executionTimeoutMs` from `delivery.*`, pulls signals from
88
91
  * `delivery.signals.*`.
89
92
  *
90
93
  * @param {object|undefined} config
@@ -92,23 +95,14 @@ function mergeSignals(userSignals) {
92
95
  * maxTickets: number,
93
96
  * executionTimeoutMs: number,
94
97
  * leaseTtlMs: number,
95
- * planningContext: { maxBytes: number, summaryMode: string },
96
98
  * signals: ReturnType<typeof mergeSignals>,
97
99
  * }}
98
100
  */
99
101
  export function resolveLimits(config) {
100
- const planning =
101
- config?.planning && typeof config.planning === 'object'
102
- ? config.planning
103
- : {};
104
102
  const delivery =
105
103
  config?.delivery && typeof config.delivery === 'object'
106
104
  ? config.delivery
107
105
  : {};
108
- const planningContextUser =
109
- planning.context && typeof planning.context === 'object'
110
- ? planning.context
111
- : {};
112
106
  const execution =
113
107
  delivery.execution && typeof delivery.execution === 'object'
114
108
  ? delivery.execution
@@ -120,10 +114,6 @@ export function resolveLimits(config) {
120
114
  executionTimeoutMs:
121
115
  execution.timeoutMs ?? LIMITS_DEFAULTS.executionTimeoutMs,
122
116
  leaseTtlMs: lease.ttlMs ?? LIMITS_DEFAULTS.leaseTtlMs,
123
- planningContext: {
124
- ...LIMITS_DEFAULTS.planningContext,
125
- ...planningContextUser,
126
- },
127
117
  signals: mergeSignals(delivery.signals),
128
118
  };
129
119
  }
@@ -366,14 +366,19 @@ function resolveCoverageGate(userBlock) {
366
366
  }
367
367
 
368
368
  /**
369
- * Framework defaults for `delivery.quality.codingGuardrails`. The legacy
370
- * field name `miDropRefactor` was renamed to `miDropMustRefactor` in
371
- * Story 1 to avoid semantic collision with `autoRefresh.miDropCap`.
369
+ * Framework defaults for `delivery.quality.codingGuardrails`.
370
+ *
371
+ * `miDropMustRefactor` was retired in Story #4531: schema-validated,
372
+ * defaulted, and resolved, but never consumed — the gate it named
373
+ * (`quality-preview.js`'s `computeExitCode`) short-circuits on `miExit`
374
+ * (derived from the already-consumed `gates.maintainability.tolerance`)
375
+ * before this value is ever read. `maintainability.tolerance` is the one
376
+ * documented MI-drop control now; see `lib/migrations/index.js` for the
377
+ * consumer-config migration that strips a leftover key on upgrade.
372
378
  */
373
379
  export const CODING_GUARDRAILS_DEFAULTS = Object.freeze({
374
380
  cyclomaticFlag: 8,
375
381
  cyclomaticMustFix: 12,
376
- miDropMustRefactor: 1.5,
377
382
  requireSiblingTest: false,
378
383
  });
379
384
 
@@ -393,8 +398,6 @@ export function resolveCodingGuardrails(userBlock) {
393
398
  cyclomaticFlag: userBlock.cyclomaticFlag ?? defaults.cyclomaticFlag,
394
399
  cyclomaticMustFix:
395
400
  userBlock.cyclomaticMustFix ?? defaults.cyclomaticMustFix,
396
- miDropMustRefactor:
397
- userBlock.miDropMustRefactor ?? defaults.miDropMustRefactor,
398
401
  requireSiblingTest:
399
402
  typeof userBlock.requireSiblingTest === 'boolean'
400
403
  ? userBlock.requireSiblingTest
@@ -402,9 +405,10 @@ export function resolveCodingGuardrails(userBlock) {
402
405
  };
403
406
  }
404
407
 
408
+ // autoRefresh.miDropCap was retired alongside codingGuardrails.
409
+ // miDropMustRefactor in Story #4531 — same unconsumed-knob shape, same fix.
405
410
  const AUTO_REFRESH_DEFAULTS = Object.freeze({
406
411
  enabled: true,
407
- miDropCap: 1.5,
408
412
  crapJumpCap: 5,
409
413
  scope: 'diff',
410
414
  });
@@ -416,7 +420,6 @@ function resolveAutoRefresh(userBlock) {
416
420
  if (userBlock == null || typeof userBlock !== 'object') {
417
421
  return {
418
422
  enabled: defaults.enabled,
419
- miDropCap: defaults.miDropCap,
420
423
  crapJumpCap: defaults.crapJumpCap,
421
424
  scope: defaults.scope,
422
425
  };
@@ -429,12 +432,6 @@ function resolveAutoRefresh(userBlock) {
429
432
  typeof userBlock.enabled === 'boolean'
430
433
  ? userBlock.enabled
431
434
  : defaults.enabled,
432
- miDropCap:
433
- typeof userBlock.miDropCap === 'number' &&
434
- Number.isFinite(userBlock.miDropCap) &&
435
- userBlock.miDropCap >= 0
436
- ? userBlock.miDropCap
437
- : defaults.miDropCap,
438
435
  crapJumpCap:
439
436
  typeof userBlock.crapJumpCap === 'number' &&
440
437
  Number.isFinite(userBlock.crapJumpCap) &&
@@ -3,18 +3,11 @@
3
3
  *
4
4
  * Post-reshape, only `delivery.deliverRunner` and `delivery.codeReview` are
5
5
  * configurable via this accessor; everything else lives in framework-internal
6
- * constants exported alongside (`DEFAULT_STORY_MERGE_RETRY`,
7
- * `DEFAULT_DECOMPOSER`). `delivery.epicAudit` was removed on v2 (Story-only
8
- * delivery — no epic-audit runner; remediation policy lives on
9
- * `delivery.codeReview`).
6
+ * constants exported alongside (`DEFAULT_DECOMPOSER`).
7
+ * `delivery.epicAudit` was removed on v2 (Story-only delivery — no
8
+ * epic-audit runner; remediation policy lives on `delivery.codeReview`).
10
9
  */
11
10
 
12
- /** Hardcoded story-merge retry policy (was `orchestration.runners.storyMergeRetry`). */
13
- export const DEFAULT_STORY_MERGE_RETRY = Object.freeze({
14
- maxAttempts: 3,
15
- backoffMs: Object.freeze([250, 500, 1000]),
16
- });
17
-
18
11
  /** Hardcoded decomposer concurrency cap (was `orchestration.runners.decomposer.concurrencyCap`). */
19
12
  export const DEFAULT_DECOMPOSER = Object.freeze({
20
13
  concurrencyCap: 3,
@@ -33,14 +26,13 @@ export const DEFAULT_DECOMPOSER = Object.freeze({
33
26
  * reduces wall-clock time where dependencies allow. See `deliver.md` and
34
27
  * `agentrc-reference.json` `delivery.deliverRunner.concurrencyCap`.
35
28
  *
36
- * **`verifyConcurrencyCap`** (Epic #3019 Tech Spec §1.4 / Story #3024) is a
37
- * separate knob that bounds the `verifyWaveResults` loop independently of
38
- * Story-dispatch concurrency, so operators can tune ticket-verify parallelism
39
- * without raising the wave fan-out. Default 4.
29
+ * Story #4545 removed the sibling `verifyConcurrencyCap`: the
30
+ * `verifyWaveResults` loop it claimed to bound never existed in the tree, and
31
+ * its only reader was the retired execution-analysis CLI, which echoed the
32
+ * number into a report rather than bounding anything.
40
33
  */
41
34
  const DEFAULT_DELIVER_RUNNER = Object.freeze({
42
35
  concurrencyCap: 3,
43
- verifyConcurrencyCap: 4,
44
36
  });
45
37
 
46
38
  /**
@@ -59,9 +51,8 @@ export const DEFAULT_CODE_REVIEW = Object.freeze({
59
51
  *
60
52
  * @param {object | null | undefined} config
61
53
  * @returns {{
62
- * deliverRunner: { concurrencyCap: number, verifyConcurrencyCap: number },
54
+ * deliverRunner: { concurrencyCap: number },
63
55
  * codeReview: { maxFixAttempts: number, maxFixScopeFiles: number, autoFixSeverity: 'high'|'medium' },
64
- * storyMergeRetry: { maxAttempts: number, backoffMs: readonly number[] },
65
56
  * decomposer: { concurrencyCap: number },
66
57
  * }}
67
58
  */
@@ -73,9 +64,6 @@ export function getRunners(config) {
73
64
  concurrencyCap:
74
65
  deliverRunnerUser.concurrencyCap ??
75
66
  DEFAULT_DELIVER_RUNNER.concurrencyCap,
76
- verifyConcurrencyCap:
77
- deliverRunnerUser.verifyConcurrencyCap ??
78
- DEFAULT_DELIVER_RUNNER.verifyConcurrencyCap,
79
67
  },
80
68
  codeReview: {
81
69
  maxFixAttempts:
@@ -85,7 +73,6 @@ export function getRunners(config) {
85
73
  autoFixSeverity:
86
74
  codeReviewUser.autoFixSeverity ?? DEFAULT_CODE_REVIEW.autoFixSeverity,
87
75
  },
88
- storyMergeRetry: DEFAULT_STORY_MERGE_RETRY,
89
76
  decomposer: DEFAULT_DECOMPOSER,
90
77
  };
91
78
  }
@@ -13,15 +13,13 @@
13
13
  * ├─ techspec.md
14
14
  * ├─ manifest.md (dispatch manifest)
15
15
  * ├─ retro.md (mirror of GitHub retro at Epic close)
16
- * ├─ perf-report.md (analyzer output, Epic-level)
17
16
  * ├─ lifecycle.ndjson (lifecycle bus ledger)
18
17
  * ├─ checkpoints/... (pre-v2 epic-runner state store; retained layout)
19
- * ├─ <name> (epicArtifactPath escape hatch)
18
+ * ├─ <name> (runArtifactPath escape hatch)
20
19
  * └─ stories/
21
20
  * └─ story-<sid>/
22
21
  * ├─ manifest.md (story dispatch manifest)
23
22
  * ├─ signals.ndjson (append-only signals writer)
24
- * ├─ perf-summary.md
25
23
  * └─ <name> (storyArtifactPath escape hatch)
26
24
  *
27
25
  * Standalone Stories (no parent Epic) follow the same shape under
@@ -42,11 +40,12 @@
42
40
  * resolve a *relative* `tempRoot` against the **main checkout root** (the
43
41
  * parent of `git rev-parse --git-common-dir`) rather than `process.cwd()`.
44
42
  * Without this, a story child that `cd`s into `.worktrees/story-<id>/` before
45
- * calling `story-phase.js` would append `story.heartbeat` records to
43
+ * emitting a lifecycle record would append it to
46
44
  * `<worktree>/temp/run-N/lifecycle.ndjson`, while the `/deliver` host
47
45
  * (running from the main checkout) reads the main-checkout copy — so the
48
- * idle-watchdog never sees heartbeats and the Epic-lease guard silently
49
- * reclaims live foreign claims (the audit-#3513 bug class). Anchoring the
46
+ * host never sees the child's records (the audit-#3513 bug class; its
47
+ * original `story.heartbeat` instance is gone with that emitter, but the
48
+ * divergence applies to every ledger writer). Anchoring the
50
49
  * ledger to the git common dir makes the worktree child writer and the
51
50
  * main-checkout host reader converge on a single file regardless of cwd. An
52
51
  * absolute `tempRoot` is honoured verbatim; only relative roots are anchored.
@@ -155,11 +154,9 @@ export function tempRootFrom(config) {
155
154
  : 'temp';
156
155
  }
157
156
 
158
- const epicId = (id) => {
157
+ const runId = (id) => {
159
158
  if (!Number.isInteger(id) || id <= 0) {
160
- throw new Error(
161
- `[temp-paths] epicId must be a positive integer; got ${id}`,
162
- );
159
+ throw new Error(`[temp-paths] runId must be a positive integer; got ${id}`);
163
160
  }
164
161
  return id;
165
162
  };
@@ -206,19 +203,14 @@ const artifactName = (name) => {
206
203
  };
207
204
 
208
205
  /**
209
- * `temp/run-<eid>/` — every Epic-scoped artifact lives under here.
206
+ * `temp/run-<id>/` — every run-scoped artifact lives under here.
210
207
  *
211
- * @param {number} eid
208
+ * @param {number} rid
212
209
  * @param {object} [config]
213
210
  * @returns {string}
214
211
  */
215
212
  export function runTempDir(rid, config) {
216
- return path.join(anchorTempRoot(tempRootFrom(config)), `run-${epicId(rid)}`);
217
- }
218
-
219
- /** @deprecated Use {@link runTempDir}. */
220
- export function epicTempDir(eid, config) {
221
- return runTempDir(eid, config);
213
+ return path.join(anchorTempRoot(tempRootFrom(config)), `run-${runId(rid)}`);
222
214
  }
223
215
 
224
216
  /**
@@ -246,7 +238,7 @@ export function storyTempDir(eid, sid, config) {
246
238
  const parent =
247
239
  checkedEid === null
248
240
  ? path.join(anchorTempRoot(tempRootFrom(config)), 'standalone')
249
- : epicTempDir(checkedEid, config);
241
+ : runTempDir(checkedEid, config);
250
242
  return path.join(parent, 'stories', `story-${storyId(sid)}`);
251
243
  }
252
244
 
@@ -272,7 +264,7 @@ export function signalsFile(eid, sid, config) {
272
264
  * needs an on-disk home even though there is no `run-<id>/` directory to
273
265
  * anchor the event to.
274
266
  *
275
- * Mirrors `epicLedgerPath` exactly, one level down: `eid === null` routes
267
+ * Mirrors `runLedgerPath` exactly, one level down: `eid === null` routes
276
268
  * through `storyTempDir`'s standalone branch to
277
269
  * `<tempRoot>/standalone/stories/story-<sid>/lifecycle.ndjson`; a real
278
270
  * `eid` routes to `<tempRoot>/run-<eid>/stories/story-<sid>/lifecycle.ndjson`,
@@ -298,14 +290,13 @@ export const storyLedgerPath = (eid, sid, config) =>
298
290
  * @param {object} [config]
299
291
  * @returns {string}
300
292
  */
301
- export function epicArtifactPath(eid, name, config) {
302
- return path.join(epicTempDir(eid, config), artifactName(name));
293
+ export function runArtifactPath(eid, name, config) {
294
+ return path.join(runTempDir(eid, config), artifactName(name));
303
295
  }
304
296
 
305
297
  /**
306
298
  * Escape hatch for a Story-level artifact whose name isn't part of the
307
- * canonical layout (signals.ndjson + perf-summary.md + manifest.md ship
308
- * named helpers).
299
+ * canonical layout (signals.ndjson + manifest.md ship named helpers).
309
300
  *
310
301
  * @param {number} eid
311
302
  * @param {number} sid
@@ -313,37 +304,10 @@ export function epicArtifactPath(eid, name, config) {
313
304
  * @param {object} [config]
314
305
  * @returns {string}
315
306
  */
316
- export function storyArtifactPath(eid, sid, name, config) {
307
+ function storyArtifactPath(eid, sid, name, config) {
317
308
  return path.join(storyTempDir(eid, sid, config), artifactName(name));
318
309
  }
319
310
 
320
- // --- Canonical Epic-level filenames (Tech Spec #1032 §tempRoot) ---
321
-
322
- export const epicTechSpecPath = (eid, config) =>
323
- epicArtifactPath(eid, 'techspec.md', config);
324
- export const epicManifestPath = (eid, config) =>
325
- epicArtifactPath(eid, 'manifest.md', config);
326
- export const epicRetroMirrorPath = (eid, config) =>
327
- epicArtifactPath(eid, 'retro.md', config);
328
- export const epicPerfReportPath = (eid, config) =>
329
- epicArtifactPath(eid, 'perf-report.md', config);
330
-
331
- /**
332
- * `temp/run-<eid>/epic-perf-report.json` — canonical JSON snapshot of
333
- * the `epic-perf-report` payload persisted at /deliver close
334
- * (Epic #3019 / Story #3029 / Task #3040). When present alongside the
335
- * `epic-perf-report` structured comment, the report is discoverable
336
- * from the file system without round-tripping the ticketing provider,
337
- * and the `epic-handoff` structured close comment links it by relative
338
- * path.
339
- *
340
- * @param {number} eid
341
- * @param {object} [config]
342
- * @returns {string}
343
- */
344
- export const epicPerfReportJsonPath = (eid, config) =>
345
- epicArtifactPath(eid, 'epic-perf-report.json', config);
346
-
347
311
  /**
348
312
  * `temp/run-<eid>/lifecycle.ndjson` — append-only lifecycle bus ledger
349
313
  * (Story #2510). The LedgerWriter persists every emitted/completed/failed
@@ -357,12 +321,10 @@ export const epicPerfReportJsonPath = (eid, config) =>
357
321
  * @param {object} [config]
358
322
  * @returns {string}
359
323
  */
360
- export const epicLedgerPath = (eid, config) =>
361
- epicArtifactPath(eid, 'lifecycle.ndjson', config);
324
+ export const runLedgerPath = (eid, config) =>
325
+ runArtifactPath(eid, 'lifecycle.ndjson', config);
362
326
 
363
327
  // --- Canonical Story-level filenames ---
364
328
 
365
329
  export const storyManifestPath = (eid, sid, config) =>
366
330
  storyArtifactPath(eid, sid, 'manifest.md', config);
367
- export const storyPerfSummaryPath = (eid, sid, config) =>
368
- storyArtifactPath(eid, sid, 'perf-summary.md', config);
@@ -32,9 +32,11 @@ const EXECUTION_SCHEMA = {
32
32
 
33
33
  /**
34
34
  * `delivery.lease` — assignee-as-lease primitive (Story #3480). `ttlMs` is
35
- * the staleness window: a ticket claim whose owner has not emitted a
36
- * `story.heartbeat` within this many milliseconds is reclaimable by another
37
- * operator. Defaults to 900000 (15 min) in `lib/config/limits.js`.
35
+ * the staleness window: a ticket claim whose owner's last heartbeat is older
36
+ * than this many milliseconds is reclaimable by another operator. Defaults to
37
+ * 900000 (15 min) in `lib/config/limits.js`. Note the shipped guards fail
38
+ * closed (no live heartbeat source since A22 removed the inert emitter), so
39
+ * a stranded claim is cleared with `--steal` rather than by TTL expiry.
38
40
  */
39
41
  const LEASE_SCHEMA = {
40
42
  type: 'object',
@@ -64,7 +66,6 @@ const DELIVER_RUNNER_SCHEMA = {
64
66
  type: 'object',
65
67
  properties: {
66
68
  concurrencyCap: { type: 'integer', minimum: 1 },
67
- verifyConcurrencyCap: { type: 'integer', minimum: 1 },
68
69
  },
69
70
  additionalProperties: false,
70
71
  };
@@ -137,19 +138,36 @@ const SIGNALS_SCHEMA = {
137
138
  };
138
139
 
139
140
  /**
140
- * `delivery.mergeWatch` — knobs consumed by the MergeWatcher lifecycle
141
- * listener (Story #2896, Epic #2880). `intervalSeconds` is the poll
142
- * cadence between `gh pr view --json mergeCommit,mergedAt` probes after
143
- * `epic.merge.armed`; `maxBudgetSeconds` is the total wall-clock budget
144
- * before the watcher surfaces `agent::blocked` with reason
145
- * `budget-exceeded`. Both keys default in the listener when omitted
146
- * (30s / 3600s).
141
+ * `delivery.mergeWatch` — knobs consumed by the close-and-land merge wait
142
+ * listener (Story #2896, Epic #2880) and by the close-and-land merge wait
143
+ * (`single-story-close/phases/confirm-merge.js`). `intervalSeconds` is the
144
+ * poll cadence between `gh pr view` probes after the arm.
145
+ *
146
+ * The two budgets are deliberately separate axes (Story #4543):
147
+ *
148
+ * - `maxWaitSeconds` bounds **one invocation** of the merge wait. Its
149
+ * default (300s) fits inside a single host tool invocation, whose
150
+ * ceiling is ~10 minutes; the gates that run before the wait already
151
+ * consume minutes of that. Expiry is NOT a block — the wait returns a
152
+ * resumable `pending` terminal with no label mutation. A headless caller
153
+ * with no such ceiling raises it to keep land-in-one-block semantics.
154
+ * - `maxBudgetSeconds` bounds the **cumulative** wait across resumes,
155
+ * anchored at the PR's `createdAt` so re-entering the wait does not
156
+ * restart the clock. Exhausting *this* is the genuine give-up condition
157
+ * that classifies and blocks.
158
+ *
159
+ * `updateAttempts` caps how many times the wait will bring a
160
+ * behind-the-base PR up to date before giving the branch up as unwinnable,
161
+ * rather than waiting out the budget behind a base it could have merged.
162
+ * All keys default in the consumer when omitted (30s / 300s / 3600s / 3).
147
163
  */
148
164
  const MERGE_WATCH_SCHEMA = {
149
165
  type: 'object',
150
166
  properties: {
151
167
  intervalSeconds: { type: 'integer', minimum: 1 },
168
+ maxWaitSeconds: { type: 'integer', minimum: 1 },
152
169
  maxBudgetSeconds: { type: 'integer', minimum: 1 },
170
+ updateAttempts: { type: 'integer', minimum: 0 },
153
171
  },
154
172
  additionalProperties: false,
155
173
  };
@@ -167,8 +185,8 @@ const MERGE_WATCH_SCHEMA = {
167
185
  // context; false falls back to `subagent_type: general-purpose` (the instant
168
186
  // per-consumer revert + the escape for hosts that ignore `.claude/agents/`).
169
187
  // `delivery.routing.freshCriticSampleRate` (default 0.2, clamped [0, 1]) is the
170
- // maker-checker sampling floor forcing a fraction of low-risk acceptance
171
- // clusters through a fresh critic.
188
+ // maker-checker sampling floor forcing a fraction of low-derived-level
189
+ // acceptance clusters through a fresh critic.
172
190
  const ROUTING_SCHEMA = {
173
191
  type: 'object',
174
192
  properties: {
@@ -14,12 +14,20 @@
14
14
  // aggregate into per-gate files under `config/gates/`.
15
15
  import { GATES_SCHEMA } from './config/gates/index.js';
16
16
 
17
+ // Story #4531: miDropMustRefactor (here) and autoRefresh.miDropCap (below)
18
+ // were retired. Both were schema-validated, defaulted, and resolved, but
19
+ // never consumed by the gate they were named for — quality-preview.js's
20
+ // computeExitCode short-circuits on miExit (derived from the ALREADY-
21
+ // consumed delivery.quality.gates.maintainability.tolerance) before either
22
+ // knob is ever read. maintainability.tolerance is now the single documented
23
+ // MI-drop control. See lib/migrations/index.js for the consumer-config
24
+ // migration that strips these keys on upgrade (additionalProperties: false
25
+ // below means a leftover key is a hard AJV failure, not a silent no-op).
17
26
  const CODING_GUARDRAILS_SCHEMA = {
18
27
  type: 'object',
19
28
  properties: {
20
29
  cyclomaticFlag: { type: 'integer', minimum: 1 },
21
30
  cyclomaticMustFix: { type: 'integer', minimum: 1 },
22
- miDropMustRefactor: { type: 'number', minimum: 0 },
23
31
  requireSiblingTest: { type: 'boolean' },
24
32
  },
25
33
  additionalProperties: false,
@@ -29,7 +37,6 @@ const AUTO_REFRESH_SCHEMA = {
29
37
  type: 'object',
30
38
  properties: {
31
39
  enabled: { type: 'boolean' },
32
- miDropCap: { type: 'number', minimum: 0 },
33
40
  crapJumpCap: { type: 'number', minimum: 0 },
34
41
  scope: { type: 'string', enum: ['diff', 'full'] },
35
42
  },
@@ -109,25 +109,57 @@ const PROJECT_SCHEMA = {
109
109
 
110
110
  /**
111
111
  * Curated webhook event vocabulary. The webhook channel is gated by an
112
- * explicit allowlist of event names — the webhook narrative is "epic %
113
- * progress + blockers", not the firehose of per-story transitions that the
114
- * GitHub-comment channel still receives.
112
+ * explicit allowlist of event names — the vocabulary mirrors the events the
113
+ * v2 runtime actually emits through `notify()` (Story transitions, merge
114
+ * outcomes, loop lifecycle beats).
115
+ *
116
+ * `story.heartbeat` was retired here (A22): the vocabulary's contract is
117
+ * "events the runtime actually emits", and nothing could emit this one. Its
118
+ * emitter (`emit-story-heartbeat.js`) demanded an `epicId >= 1` while the
119
+ * sole call path (`single-story-init.js` → `setActiveStoryEnv`) passed
120
+ * `epicId: null`, so `CC_EPIC_ID` was never set and the hook that would have
121
+ * fired the beat always short-circuited. Emitter, hook, and schema are all
122
+ * deleted; keeping the name allowlistable would let an operator subscribe to
123
+ * a channel that can never deliver. Removing it from the enum makes a
124
+ * resurrection fail loudly at config-validation time rather than silently
125
+ * never firing.
115
126
  */
116
127
  export const WEBHOOK_EVENT_NAMES = Object.freeze([
117
- 'epic-started',
118
- 'epic-progress',
119
- 'epic-blocked',
120
- 'epic-unblocked',
121
- 'epic-complete',
128
+ 'state-transition',
129
+ 'story-merged',
130
+ 'story-closing',
131
+ 'operator-message',
132
+ 'merge.unlanded',
133
+ 'merge.flip-failed',
134
+ 'loop.tick',
122
135
  ]);
123
136
 
124
137
  /**
125
138
  * Curated GitHub-comment event vocabulary. The comment channel is gated by
126
139
  * an explicit allowlist of event names — same model as `webhookEvents`.
140
+ *
141
+ * **Deliberately narrower than {@link WEBHOOK_EVENT_NAMES}**, and the axis
142
+ * is ticket scope, not importance. A comment is written *onto a Story
143
+ * issue*, so only events that are about one Story, and whose message reads
144
+ * as narrative an operator wants durably on the ticket, belong here. The
145
+ * webhook-only remainder — `merge.unlanded`, `merge.flip-failed`,
146
+ * `loop.tick` — are run-scoped or firehose beats;
147
+ * mirroring them onto the ticket would bury the narrative under machine
148
+ * chatter, and `notify()` drops a comment for any dispatch without a
149
+ * resolvable ticket id regardless.
150
+ *
151
+ * `story-closing` IS in scope by that rule (Story-scoped, `level: 'story'`,
152
+ * human-readable — the same shape as `story-merged`) and its earlier
153
+ * absence was an oversight: the event was emittable to webhooks but could
154
+ * not be allowlisted for comments at all. It is in the vocabulary but NOT
155
+ * in the shipped default (`config/github.js` `NOTIFICATIONS_DEFAULTS`) —
156
+ * opting in is an operator choice, not a behaviour change forced on every
157
+ * consumer.
127
158
  */
128
159
  export const COMMENT_EVENT_NAMES = Object.freeze([
129
160
  'state-transition',
130
161
  'story-merged',
162
+ 'story-closing',
131
163
  'operator-message',
132
164
  ]);
133
165
 
@@ -208,19 +240,14 @@ const GITHUB_SCHEMA = {
208
240
  // planning.* — inputs to /plan
209
241
  // ---------------------------------------------------------------------------
210
242
 
211
- /**
212
- * `planning.context` bounded planning-context budget for `--emit-context`
213
- * payloads. When the full payload would exceed `maxBytes`, planners switch
214
- * to a summary representation.
215
- */
216
- const PLANNING_CONTEXT_SCHEMA = {
217
- type: 'object',
218
- properties: {
219
- maxBytes: { type: 'integer', minimum: 1024 },
220
- summaryMode: { type: 'string', enum: ['auto', 'always', 'never'] },
221
- },
222
- additionalProperties: false,
223
- };
243
+ // Story #4541: `planning.context.{maxBytes, summaryMode}` was retired. The
244
+ // `applyBudget` pass it fed lost its last caller in the v2 cutover, and it
245
+ // bounded a field the envelope builders discarded before shipping the raw seed
246
+ // anyway so the key resolved but capped nothing. The live bound on
247
+ // planner-context size is the fixed `PLAN_CONTEXT_ENVELOPE_BYTE_CEILING` in
248
+ // `lib/orchestration/plan-context.js`. Setting `planning.context` is now
249
+ // rejected as an additional property, so a resurrected key fails loudly rather
250
+ // than silently doing nothing.
224
251
 
225
252
  /**
226
253
  * Story #2634 — `planning.codebaseSnapshot` controls the structural
@@ -250,7 +277,6 @@ const PLANNING_SCHEMA = {
250
277
  type: 'object',
251
278
  properties: {
252
279
  riskHeuristics: LIST_OR_EXTENDER_OF_STRINGS,
253
- context: PLANNING_CONTEXT_SCHEMA,
254
280
  codebaseSnapshot: CODEBASE_SNAPSHOT_SCHEMA,
255
281
  // Cross-Story conflict-finding severity gates. Off by default so
256
282
  // existing repos keep advisory-only behaviour; flipping either to