mandrel 2.0.0 → 2.2.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 (323) hide show
  1. package/.agents/README.md +59 -28
  2. package/.agents/agents/acceptance-critic.md +20 -9
  3. package/.agents/agents/story-worker.md +45 -48
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +60 -46
  6. package/.agents/docs/agentrc-reference.json +8 -13
  7. package/.agents/docs/configuration.md +33 -57
  8. package/.agents/docs/execution-reference.md +39 -10
  9. package/.agents/docs/quality-gates.md +17 -19
  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/gherkin-standards.md +10 -0
  14. package/.agents/rules/git-conventions-reference.md +42 -51
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
  16. package/.agents/schemas/agentrc.schema.json +35 -46
  17. package/.agents/schemas/audit-rules.json +59 -1
  18. package/.agents/schemas/audit-rules.schema.json +33 -1
  19. package/.agents/schemas/lifecycle/README.md +1 -2
  20. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  21. package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
  22. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
  23. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  24. package/.agents/schemas/signal-event.schema.json +3 -3
  25. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  26. package/.agents/schemas/validation-evidence.schema.json +1 -1
  27. package/.agents/scripts/acceptance-eval.js +24 -68
  28. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  29. package/.agents/scripts/bootstrap.js +3 -3
  30. package/.agents/scripts/check-dead-exports.js +43 -104
  31. package/.agents/scripts/check-doc-links.js +2 -2
  32. package/.agents/scripts/check-lifecycle-lint.js +1 -1
  33. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  34. package/.agents/scripts/deliver-recover.js +122 -0
  35. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  36. package/.agents/scripts/evidence-gate.js +20 -50
  37. package/.agents/scripts/generate-skills-index.js +17 -1
  38. package/.agents/scripts/generate-workflows-doc.js +4 -4
  39. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  40. package/.agents/scripts/lib/audit-suite/selector.js +323 -23
  41. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
  42. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  43. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  44. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  45. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  46. package/.agents/scripts/lib/checks/core-bare-clean.js +4 -1
  47. package/.agents/scripts/lib/checks/index.js +1 -1
  48. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  49. package/.agents/scripts/lib/checks/state.js +17 -248
  50. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +3 -3
  51. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  52. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  53. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  54. package/.agents/scripts/lib/cli-args.js +23 -2
  55. package/.agents/scripts/lib/close-validation/gates.js +13 -13
  56. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  57. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  58. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  59. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  60. package/.agents/scripts/lib/config/acceptance-eval.js +2 -2
  61. package/.agents/scripts/lib/config/delivery-routing.js +7 -6
  62. package/.agents/scripts/lib/config/explain.js +10 -16
  63. package/.agents/scripts/lib/config/github.js +7 -5
  64. package/.agents/scripts/lib/config/limits.js +15 -25
  65. package/.agents/scripts/lib/config/quality.js +11 -14
  66. package/.agents/scripts/lib/config/runners.js +8 -21
  67. package/.agents/scripts/lib/config/temp-paths.js +18 -56
  68. package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
  69. package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
  70. package/.agents/scripts/lib/config-settings-schema.js +48 -22
  71. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  72. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  73. package/.agents/scripts/lib/duplicate-search.js +38 -7
  74. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  75. package/.agents/scripts/lib/format-generated-json.js +97 -0
  76. package/.agents/scripts/lib/framework-version.js +19 -189
  77. package/.agents/scripts/lib/gh-exec.js +8 -0
  78. package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
  79. package/.agents/scripts/lib/git-utils.js +0 -14
  80. package/.agents/scripts/lib/json-utils.js +1 -2
  81. package/.agents/scripts/lib/label-constants.js +0 -15
  82. package/.agents/scripts/lib/label-taxonomy.js +1 -12
  83. package/.agents/scripts/lib/observability/active-story-env.js +42 -163
  84. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  85. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  86. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  87. package/.agents/scripts/lib/observability/source-classifier.js +2 -2
  88. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  89. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  90. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  91. package/.agents/scripts/lib/orchestration/ceremony-routing.js +43 -45
  92. package/.agents/scripts/lib/orchestration/change-set.js +103 -0
  93. package/.agents/scripts/lib/orchestration/code-review.js +70 -191
  94. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
  95. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  96. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  97. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  98. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  99. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  100. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +9 -11
  101. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  102. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  103. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +7 -3
  104. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  105. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  106. package/.agents/scripts/lib/orchestration/merge-block-class.js +76 -20
  107. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  108. package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
  109. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
  110. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
  111. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  112. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
  113. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
  114. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  115. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
  116. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
  117. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
  118. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  119. package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
  120. package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
  121. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
  122. package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
  123. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  124. package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
  125. package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
  126. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  127. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  128. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  129. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  130. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  131. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  132. package/.agents/scripts/lib/orchestration/run-epilogue.js +374 -16
  133. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
  134. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  135. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  136. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +4 -13
  137. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  138. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +72 -30
  139. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  140. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  141. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +12 -8
  142. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  143. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  144. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +264 -43
  145. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  146. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  147. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
  148. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
  149. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
  150. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  151. package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
  152. package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
  153. package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
  154. package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
  155. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  156. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
  157. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
  158. package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
  159. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
  160. package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
  161. package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
  162. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  163. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  164. package/.agents/scripts/lib/planning-corpus.js +12 -286
  165. package/.agents/scripts/lib/preflight-runner.js +2 -2
  166. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  167. package/.agents/scripts/lib/signals/index.js +4 -17
  168. package/.agents/scripts/lib/signals/read.js +35 -35
  169. package/.agents/scripts/lib/signals/schema.js +8 -11
  170. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  171. package/.agents/scripts/lib/signals/write.js +0 -1
  172. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  173. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  174. package/.agents/scripts/lib/story-adjacency.js +8 -7
  175. package/.agents/scripts/lib/story-body/story-body.js +81 -13
  176. package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
  177. package/.agents/scripts/lib/test-env.js +14 -1
  178. package/.agents/scripts/lib/test-tiers.js +0 -3
  179. package/.agents/scripts/lib/ticket-body-sections.js +0 -14
  180. package/.agents/scripts/lib/validation-evidence.js +31 -59
  181. package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
  182. package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
  183. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  184. package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
  185. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  186. package/.agents/scripts/plan-context.js +38 -7
  187. package/.agents/scripts/plan-critics.js +203 -0
  188. package/.agents/scripts/plan-persist.js +145 -35
  189. package/.agents/scripts/plan-run-epilogue.js +83 -38
  190. package/.agents/scripts/post-structured-comment.js +0 -38
  191. package/.agents/scripts/pr-watch-with-update.js +43 -22
  192. package/.agents/scripts/providers/github/compose.js +0 -1
  193. package/.agents/scripts/providers/github/errors.js +0 -19
  194. package/.agents/scripts/providers/github/issues.js +1 -11
  195. package/.agents/scripts/providers/github/mappers.js +5 -0
  196. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  197. package/.agents/scripts/providers/github/tickets.js +33 -153
  198. package/.agents/scripts/providers/github.js +17 -6
  199. package/.agents/scripts/quality-preview.js +13 -6
  200. package/.agents/scripts/resolve-stories.js +236 -0
  201. package/.agents/scripts/run-coverage.js +4 -1
  202. package/.agents/scripts/run-lint.js +2 -2
  203. package/.agents/scripts/run-verify.js +31 -2
  204. package/.agents/scripts/signals-view.js +9 -10
  205. package/.agents/scripts/single-story-close.js +173 -18
  206. package/.agents/scripts/single-story-confirm-merge.js +288 -15
  207. package/.agents/scripts/single-story-init.js +6 -10
  208. package/.agents/scripts/stories-wave-tick.js +380 -53
  209. package/.agents/scripts/story-plan.js +3 -3
  210. package/.agents/scripts/update-ticket-state.js +8 -50
  211. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  212. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  213. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  214. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  215. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  216. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  217. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  218. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  219. package/.agents/skills/core/idea-refinement/SKILL.md +3 -3
  220. package/.agents/skills/core/scope-triage/SKILL.md +3 -0
  221. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  222. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  223. package/.agents/skills/skills.index.json +2 -12
  224. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  225. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  226. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  227. package/.agents/workflows/audit-architecture.md +3 -4
  228. package/.agents/workflows/audit-clean-code.md +4 -4
  229. package/.agents/workflows/audit-documentation.md +4 -5
  230. package/.agents/workflows/audit-lighthouse.md +8 -0
  231. package/.agents/workflows/audit-navigability.md +10 -0
  232. package/.agents/workflows/audit-performance.md +2 -3
  233. package/.agents/workflows/audit-quality.md +8 -9
  234. package/.agents/workflows/audit-security.md +1 -2
  235. package/.agents/workflows/audit-seo.md +10 -0
  236. package/.agents/workflows/audit-ux-ui.md +7 -0
  237. package/.agents/workflows/deliver.md +133 -45
  238. package/.agents/workflows/git-cleanup.md +2 -2
  239. package/.agents/workflows/git-deliver.md +1 -1
  240. package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
  241. package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
  242. package/.agents/workflows/helpers/code-review.md +14 -12
  243. package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
  244. package/.agents/workflows/helpers/deliver-story.md +209 -118
  245. package/.agents/workflows/helpers/parallel-tooling.md +2 -2
  246. package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
  247. package/.agents/workflows/plan.md +239 -19
  248. package/.agents/workflows/qa-assist.md +6 -6
  249. package/.agents/workflows/qa-explore.md +3 -3
  250. package/.agents/workflows/qa-run.md +1 -5
  251. package/bin/mandrel.js +12 -1
  252. package/docs/CHANGELOG.md +62 -0
  253. package/lib/cli/registry.js +262 -19
  254. package/lib/cli/sync-agents.js +157 -0
  255. package/lib/cli/sync-commands.js +115 -6
  256. package/lib/cli/sync.js +168 -6
  257. package/lib/cli/update.js +105 -8
  258. package/lib/cli/version-helpers.js +131 -0
  259. package/lib/migrations/README.md +7 -5
  260. package/lib/migrations/index.js +17 -9
  261. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  262. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  263. package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
  264. package/package.json +2 -2
  265. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  266. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  267. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  268. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  269. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  270. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  271. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  272. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  273. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  274. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  275. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  276. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  277. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  278. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  279. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  280. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  281. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  282. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  283. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  284. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  285. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  286. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  287. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  288. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  289. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  290. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  291. package/.agents/schemas/risk-verdict.schema.json +0 -53
  292. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  293. package/.agents/scripts/analyze-execution.js +0 -444
  294. package/.agents/scripts/check-prepush-recovery.js +0 -90
  295. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  296. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  297. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -187
  298. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  299. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  300. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  301. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +0 -128
  302. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
  303. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  304. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  305. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  306. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  307. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  308. package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
  309. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  310. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  311. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  312. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -21
  313. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  314. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  315. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  316. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -397
  317. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  318. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
  319. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  320. package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
  321. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
  322. package/.agents/scripts/resolve-plan-run.js +0 -117
  323. package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
