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
@@ -1,87 +1,118 @@
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
+ Capture `stories[]`, `dag[]`, and `done[]` from the envelope. Do **not**
71
+ rebuild the graph by hand it is discovered from live state, including
72
+ edges a body does not spell out and blockers outside the delivered set.
58
73
 
59
- ```json
60
- [{ "id": 101, "dependsOn": [] }, { "id": 102, "dependsOn": [101] }]
61
- ```
74
+ Resolution hard-errors (exit 1) on a named id that is not a Story, still
75
+ carries an `Epic: #N` footer, or whose native dependency edges cannot be
76
+ read. A failed edge read is fatal by design: a missing gate would
77
+ co-dispatch a Story against an unlanded blocker.
62
78
 
63
- 3. **Confirm (N>1).** Present the order and wait unless `--yes`.
79
+ 2. **Confirm (N>1).** Present the order and wait unless `--yes`.
64
80
 
65
- 4. **Sequence.** Loop until every Story is done:
81
+ 3. **Sequence.** Loop until every Story is done:
66
82
 
67
83
  ```bash
68
84
  node .agents/scripts/stories-wave-tick.js \
69
- --dag '<json>' --done <csv> --in-flight <n> --concurrency <n>
85
+ --dag '<dag from step 1>' --done <csv> --in-flight <n> --concurrency <n>
70
86
  ```
71
87
 
88
+ **Seed the first beat's `--done` from the resolver's `done[]`** — not from
89
+ an empty string. That array carries the blockers that have already landed,
90
+ including foreign ones outside the delivered set. Seeding it empty
91
+ discards exactly the cross-run resolution this step exists for, and the
92
+ run wedges on a blocker that finished weeks ago. On later beats, `--done`
93
+ is `done[]` plus every Story that has since closed.
94
+
95
+ Branch on the exit code:
96
+ - **0** — dispatch each `ready` id. An empty `ready` with work in flight
97
+ means "waiting"; keep looping.
98
+ - **2** — `cycleError`: the graph is self-referential. Fix the
99
+ `depends_on` declarations; do not retry.
100
+ - **3** — `wedged`: nothing is dispatchable, nothing is in flight, and
101
+ undone Stories are waiting on blockers that are not done. The envelope
102
+ names the stuck ids and their unmet blockers. Either land the blocker
103
+ first or include it in `--ids`. Do not retry unchanged — the state
104
+ cannot improve on its own.
105
+
72
106
  For each `ready` Story id, read
73
107
  [`helpers/deliver-story.md`](helpers/deliver-story.md) **in full** and
74
108
  execute it (init → implement → ceremony → close-and-land). Under
75
109
  `--yes` / injected helper content, execute directly without a re-read
76
110
  turn.
77
111
 
78
- 5. **Per-run epilogue (N>1).** After the last Story lands:
112
+ 4. **Per-run epilogue (N>1).** After the last Story lands, keyed on the
113
+ delivered id set:
79
114
 
80
115
  ```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
116
  node .agents/scripts/plan-run-epilogue.js --stories 101,102
86
117
  ```
87
118
 
@@ -112,21 +143,43 @@ to `main`.
112
143
  ## Ceremony (profiles + two scopes)
113
144
 
114
145
  Ceremony depth is selected by `delivery.routing.ceremonyProfile`
