mandrel 1.94.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 (560) hide show
  1. package/.agents/README.md +116 -99
  2. package/.agents/agents/acceptance-critic.md +9 -7
  3. package/.agents/agents/story-worker.md +45 -51
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +498 -1287
  6. package/.agents/docs/agentrc-reference.json +185 -80
  7. package/.agents/docs/configuration.md +132 -190
  8. package/.agents/docs/execution-reference.md +51 -25
  9. package/.agents/docs/quality-gates.md +25 -33
  10. package/.agents/docs/workflows.md +8 -8
  11. package/.agents/instructions.md +113 -139
  12. package/.agents/rules/ci-remediation.md +11 -15
  13. package/.agents/rules/git-conventions-reference.md +48 -58
  14. package/.agents/rules/git-conventions.md +16 -22
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  16. package/.agents/schemas/agentrc.schema.json +83 -254
  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/retro.end.schema.json +1 -1
  24. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  25. package/.agents/schemas/signal-event.schema.json +3 -3
  26. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  27. package/.agents/schemas/validation-evidence.schema.json +1 -1
  28. package/.agents/scripts/acceptance-eval.js +22 -66
  29. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  30. package/.agents/scripts/audit-to-stories.js +7 -7
  31. package/.agents/scripts/boot-sweep.js +1 -1
  32. package/.agents/scripts/bootstrap.js +3 -3
  33. package/.agents/scripts/check-dead-exports.js +43 -104
  34. package/.agents/scripts/check-doc-links.js +2 -2
  35. package/.agents/scripts/check-lifecycle-lint.js +7 -10
  36. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  37. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  38. package/.agents/scripts/deliver-recover.js +122 -0
  39. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  40. package/.agents/scripts/evidence-gate.js +20 -50
  41. package/.agents/scripts/generate-skills-index.js +17 -1
  42. package/.agents/scripts/generate-workflows-doc.js +4 -4
  43. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  44. package/.agents/scripts/lib/Logger.js +6 -10
  45. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  46. package/.agents/scripts/lib/audit-suite/selector.js +328 -28
  47. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  48. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  49. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
  50. package/.agents/scripts/lib/baselines/reader.js +1 -6
  51. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  52. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  53. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  54. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  55. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  56. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  57. package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
  58. package/.agents/scripts/lib/checks/index.js +3 -2
  59. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  60. package/.agents/scripts/lib/checks/state.js +17 -248
  61. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
  62. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  63. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  64. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  65. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  66. package/.agents/scripts/lib/cli-args.js +39 -9
  67. package/.agents/scripts/lib/close-validation/gates.js +15 -15
  68. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  69. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  70. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  71. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  72. package/.agents/scripts/lib/config/ci.js +6 -31
  73. package/.agents/scripts/lib/config/delivery-routing.js +52 -35
  74. package/.agents/scripts/lib/config/explain.js +61 -48
  75. package/.agents/scripts/lib/config/github.js +7 -5
  76. package/.agents/scripts/lib/config/limits.js +29 -80
  77. package/.agents/scripts/lib/config/paths.js +0 -2
  78. package/.agents/scripts/lib/config/quality.js +12 -15
  79. package/.agents/scripts/lib/config/runners.js +20 -66
  80. package/.agents/scripts/lib/config/temp-paths.js +30 -63
  81. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  82. package/.agents/scripts/lib/config-resolver.js +2 -7
  83. package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
  84. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
  85. package/.agents/scripts/lib/config-settings-schema.js +100 -60
  86. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  87. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  88. package/.agents/scripts/lib/dependency-parser.js +3 -2
  89. package/.agents/scripts/lib/doc-tiers.js +2 -2
  90. package/.agents/scripts/lib/duplicate-search.js +242 -41
  91. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  92. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  93. package/.agents/scripts/lib/format-generated-json.js +97 -0
  94. package/.agents/scripts/lib/framework-version.js +19 -190
  95. package/.agents/scripts/lib/gh-exec.js +8 -0
  96. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  97. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
  98. package/.agents/scripts/lib/git-utils.js +32 -20
  99. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  100. package/.agents/scripts/lib/json-utils.js +1 -2
  101. package/.agents/scripts/lib/label-constants.js +10 -38
  102. package/.agents/scripts/lib/label-taxonomy.js +10 -55
  103. package/.agents/scripts/lib/observability/active-story-env.js +44 -165
  104. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  105. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  106. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  107. package/.agents/scripts/lib/observability/source-classifier.js +5 -5
  108. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  109. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  110. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  111. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  112. package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
  113. package/.agents/scripts/lib/orchestration/code-review.js +78 -436
  114. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  115. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
  116. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  117. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  118. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  119. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  120. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  121. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  122. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  123. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  124. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  125. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
  126. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  127. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  128. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  129. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
  130. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  131. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  132. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  133. package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
  134. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  135. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  136. package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
  137. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
  138. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
  139. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  140. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  141. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
  142. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
  143. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  144. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
  145. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
  146. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
  147. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  148. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  149. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  150. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
  151. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  152. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
  153. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  154. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  155. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  156. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  157. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  158. package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
  159. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  160. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  161. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  162. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  163. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  164. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  165. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  166. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  167. package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
  168. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
  169. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  170. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  171. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
  172. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  173. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
  174. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  175. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  176. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
  177. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  178. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  179. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
  180. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  181. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  182. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  183. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  184. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  185. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  186. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  187. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
  188. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  189. package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
  190. package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
  191. package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
  192. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  193. package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
  194. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  195. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
  196. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
  197. package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
  198. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
  199. package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
  200. package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
  201. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  202. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  203. package/.agents/scripts/lib/planning-corpus.js +12 -281
  204. package/.agents/scripts/lib/preflight-runner.js +4 -4
  205. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  206. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  207. package/.agents/scripts/lib/signals/index.js +4 -17
  208. package/.agents/scripts/lib/signals/read.js +35 -35
  209. package/.agents/scripts/lib/signals/schema.js +8 -11
  210. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  211. package/.agents/scripts/lib/signals/write.js +0 -1
  212. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  213. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  214. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  215. package/.agents/scripts/lib/story-adjacency.js +17 -19
  216. package/.agents/scripts/lib/story-body/story-body.js +130 -75
  217. package/.agents/scripts/lib/story-plan.js +2 -4
  218. package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
  219. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  220. package/.agents/scripts/lib/test-env.js +14 -1
  221. package/.agents/scripts/lib/test-tiers.js +0 -3
  222. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
  223. package/.agents/scripts/lib/validation-evidence.js +32 -60
  224. package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
  225. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  226. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  227. package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
  228. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  229. package/.agents/scripts/lint-issue-body.js +71 -40
  230. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  231. package/.agents/scripts/notify.js +4 -3
  232. package/.agents/scripts/plan-context.js +102 -80
  233. package/.agents/scripts/plan-persist.js +230 -279
  234. package/.agents/scripts/plan-run-epilogue.js +142 -0
  235. package/.agents/scripts/post-structured-comment.js +0 -38
  236. package/.agents/scripts/pr-watch-with-update.js +43 -22
  237. package/.agents/scripts/providers/github/compose.js +0 -1
  238. package/.agents/scripts/providers/github/errors.js +0 -19
  239. package/.agents/scripts/providers/github/issues.js +13 -39
  240. package/.agents/scripts/providers/github/mappers.js +5 -12
  241. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  242. package/.agents/scripts/providers/github/tickets.js +33 -156
  243. package/.agents/scripts/providers/github.js +17 -6
  244. package/.agents/scripts/resolve-stories.js +236 -0
  245. package/.agents/scripts/run-coverage.js +4 -1
  246. package/.agents/scripts/run-lint.js +2 -2
  247. package/.agents/scripts/run-verify.js +31 -2
  248. package/.agents/scripts/signals-view.js +25 -21
  249. package/.agents/scripts/single-story-close.js +178 -26
  250. package/.agents/scripts/single-story-confirm-merge.js +313 -24
  251. package/.agents/scripts/single-story-init.js +35 -30
  252. package/.agents/scripts/stories-wave-tick.js +85 -10
  253. package/.agents/scripts/story-plan.js +28 -49
  254. package/.agents/scripts/update-ticket-state.js +14 -65
  255. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  256. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  257. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  258. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  259. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  260. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  261. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  262. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  263. package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
  264. package/.agents/skills/core/scope-triage/SKILL.md +31 -172
  265. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  266. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  267. package/.agents/skills/skills.index.json +3 -53
  268. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  269. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  270. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  271. package/.agents/starter-agentrc.json +0 -5
  272. package/.agents/templates/agent-protocol.md +9 -10
  273. package/.agents/workflows/audit-architecture.md +6 -7
  274. package/.agents/workflows/audit-clean-code.md +7 -7
  275. package/.agents/workflows/audit-dependencies.md +3 -3
  276. package/.agents/workflows/audit-devops.md +3 -3
  277. package/.agents/workflows/audit-documentation.md +9 -10
  278. package/.agents/workflows/audit-lighthouse.md +11 -3
  279. package/.agents/workflows/audit-navigability.md +13 -2
  280. package/.agents/workflows/audit-performance.md +5 -6
  281. package/.agents/workflows/audit-privacy.md +3 -3
  282. package/.agents/workflows/audit-quality.md +11 -12
  283. package/.agents/workflows/audit-security.md +4 -5
  284. package/.agents/workflows/audit-seo.md +13 -3
  285. package/.agents/workflows/audit-sre.md +3 -3
  286. package/.agents/workflows/audit-to-stories.md +20 -20
  287. package/.agents/workflows/audit-ux-ui.md +10 -3
  288. package/.agents/workflows/deliver.md +177 -176
  289. package/.agents/workflows/git-cleanup.md +5 -6
  290. package/.agents/workflows/git-deliver.md +1 -1
  291. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  292. package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
  293. package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
  294. package/.agents/workflows/helpers/code-review.md +75 -196
  295. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
  296. package/.agents/workflows/helpers/deliver-story.md +606 -0
  297. package/.agents/workflows/helpers/diagnose.md +10 -10
  298. package/.agents/workflows/helpers/parallel-tooling.md +3 -3
  299. package/.agents/workflows/helpers/signals.md +16 -16
  300. package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
  301. package/.agents/workflows/mandrel-update.md +2 -1
  302. package/.agents/workflows/plan.md +277 -145
  303. package/.agents/workflows/qa-assist.md +27 -33
  304. package/.agents/workflows/qa-explore.md +29 -38
  305. package/.agents/workflows/qa-run.md +2 -6
  306. package/README.md +9 -8
  307. package/bin/mandrel.js +12 -1
  308. package/docs/CHANGELOG.md +70 -0
  309. package/lib/cli/registry.js +262 -19
  310. package/lib/cli/sync-agents.js +157 -0
  311. package/lib/cli/sync-commands.js +115 -6
  312. package/lib/cli/sync.js +168 -6
  313. package/lib/cli/update.js +105 -8
  314. package/lib/cli/version-helpers.js +131 -0
  315. package/lib/migrations/README.md +7 -5
  316. package/lib/migrations/index.js +12 -8
  317. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  318. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  319. package/package.json +2 -2
  320. package/.agents/agents/retro.md +0 -42
  321. package/.agents/personas/architect.md +0 -113
  322. package/.agents/personas/devops-engineer.md +0 -38
  323. package/.agents/personas/engineer.md +0 -33
  324. package/.agents/personas/project-manager.md +0 -114
  325. package/.agents/personas/qa-engineer.md +0 -95
  326. package/.agents/personas/security-engineer.md +0 -111
  327. package/.agents/personas/technical-writer.md +0 -101
  328. package/.agents/schemas/dispatch-manifest.json +0 -232
  329. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  330. package/.agents/schemas/epic-spec.schema.json +0 -153
  331. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  332. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  333. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  334. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  335. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  336. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  337. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  338. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  339. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  340. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  341. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  342. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  343. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  344. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  345. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  346. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  347. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  348. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  349. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  350. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  351. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  352. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  353. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  354. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  355. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  356. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  357. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  358. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  359. package/.agents/schemas/risk-verdict.schema.json +0 -66
  360. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  361. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  362. package/.agents/scripts/analyze-execution.js +0 -444
  363. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  364. package/.agents/scripts/check-prepush-recovery.js +0 -90
  365. package/.agents/scripts/dispatcher.js +0 -295
  366. package/.agents/scripts/epic-audit-prepare.js +0 -497
  367. package/.agents/scripts/epic-audit-recheck.js +0 -274
  368. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  369. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  370. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  371. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  372. package/.agents/scripts/epic-plan-clarity.js +0 -211
  373. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  374. package/.agents/scripts/epic-reconcile.js +0 -625
  375. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  376. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  377. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  378. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  379. package/.agents/scripts/lib/config/preflight.js +0 -58
  380. package/.agents/scripts/lib/config/retro.js +0 -77
  381. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  382. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  383. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  384. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  385. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  386. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
  387. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  388. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  389. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  390. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
  391. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  392. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  393. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  394. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  395. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  396. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  397. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  398. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  399. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  400. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  401. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  402. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  403. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  404. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  405. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  406. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  407. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  408. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
  409. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  410. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  411. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  412. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  413. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  414. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  415. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  416. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  417. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  418. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  419. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  420. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  421. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  422. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  423. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  424. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  425. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  426. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
  427. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  428. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  429. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  430. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  431. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  432. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  433. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  434. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  435. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  436. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  437. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  438. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  439. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  440. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  441. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  442. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  443. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  444. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  445. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  446. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  447. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  448. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  449. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  450. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  451. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  452. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  453. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  454. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  455. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  456. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  457. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  458. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  459. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  460. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  461. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
  462. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  463. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  464. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  465. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
  466. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  467. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  468. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  469. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  470. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  471. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  472. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  473. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  474. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  475. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  476. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  477. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  478. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  479. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  480. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  481. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  482. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  483. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  484. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  485. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  486. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  487. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  488. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  489. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  490. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  491. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  492. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  493. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  494. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  495. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  496. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  497. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  498. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  499. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  500. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  501. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  502. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  503. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  504. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  505. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  506. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  507. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  508. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  509. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  510. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  511. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  512. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  513. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  514. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  515. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  516. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  517. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  518. package/.agents/scripts/lib/spec/index.js +0 -36
  519. package/.agents/scripts/lib/spec/loader.js +0 -425
  520. package/.agents/scripts/lib/spec/state.js +0 -208
  521. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  522. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  523. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  524. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  525. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  526. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  527. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  528. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  529. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  530. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  531. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  532. package/.agents/scripts/lifecycle-emit.js +0 -510
  533. package/.agents/scripts/retro-run.js +0 -218
  534. package/.agents/scripts/slice-phase.js +0 -361
  535. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  536. package/.agents/scripts/story-close.js +0 -294
  537. package/.agents/scripts/story-init.js +0 -599
  538. package/.agents/scripts/story-phase.js +0 -369
  539. package/.agents/scripts/wave-tick.js +0 -464
  540. package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
  541. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  542. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  543. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  544. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  545. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  546. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  547. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  548. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  549. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  550. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  551. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  552. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  553. package/.agents/workflows/helpers/epic-audit.md +0 -189
  554. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  555. package/.agents/workflows/helpers/epic-testing.md +0 -125
  556. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  557. package/.agents/workflows/helpers/plan-epic.md +0 -353
  558. package/.agents/workflows/helpers/plan-story.md +0 -251
  559. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  560. package/.agents/workflows/helpers/single-story-deliver.md +0 -557