@@ -1,87 +1,153 @@
1
1
  ---
2
2
  description:
3
- Unified delivery entry point. Delivers one or more Stories via the single
4
- deliver-story engine story-<id> PR main. Sequences N>1 by depends_on
5
- and runs the per-run epilogue once at the end.
3
+ Unified delivery entry point. Takes a list of Story ids, resolves their
4
+ dependency graph from live state, and delivers each via the single
5
+ deliver-story engine story-<id> PR main.
6
6
  ---
7
7
 
8
- # /deliver <storyId...> | --run <planRunId>
8
+ # /deliver <storyId...>
9
9
 
10
10
  ## Role
11
11
 
12
- Single delivery path. `/deliver` owns input resolution and sequencing only
13
- every Story runs through
14
- [`helpers/deliver-story.md`](helpers/deliver-story.md) (the evolved
15
- single-Story engine). There is no Epic wave loop, no `epic/<id>` integration
16
- branch, and no `--no-ff` wave merges.
12
+ Single delivery path with a single input shape: **a list of Story ids**.
13
+ `/deliver` owns input resolution and sequencing only — every Story runs
14
+ through [`helpers/deliver-story.md`](helpers/deliver-story.md). There is no
15
+ Epic wave loop, no `epic/<id>` integration branch, and no `--no-ff` wave
16
+ merges.
17
+
18
+ The dependency graph is **discovered, not declared**: `resolve-stories.js`
19
+ reads it from live state (body edges ∪ native GitHub `blocked_by` edges,
20
+ with every blocker resolved against its real issue state). You never hand it
21
+ a graph, and there is no batch label — which is what lets you deliver
22
+ Stories **across plan runs and over time**: a Story whose blocker landed
23
+ weeks ago in a different run is simply ready.
17
24
 