115
- (`minimal` | `standard` | `strict`, default `standard`) and the Story's
116
- planning risk:
146
+ (`minimal` | `standard` | `strict`, default `standard`) and the **change
147
+ level derived from the Story's own diff** — the changed files' intersection
148
+ with the sensitive-path classes in `audit-rules.json`
149
+ (`review-depth.js#deriveChangeLevel`), not a planner-authored verdict
150
+ (Story #4542):
117
151
 
118
152
  | Profile | Acceptance critic | When to use |
119
153
  | --- | --- | --- |
120
154
  | `minimal` | Always inline | Tiny trusted N=1 Stories |
121
- | `standard` | Risk-routed (+ sampling floor) | Default |
155
+ | `standard` | Derived-level routed (+ sampling floor) | Default |
122
156
  | `strict` | Always fresh-context | High-assurance / regulated surfaces |
123
157
 
124
158
  | Scope | What runs | Mechanism |
125
159
  | --- | --- | --- |
126
160
  | **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` |
161
+ | **Per-Story (profile + derived level)** | Acceptance critic mode; review depth | `ceremony-routing.js` + `review-depth.js` + `code-review.js` |
128
162
  | **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 |
163
+ | **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) |
164
+
165
+ ## Reading a Story's outcome
166
+
167
+ Each Story's delivery ends in exactly one schema-validated terminal envelope
168
+ ([`story-deliver-terminal.schema.json`](../schemas/story-deliver-terminal.schema.json),
169
+ Story #4543) — `landed` | `pending` | `blocked` | `failed`. That schema is the
170
+ SSOT for the shape; this workflow does not restate its fields.
171
+
172
+ `pending` is **not** a failure: the bounded merge wait expired with the PR
173
+ healthy and in flight (or a human owns the merge), nothing was mutated, and
174
+ the envelope's `nextCommand` names what resumes it. Run that command rather
175
+ than re-dispatching the Story.
176
+
177
+ For a Story in an unclear state — including the merged-but-label-stale one a
178
+ `/deliver` re-run refuses outright — probe it read-only:
179
+
180
+ ```bash
181
+ node .agents/scripts/deliver-recover.js --story <storyId>
182
+ ```
130
183
 
131
184
  ## Constraints
132
185
 
@@ -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
@@ -33,7 +33,7 @@ mid-delivery, and evaluates the actual work product.
33
33
  continuation of your implementing turn — so the evaluator does not grade its
34
34
  own homework.
35
35
 
36
- > **Sub-agent type + risk-routed ceremony (Epic #4478, M7-B).** When
36
+ > **Sub-agent type + derived-level ceremony (Epic #4478, M7-B).** When
37
37
  > `delivery.routing.roleScopedAgents` is enabled (the **default**), dispatch
38
38
  > the critic with `subagent_type: acceptance-critic` — it boots on the
39
39
  > role-scoped [`acceptance-critic`](../../agents/acceptance-critic.md) context
@@ -42,20 +42,28 @@ mid-delivery, and evaluates the actual work product.
42
42
  > kill-switch is **off** (`roleScopedAgents: false`), fall back to
43
43
  > `subagent_type: general-purpose`.
44
44
  >
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
45
+ > **Whether to spawn fresh at all is routed off the derived change level**
46
+ > the same signal `review-depth.js` resolves depth from, so the two
47
+ > decisions cannot disagree. Derive it with `deriveChangeLevel` from
48
+ > [`review-depth.js`](../../scripts/lib/orchestration/review-depth.js) over
49
+ > the Story's changed files (`git diff --name-only main...story-<id>`), then
50
+ > resolve the ceremony per cluster with `resolveCeremonyForRisk` from
48
51
  > [`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**.
52
+ > using that `derivedLevel` and `delivery.routing.freshCriticSampleRate`:
53
+ > **`high` (the diff touches a sensitive path registered in
54
+ > `audit-rules.json`) → `fresh`** (spawn the critic); **`low` (it touches
55
+ > none) → `inline`** (the contract-identical inline fallback below),
56
+ > **except** the `freshCriticSampleRate` fraction of low-level clusters the
57
+ > sampling floor forces `fresh` so a low level never means zero independent
58
+ > checking; **`null` / unknown (the diff could not be enumerated) → `fresh` +
59
+ > full ceremony** (fail-safe). This chooses fresh-vs-inline **per cluster
60
+ > only — it never changes the cluster count**.
57
61
  >
58
- > **Inline-critic path (low-risk-routed OR nesting-absent harness).** The
62
+ > Story #4542 re-based this off the planner-authored risk verdict: a level
63
+ > the plan asserted about itself was exactly the signal that could *reduce*
64
+ > independent checking, and nothing verified it against the diff.
65
+ >
66
+ > **Inline-critic path (low-level-routed OR nesting-absent harness).** The
59
67
  > verdict is authored **inline** whenever the risk router above resolves to
60
68
  > `inline` (a low-risk cluster not caught by the sampling floor), and also as
61
69
  > a **fallback** on any harness that cannot spawn the fresh critic.
@@ -58,13 +58,13 @@ review-time prose rule.
58
58
 
59
59
  Per-file Maintainability Index (MI) is tracked in
60
60
  [`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.
61
+ A commit that drops a file's MI by more than the configured
62
+ `delivery.quality.gates.maintainability.tolerance` (default `0.5` points)
63
+ requires a refactor in the same Story — not a baseline bump. `tolerance` is
64
+ the single MI-drop control: it is not a noise filter beneath a separate
65
+ must-refactor ceiling any drop past it is treated as a regression that
66
+ must be undone or offset, not absorbed. Set `tolerance` higher only when the
67
+ project deliberately wants a looser MI-drop budget.
68
68
 
69
69
  `quality:preview --changed-since HEAD` shows the per-file MI delta in the
70
70
  working tree before the commit lands.
@@ -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
 
@@ -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