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
@@ -131,30 +131,342 @@ export function planRunEpilogue({ planRunId, stories } = {}) {
131
131
  };
132
132
  }
133
133
 
134
- async function listChangedFiles(cwd, baseRef = 'origin/main') {
134
+ /**
135
+ * How many first-parent commits of the base ref to scan when looking for the
136
+ * run's landed squash-merges. The epilogue fires immediately after the run's
137
+ * last Story lands, so the run's merges sit within the first handful of
138
+ * commits; the limit only bounds the pathological case.
139
+ * @type {number}
140
+ */
141
+ const BASE_SCAN_LIMIT = 500;
142
+
143
+ /** ASCII unit separator — cannot occur in a git commit subject. */
144
+ const FIELD_SEP = '\x1f';
145
+
146
+ /**
147
+ * Read the base ref's first-parent history as `{ sha, parents, subject }`
148
+ * records, newest-first.
149
+ *
150
+ * @param {object} args
151
+ * @param {string} args.cwd
152
+ * @param {string} args.baseRef
153
+ * @param {number} args.scanLimit
154
+ * @param {{ gitSpawn: Function }} args.git
155
+ * @returns {{ ok: true, commits: Array<{sha: string, parents: string[], subject: string}> }
156
+ * | { ok: false, reason: string }}
157
+ */
158
+ function readFirstParentHistory({ cwd, baseRef, scanLimit, git }) {
159
+ let result;
160
+ try {
161
+ result = git.gitSpawn(
162
+ cwd,
163
+ 'log',
164
+ '--first-parent',
165
+ baseRef,
166
+ `--max-count=${scanLimit}`,
167
+ `--format=%H${FIELD_SEP}%P${FIELD_SEP}%s`,
168
+ );
169
+ } catch (err) {
170
+ return {
171
+ ok: false,
172
+ reason: `\`git log ${baseRef}\` could not be spawned: ${err?.message ?? String(err)}`,
173
+ };
174
+ }
175
+ if (result?.status !== 0) {
176
+ const detail =
177
+ String(result?.stderr ?? '').split('\n')[0] || 'unknown error';
178
+ return {
179
+ ok: false,
180
+ reason: `\`git log ${baseRef}\` failed (is \`${baseRef}\` fetched?): ${detail}`,
181
+ };
182
+ }
183
+ const commits = String(result.stdout ?? '')
184
+ .split('\n')
185
+ .map((line) => line.trim())
186
+ .filter(Boolean)
187
+ .map((line) => {
188
+ const [sha, parents, ...rest] = line.split(FIELD_SEP);
189
+ return {
190
+ sha,
191
+ parents: parents ? parents.split(' ').filter(Boolean) : [],
192
+ subject: rest.join(FIELD_SEP),
193
+ };
194
+ });
195
+ return { ok: true, commits };
196
+ }
197
+
198
+ /**
199
+ * One trailing `(#<n>)` / `(refs #<n>)` marker, anchored at the end of what
200
+ * is left of a subject after the markers to its right have been peeled off.
201
+ */
202
+ const TRAILING_MARKER_RE = /\s*\((?:refs\s+)?#(\d+)\)$/;
203
+
204
+ /**
205
+ * Peel the **trailing run** of `(#<n>)` markers off a squash subject.
206
+ *
207
+ * The shape this parses is fixed by the close pipeline plus GitHub: the PR
208
+ * title `normalizePrTitle` writes ends with `(#<storyId>)`, and GitHub's
209
+ * squash appends ` (#<prNumber>)` to it — so a landed Story merge reads
210
+ * `<subject> (#<storyId>) (#<prNumber>)` and the Story's own marker is the
211
+ * *second-to-last* marker, not the last one. Both are returned; the caller
212
+ * decides which ids it cares about.
213
+ *
214
+ * Why the trailing run rather than a substring scan (the bug this replaces):
215
+ * `subject.includes('(#101)')` matched the id **anywhere**, so an unrelated
216
+ * later commit quoting an old marker — canonically a revert, whose subject
217
+ * embeds the reverted title verbatim: `revert: "fix: x (#101) (#900)" (#950)`
218
+ * — anchored the run on a far-older commit and inflated the roster diff with
219
+ * everything in between. Peeling from the right stops at the first character
220
+ * that is not part of a marker (the closing quote, above), so a quoted marker
221
+ * is structurally out of reach.
222
+ *
223
+ * The `refs #` form is accepted because it is the other PR-title shape this
224
+ * repo's own history carries (`feat(x): … (refs #4575) (#4582)`) — the
225
+ * `refs #<id>` convention from `rules/git-conventions.md`. A plain substring
226
+ * scan for `(#4575)` never matched those at all.
227
+ *
228
+ * @param {string} subject
229
+ * @returns {number[]} Marker ids, right-to-left (PR number first).
230
+ */
231
+ function trailingMarkerIds(subject) {
232
+ const ids = [];
233
+ let rest = typeof subject === 'string' ? subject.trimEnd() : '';
234
+ for (;;) {
235
+ const match = TRAILING_MARKER_RE.exec(rest);
236
+ if (!match) return ids;
237
+ ids.push(Number(match[1]));
238
+ rest = rest.slice(0, match.index).trimEnd();
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Resolve the **pre-run base sha**: the commit the base branch pointed at
244
+ * before the run's first Story landed.
245
+ *
246
+ * Why not `origin/main...HEAD` (the bug this replaces): the epilogue runs
247
+ * *after* the run's last Story lands, so HEAD in the main checkout is either
248
+ * `origin/main` itself or an ancestor of it. The three-dot merge-base is then
249
+ * HEAD, and the diff is empty **by construction** — it never reported the
250
+ * run's real diff. Rolling HEAD back does not help, so branch-reaping /
251
+ * cleanup ordering is not the cause; the refs being compared are.
252
+ *
253
+ * The derivation walks the base ref's first-parent history for the run's
254
+ * landed squash-merges. Every Story PR title carries a `(#<storyId>)` suffix
255
+ * (guaranteed by `normalizePrTitle` in the close pipeline) and GitHub uses the
256
+ * PR title as the squash subject, so the marker is a reliable, offline handle
257
+ * that does **not** depend on the Story branches still existing. The earliest
258
+ * such merge's first parent is the pre-run base.
259
+ *
260
+ * @param {object} args
261
+ * @param {Array<string|number>} args.stories - Story ids in the run.
262
+ * @param {string} args.cwd
263
+ * @param {string} [args.baseRef] - Remote-tracking base ref, e.g. `origin/main`.
264
+ * @param {number} [args.scanLimit]
265
+ * @param {{ gitSpawn: Function }} [args.git]
266
+ * @returns {{ resolved: true, baseSha: string, mergeSha: string, storyId: number, baseRef: string }
267
+ * | { resolved: false, reason: string, baseRef: string }}
268
+ */
269
+ export function resolveRunBaseSha({
270
+ stories,
271
+ cwd,
272
+ baseRef = 'origin/main',
273
+ scanLimit = BASE_SCAN_LIMIT,
274
+ git = { gitSpawn },
275
+ } = {}) {
276
+ const ids = (Array.isArray(stories) ? stories : [])
277
+ .map(Number)
278
+ .filter((n) => Number.isInteger(n) && n > 0);
279
+ if (ids.length === 0) {
280
+ return {
281
+ resolved: false,
282
+ baseRef,
283
+ reason:
284
+ 'the run carries no numeric Story ids to match landed merges against',
285
+ };
286
+ }
287
+
288
+ const history = readFirstParentHistory({ cwd, baseRef, scanLimit, git });
289
+ if (!history.ok) {
290
+ return { resolved: false, baseRef, reason: history.reason };
291
+ }
292
+
293
+ // `git log` is newest-first; walk backwards so the first hit is the
294
+ // *earliest* merge belonging to the run.
295
+ const wanted = new Set(ids);
296
+ for (let i = history.commits.length - 1; i >= 0; i -= 1) {
297
+ const commit = history.commits[i];
298
+ const hit = trailingMarkerIds(commit.subject).find((id) => wanted.has(id));
299
+ if (hit === undefined) continue;
300
+ const baseSha = commit.parents[0];
301
+ if (!baseSha) {
302
+ return {
303
+ resolved: false,
304
+ baseRef,
305
+ reason: `the earliest landed merge for the run (${commit.sha}, Story #${hit}) is a root commit — it has no first parent to use as the pre-run base`,
306
+ };
307
+ }
308
+ return {
309
+ resolved: true,
310
+ baseRef,
311
+ baseSha,
312
+ mergeSha: commit.sha,
313
+ storyId: hit,
314
+ };
315
+ }
316
+
317
+ return {
318
+ resolved: false,
319
+ baseRef,
320
+ reason: `no landed squash-merge carrying a \`(#<storyId>)\` marker for ${ids
321
+ .map((id) => `#${id}`)
322
+ .join(
323
+ ', ',
324
+ )} was found in the last ${scanLimit} first-parent commits of \`${baseRef}\` — has the run landed?`,
325
+ };
326
+ }
327
+
328
+ /**
329
+ * List the files the run changed: `<pre-run base>...<baseRef>`.
330
+ *
331
+ * @returns {{ ok: true, files: string[] } | { ok: false, reason: string }}
332
+ */
333
+ function listChangedFiles({ cwd, baseSha, headRef, git }) {
334
+ const range = `${baseSha}...${headRef}`;
335
+ let result;
135
336
  try {
136
- const result = gitSpawn(cwd, 'diff', '--name-only', `${baseRef}...HEAD`);
137
- if (result.status !== 0) return [];
138
- return String(result.stdout ?? '')
337
+ result = git.gitSpawn(cwd, 'diff', '--name-only', range);
338
+ } catch (err) {
339
+ return {
340
+ ok: false,
341
+ reason: `\`git diff ${range}\` could not be spawned: ${err?.message ?? String(err)}`,
342
+ };
343
+ }
344
+ if (result?.status !== 0) {
345
+ const detail =
346
+ String(result?.stderr ?? '').split('\n')[0] || 'unknown error';
347
+ return { ok: false, reason: `\`git diff ${range}\` failed: ${detail}` };
348
+ }
349
+ return {
350
+ ok: true,
351
+ files: String(result.stdout ?? '')
139
352
  .split('\n')
140
353
  .map((line) => line.trim())
141
- .filter(Boolean);
142
- } catch {
143
- return [];
354
+ .filter(Boolean),
355
+ };
356
+ }
357
+
358
+ /**
359
+ * Resolve the run's combined landed diff, or an explicit reason it could not
360
+ * be computed. Never conflates "could not compute" with "zero files changed".
361
+ *
362
+ * @returns {{ resolved: boolean, changedFiles: string[], baseSha: string|null,
363
+ * mergeSha: string|null, baseRef: string, reason: string|null }}
364
+ */
365
+ function resolveCombinedDiff({ stories, cwd, baseRef, git }) {
366
+ const base = resolveRunBaseSha({ stories, cwd, baseRef, git });
367
+ if (!base.resolved) {
368
+ return {
369
+ resolved: false,
370
+ changedFiles: [],
371
+ baseSha: null,
372
+ mergeSha: null,
373
+ baseRef,
374
+ reason: base.reason,
375
+ };
376
+ }
377
+ const diff = listChangedFiles({
378
+ cwd,
379
+ baseSha: base.baseSha,
380
+ headRef: baseRef,
381
+ git,
382
+ });
383
+ if (!diff.ok) {
384
+ return {
385
+ resolved: false,
386
+ changedFiles: [],
387
+ baseSha: base.baseSha,
388
+ mergeSha: base.mergeSha,
389
+ baseRef,
390
+ reason: diff.reason,
391
+ };
144
392
  }
393
+ return {
394
+ resolved: true,
395
+ changedFiles: diff.files,
396
+ baseSha: base.baseSha,
397
+ mergeSha: base.mergeSha,
398
+ baseRef,
399
+ reason: null,
400
+ };
401
+ }
402
+
403
+ /**
404
+ * The diff line of the roster comment. An unresolved base MUST read as a
405
+ * loud failure, never as `Changed files considered: 0`.
406
+ *
407
+ * @param {ReturnType<typeof resolveCombinedDiff>} diff
408
+ * @returns {string[]}
409
+ */
410
+ function renderDiffLines(diff) {
411
+ if (!diff.resolved) {
412
+ return [
413
+ '> ⚠️ **Combined landed diff unavailable — this is NOT "zero files changed".**',
414
+ `> The pre-run base sha could not be resolved: ${diff.reason}`,
415
+ '> Walk the lenses below against the run diff determined by hand.',
416
+ '> Lens selection was **keyword-only**: with no change set, no lens',
417
+ '> `filePatterns` trigger could fire, so the roster below reflects the',
418
+ "> primary Story's prose rather than what the run touched. Treat it as a",
419
+ '> starting point, not a roster.',
420
+ ];
421
+ }
422
+ return [
423
+ `Combined landed diff \`${diff.baseSha}...${diff.baseRef}\` — ` +
424
+ `**${diff.changedFiles.length}** changed file(s).`,
425
+ ];
426
+ }
427
+
428
+ /**
429
+ * @param {object} config
430
+ * @returns {string} the remote-tracking base ref, e.g. `origin/main`.
431
+ */
432
+ function resolveBaseRef(config) {
433
+ const baseBranch = config?.project?.baseBranch;
434
+ const branch =
435
+ typeof baseBranch === 'string' && baseBranch.trim() !== ''
436
+ ? baseBranch.trim()
437
+ : 'main';
438
+ return `origin/${branch}`;
145
439
  }
146
440
 
147
- async function executeAuditRoster({ planRunId, stories, cwd, provider }) {
441
+ async function executeAuditRoster({
442
+ planRunId,
443
+ stories,
444
+ cwd,
445
+ provider,
446
+ config,
447
+ git,
448
+ selectAuditsFn,
449
+ }) {
148
450
  const primaryId = Number(stories[0]);
149
- const changedFiles = await listChangedFiles(cwd);
451
+ const diff = resolveCombinedDiff({
452
+ stories,
453
+ cwd,
454
+ baseRef: resolveBaseRef(config),
455
+ git,
456
+ });
457
+ // Hand `selectAudits` the change set we just resolved — never a git range for
458
+ // it to re-derive. This function runs in the main checkout *after* the run's
459
+ // Stories merged, so every range it could name (`main...HEAD`) is empty by
460
+ // construction; asking for one is how the roster came to select lenses from
461
+ // zero files while printing the correct file list beside them (Story #4571).
462
+ const lensGrounding = diff.resolved ? 'diff' : 'keyword-only';
150
463
  let selectedAudits = [];
151
464
  if (Number.isInteger(primaryId) && primaryId > 0) {
152
- const selected = await selectAudits({
465
+ const selected = await selectAuditsFn({
153
466
  ticketId: primaryId,
154
467
  gate: 'gate3',
155
468
  provider,
156
- baseBranch: 'main',
157
- headRef: 'HEAD',
469
+ changedFiles: diff.resolved ? diff.changedFiles : [],
158
470
  });
159
471
  selectedAudits = Array.isArray(selected?.selectedAudits)
160
472
  ? selected.selectedAudits
@@ -162,14 +474,20 @@ async function executeAuditRoster({ planRunId, stories, cwd, provider }) {
162
474
  ? selected
163
475
  : [];
164
476
  }
477
+ if (!diff.resolved) {
478
+ Logger.warn(
479
+ `[run-epilogue] plan-run ${planRunId}: combined landed diff unavailable — ${diff.reason}`,
480
+ );
481
+ }
165
482
  const body = [
166
483
  '### plan-run-audit-roster',
167
484
  '',
168
485
  `Cross-Story audit roster for plan-run \`${planRunId}\`.`,
169
486
  '',
170
- `Changed files considered: ${changedFiles.length}.`,
487
+ ...renderDiffLines(diff),
171
488
  '',
172
- '**Selected lenses** (host MUST walk each against the combined landed diff):',
489
+ `**Selected lenses** (host MUST walk each against the combined landed diff) — ` +
490
+ `grounding: \`${lensGrounding}\`:`,
173
491
  ...(selectedAudits.length > 0
174
492
  ? selectedAudits.map((lens) => `- \`${lens}\``)
175
493
  : ['- _(none — docs-only or no matching change-set lenses)_']),
@@ -179,7 +497,15 @@ async function executeAuditRoster({ planRunId, stories, cwd, provider }) {
179
497
  {
180
498
  planRunId,
181
499
  stories: stories.map(Number),
182
- changedFiles,
500
+ baseResolution: {
501
+ resolved: diff.resolved,
502
+ baseRef: diff.baseRef,
503
+ baseSha: diff.baseSha,
504
+ mergeSha: diff.mergeSha,
505
+ reason: diff.reason,
506
+ },
507
+ changedFiles: diff.resolved ? diff.changedFiles : null,
508
+ lensGrounding,
183
509
  selectedAudits,
184
510
  },
185
511
  null,
@@ -198,7 +524,23 @@ async function executeAuditRoster({ planRunId, stories, cwd, provider }) {
198
524
  return {
199
525
  kind: 'audit-roster',
200
526
  selectedAudits,
201
- changedFileCount: changedFiles.length,
527
+ // Whether the lenses above were chosen from the run's landed files
528
+ // (`diff`) or, with no resolvable base, from the primary Story's prose
529
+ // alone (`keyword-only`). The two are not interchangeable: a keyword-only
530
+ // roster cannot select a lens that declares no keywords, so its silence
531
+ // about a lens says nothing about the code.
532
+ lensGrounding,
533
+ // `null` — not `0` — when unresolved: a zero count must only ever mean
534
+ // "the run genuinely changed nothing".
535
+ changedFileCount: diff.resolved ? diff.changedFiles.length : null,
536
+ changedFiles: diff.resolved ? diff.changedFiles : null,
537
+ baseResolution: {
538
+ resolved: diff.resolved,
539
+ baseRef: diff.baseRef,
540
+ baseSha: diff.baseSha,
541
+ mergeSha: diff.mergeSha,
542
+ reason: diff.reason,
543
+ },
202
544
  };
203
545
  }
204
546
 
@@ -259,6 +601,10 @@ async function executeFollowUpRollup({
259
601
  storyId: primaryId,
260
602
  proposals,
261
603
  graduated,
604
+ // Story #4578 — the run's Story count is what lets an empty roll-up
605
+ // render as a flagged claim ("0 signals across N Stories") rather than
606
+ // as "nothing to follow up".
607
+ storyCount: stories.length,
262
608
  }).replace(
263
609
  `from Story #${primaryId}`,
264
610
  `from plan-run \`${planRunId}\` (primary Story #${primaryId})`,
@@ -268,7 +614,12 @@ async function executeFollowUpRollup({
268
614
  return {
269
615
  kind: 'follow-up-rollup',
270
616
  signalCount: signals.length,
617
+ storyCount: stories.length,
271
618
  filed: graduated.filed?.length ?? 0,
619
+ // Story #4578 — zero signals across a multi-Story run is a claim, not a
620
+ // clean bill of health. Surfaced on the step result so the CLI can warn
621
+ // the operator without re-deriving it from the comment prose.
622
+ emptyRollupSuspect: signals.length === 0 && stories.length > 1,
272
623
  };
273
624
  }
274
625
 
@@ -359,6 +710,8 @@ async function executeSiblingCoherence({ planRunId, stories, provider }) {
359
710
  * @param {object} args.provider
360
711
  * @param {object} [args.config]
361
712
  * @param {string} [args.cwd]
713
+ * @param {{ gitSpawn: Function }} [args.git] - Injection seam for tests.
714
+ * @param {typeof selectAudits} [args.selectAuditsFn] - Injection seam for tests.
362
715
  * @returns {Promise<object>}
363
716
  */
364
717
  export async function runPlanRunEpilogue({
@@ -367,6 +720,8 @@ export async function runPlanRunEpilogue({
367
720
  provider,
368
721
  config,
369
722
  cwd = process.cwd(),
723
+ git = { gitSpawn },
724
+ selectAuditsFn = selectAudits,
370
725
  } = {}) {
371
726
  const plan = planRunEpilogue({ planRunId, stories });
372
727
  if (!plan.applicable) {
@@ -387,6 +742,9 @@ export async function runPlanRunEpilogue({
387
742
  stories: plan.stories,
388
743
  cwd,
389
744
  provider,
745
+ config,
746
+ git,
747
+ selectAuditsFn,
390
748
  }),
391
749
  );
392
750
  } else if (step.kind === 'follow-up-rollup') {
@@ -28,6 +28,30 @@
28
28
  import { gh as defaultGh } from '../../../gh-exec.js';
29
29
  import { resolveAutoMergeArmCwd } from '../../auto-merge-cwd.js';
30
30
 
31
+ /**
32
+ * Arm reasons that mean **the operator deliberately owns the merge** — the PR
33
+ * was never armed because it was asked not to be, not because arming failed.
34
+ *
35
+ * The distinction is load-bearing: an un-armed-by-request PR has nothing for
36
+ * close to land, so `resolveWaitForMerge` (`./options.js`) resolves
37
+ * `waitForMerge` to `false` for these reasons and the Story rests at
38
+ * `agent::closing` for the human. Every *other* falsy arm outcome
39
+ * (`pr-number-unparseable`, an `enableAutoMerge` failure) is a genuine fault
40
+ * and still routes through the merge-unlanded block path.
41
+ */
42
+ const OPERATOR_MERGE_ARM_REASONS = Object.freeze([
43
+ 'disabled-by-flag',
44
+ 'disabled-by-policy-strict',
45
+ ]);
46
+
47
+ /**
48
+ * @param {string|null|undefined} reason
49
+ * @returns {boolean}
50
+ */
51
+ export function isOperatorMergeReason(reason) {
52
+ return OPERATOR_MERGE_ARM_REASONS.includes(reason);
53
+ }
54
+
31
55
  /**
32
56
  * Enable GitHub native auto-merge on the PR. Non-fatal.
33
57
  *
@@ -18,7 +18,11 @@
18
18
  import { syncBranchFromBase } from '../../../git/sync-from-base.js';
19
19
  import { Logger } from '../../../Logger.js';
20
20
  import { AGENT_LABELS } from '../../../label-constants.js';
21
- import { upsertStructuredComment } from '../../ticketing/state.js';
21
+ import {
22
+ STATE_LABELS,
23
+ transitionTicketState,
24
+ upsertStructuredComment,
25
+ } from '../../ticketing.js';
22
26
 
23
27
  /**
24
28
  * Orchestrate the pre-push base-sync step: run `syncBranchFromBase`
@@ -76,7 +80,7 @@ export async function runBaseSyncPhase({
76
80
  : syncResult.stderr
77
81
  ? `: ${syncResult.stderr.slice(0, 200)}`
78
82
  : '') +
79
- `. Story transitioned to ${AGENT_LABELS.BLOCKED}; resolve in ${syncCwd} and re-run \`/single-story-deliver\`.`,
83
+ `. Story transitioned to ${AGENT_LABELS.BLOCKED}; resolve in ${syncCwd} and re-run \`/deliver ${storyId}\`.`,
80
84
  );
81
85
  }
82
86
  progress('SYNC', `✅ Synced from origin/${baseBranch} (${syncResult.kind}).`);
@@ -126,13 +130,11 @@ export async function handleSyncFailure({
126
130
  );
127
131
  }
128
132
 
133
+ // Story #4539 — the canonical mutator, not a direct label write: a bare
134
+ // `provider.updateTicket` skips the Projects v2 column sync (Story
135
+ // #2548) and strands the board on the Story's prior status.
129
136
  try {
130
- await provider.updateTicket(storyId, {
131
- labels: {
132
- add: [AGENT_LABELS.BLOCKED],
133
- remove: [AGENT_LABELS.EXECUTING, AGENT_LABELS.READY, AGENT_LABELS.DONE],
134
- },
135
- });
137
+ await transitionTicketState(provider, storyId, STATE_LABELS.BLOCKED, {});
136
138
  progress('SYNC', `🚧 Flipped Story #${storyId} → ${AGENT_LABELS.BLOCKED}.`);
137
139
  } catch (err) {
138
140
  Logger.warn?.(
@@ -164,7 +166,7 @@ export function buildSyncFailureCommentBody({
164
166
  const lines = [
165
167
  `### ${heading}`,
166
168
  '',
167
- '`/single-story-deliver` close-validation passed, but the pre-push',
169
+ '`/deliver` close-validation passed, but the pre-push',
168
170
  `sync against \`origin/${baseBranch}\` could not complete. The Story has`,
169
171
  `been transitioned to \`agent::blocked\`. To resume:`,
170
172
  '',
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Standalone evidence keyspace (Story #4250). Standalone Stories have no
10
10
  * parent Epic, so they cannot scope a `validation-evidence.json` under a
11
- * `temp/epic-<id>/` tree. Rather than feed a null `epicId` into the
11
+ * `temp/run-<id>/` tree. Rather than feed a null `epicId` into the
12
12
  * Epic-keyed path (which structurally disabled the evidence cache and
13
13
  * forced every re-run — base-sync conflict, review remediation, baseline
14
14
  * absorb — to re-execute ALL gates including the coverage suite), the
@@ -45,7 +45,7 @@ import { runScopedFormatAutofix as defaultRunScopedFormatAutofix } from '../../s
45
45
  *
46
46
  * Gates are built from the canonical resolved config (`buildDefaultGates`
47
47
  * reads `project.commands` and `delivery.quality.gates.crap.enabled`); the
48
- * `baseBranch` is forwarded as the gate `epicBranch` so the format gate's
48
+ * `baseBranch` is forwarded as the gate `baseBranch` so the format gate's
49
49
  * changed-file scope anchors on it. `standalone: true` routes the evidence
50
50
  * cache to the storyId-anchored keyspace.
51
51
  *
@@ -92,7 +92,7 @@ export async function runCloseValidationPhase({
92
92
  cwd,
93
93
  worktreePath,
94
94
  storyId,
95
- epicBranch: baseBranch,
95
+ baseBranch,
96
96
  storyBranch,
97
97
  config,
98
98
  logger: Logger,
@@ -127,7 +127,7 @@ export async function runCloseValidationPhase({
127
127
  worktreePath,
128
128
  gates: buildDefaultGates({
129
129
  config,
130
- epicBranch: baseBranch,
130
+ baseBranch,
131
131
  cwd: worktreePath || cwd,
132
132
  log: (m) => Logger.info(m),
133
133
  }),
@@ -22,13 +22,13 @@
22
22
  *
23
23
  * Delegates the `runCodeReview` invocation to `runStoryReviewCore`
24
24
  * (exported from `story-close/phases/code-review.js`) so the close path
25
- * shares a single invocation pattern (Story #3653). When `planningRisk`
26
- * is omitted, loads it from the Story's `story-plan-state` checkpoint.
25
+ * shares a single invocation pattern (Story #3653). Review depth needs no
26
+ * input here: it is derived from this Story's own diff inside `runCodeReview`
27
+ * (Story #4542).
27
28
  */
28
29
 
29
30
  import { parsePrNumberFromUrl } from '../../../github-url.js';
30
- import { runStoryReviewCore } from '../../story-close/phases/code-review.js';
31
- import { resolveStoryPlanningRisk } from '../../story-plan-state.js';
31
+ import { runStoryReviewCore } from '../../story-close/phases/review-core.js';
32
32
  import { postStructuredComment } from '../../ticketing/state.js';
33
33
 
34
34
  /**
@@ -78,7 +78,6 @@ async function invokeStoryReviewCore({
78
78
  baseBranch,
79
79
  prNumber,
80
80
  provider,
81
- planningRisk,
82
81
  runCodeReviewFn,
83
82
  runLocalLensReviewFn,
84
83
  progress,
@@ -89,11 +88,6 @@ async function invokeStoryReviewCore({
89
88
  headRef: storyBranch,
90
89
  commentTargetId: prNumber,
91
90
  provider,
92
- planningRisk: await resolveStoryPlanningRisk({
93
- provider,
94
- storyId,
95
- planningRisk,
96
- }),
97
91
  progress,
98
92
  progressTag: 'REVIEW',
99
93
  runCodeReviewFn,
@@ -167,7 +161,6 @@ async function postStoryReviewCrossRef({
167
161
  * prUrl: string,
168
162
  * prNumber: number|null,
169
163
  * provider: object,
170
- * planningRisk?: object|null, // omit to load from story-plan-state
171
164
  * runCodeReviewFn: Function,
172
165
  * runLocalLensReviewFn?: Function,
173
166
  * progress: (tag: string, msg: string) => void,
@@ -190,7 +183,6 @@ export async function runStoryScopeReview({
190
183
  prUrl,
191
184
  prNumber,
192
185
  provider,
193
- planningRisk,
194
186
  runCodeReviewFn,
195
187
  runLocalLensReviewFn,
196
188
  progress,
@@ -214,7 +206,6 @@ export async function runStoryScopeReview({
214
206
  baseBranch,
215
207
  prNumber,
216
208
  provider,
217
- planningRisk,
218
209
  runCodeReviewFn,
219
210
  runLocalLensReviewFn,
220
211
  progress,