18
25
  ## Inputs
19
26
 
20
27
  | Invocation | Behavior |
21
28
  | --- | --- |
22
29
  | `/deliver <storyId>` | Deliver one Story via `helpers/deliver-story.md`. |
23
- | `/deliver <storyId> <storyId> ...` | Sequence Stories in `depends_on` order via `stories-wave-tick.js`; each ready Story runs `deliver-story`. Default concurrency is **3**. |
24
- | `/deliver --run <planRunId>` | Resolve Stories labeled `plan-run::<planRunId>` (envelope includes `dag` + `done`); sequence as above; after the last Story lands, run the per-run epilogue. |
30
+ | `/deliver <storyId> <storyId> ...` | Resolve the set with `resolve-stories.js`, then sequence by the discovered graph via `stories-wave-tick.js`. Default concurrency is **3**. |
31
+
32
+ Any named ticket that is not `type::story`, or that still carries an
33
+ `Epic: #N` footer, is a hard error naming the id and the fix (close or
34
+ re-plan as a v2 Story). Resolution refuses the whole set rather than
35
+ silently dropping the offending id and under-delivering.
25
36
 
26
- Any ticket that is not `type::story`, or that still carries an `Epic: #N`
27
- reference, is a hard error naming the ID and the fix (close or re-plan as a
28
- v2 Story).
37
+ > **Retired (Story #4540).** `--run <planRunId>` and the `plan-run::<id>`
38
+ > label are gone, along with `--dep`. Batch identity was the wrong axis:
39
+ > it could not express an edge to a Story planned in another run, while
40
+ > ordering already lives in the dependency edges themselves. Deliver the
41
+ > ids; the graph resolves itself.
29
42
 
30
43
  ## Flags
31
44
 
32
45
  | Flag | Meaning |
33
46
  | --- | --- |
34
- | `--run <planRunId>` | Deliver every Story in the plan-run (label `plan-run::<id>`). |
35
- | `--dep <from>:<to>` | Extra operator dependency edge (Story id → Story id). |
36
47
  | `--concurrency <n>` | Ready-set fan-out cap (default **3** from `delivery.deliverRunner.concurrencyCap`; set `1` for sequential). |
37
48
  | `--yes` | Suppress the multi-Story confirmation gate. |
38
49
  | `--steal` | Forwarded to `single-story-init.js` / lease steal. |
39
- | `--wait-merge` | Force close-and-land (default when `delivery.routing.closeAndLand` is true). |
50
+ | `--wait-merge` | Force close-and-land (the default; `delivery.routing.closeAndLand`, default `true`). |
40
51
  | `--no-wait-merge` | Opt out of close-and-land; stop at `agent::closing` for a human land. |
41
52
 
42
- ## Procedure
53
+ **Operator-merge implies no-wait.** `--no-auto-merge` and
54
+ `delivery.ci.autoMerge: "strict"` deliberately leave the PR un-armed, so
55
+ there is nothing for close to land: the Story rests at `agent::closing` for
56
+ the human merge, and is **not** flipped to `agent::blocked`. An explicit
57
+ `--wait-merge` does not override this — close cannot land a PR that was
58
+ never armed. A genuine *arm failure* is different: it still waits and still
59
+ blocks, because that is a fault to report rather than an operator decision
60
+ to respect.
43
61
 
44
- 1. **Resolve the Story set.**
45
- - Positional IDs → use them.
46
- - `--run <planRunId>` →
62
+ ## Procedure
47
63
 
48
- ```bash
49
- node .agents/scripts/resolve-plan-run.js --run <planRunId>
50
- ```
64
+ 1. **Resolve the set.** One command, for one Story or many:
51
65
 
52
- Capture `stories[]`, `dag[]`, and `done[]` from the envelope. Prefer
53
- the emitted `dag` — do **not** rebuild it by hand when `--run` was used.
66
+ ```bash
67
+ node .agents/scripts/resolve-stories.js --ids <id,id,...>
68
+ ```
54
69
 
55
- 2. **Build the DAG (positional only).** When delivering positional IDs
56
- (no `--run`), read `depends_on` / `blocked by` from each body and merge
57
- `--dep` edges into a JSON DAG for `stories-wave-tick.js`:
70
+ This validates the set and shows the operator what will run: read
71
+ `stories[]`, `dag[]`, and `done[]` to present the order in step 2. You do
72
+ **not** thread them into step 3 the tick re-resolves the graph itself
73
+ from the same machinery, every beat. Do **not** rebuild the graph by hand;
74
+ it is discovered from live state, including edges a body does not spell
75
+ out and blockers outside the delivered set.
58
76
 
59
- ```json
60
- [{ "id": 101, "dependsOn": [] }, { "id": 102, "dependsOn": [101] }]
61
- ```
77
+ Resolution hard-errors (exit 1) on a named id that is not a Story, still
78
+ carries an `Epic: #N` footer, or whose native dependency edges cannot be
79
+ read. A failed edge read is fatal by design: a missing gate would
80
+ co-dispatch a Story against an unlanded blocker.
62
81
 
63
- 3. **Confirm (N>1).** Present the order and wait unless `--yes`.
82
+ 2. **Confirm (N>1).** Present the order and wait unless `--yes`.
64
83
 
65
- 4. **Sequence.** Loop until every Story is done:
84
+ 3. **Sequence.** Loop until the tick reports `epilogueDue: true`:
66
85
 
67
86
  ```bash
68
87
  node .agents/scripts/stories-wave-tick.js \
69
- --dag '<json>' --done <csv> --in-flight <n> --concurrency <n>
88
+ --stories <id,id,...> --probe-live --concurrency <n> \
89
+ --dispatched <every id you have dispatched so far>
70
90
  ```
71
91
 
92
+ Each beat re-probes live state: it re-resolves the graph, classifies done
93
+ (`agent::done` or a closed issue — including foreign blockers that landed
94
+ in another run), and derives in-flight from live `agent::executing` /
95
+ `agent::closing` labels. You never compute `done` or `in-flight` — that
96
+ accounting is read from reality every beat (Story #4594).
97
+
98
+ **`--dispatched` is the one thing you must tell it (Story #4601).** List
99
+ every Story id you have spawned this run. Live state cannot report a Story
100
+ you dispatched ninety seconds ago: `single-story-init.js` flips
101
+ `agent::executing` at step 6 of 6, *after* a 3–6 minute worktree install,
102
+ so until then the Story still reads `agent::ready` and the next beat hands
103
+ it back — a second sub-agent then joins the first on the same branch and
104
+ worktree, interleaving commits.
105
+
106
+ The rule is **append-only: add each id as you dispatch it and never remove
107
+ one.** The flag is additive, not authoritative — the probe unions it into
108
+ the label-derived set and then filters it against live state, so an id that
109
+ has since gone `agent::done` is dropped for you. Re-listing an id costs
110
+ nothing and cannot double-count a slot; *omitting* one is the only way to
111
+ get this wrong. This is why `--dispatched` is not the `--done` bookkeeping
112
+ #4594 retired, and why `--in-flight` remains rejected under `--probe-live`.
113
+
114
+ Branch on the exit code:
115
+ - **0** — dispatch each `ready` id (the set is already capped and
116
+ overlap-free). An empty `ready` with work in flight means "waiting";
117
+ keep looping. `epilogueDue: true` means every Story is done — leave the
118
+ loop and go to step 4.
119
+ - **2** — `cycleError`: the graph is self-referential. Fix the
120
+ `depends_on` declarations; do not retry.
121
+ - **3** — `wedged`: nothing is dispatchable, nothing is in flight, and
122
+ undone Stories are waiting on blockers that are not done. The envelope
123
+ names the stuck ids and their unmet blockers. Either land the blocker
124
+ first or include it in `--ids`. Do not retry unchanged — the state
125
+ cannot improve on its own.
126
+ - **4** — `blocked`: one or more Stories carry `agent::blocked`, named in
127
+ `blocked[]` with `blockedReason`. This is the protocol's HITL pause
128
+ ([`instructions.md` § 1.J](../instructions.md)) — **stop the loop and
129
+ surface it to the operator; do not poll.** No beat can clear it, because
130
+ a human owes a decision. Read the Story's friction comment, and resume
131
+ only once the operator has unblocked it:
132
+
133
+ ```bash
134
+ gh issue view <id> --comments
135
+ node .agents/scripts/update-ticket-state.js --ticket <id> --state agent::ready
136
+ ```
137
+
138
+ A blocked Story outranks a wedge (its blockers are moot while a human
139
+ owes a decision) but not a cycle (exit 2 — fix the graph first).
140
+
72
141
  For each `ready` Story id, read
73
142
  [`helpers/deliver-story.md`](helpers/deliver-story.md) **in full** and
74
143
  execute it (init → implement → ceremony → close-and-land). Under
75
144
  `--yes` / injected helper content, execute directly without a re-read
76
145
  turn.
77
146
 
78
- 5. **Per-run epilogue (N>1).** After the last Story lands:
147
+ 4. **Per-run epilogue (N>1).** Once step 3 reports `epilogueDue: true`
148
+ (every Story done), keyed on the delivered id set:
79
149
 
80
150
  ```bash
81
- # Plan-run label path:
82
- node .agents/scripts/plan-run-epilogue.js --run <planRunId>
83
-
84
- # Positional multi-Story path (synthesizes an adhoc planRunId):
85
151
  node .agents/scripts/plan-run-epilogue.js --stories 101,102
86
152
  ```
87
153
 
@@ -112,21 +178,43 @@ to `main`.
112
178
  ## Ceremony (profiles + two scopes)
113
179
 
114
180
  Ceremony depth is selected by `delivery.routing.ceremonyProfile`
115
- (`minimal` | `standard` | `strict`, default `standard`) and the Story's
116
- planning risk:
181
+ (`minimal` | `standard` | `strict`, default `standard`) and the **change
182
+ level derived from the Story's own diff** — the changed files' intersection
183
+ with the sensitive-path classes in `audit-rules.json`
184
+ (`review-depth.js#deriveChangeLevel`), not a planner-authored verdict
185
+ (Story #4542):
117
186
 
118
187
  | Profile | Acceptance critic | When to use |
119
188
  | --- | --- | --- |
120
189
  | `minimal` | Always inline | Tiny trusted N=1 Stories |
121
- | `standard` | Risk-routed (+ sampling floor) | Default |
190
+ | `standard` | Derived-level routed (+ sampling floor) | Default |
122
191
  | `strict` | Always fresh-context | High-assurance / regulated surfaces |
123
192
 
124
193
  | Scope | What runs | Mechanism |
125
194
  | --- | --- | --- |
126
195
  | **Per-Story (always)** | Gates, branch discipline, close-and-land | `deliver-story` / `single-story-close` |
127
- | **Per-Story (profile + risk)** | Acceptance critic mode; review depth; audit lenses | `ceremony-routing.js` + `review-depth.js` + `code-review.js` |
196
+ | **Per-Story (profile + derived level)** | Acceptance critic mode; review depth | `ceremony-routing.js` + `review-depth.js` + `code-review.js` |
128
197
  | **Per-run (N>1)** | Audit roster · follow-up roll-up · sibling coherence | `plan-run-epilogue.js` once at run end |
129
- | **Per-Story land** | Actionable follow-ups from friction | `captureStoryFollowUps` in confirm-merge |
198
+ | **Per-Story land tail** | Follow-up capture · status resync · ref cleanup · base fast-forward | `single-story-close/phases/post-land.js` (in-process, per-step reported) |
199
+
200
+ ## Reading a Story's outcome
201
+
202
+ Each Story's delivery ends in exactly one schema-validated terminal envelope
203
+ ([`story-deliver-terminal.schema.json`](../schemas/story-deliver-terminal.schema.json),
204
+ Story #4543) — `landed` | `pending` | `blocked` | `failed`. That schema is the
205
+ SSOT for the shape; this workflow does not restate its fields.
206
+
207
+ `pending` is **not** a failure: the bounded merge wait expired with the PR
208
+ healthy and in flight (or a human owns the merge), nothing was mutated, and
209
+ the envelope's `nextCommand` names what resumes it. Run that command rather
210
+ than re-dispatching the Story.
211
+
212
+ For a Story in an unclear state — including the merged-but-label-stale one a
213
+ `/deliver` re-run refuses outright — probe it read-only:
214
+
215
+ ```bash
216
+ node .agents/scripts/deliver-recover.js --story <storyId>
217
+ ```
130
218
 
131
219
  ## Constraints
132
220
 
@@ -24,7 +24,7 @@ confirmation:
24
24
  already gone (or never existed) but whose `origin/<branch>` still
25
25
  points at a merged PR — even without `--remote`; `--remote` is still
26
26
  required to *delete* them. A third branch, whose content already
27
- landed in `<base>` by another route (a squash-merged Epic PR, a
27
+ landed in `<base>` by another route (a squash-merged PR, a
28
28
  cherry-pick, a manual `merge --squash`), is caught by a
29
29
  **content-equivalence probe** (`git merge-tree --write-tree`,
30
30
  git ≥ 2.38) even when it has no merged PR of its own and is not a
@@ -40,7 +40,7 @@ passed, **all four phases run** sequentially. Pass any of
40
40
  narrow the run.
41
41
 
42
42
  > **When to run**: After a session that landed several PRs, or before
43
- > starting a new Epic / Story, to put the local checkout into a known
43
+ > starting a new Story, to put the local checkout into a known
44
44
  > tidy state.
45
45
  >
46
46
  > **Persona**: `devops-engineer` · **Skills**:
@@ -10,7 +10,7 @@ description: >-
10
10
  # /git-deliver [Message] [--no-push] [--pr] [--draft] [--no-auto-merge] [--branch <name>] [--base <branch>]
11
11
 
12
12
  The **single source of truth** for getting outstanding working-tree changes
13
- out the door when they do not belong to a planned Epic (typo fixes, doc
13
+ out the door when they do not belong to a planned Story (typo fixes, doc
14
14
  tweaks, dependency bumps, operator housekeeping, benchmark result commits
15
15
  from mandrel-bench's `/benchmark` Step 4). It is the ad-hoc counterpart to
16
16
  the heavyweight `/deliver` pipeline: one command that **detects the git
@@ -13,8 +13,10 @@ description: >-
13
13
  > only its wrapper (Story label transitions).
14
14
 
15
15
  After the implementation commits land and **before** the Story proceeds to
16
- close, run an explicit, **independent** eval pass that scores the working diff
17
- against **each** `acceptance[]` item individually. This is the acceptance gate
16
+ close, run an explicit, **independent** eval pass that scores the change set
17
+ computed once for this Story and injected into the critic — never one the
18
+ critic re-derives (Story #4593) — against **each** `acceptance[]` item
19
+ individually. This is the acceptance gate
18
20
  the close-validation chain does not provide: that chain (lint / test / format /
19
21
  maintainability / coverage / crap) proves the code is *healthy*, not that it
20
22
  satisfies *this Story's* acceptance criteria.
@@ -33,7 +35,7 @@ mid-delivery, and evaluates the actual work product.
33
35
  continuation of your implementing turn — so the evaluator does not grade its
34
36
  own homework.
35
37
 
36
- > **Sub-agent type + risk-routed ceremony (Epic #4478, M7-B).** When
38
+ > **Sub-agent type + derived-level ceremony (Epic #4478, M7-B).** When
37
39
  > `delivery.routing.roleScopedAgents` is enabled (the **default**), dispatch
38
40
  > the critic with `subagent_type: acceptance-critic` — it boots on the
39
41
  > role-scoped [`acceptance-critic`](../../agents/acceptance-critic.md) context
@@ -42,20 +44,31 @@ mid-delivery, and evaluates the actual work product.
42
44
  > kill-switch is **off** (`roleScopedAgents: false`), fall back to
43
45
  > `subagent_type: general-purpose`.
44
46
  >
45
- > **Whether to spawn fresh at all is risk-routed** (mirrors the risk
46
- > review-depth and risk audit-lens routers). Resolve it per cluster with
47
- > `resolveCeremonyForRisk` from
47
+ > **Whether to spawn fresh at all is routed off the derived change level**
48
+ > the same signal `review-depth.js` resolves depth from, so the two
49
+ > decisions cannot disagree. Derive it with `deriveChangeLevel` from
50
+ > [`review-depth.js`](../../scripts/lib/orchestration/review-depth.js) over
51
+ > the **change set your caller computed once** for this Story (Story #4593 —
52
+ > `computeChangeSet` from
53
+ > [`change-set.js`](../../scripts/lib/orchestration/change-set.js); see
54
+ > [`deliver-story.md`](deliver-story.md) Step 2), then
55
+ > resolve the ceremony per cluster with `resolveCeremonyForRisk` from
48
56
  > [`ceremony-routing.js`](../../scripts/lib/orchestration/ceremony-routing.js)
49
- > using the **Story's** `planningRisk.overallLevel` (or folded
50
- > `risk-verdict`) and `delivery.routing.freshCriticSampleRate`:
51
- > **`high`/`medium` risk → `fresh`** (spawn the critic); **`low` risk
52
- > `inline`** (the contract-identical inline fallback below), **except** the
53
- > `freshCriticSampleRate` fraction of low-risk clusters the sampling floor
54
- > forces `fresh` so low risk never means zero independent checking; **missing
55
- > / unknown risk → `fresh` + full ceremony** (fail-safe). This chooses
56
- > fresh-vs-inline **per cluster only — it never changes the cluster count**.
57
+ > using that `derivedLevel` and `delivery.routing.freshCriticSampleRate`:
58
+ > **`high` (the diff touches a sensitive path registered in
59
+ > `audit-rules.json`) → `fresh`** (spawn the critic); **`low` (it touches
60
+ > none) → `inline`** (the contract-identical inline fallback below),
61
+ > **except** the `freshCriticSampleRate` fraction of low-level clusters the
62
+ > sampling floor forces `fresh` so a low level never means zero independent
63
+ > checking; **`null` / unknown (the diff could not be enumerated) → `fresh` +
64
+ > full ceremony** (fail-safe). This chooses fresh-vs-inline **per cluster
65
+ > only — it never changes the cluster count**.
57
66
  >
58
- > **Inline-critic path (low-risk-routed OR nesting-absent harness).** The
67
+ > Story #4542 re-based this off the planner-authored risk verdict: a level
68
+ > the plan asserted about itself was exactly the signal that could *reduce*
69
+ > independent checking, and nothing verified it against the diff.
70
+ >
71
+ > **Inline-critic path (low-level-routed OR nesting-absent harness).** The
59
72
  > verdict is authored **inline** whenever the risk router above resolves to
60
73
  > `inline` (a low-risk cluster not caught by the sampling floor), and also as
61
74
  > a **fallback** on any harness that cannot spawn the fresh critic.
@@ -79,8 +92,12 @@ mid-delivery, and evaluates the actual work product.
79
92
  > comment (if you block) that the inline fallback was used.
80
93
 
81
94
  The critic:
82
- - Inspects the working diff (`git diff origin/<baseBranch>...HEAD`) and the
83
- Story's inline `acceptance[]` / `verify[]` arrays.
95
+ - Inspects the **change set handed to it in its spawn context** — the one
96
+ list computed above — and the Story's inline `acceptance[]` / `verify[]`
97
+ arrays. Pass the file list explicitly when you dispatch the critic; it
98
+ does not re-enumerate the diff for itself (Story #4593), so a commit
99
+ landing mid-ceremony cannot leave the critic scoring a different change
100
+ than the one that routed it.
84
101
  - **Runs the `verify[]` commands** and consumes their output as **required
85
102
  evidence** when scoring the relevant acceptance items. `verify[]` is not
86
103
  optional advisory pre-flight — a criterion cannot be scored `met` without
@@ -15,8 +15,10 @@ read the same numbers from here so a "high cyclomatic complexity" finding in
15
15
 
16
16
  Run [`npm run quality:preview`](../../../package.json) before committing
17
17
  on any Story that touches production source. The preview runs
18
- `quality-preview.js` with `--changed-since HEAD`, which exercises the
19
- same maintainability and CRAP engines (`escomplex` + `c8` coverage) that
18
+ `quality-preview.js`, which scopes the diff to `HEAD` by default (the
19
+ alias passes no `--changed-since`; the script defaults to `HEAD`) and
20
+ exercises the same maintainability and CRAP engines (`escomplex` +
21
+ `c8` coverage) that
20
22
  `check-baselines.js` enforces at merge time, then merges the results
21
23
  into a single per-file delta table. A clean preview means the commit
22
24
  will not bounce off the unified baselines gate. The `.husky/pre-commit`
@@ -58,16 +60,17 @@ review-time prose rule.
58
60
 
59
61
  Per-file Maintainability Index (MI) is tracked in
60
62
  [`baselines/maintainability.json`](../../../baselines/maintainability.json).
61
- A commit that drops a file's MI by more than
62
- `delivery.quality.codingGuardrails.miDropMustRefactor` points (default
63
- `1.5`) requires a refactor in the same Story — not a baseline bump. The MI
64
- ratchet's per-file `tolerance` (default `0.5`) is a noise filter, **not**
65
- permission to spend the budget; the 1.5-point ceiling is the upper bound
66
- above which the change is treated as a regression that must be undone or
67
- offset, not absorbed.
68
-
69
- `quality:preview --changed-since HEAD` shows the per-file MI delta in the
70
- working tree before the commit lands.
63
+ A commit that drops a file's MI by more than the configured
64
+ `delivery.quality.gates.maintainability.tolerance` (default `0.5` points)
65
+ requires a refactor in the same Story — not a baseline bump. `tolerance` is
66
+ the single MI-drop control: it is not a noise filter beneath a separate
67
+ must-refactor ceiling any drop past it is treated as a regression that
68
+ must be undone or offset, not absorbed. Set `tolerance` higher only when the
69
+ project deliberately wants a looser MI-drop budget.
70
+
71
+ `quality:preview` shows the per-file MI delta in the working tree before
72
+ the commit lands (scoped to `HEAD` by default — the alias passes no
73
+ `--changed-since`; the script defaults to `HEAD`).
71
74
 
72
75
  ## Rename = baseline-refresh
73
76
 
@@ -30,7 +30,7 @@ the change set is reviewed by a process the maker cannot influence. The
30
30
  enforcing code path is
31
31
  [`runStoryScopeReview`](../../scripts/lib/orchestration/single-story-close/phases/code-review.js)
32
32
  → shared
33
- [`runStoryReviewCore`](../../scripts/lib/orchestration/story-close/phases/code-review.js).
33
+ [`runStoryReviewCore`](../../scripts/lib/orchestration/story-close/phases/review-core.js).
34
34
  A future refactor MUST preserve this isolation: do not move Story-scope
35
35
  review into the maker's context or run it as a step of the delivering
36
36
  child.
@@ -57,14 +57,16 @@ the argument envelope.
57
57
 
58
58
  ### Review depth (`depth`)
59
59
 
60
- `depth` is the risk-derived thoroughness lever introduced by Story #3876 and
61
- made a live consumed signal end to end by Story #3937. The live `/deliver`
62
- close path resolves it from the Story's judged `planningRisk` envelope
63
- (read from the per-Story `story-plan-state` checkpoint via
64
- [`resolveStoryPlanningRisk`](../../scripts/lib/orchestration/story-plan-state.js);
65
- `high` `deep`, `low` `light`, everything else including a missing
66
- checkpoint `standard`) and passes it into `runCodeReview`.
67
- `runCodeReview` forwards `depth` to every provider's `runReview` input.
60
+ `depth` is the thoroughness lever introduced by Story #3876, made a live
61
+ consumed signal end to end by Story #3937, and re-based on an observable signal
62
+ by Story #4542. `runCodeReview` derives it from the diff it already enumerates,
63
+ via [`review-depth.js`](../../scripts/lib/orchestration/review-depth.js): the
64
+ changed files' intersection with the `sensitivePaths` classes registered in
65
+ `audit-rules.json` gives the level, their count gives the width, and
66
+ `resolveDepth` folds the two (a sensitive path OR a wide diff → `deep`; neither,
67
+ on a small diff → `light`; an unenumerable diff `standard`). It takes no
68
+ planner-authored input and reads no checkpoint. `runCodeReview` forwards `depth`
69
+ to every provider's `runReview` input.
68
70
 
69
71
  It is an **input-only** signal: it changes *how thorough* the review is, never
70
72
  the findings envelope (`{ status, severity, posted, report, halted,
@@ -97,7 +99,7 @@ review yourself, honor the `depth` semantics above directly.
97
99
  2. Resolve `[BASE_REF]` from `baseRef` and `[HEAD_REF]` from `headRef`.
98
100
  3. Fetch the Story ticket and resolve the planning context from its own
99
101
  body: folded `## Spec` / `## Slicing`, acceptance criteria, and the
100
- `story-plan-state` / `risk-verdict` structured comments when present.
102
+ `story-plan-state` structured comment when present.
101
103
  4. Read that Spec fully to understand the intended scope, architectural
102
104
  decisions, and acceptance criteria. Do **not** look for a parent Epic.
103
105
 
@@ -120,7 +122,7 @@ The pipeline will:
120
122
  ### Step 1a — Story-scope local-lens pass (`scope: story` only, Epic #4405)
121
123
 
122
124
  When `scope === 'story'`, the shared review spine
123
- [`runStoryReviewCore`](../../scripts/lib/orchestration/story-close/phases/code-review.js)
125
+ [`runStoryReviewCore`](../../scripts/lib/orchestration/story-close/phases/review-core.js)
124
126
  runs a **shift-left local-lens pass** in the same close subprocess, *before*
125
127
  returning the review envelope. It:
126
128
 
@@ -376,7 +378,7 @@ in-place.
376
378
  structured comment for the operator to triage in Step 5.
377
379
  2. **Leave the finding on the structured comment for Step 5.** Required
378
380
  when the finding falls into any of the following classes:
379
- - `spec-deviation` — the change diverges from the Epic/Tech Spec.
381
+ - `spec-deviation` — the change diverges from the Story `## Spec`.
380
382
  - `secrets` — credentials, tokens, or PII surfaced in the diff.
381
383
  - `test-deletion` — coverage was removed without an explicit
382
384
  decision in the spec.
@@ -161,9 +161,11 @@ The `single-story-close.js` script, in order:
161
161
  would strand a CLOSED issue with no merged work if the PR later failed
162
162
  CI, went `BEHIND` base, or was closed without merging. The Story rests
163
163
  at `agent::closing` while the PR is open with auto-merge armed; the
164
- `agent::done` flip (which closes the issue) is deferred to Step 5.5's
165
- `single-story-confirm-merge.js`. A Story only reaches `agent::done` once
166
- its PR to `main` is confirmed merged.
164
+ `agent::done` flip (which closes the issue) is deferred to Step 5's
165
+ merge confirmation — `single-story-confirm-merge.js` on a
166
+ `--no-wait-merge` run, or the in-close confirm phase on the
167
+ close-and-land default. (Step 5.5 is the Status-column resync.) A Story
168
+ only reaches `agent::done` once its PR to `main` is confirmed merged.
167
169
  5. Reaps the worktree when `delivery.worktreeIsolation.reapOnSuccess`
168
170
  is enabled.
169
171
  6. **Releases the Story lease** (Story #3483). Clears the Story assignment
@@ -171,8 +173,12 @@ The `single-story-close.js` script, in order:
171
173
  unclaimed ticket. The release is a no-op when the operator no longer
172
174
  holds the claim (a later run took over via reclaim/steal), so a late
173
175
  close never yanks a live claim away from its current owner. Best-effort:
174
- a release failure is logged but does not fail an otherwise-clean close
175
- the lease goes stale via TTL regardless. The close result carries
176
+ a release failure is logged but does not fail an otherwise-clean close.
177
+ Note the lease does **not** expire on its own: the standalone lease is
178
+ fail-closed by design (it anchors its heartbeat to now, so a foreign
179
+ claim always reads as live regardless of the configured TTL), so a
180
+ claim stranded by a failed release is cleared only by `--steal` or by
181
+ de-assigning the ticket. The close result carries
176
182
  `leaseReleased: <boolean>`.
177
183
 
178
184
  `--skip-validation` bypasses Step 1 (gates). Use only when re-running
@@ -289,9 +295,8 @@ when `--pr` is omitted) and:
289
295
  - **Story already `agent::done` / issue already closed** → idempotent
290
296
  `{ action: 'noop', reason: 'already-done' }`.
291
297
 
292
- This is the standalone counterpart to the epic path's post-merge
293
- `agent::done` flip in `post-merge-close.js` (#2155): the issue closes
294
- exactly when the work has merged, never at PR-open.
298
+ The issue closes exactly when the work has merged, never at PR-open
299
+ (#2155).
295
300
 
296
301
  ---
297
302
 
@@ -386,33 +391,69 @@ up").
386
391
 
387
392
  ## Step 7 — Return-contract detail
388
393
 
389
- **The auto-merge wait does not produce a fourth status.** There is no
390
- "pending" or "waiting" terminal — the CI/auto-merge wait is handled
391
- *internally* by blocking on `pr-watch-with-update.js` (Step 4) and confirming
392
- the merge (Step 5). You return **only** when you have reached a genuinely
393
- terminal state:
394
-
395
- - **`status: "done"`** — the PR is confirmed `state: "MERGED"` (Step 5),
396
- the Story carries `agent::done`, and Steps 5.5 / 6 have run. `phase: "done"`,
397
- `branchDeleted: true`.
398
- - **`status: "blocked"`** you transitioned the Story to `agent::blocked`
399
- and posted a `friction` comment (acceptance self-eval block in Step 1a, a
400
- base-sync conflict, or an operator-blocking CI failure / Anti-Thrashing
401
- stop in Step 4). `phase: "blocked"`, `blockerCommentId` set.
402
- - **`status: "failed"`** an unrecoverable failure outside the blocked
403
- protocol. `phase` reflects where it died.
404
-
405
- A turn that ends with prose ("I'll wait for the watch task…", "the next event
406
- will be its completion notification…") and an **unconfirmed merge** is a
407
- **contract violation** (the Story #1553 / PR #1554 failure mode): the parent
408
- wave loop cannot distinguish "still working" from "done but silent", and the
409
- Story strands at `agent::closing`. If you genuinely cannot confirm the merge,
410
- that is a `blocked` or `failed` outcome with the JSON contract not a
411
- prose hand-off.
394
+ The field-level contract is the shipped schema
395
+ [`story-deliver-terminal.schema.json`](../../schemas/story-deliver-terminal.schema.json)
396
+ (Story #4543) not this file, and not
397
+ [`agents/story-worker.md`](../../agents/story-worker.md). All three used to
398
+ carry their own prose version; the schema is now the only definition. What
399
+ follows is the *judgement* around it, which a schema cannot express.
400
+
401
+ ### `pending` is a real status and it is not a park
402
+
403
+ Earlier revisions asserted "the auto-merge wait does not produce a fourth
404
+ status", on the reasoning that the wait is internally blocking so a run either
405
+ merges or blocks. That was true only while the wait was unbounded — and it was
406
+ never actually unbounded, because the host kills a tool invocation at ~10
407
+ minutes. So a close-and-land whose CI outlived that ceiling took **no**
408
+ terminal path at all: no event, no label, the Story parked at
409
+ `agent::closing`. The status the model refused to name was the one that kept
410
+ happening.
411
+
412
+ `pending` names it, with its own exit code (3):
413
+
414
+ - It is **resumable**: no label was mutated, no `merge.unlanded` was emitted,
415
+ and `nextCommand` names the one command that continues it. The cumulative
416
+ budget is anchored at the PR's `createdAt`, so resuming does not restart the
417
+ clock and the give-up bound still means something.
418
+ - It is **not** a park. Returning `pending` because you would rather not wait
419
+ is the Story #1553 / PR #1554 failure mode wearing a schema. Return it only
420
+ when the bound genuinely expired, or a human owns the merge.
421
+
422
+ The no-park rule is therefore unchanged in substance: a turn that ends with
423
+ prose ("I'll wait for the watch task…", "the next event will be its
424
+ completion notification…") and an unconfirmed merge is a **contract
425
+ violation** — the parent cannot distinguish "still working" from "done but
426
+ silent". What changed is that there is now an honest, machine-readable way to
427
+ say "not finished, here is exactly how to continue" instead of a choice
428
+ between lying and blocking forever.
429
+
430
+ ### Exit-code compatibility note (`--no-wait-merge`)
431
+
432
+ Every close flag keeps its meaning, but the **exit code** of a
433
+ `--no-wait-merge` (or `--no-auto-merge` / `autoMerge: "strict"`) run changed:
434
+ it now exits **3** (`pending`) rather than 0, because the PR is open and a
435
+ human still owns the merge. Reporting `landed` would be a lie, and `landed` is
436
+ what exit 0 means. A wrapper that shells out and tests `exit == 0` to mean
437
+ "close finished" must be updated to treat 3 as the operator-merge success
438
+ path; `!= 0` no longer implies failure.
439
+
440
+ ### Per-status judgement
441
+
442
+ - **`landed`** — the only status that means done. A `false` in `tail.*`
443
+ degrades the report, never the land: the merge is on the base branch, and
444
+ failing it because a Projects v2 mutation flaked would report a false
445
+ negative about work that demonstrably shipped.
446
+ - **`pending`** — see above.
447
+ - **`blocked`** — you (or the close pipeline) transitioned the Story to
448
+ `agent::blocked` and posted a `friction` comment. `blocked.blockClass` comes
449
+ from the shared classifier, never an ad hoc string, and
450
+ `blocked.frictionCommentId` points at the remediation.
451
+ - **`failed`** — an unrecoverable failure outside the blocked protocol.
452
+ `phase` reflects where it died.
412
453
 
413
454
  > **Handoff discipline — report state, not process.** Populate the envelope
414
455
  > with essential terminal state only (mirroring the fields
415
- > `single-story-close.js` / `story-phase.js` already emit). Do not narrate the
456
+ > `single-story-close.js` already emits). Do not narrate the
416
457
  > steps you took, and do not prescribe how the next stage should work. Prose
417
458
  > process commentary only bloats the hydrated prompt. When run **interactively** (no parent
418
459
  > aggregator), this JSON envelope is optional — relay terminal state to the