@@ -12,7 +12,7 @@
12
12
  * reconcile — dispatching it is pure token spend for a no-op. This module
13
13
  * computes that decision **deterministically**, off the same two inputs the
14
14
  * critic itself reads (the draft array and the Epic body's Delivery Slicing
15
- * table), so `helpers/plan-epic.md` Phase 8.3 can skip the sub-agent
15
+ * table), so the planning workflow can skip the sub-agent
16
16
  * dispatch when it is provably safe to.
17
17
  *
18
18
  * **Fail-open by design.** Every ambiguous case — a missing or unparseable
@@ -30,7 +30,7 @@
30
30
  * Epic body off disk / the GitHub API.
31
31
  */
32
32
 
33
- import { DELIVERY_SLICING_RE as DELIVERY_SLICING_HEADING_RE } from '../epic-body-sections.js';
33
+ import { DELIVERY_SLICING_RE as DELIVERY_SLICING_HEADING_RE } from '../ticket-body-sections.js';
34
34
 
35
35
  /** A row is a markdown table line: starts with `|` once trimmed. */
36
36
  const TABLE_ROW_RE = /^\|/;
@@ -123,7 +123,7 @@ export function parseDeliverySlicingTable(epicBody) {
123
123
 
124
124
  /**
125
125
  * True when `story` is the recognized wave-0 BDD scaffold Story — identified
126
- * by the literal `bdd-scaffold` goal token the `epic-plan-decompose-author`
126
+ * by the literal `bdd-scaffold` goal token the decomposer prompt
127
127
  * skill's WAVE-0 BDD SCAFFOLD STORY section requires. Scaffold Stories are
128
128
  * not a Delivery Slicing slice, so they are excluded from the count
129
129
  * comparison — BDD-adopting consumer repos still benefit from the
@@ -145,7 +145,7 @@ function isBddScaffoldStory(story) {
145
145
  *
146
146
  * @param {object} input
147
147
  * @param {object[]} input.draftStories - The draft `tickets.json` array
148
- * (`epic-plan-decompose-author`'s output) — raw Story ticket objects with
148
+ * (the decomposer's output) — raw Story ticket objects with
149
149
  * top-level `slug` / `depends_on` / `body` (serialized string).
150
150
  * @param {string} input.epicBody - The Epic body carrying the folded Tech
151
151
  * Spec sections (`## Delivery Slicing` onward).
@@ -8,7 +8,7 @@
8
8
  * @module lib/orchestration/context-envelope
9
9
  */
10
10
 
11
- /** @typedef {'protocolPolicy' | 'persona' | 'skillCapsules' | 'hierarchy' | 'acceptanceCriteria' | 'verificationCommands' | 'taskInstructions'} SectionName */
11
+ /** @typedef {'protocolPolicy' | 'skillCapsules' | 'hierarchy' | 'acceptanceCriteria' | 'verificationCommands' | 'taskInstructions'} SectionName */
12
12
 
13
13
  /**
14
14
  * @typedef {object} SectionSource
@@ -37,7 +37,7 @@
37
37
  /**
38
38
  * @typedef {object} ContextEnvelope
39
39
  * @property {'1'} schemaVersion
40
- * @property {{ id: number, title: string, persona?: string, skills?: string[], protocolVersion?: string }} task
40
+ * @property {{ id: number, title: string, skills?: string[], protocolVersion?: string }} task
41
41
  * @property {Section[]} sections
42
42
  * @property {TicketSnapshot[]} provenance
43
43
  * @property {{ maxTokens: number, used: number, elided: string[] }} budget
@@ -51,7 +51,6 @@ export const PROMPT_SECTION_SEPARATOR =
51
51
  /** Rendering order for {@link envelopeToPrompt} (not elision priority). */
52
52
  export const SECTION_RENDER_ORDER = Object.freeze([
53
53
  'protocolPolicy',
54
- 'persona',
55
54
  'skillCapsules',
56
55
  'hierarchy',
57
56
  'acceptanceCriteria',
@@ -65,7 +64,6 @@ export const DEFAULT_SECTION_PRIORITIES = Object.freeze({
65
64
  hierarchy: 20,
66
65
  acceptanceCriteria: 30,
67
66
  verificationCommands: 40,
68
- persona: 50,
69
67
  protocolPolicy: 80,
70
68
  taskInstructions: 100,
71
69
  });
@@ -76,7 +74,6 @@ export const DEFAULT_ELIDE_POLICIES = Object.freeze({
76
74
  hierarchy: 'summarize',
77
75
  acceptanceCriteria: 'summarize',
78
76
  verificationCommands: 'drop',
79
- persona: 'summarize',
80
77
  protocolPolicy: 'drop',
81
78
  taskInstructions: 'drop',
82
79
  });
@@ -0,0 +1,328 @@
1
+ /**
2
+ * deliver-recover.js — probe a stranded Story and name its ONE next command
3
+ * (Story #4543).
4
+ *
5
+ * Recovery here is a **read, not a repair**. Every input is already
6
+ * probeable — labels and lease from the ticket, the branch locally and via
7
+ * its tracking ref, the worktree path, the PR by head branch (with state,
8
+ * merge, and checks probes) — so this module is probes, a decision table
9
+ * over `label × PR × branch × worktree`, and one command with the evidence it
10
+ * was derived from. It never mutates anything, and it never prints a menu of
11
+ * options: a menu is what an operator already has, and it is the thing they
12
+ * cannot act on.
13
+ *
14
+ * The strand shapes the table resolves, and why each is real:
15
+ *
16
+ * - `executing` with no PR → resume implementation. The work never reached
17
+ * close.
18
+ * - `closing` with a pending PR → resume the land. The overwhelmingly
19
+ * common shape now that the merge wait is bounded: the wait returned
20
+ * `pending` and something has to pick it back up.
21
+ * - `closing` with a red PR → enter the fix loop. Waiting is pointless; no
22
+ * budget turns a failed check green.
23
+ * - `closing` with a MERGED PR → run confirm. **This is the strand a
24
+ * `/deliver` re-run refuses outright**, because `single-story-init.js`
25
+ * hard-errors on an already-closed Story — so before this surface, the
26
+ * merged-but-label-stale Story had no automated way back.
27
+ * - `done` with a drifted board → run resync. The GitHub Projects bot won
28
+ * the race.
29
+ * - `blocked` → print the class-specific remediation the friction comment
30
+ * already names, rather than inventing a second opinion about a
31
+ * condition that was already classified.
32
+ *
33
+ * The command vocabulary is shared with the terminal envelope
34
+ * (`story-deliver-terminal.js#NEXT_COMMANDS`), so recovery and normal
35
+ * resumption speak one language instead of two dialects for one state.
36
+ */
37
+
38
+ import { gh as defaultGh } from '../gh-exec.js';
39
+ import { gitSpawn as defaultGitSpawn, getStoryBranch } from '../git-utils.js';
40
+ import { deriveChecksStatus } from './merge-poll.js';
41
+ import { NEXT_COMMANDS } from './story-deliver-terminal.js';
42
+ import { STATE_LABELS } from './ticketing.js';
43
+
44
+ /**
45
+ * Probe the ticket: state labels, issue open/closed, and the lease holder.
46
+ *
47
+ * @returns {Promise<object>}
48
+ */
49
+ export async function probeTicket({ provider, storyId }) {
50
+ try {
51
+ const ticket = await provider.getTicket(storyId);
52
+ const labels = Array.isArray(ticket?.labels) ? ticket.labels : [];
53
+ const stateLabel =
54
+ labels.find((l) => typeof l === 'string' && l.startsWith('agent::')) ??
55
+ null;
56
+ return {
57
+ ok: true,
58
+ stateLabel,
59
+ labels,
60
+ issueState: ticket?.state ?? null,
61
+ title: ticket?.title ?? null,
62
+ lease: ticket?.assignees?.[0] ?? ticket?.assignee ?? null,
63
+ };
64
+ } catch (err) {
65
+ return { ok: false, error: String(err?.message ?? err) };
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Probe the Story branch locally and its remote tracking ref, plus the
71
+ * worktree path. Pure git — no network.
72
+ *
73
+ * @returns {object}
74
+ */
75
+ export function probeBranch({ cwd, storyBranch, config, gitSpawnFn }) {
76
+ const spawn = gitSpawnFn ?? defaultGitSpawn;
77
+ const localRef = spawn(
78
+ cwd,
79
+ 'show-ref',
80
+ '--verify',
81
+ '--quiet',
82
+ `refs/heads/${storyBranch}`,
83
+ );
84
+ const remoteRef = spawn(
85
+ cwd,
86
+ 'show-ref',
87
+ '--verify',
88
+ '--quiet',
89
+ `refs/remotes/origin/${storyBranch}`,
90
+ );
91
+ const worktreeRoot =
92
+ config?.delivery?.worktreeIsolation?.root ?? '.worktrees';
93
+ const worktrees = spawn(cwd, 'worktree', 'list', '--porcelain');
94
+ const worktreePath =
95
+ worktrees.status === 0 &&
96
+ typeof worktrees.stdout === 'string' &&
97
+ worktrees.stdout.includes(`${worktreeRoot}/${storyBranch}`)
98
+ ? `${worktreeRoot}/${storyBranch}`
99
+ : null;
100
+ return {
101
+ local: localRef.status === 0,
102
+ remote: remoteRef.status === 0,
103
+ worktreePath,
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Probe the PR for the Story branch. `--state all` is required: a merged PR
109
+ * is no longer `open`, and the merged-but-label-stale strand is precisely
110
+ * the one that matters most here.
111
+ *
112
+ * @returns {Promise<object|null>}
113
+ */
114
+ export async function probePr({ storyBranch, gh = defaultGh }) {
115
+ try {
116
+ const rows = await gh.pr.list(
117
+ ['--head', storyBranch, '--state', 'all'],
118
+ ['number', 'url', 'state', 'mergedAt', 'statusCheckRollup'],
119
+ );
120
+ if (!Array.isArray(rows) || rows.length === 0) return null;
121
+ const row = rows[0];
122
+ return {
123
+ number: Number(row?.number) || null,
124
+ url: row?.url ?? null,
125
+ state: row?.state ?? null,
126
+ mergedAt: row?.mergedAt ?? null,
127
+ checksStatus: deriveChecksStatus(row?.statusCheckRollup),
128
+ };
129
+ } catch (err) {
130
+ return { error: String(err?.message ?? err) };
131
+ }
132
+ }
133
+
134
+ /**
135
+ * The decision table. Pure: every input is an already-observed probe, so the
136
+ * mapping is testable without git, GitHub, or a clock.
137
+ *
138
+ * Returns exactly one `{ shape, nextCommand, evidence[], detail }` — never a
139
+ * list of candidates.
140
+ *
141
+ * @param {{ storyId: number, ticket: object, branch: object, pr: object|null }} probes
142
+ * @returns {{ shape: string, nextCommand: string|null, detail: string, evidence: string[] }}
143
+ */
144
+ export function decideRecovery({ storyId, ticket, branch, pr }) {
145
+ const evidence = [
146
+ `label=${ticket?.stateLabel ?? 'none'}`,
147
+ `issue=${ticket?.issueState ?? 'unknown'}`,
148
+ `pr=${pr?.number ? `#${pr.number} ${pr.state ?? '?'}` : 'none'}`,
149
+ `checks=${pr?.checksStatus ?? 'n/a'}`,
150
+ `branch.local=${branch?.local ?? false}`,
151
+ `branch.remote=${branch?.remote ?? false}`,
152
+ `worktree=${branch?.worktreePath ?? 'none'}`,
153
+ `lease=${ticket?.lease ?? 'unclaimed'}`,
154
+ ];
155
+
156
+ const label = ticket?.stateLabel;
157
+ const merged = pr?.state === 'MERGED' || Boolean(pr?.mergedAt);
158
+
159
+ // A merged PR outranks every label reading. The code is on the base
160
+ // branch; whatever the label says, the only thing left is the flip + tail.
161
+ if (merged && label !== STATE_LABELS.DONE) {
162
+ return {
163
+ shape: 'merged-label-stale',
164
+ nextCommand: NEXT_COMMANDS.confirmMerge(storyId),
165
+ detail:
166
+ `PR #${pr.number} is MERGED but the Story is at \`${label ?? 'no state label'}\`. ` +
167
+ `A /deliver re-run cannot fix this — single-story-init.js hard-errors on an ` +
168
+ `already-closed Story. The confirm CLI is idempotent and flips the label from ` +
169
+ `the already-merged PR, then runs the land tail.`,
170
+ evidence,
171
+ };
172
+ }
173
+
174
+ if (label === STATE_LABELS.BLOCKED) {
175
+ return {
176
+ shape: 'blocked',
177
+ nextCommand: NEXT_COMMANDS.recover(storyId),
178
+ detail:
179
+ `Story is at \`agent::blocked\`. The block was already classified when it was ` +
180
+ `filed — read the \`friction\` comment on #${storyId} for the class-specific ` +
181
+ `remediation, resolve it, then transition back to \`agent::executing\`. ` +
182
+ `Re-run this probe afterwards to confirm the strand cleared.`,
183
+ evidence,
184
+ };
185
+ }
186
+
187
+ if (label === STATE_LABELS.DONE) {
188
+ return {
189
+ shape: 'done-board-drift',
190
+ nextCommand: NEXT_COMMANDS.resync(storyId),
191
+ detail:
192
+ `Story is \`agent::done\`. Nothing to deliver. If the Projects board still shows ` +
193
+ `it as In Progress, the GitHub built-in workflow won the post-merge race; the ` +
194
+ `resync re-asserts the column and is a no-op otherwise.`,
195
+ evidence,
196
+ };
197
+ }
198
+
199
+ if (label === STATE_LABELS.CLOSING) {
200
+ if (pr?.checksStatus === 'failure') {
201
+ return {
202
+ shape: 'closing-pr-red',
203
+ nextCommand: NEXT_COMMANDS.watchCi(storyId, pr.number),
204
+ detail:
205
+ `PR #${pr.number} has a red required check. Waiting cannot help — fix the ` +
206
+ `failure and push a new commit on \`story-${storyId}\`; auto-merge stays armed ` +
207
+ `across retries.`,
208
+ evidence,
209
+ };
210
+ }
211
+ if (pr?.number) {
212
+ return {
213
+ shape: 'closing-pr-pending',
214
+ nextCommand: NEXT_COMMANDS.resumeLand(storyId),
215
+ detail:
216
+ `PR #${pr.number} is open and healthy. This is the normal resumable shape after ` +
217
+ `a bounded merge wait returned \`pending\`. The confirm CLI polls it to a ` +
218
+ `confirmed merge and runs the land tail.`,
219
+ evidence,
220
+ };
221
+ }
222
+ return {
223
+ shape: 'closing-no-pr',
224
+ nextCommand: NEXT_COMMANDS.close(storyId),
225
+ detail:
226
+ `Story is at \`agent::closing\` but no PR exists for \`story-${storyId}\`. The ` +
227
+ `close did not reach the pull-request phase; re-run it (close is idempotent and ` +
228
+ `reuses an existing PR when one is found).`,
229
+ evidence,
230
+ };
231
+ }
232
+
233
+ if (label === STATE_LABELS.EXECUTING) {
234
+ if (pr?.number) {
235
+ return {
236
+ shape: 'executing-with-pr',
237
+ nextCommand: NEXT_COMMANDS.close(storyId),
238
+ detail:
239
+ `PR #${pr.number} exists but the Story is still \`agent::executing\` — the close ` +
240
+ `opened the PR and then died before the label flip. Re-run close; it reuses the ` +
241
+ `open PR rather than opening a duplicate.`,
242
+ evidence,
243
+ };
244
+ }
245
+ return {
246
+ shape: 'executing-no-pr',
247
+ nextCommand: NEXT_COMMANDS.implement(storyId),
248
+ detail:
249
+ `Story is \`agent::executing\` with no PR. Implementation never finished. Re-init ` +
250
+ `(idempotent — it reuses the existing branch and worktree) and resume in the ` +
251
+ `worktree it prints.`,
252
+ evidence,
253
+ };
254
+ }
255
+
256
+ return {
257
+ shape: 'ready',
258
+ nextCommand: NEXT_COMMANDS.close(storyId),
259
+ detail:
260
+ `Story is at \`${label ?? 'no agent:: state label'}\` — not mid-delivery, so there ` +
261
+ `is no strand to recover. Deliver it normally via /deliver ${storyId}.`,
262
+ evidence,
263
+ };
264
+ }
265
+
266
+ /**
267
+ * Probe live state and resolve the single next command. Read-only.
268
+ *
269
+ * @param {object} args
270
+ * @param {number} args.storyId
271
+ * @param {string} args.cwd
272
+ * @param {object} args.provider
273
+ * @param {object} [args.config]
274
+ * @param {object} [args.gh]
275
+ * @param {Function} [args.gitSpawnFn]
276
+ * @returns {Promise<object>}
277
+ */
278
+ export async function recoverStory({
279
+ storyId,
280
+ cwd,
281
+ provider,
282
+ config,
283
+ gh = defaultGh,
284
+ gitSpawnFn,
285
+ }) {
286
+ const storyBranch = getStoryBranch(storyId);
287
+ const ticket = await probeTicket({ provider, storyId });
288
+ if (!ticket.ok) {
289
+ throw new Error(
290
+ `deliver-recover: could not read Story #${storyId}: ${ticket.error}`,
291
+ );
292
+ }
293
+ const branch = probeBranch({ cwd, storyBranch, config, gitSpawnFn });
294
+ const pr = await probePr({ storyBranch, gh });
295
+ const decision = decideRecovery({ storyId, ticket, branch, pr });
296
+ return {
297
+ storyId,
298
+ storyBranch,
299
+ probes: { ticket, branch, pr },
300
+ ...decision,
301
+ };
302
+ }
303
+
304
+ /**
305
+ * Render the operator-facing report: the shape, the one command, and the
306
+ * evidence it was derived from — so the operator can check the reasoning
307
+ * rather than trust it.
308
+ *
309
+ * @param {object} recovery
310
+ * @returns {string}
311
+ */
312
+ export function renderRecovery(recovery) {
313
+ const lines = [
314
+ `Story #${recovery.storyId} — ${recovery.shape}`,
315
+ '',
316
+ recovery.detail,
317
+ '',
318
+ 'Evidence:',
319
+ ...recovery.evidence.map((e) => ` - ${e}`),
320
+ '',
321
+ ];
322
+ if (recovery.nextCommand) {
323
+ lines.push('Next command:', ` ${recovery.nextCommand}`, '');
324
+ } else {
325
+ lines.push('Next command: none — nothing to do.', '');
326
+ }
327
+ return lines.join('\n');
328
+ }
@@ -1,7 +1,12 @@
1
1
  /**
2
- * detectors-phase.js — pure post-merge phase that runs the per-Story
3
- * signal detectors (rework + retry) before `analyze-execution.js` shells
4
- * out to render the `<!-- structured:story-perf-summary -->` comment.
2
+ * detectors-phase.js — pure phase that runs the per-Story signal detectors
3
+ * (rework + retry) over the local NDJSON stream.
4
+ *
5
+ * Story #4545 — this phase has no production caller. Its sequencer
6
+ * (`post-merge-pipeline.js`) went in the v2.0.0 cutover, and the
7
+ * `analyze-execution.js` consumer it fed was deleted with the
8
+ * execution-analysis surface. Kept alive only by its own test — the
9
+ * test-importer blind spot the dead-exports ratchet cannot see.
5
10
  *
6
11
  * Extracted from `post-merge-pipeline.js` (Story #1770 / Task #1779) to
7
12
  * keep the parent sequencer's maintainability score above its baseline
@@ -39,8 +44,9 @@
39
44
  * @module lib/orchestration/detectors-phase
40
45
  */
41
46
 
47
+ import path from 'node:path';
42
48
  import { getSignals } from '../config/limits.js';
43
- import { storyArtifactPath } from '../config/temp-paths.js';
49
+ import { storyTempDir } from '../config/temp-paths.js';
44
50
  import { Logger } from '../Logger.js';
45
51
  import { appendSignal } from '../observability/signals-writer.js';
46
52
  import { detectRetry, detectRework } from '../signals/detectors/index.js';
@@ -114,7 +120,7 @@ function isValidIdPair(eid, sid) {
114
120
 
115
121
  /**
116
122
  * Run the rework + retry detectors for one Story and persist every
117
- * emission to `temp/epic-<eid>/stories/story-<sid>/signals.ndjson`.
123
+ * emission to `temp/run-<id>/stories/story-<sid>/signals.ndjson`.
118
124
  *
119
125
  * @param {{
120
126
  * epicId: number|string,
@@ -159,7 +165,7 @@ export async function detectorsPhase(ctx) {
159
165
  return { rework: 0, retry: 0 };
160
166
  }
161
167
 
162
- const tracesPath = storyArtifactPath(eid, sid, 'traces.ndjson', config);
168
+ const tracesPath = path.join(storyTempDir(eid, sid, config), 'traces.ndjson');
163
169
  const taskId = resolveLastTaskId(tasks);
164
170
  const baseArgs = { tracesPath, epicId: eid, storyId: sid, taskId };
165
171
  const common = {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * docs-digest.js — per-Epic docs digest builder (Story #4338).
2
+ * docs-digest.js — per-run docs digest builder (Story #4338).
3
3
  *
4
4
  * `/deliver` story sub-agents previously re-read every file in
5
5
  * `project.docsContextFiles` on every Story, re-paying the full docs payload
@@ -16,8 +16,8 @@
16
16
  * Story #4433 extends this module with {@link ensureDocsDigest}, a shared
17
17
  * generate-and-write export so the planner-context surface
18
18
  * (`plan-context.js` / `authoring-context.js`) can produce a session docs
19
- * digest without duplicating the mkdir+writeFile plumbing
20
- * `epic-deliver-prepare.js` already owns for the delivery-children digest.
19
+ * digest without duplicating the mkdir+writeFile plumbing shared by
20
+ * `plan-context.js` / `authoring-context.js` and the `/deliver` workflow.
21
21
  */
22
22
 
23
23
  import fs from 'node:fs';
@@ -110,7 +110,7 @@ function renderDocSection(doc) {
110
110
  }
111
111
 
112
112
  /**
113
- * Build the per-Epic docs digest markdown from the configured docs context
113
+ * Build the per-run docs digest markdown from the configured docs context
114
114
  * files. Missing files are skipped silently (the read seam returns only the
115
115
  * files it could stat + read). Returns `null` when there is nothing to digest
116
116
  * — i.e. `docsContextFiles` is empty/unset — so callers surface a null
@@ -130,7 +130,7 @@ export async function buildDocsDigest({ docsContextFiles, docsRoot } = {}) {
130
130
  const header = [
131
131
  '# Docs digest',
132
132
  '',
133
- 'Per-Epic outline of the project docs context set. Each entry lists the',
133
+ 'Per-run outline of the project docs context set. Each entry lists the',
134
134
  'file path, byte size, and its heading outline (with line numbers) plus',
135
135
  'the first paragraph under each `##` section. Read the full file on demand',
136
136
  'when a section looks relevant — do **not** ingest the whole set per Story.',
@@ -144,10 +144,10 @@ export async function buildDocsDigest({ docsContextFiles, docsRoot } = {}) {
144
144
  /**
145
145
  * Build the docs digest and write it to `outputPath`, returning `null` (no
146
146
  * write) when there is nothing to digest. This is the single shared
147
- * generate-and-persist export both digest producers call: the per-Epic
148
- * delivery-children digest (`epic-deliver-prepare.js`) and the planner-
147
+ * generate-and-persist export both digest producers call: the per-run
148
+ * `/deliver` docs digest (`helpers/deliver-story.md`) and the planner-
149
149
  * context digest (`plan-context.js` → `authoring-context.js`, Story
150
- * #4433). Callers own path construction (temp-root layout, epic id, etc.)
150
+ * #4433). Callers own path construction (temp-root layout, run id, etc.)
151
151
  * so both surfaces can keep — or deliberately share — their own convention;
152
152
  * this function only owns "build digest, ensure parent dir, write file".
153
153
  *
@@ -45,11 +45,10 @@
45
45
  * the shared-editor conflict gate's domain — that finding's rendering is
46
46
  * cross-referenced (see `renderMismatch`), not duplicated here.
47
47
  *
48
- * Legacy compatibility: stories whose `body.changes` items are still bare
49
- * strings carry no assumption and are skipped silently here. The
50
- * deprecation signal is emitted *once* per validator invocation through
51
- * `collectDeprecationWarnings`, so consumers running an older planner
52
- * see a clear migration nudge without a hard failure mid-flight.
48
+ * String bullets: stories whose `body.changes` items are still bare
49
+ * strings are hard errors they are pushed to `errors[]` by the
50
+ * validator's body-shape gate before this module runs. There is no
51
+ * silent skip or deprecation nudge.
53
52
  */
54
53
 
55
54
  import { gitSpawn } from '../git-utils.js';
@@ -319,21 +318,16 @@ export function validateStoryFileAssumptions(opts) {
319
318
  const entries = collectStoryAssumptionEntries(story);
320
319
 
321
320
  if (entries.length === 0) {
322
- // Legacy path: this Story carries no object-form entries. Emit a
323
- // single deprecation warning so the operator sees the migration
324
- // nudge once per Story rather than per-bullet.
325
321
  if (hasLegacyChangeBullets(story)) {
326
- warnings.push(
327
- `"${slug}" → body.changes uses legacy string bullets without { path, assumption }. Migrate to object form so Phase 8 can verify file-state assumptions. See Story #2636.`,
322
+ errors.push(
323
+ `"${slug}" → body.changes uses legacy string bullets without { path, assumption }. Migrate every bullet to object form so Phase 8 can verify file-state assumptions. See Story #2636.`,
328
324
  );
329
325
  }
330
326
  continue;
331
327
  }
332
328
 
333
- // Partial-migration warning: some entries are object-form, some are
334
- // still strings. Surface once so the operator notices the gap.
335
329
  if (hasLegacyChangeBullets(story)) {
336
- warnings.push(
330
+ errors.push(
337
331
  `"${slug}" → body.changes mixes object-form entries with legacy string bullets. Migrate every bullet for full freshness coverage.`,
338
332
  );
339
333
  }
@@ -26,7 +26,7 @@ function resolveBaseBranch(cwd, override) {
26
26
  if (override) return override;
27
27
  try {
28
28
  const cfg = resolveConfig({ cwd });
29
- return cfg?.project?.baseBranch || cfg?.agentSettings?.baseBranch || 'main';
29
+ return cfg?.project?.baseBranch || 'main';
30
30
  } catch {
31
31
  return 'main';
32
32
  }
@@ -59,6 +59,36 @@ export function planFastForward(ctx) {
59
59
  return { runnable: true, behind: ff.behind, currentBranch: cur };
60
60
  }
61
61
 
62
+ /**
63
+ * Return HEAD to the branch it started on.
64
+ *
65
+ * {@link maybeCheckout} moves the checkout to `baseBranch` so `merge
66
+ * --ff-only` has somewhere to land. Leaving it there silently relocates the
67
+ * operator: this phase runs from the MAIN checkout — which may be parked on
68
+ * unrelated work — and the close tail can reach it long after the operator
69
+ * walked away (a belated `single-story-confirm-merge --wait`, for instance).
70
+ * Fast-forwarding the base branch is the contract every delivering flow owes
71
+ * the checkout; moving someone off the branch they were using is not, and it
72
+ * is the kind of surprise that gets subsequent work committed to the wrong
73
+ * branch.
74
+ *
75
+ * Best-effort: a failed restore warns and never fails the phase — the
76
+ * fast-forward already succeeded, and `planFastForward` refuses on a dirty
77
+ * tree, so nothing uncommitted is ever at risk here.
78
+ */
79
+ function restoreBranchIfMoved({ plan, baseBranch, cwd, checkoutFn, logger }) {
80
+ const original = plan.currentBranch;
81
+ if (!original || original === baseBranch) return;
82
+ const co = checkoutFn(cwd, original);
83
+ if (!co.ok) {
84
+ logger.warn?.(
85
+ `${TAG} ⚠️ checkout left on ${baseBranch}: restoring ${original} failed: ${co.stderr}`,
86
+ );
87
+ return;
88
+ }
89
+ logger.info?.(`${TAG} ↩️ restored checkout to ${original}`);
90
+ }
91
+
62
92
  function maybeCheckout({ plan, baseBranch, cwd, checkoutFn, logger }) {
63
93
  if (!plan.currentBranch || plan.currentBranch === baseBranch) {
64
94
  return { ok: true };
@@ -108,6 +138,9 @@ export function executeFastForward(ctx) {
108
138
  logger.warn?.(
109
139
  `${TAG} ❌ merge --ff-only ${ref} failed: ${mergeRes.stderr}`,
110
140
  );
141
+ // We already moved HEAD to run the merge; put it back even on the
142
+ // failure path rather than stranding the operator on the base branch.
143
+ restoreBranchIfMoved({ plan, baseBranch, cwd, checkoutFn, logger });
111
144
  return {
112
145
  ok: false,
113
146
  applied: false,
@@ -119,5 +152,6 @@ export function executeFastForward(ctx) {
119
152
  logger.info?.(
120
153
  `${TAG} ✅ fast-forwarded ${baseBranch} by ${plan.behind} commit(s)`,
121
154
  );
155
+ restoreBranchIfMoved({ plan, baseBranch, cwd, checkoutFn, logger });
122
156
  return { ok: true, applied: true, skipped: false, behind: plan.behind };
123
157
  }
@@ -2,8 +2,9 @@
2
2
  * lease-guard-shared.js — Story #3992: single-source the lease-acquisition
3
3
  * kernel shared by the three per-surface lease guards.
4
4
  *
5
- * `epic-deliver-lease-guard.js`, `epic-plan-lease-guard.js`, and
6
- * `single-story-lease-guard.js` historically each carried their own copy of
5
+ * The per-surface lease guards — today `single-story-lease-guard.js`;
6
+ * historically also the retired Epic-tier deliver/plan guards —
7
+ * each carried their own copy of
7
8
  * the operator-handle resolution and the fail-closed acquire wrapper around
8
9
  * `ticket-lease.acquireLease` (anchor `heartbeatAt` to `now` so a foreign
9
10
  * assignee always reads as a live claim, then throw an operator-facing