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
@@ -11,19 +11,23 @@
11
11
  * adapter's `runReview()` to collect a `Finding[]`, render the
12
12
  * structured-comment body via `findings-renderer`, and post the
13
13
  * comment through the GitHub provider here (the adapter is post-free
14
- * by design). The lifecycle events (`code-review.start`/`.end`)
15
- * preserve their previous payload shape so the ledger and listener
16
- * chain are unchanged.
14
+ * by design).
15
+ *
16
+ * v2.0.0 removed the Epic tier. The Epic-scope envelope and the
17
+ * Epic-scoped `code-review.start` / `.end` lifecycle emits (whose schema
18
+ * requires `epicId`) went with it; Story scope is the only scope and the
19
+ * module no longer touches the lifecycle bus.
17
20
  *
18
21
  * Public API:
19
- * - `runCodeReview({ scope, ticketId, provider, logger, bus, ... })` →
22
+ * - `runCodeReview({ ticketId, headRef, provider, logger, ... })` →
20
23
  * `{ status, severity, posted, report, halted, blockerReason }`.
21
24
  *
22
25
  * Behaviour:
23
26
  * - Loads the configured review adapter via the factory; defaults to
24
- * `native` when `delivery.codeReview.provider` is unset.
27
+ * a single `native` chain entry when `delivery.codeReview.providers`
28
+ * is unset or empty.
25
29
  * - Always posts the unified `verification-results` structured comment on
26
- * the Epic issue (the adapter never posts; the orchestrator owns
30
+ * the target issue/PR (the adapter never posts; the orchestrator owns
27
31
  * persistence). Story #4411 (Epic #4405) unified the former
28
32
  * `code-review` and `audit-results` findings contracts into this one
29
33
  * `verification-results` marker.
@@ -36,12 +40,9 @@
36
40
  */
37
41
 
38
42
  import { hasSurvivingCritical } from '../audit-suite/findings.js';
39
- import { resolveLensTier } from '../audit-suite/selector.js';
40
43
  import { resolveConfig } from '../config-resolver.js';
41
- import { selectAuditStrategy } from '../dynamic-workflow/capability.js';
42
44
  import { gitSpawn } from '../git-utils.js';
43
- import { read as readPlanState } from './epic-plan-state-store.js';
44
- import { resolveDepth } from './review-depth.js';
45
+ import { deriveChangeLevel, resolveDepth } from './review-depth.js';
45
46
  import {
46
47
  countBySeverity,
47
48
  renderFindings,
@@ -51,29 +52,30 @@ import { upsertStructuredComment } from './ticketing.js';
51
52
 
52
53
  /**
53
54
  * Review depth tiers, ordered light → standard → deep. The depth is resolved
54
- * by the shared {@link resolveDepth} resolver from the judged risk envelope's
55
- * `overallLevel` **and** the mechanical changed-file count of the diff under
56
- * review, then threaded into the review provider's `runReview` input so a
57
- * high-risk *or* wide-footprint change gets a deeper pass than a low-risk
58
- * small one. Depth is an **input** signal only it never changes the
55
+ * by the shared {@link resolveDepth} resolver from two observable properties of
56
+ * the diff under review — whether its changed files touch a registered
57
+ * sensitive path ({@link deriveChangeLevel}) and their mechanical count then
58
+ * threaded into the review provider's `runReview` input so a sensitive *or*
59
+ * wide-footprint change gets a deeper pass than a small, unremarkable one.
60
+ * Depth is an **input** signal only — it never changes the
59
61
  * `{ status, severity, posted, report, halted, blockerReason }` output
60
- * envelope nor the `code-review` structured-comment body (Story #3876,
61
- * extended by Story #3938).
62
+ * envelope nor the `verification-results` structured-comment body (Story #3876,
63
+ * extended by Story #3938; re-based off the diff by Story #4542).
62
64
  *
63
65
  * @typedef {import('./review-depth.js').ReviewDepth} ReviewDepth
64
66
  */
65
67
 
66
68
  /**
67
- * Count the files changed in the `baseRef...headRef` diff via
68
- * `git diff --name-only`. Returns the file count, or `null` when the diff
69
- * cannot be enumerated (git failure, missing ref). A `null` count is the
70
- * neutral "width unknown" signal {@link resolveDepth} tolerates without
71
- * downgrading or escalating the depth. Best-effort — never throws.
69
+ * Enumerate the files changed in the `baseRef...headRef` diff via
70
+ * `git diff --name-only`. Returns the file list, or `null` when the diff
71
+ * cannot be enumerated (git failure, missing ref). A `null` list is the neutral
72
+ * "diff unknown" signal both {@link deriveChangeLevel} and {@link resolveDepth}
73
+ * tolerate by failing safe to `standard`. Best-effort — never throws.
72
74
  *
73
75
  * @param {{ baseRef: string, headRef: string, gitSpawnFn?: typeof gitSpawn }} args
74
- * @returns {number|null}
76
+ * @returns {string[]|null}
75
77
  */
76
- function countChangedFiles({ baseRef, headRef, gitSpawnFn = gitSpawn }) {
78
+ function listChangedFiles({ baseRef, headRef, gitSpawnFn = gitSpawn }) {
77
79
  try {
78
80
  const result = gitSpawnFn(
79
81
  process.cwd(),
@@ -85,300 +87,20 @@ function countChangedFiles({ baseRef, headRef, gitSpawnFn = gitSpawn }) {
85
87
  return null;
86
88
  }
87
89
  return result.stdout
88
- .trim()
89
90
  .split('\n')
90
- .filter((line) => line.length > 0).length;
91
+ .map((line) => line.trim())
92
+ .filter((line) => line.length > 0);
91
93
  } catch {
92
94
  return null;
93
95
  }
94
96
  }
95
97
 
96
- /**
97
- * Resolve the `planning.taskSizing` operator override the same way the ticket
98
- * validator does, so an operator who retunes sizing retunes the depth
99
- * thresholds with it. Reads `config.planning.taskSizing` first, then the
100
- * legacy `config.agentSettings.planning.taskSizing` nest; absent → `undefined`
101
- * so {@link resolveDepth} falls back to `DEFAULT_TASK_SIZING`.
102
- *
103
- * @param {object|null|undefined} config
104
- * @returns {object|undefined}
105
- */
106
- function resolveTaskSizing(config) {
107
- return (
108
- config?.planning?.taskSizing ??
109
- config?.agentSettings?.planning?.taskSizing ??
110
- undefined
111
- );
112
- }
113
-
114
- /**
115
- * Producer-side resolver (Story #3937, extended by Story #3938): read an
116
- * Epic's judged `planningRisk` envelope off its `epic-plan-state` checkpoint
117
- * and resolve the review depth via the shared {@link resolveDepth} resolver.
118
- * This is the live epic-scope counterpart to `resolveRiskRoutedLenses` in
119
- * `epic-audit-prepare.js` — it reuses the same best-effort `readPlanState`
120
- * pattern so the producer never aborts the review on a risk-read failure.
121
- *
122
- * Best-effort and total: a missing/unparseable checkpoint, an absent
123
- * `planningRisk` field, a read failure, or a malformed `overallLevel` all
124
- * degrade to `standard` (never throws). So an Epic that skipped `/plan`
125
- * (no checkpoint) still gets a passing `standard` review with no new failure
126
- * mode. The producer resolves depth from the judged risk alone (the diff is
127
- * not yet enumerated at this point); the full risk + diff-width combination is
128
- * applied in `runCodeReview`, which knows the changed-file count. A high-risk
129
- * Epic resolves to `deep` here; a low-risk one to `light` (the diff width can
130
- * only escalate, never downgrade, that producer-side resolution).
131
- *
132
- * @param {{
133
- * epicId: number,
134
- * provider: object,
135
- * readPlanState?: typeof readPlanState,
136
- * }} params
137
- * @returns {Promise<ReviewDepth>}
138
- */
139
- export async function resolveReviewDepthForEpic({
140
- epicId,
141
- provider,
142
- readPlanState: readPlanStateFn = readPlanState,
143
- }) {
144
- let state = null;
145
- try {
146
- state = await readPlanStateFn({ provider, epicId });
147
- } catch {
148
- // A read failure (provider error, malformed comment) must not abort the
149
- // review. Degrade to the neutral `standard` depth.
150
- return 'standard';
151
- }
152
- return resolveDepth({ overallLevel: state?.planningRisk?.overallLevel });
153
- }
154
-
155
- /**
156
- * The axes whose presence (at `high` risk) routes a specific post-delivery
157
- * audit lens. Mirrors the audit-workflow names under
158
- * `.agents/workflows/audit-*.md`. Story #3939 broadened the routing so every
159
- * high-risk REQUIRED axis maps to a lens rather than leaving three of them
160
- * (`data-migration`, `destructive-mutation`, `billing`) routing nothing:
161
- *
162
- * - `security` → `audit-security` (auth/secret boundary)
163
- * - `public-api` → `audit-architecture` (the canonical
164
- * architectural axis; a breaking public surface)
165
- * - `data-migration` → `audit-quality` (migration correctness +
166
- * regression coverage)
167
- * - `destructive-mutation` → `audit-security` (irreversible mutation is
168
- * an auth/abuse boundary; co-routes with
169
- * `security`, de-duplicated)
170
- * - `billing` → `audit-privacy` (money + the PII/consent
171
- * surface that travels with it)
172
- * - `critical-workflow` → `audit-quality` (the load-bearing path
173
- * warrants the deepest coverage pass)
174
- *
175
- * The `visible-behavior` axis intentionally routes NO lens: it forces the
176
- * acceptance-spec disposition at plan time and no audit lens maps cleanly to
177
- * it. Any other axis (or a low/medium-risk axis) contributes no lens.
178
- *
179
- * Every key here MUST be a value in the `axis` enum of
180
- * `.agents/schemas/risk-verdict.schema.json` — the verdict-derived envelope
181
- * can only ever carry schema-valid axes, so a key absent from that enum is
182
- * unreachable dead routing (Story #3889 removed the unreachable
183
- * `architecture` key; the architectural axis is `public-api`).
184
- */
185
- const AXIS_TO_LENS = Object.freeze({
186
- security: 'audit-security',
187
- 'public-api': 'audit-architecture',
188
- 'data-migration': 'audit-quality',
189
- 'destructive-mutation': 'audit-security',
190
- billing: 'audit-privacy',
191
- 'critical-workflow': 'audit-quality',
192
- });
193
-
194
- /**
195
- * Stable output order for routed lenses so the lens list is deterministic
196
- * regardless of axis ordering in the verdict. Every lens any axis can route
197
- * appears here exactly once; `resolveAuditLenses` filters this canonical
198
- * order down to the matched set (Story #3939).
199
- */
200
- const LENS_ORDER = Object.freeze([
201
- 'audit-security',
202
- 'audit-architecture',
203
- 'audit-quality',
204
- 'audit-privacy',
205
- ]);
206
-
207
- /**
208
- * Resolve the set of post-delivery audit lenses a judged risk envelope routes.
209
- *
210
- * High-risk axes map to their audit lens via {@link AXIS_TO_LENS}; only axes
211
- * judged `high` contribute (a `low`/`medium` axis carries no lens). The result
212
- * is de-duplicated and stably ordered by {@link LENS_ORDER} so an envelope
213
- * listing the `public-api` axis more than once routes `['audit-architecture']`
214
- * once, not twice — and two distinct axes routing the same lens (e.g.
215
- * `security` + `destructive-mutation` both → `audit-security`) collapse to a
216
- * single entry. A low-risk envelope — or any envelope with no high-risk routed
217
- * axis — resolves to an empty array (no lens beyond the existing baseline
218
- * gates).
219
- *
220
- * Pure function — no I/O, no side effects.
221
- *
222
- * @param {{ axes?: Array<{ axis?: string, level?: string }> }} [envelope]
223
- * @returns {string[]} Ordered, de-duplicated audit-lens identifiers.
224
- */
225
- export function resolveAuditLenses(envelope = {}) {
226
- const axes = Array.isArray(envelope?.axes) ? envelope.axes : [];
227
- const matched = new Set();
228
- for (const entry of axes) {
229
- if (!entry || entry.level !== 'high') continue;
230
- const lens = AXIS_TO_LENS[entry.axis];
231
- if (lens) matched.add(lens);
232
- }
233
- return LENS_ORDER.filter((lens) => matched.has(lens));
234
- }
235
-
236
- /**
237
- * Compose the Epic-close (gate3) lens roster from the change-set selection
238
- * plus every risk-routed lens.
239
- *
240
- * STOPGAP (post-#4405 review finding): Story #4412 excluded every
241
- * `local`-tier change-set lens here on the premise that the Story-scope
242
- * local-lens pass (Story #4409) verifies those concerns shift-left. That
243
- * premise does not hold yet — `runLocalLensReview`
244
- * (story-close/phases/code-review.js) materializes lens bodies with no
245
- * `artifactPrefix` (so no content persists) and no consumer acts on its
246
- * result, which left change-set lenses (security, privacy, performance,
247
- * quality, …) executed by NO reviewer at ANY tier. Local-tier lenses are
248
- * therefore KEPT at Epic close until the story-scope pass has a real
249
- * consumer; re-enable the exclusion then (tracked as a follow-up issue).
250
- * The write-time maker checklists (#4410) are advisory self-checks, not
251
- * verification. The `resolveLensTierFn` seam is retained so the
252
- * re-exclusion is a one-line revert.
253
- *
254
- * The two inputs mirror the `epic-audit-prepare.js` envelope:
255
- * - `changeSetAudits` — the raw change-set gate3 selection, kept in full
256
- * (see the stopgap note above).
257
- * - `riskRoutedAudits` — the verdict-routed high-risk lenses plus the
258
- * route-glob navigability lens. Kept in **full**, regardless of tier: a
259
- * high-risk axis (or a route-adding change set) that demands a local-tier
260
- * lens still runs it at Epic close, because that demand is the whole point
261
- * of risk routing.
262
- *
263
- * De-duplicated and order-preserving (kept change-set lenses first, then the
264
- * risk-routed extras). Pure over the injected `resolveLensTierFn` seam; the
265
- * default resolver reads `audit-rules.json` from disk.
266
- *
267
- * @param {{
268
- * changeSetAudits?: string[],
269
- * riskRoutedAudits?: string[],
270
- * resolveLensTierFn?: typeof resolveLensTier,
271
- * }} [params]
272
- * @returns {string[]} The Epic-close roster (all change-set tiers +
273
- * risk-routed; local-tier exclusion suspended per the stopgap above).
274
- */
275
- export function selectEpicCloseLenses({
276
- changeSetAudits = [],
277
- riskRoutedAudits = [],
278
- resolveLensTierFn = resolveLensTier,
279
- } = {}) {
280
- const kept = [];
281
- const seen = new Set();
282
- const add = (lens) => {
283
- if (typeof lens !== 'string' || lens.length === 0 || seen.has(lens)) return;
284
- seen.add(lens);
285
- kept.push(lens);
286
- };
287
- for (const lens of Array.isArray(changeSetAudits) ? changeSetAudits : []) {
288
- if (typeof lens !== 'string' || lens.length === 0) continue;
289
- // Stopgap: keep local-tier lenses (see docstring). The tier seam is
290
- // deliberately untouched so restoring `=== 'local' → continue` is a
291
- // one-line revert once the story-scope tier has a real consumer.
292
- void resolveLensTierFn;
293
- add(lens);
294
- }
295
- for (const lens of Array.isArray(riskRoutedAudits) ? riskRoutedAudits : []) {
296
- add(lens);
297
- }
298
- return kept;
299
- }
300
-
301
- /**
302
- * Build the post-delivery audit-lens execution plan for a judged risk
303
- * envelope. Each routed lens (see {@link resolveAuditLenses}) is paired with a
304
- * strategy decision from the **existing** `selectAuditStrategy` engine — no new
305
- * audit machinery is introduced. A low-risk envelope resolves to an empty
306
- * `lenses` array and runs no audit beyond the baseline gates (Story #3876).
307
- *
308
- * Pure with respect to the injected `selectAuditStrategyFn` (default is the
309
- * shared dynamic-workflow engine, which is itself pure over its snapshot).
310
- *
311
- * @param {{ axes?: Array<{ axis?: string, level?: string }> }} [envelope]
312
- * @param {{
313
- * snapshot?: object,
314
- * forceStrategy?: ('orchestrated'|'sequential'|null),
315
- * selectAuditStrategyFn?: typeof selectAuditStrategy,
316
- * }} [opts]
317
- * @returns {{ lenses: string[], plan: Array<{ lens: string, strategy: string, reason: string, forced: boolean }> }}
318
- */
319
- export function planAuditLenses(envelope = {}, opts = {}) {
320
- const {
321
- snapshot = {},
322
- forceStrategy = null,
323
- selectAuditStrategyFn = selectAuditStrategy,
324
- } = opts;
325
- const lenses = resolveAuditLenses(envelope);
326
- const plan = lenses.map((lens) => {
327
- const decision = selectAuditStrategyFn({ snapshot, forceStrategy });
328
- return {
329
- lens,
330
- strategy: decision.strategy,
331
- reason: decision.reason,
332
- forced: decision.forced,
333
- };
334
- });
335
- return { lenses, plan };
336
- }
337
-
338
- /**
339
- * Build the `code-review.end` payload from the normalized result envelope.
340
- * The runner result may carry a `report` field (full markdown body) which
341
- * is NOT included in the lifecycle payload: the schema's
342
- * `additionalProperties: false` forbids it, and the body can carry inline
343
- * severity counts that drift from the structured `severity` field. The
344
- * lifecycle ledger is the structured surface; the report is GitHub's
345
- * surface (posted via the structured comment).
346
- *
347
- * Story #2839: `epicId` is preserved verbatim in the lifecycle payload so
348
- * the `code-review.end` schema (additionalProperties: false, requires
349
- * `epicId`) stays unchanged. Story-scope invocations never reach this
350
- * helper — `runCodeReview` short-circuits the bus emit for `scope: 'story'`
351
- * because story-scope review sits outside the Epic lifecycle ledger.
352
- */
353
- function buildCodeReviewEndPayload({ epicId, result, durationMs }) {
354
- const payload = {
355
- epicId,
356
- status: result.status,
357
- };
358
- if (result.severity && typeof result.severity === 'object') {
359
- payload.severity = {
360
- critical: result.severity.critical ?? 0,
361
- high: result.severity.high ?? 0,
362
- medium: result.severity.medium ?? 0,
363
- suggestion: result.severity.suggestion ?? 0,
364
- };
365
- }
366
- if (typeof result.halted === 'boolean') payload.halted = result.halted;
367
- if (typeof result.posted === 'boolean') payload.posted = result.posted;
368
- if (Number.isFinite(durationMs) && durationMs >= 0) {
369
- payload.durationMs = Math.floor(durationMs);
370
- }
371
- return payload;
372
- }
373
-
374
98
  /**
375
99
  * Resolve the project base branch fallback used when a caller omits
376
100
  * `baseRef`.
377
101
  */
378
102
  function resolveConfigBase(config) {
379
- return (
380
- config?.project?.baseBranch ?? config?.agentSettings?.baseBranch ?? 'main'
381
- );
103
+ return config?.project?.baseBranch ?? 'main';
382
104
  }
383
105
 
384
106
  /** Positive-integer override, else the supplied default. */
@@ -398,7 +120,6 @@ function resolveCommentTargetId(commentTargetId, fallback) {
398
120
  * baseRef: string,
399
121
  * headRef: string,
400
122
  * commentTargetId: number,
401
- * epicIdForLedger: null,
402
123
  * }}
403
124
  */
404
125
  function resolveStoryScope(opts, config) {
@@ -421,53 +142,16 @@ function resolveStoryScope(opts, config) {
421
142
  opts.commentTargetId,
422
143
  opts.ticketId,
423
144
  ),
424
- epicIdForLedger: null,
425
145
  };
426
146
  }
427
147
 
428
148
  /**
429
- * Resolve the Epic-scope envelope from the parameterized
430
- * `{ scope: 'epic', ticketId, baseRef, headRef, commentTargetId }` shape.
431
- * `headRef` defaults to `epic/<ticketId>` and `baseRef` to the project
432
- * base branch.
433
- *
434
- * @returns {{
435
- * scope: 'epic',
436
- * ticketId: number,
437
- * baseRef: string,
438
- * headRef: string,
439
- * commentTargetId: number,
440
- * epicIdForLedger: number,
441
- * }}
442
- */
443
- function resolveEpicScope(opts, config) {
444
- if (!Number.isInteger(opts.ticketId) || opts.ticketId <= 0) {
445
- throw new TypeError(
446
- 'runCodeReview: ticketId is required (positive integer) when scope="epic".',
447
- );
448
- }
449
- return {
450
- scope: 'epic',
451
- ticketId: opts.ticketId,
452
- baseRef: opts.baseRef ?? resolveConfigBase(config),
453
- headRef: opts.headRef ?? `epic/${opts.ticketId}`,
454
- commentTargetId: resolveCommentTargetId(
455
- opts.commentTargetId,
456
- opts.ticketId,
457
- ),
458
- epicIdForLedger: opts.ticketId,
459
- };
460
- }
461
-
462
- /**
463
- * Dispatch the parameterized scope envelope
464
- * (`{ scope, ticketId, baseRef, headRef, commentTargetId }`) to the
465
- * matching pure resolver. `scope` defaults to `'epic'`.
149
+ * Resolve the scope envelope
150
+ * (`{ scope, ticketId, baseRef, headRef, commentTargetId }`). v2.0.0
151
+ * removed the Epic tier, so `'story'` is the only scope.
466
152
  */
467
153
  function resolveScopeEnvelope(opts, config) {
468
- return opts.scope === 'story'
469
- ? resolveStoryScope(opts, config)
470
- : resolveEpicScope(opts, config);
154
+ return resolveStoryScope(opts, config);
471
155
  }
472
156
 
473
157
  /**
@@ -485,36 +169,28 @@ function resolveScopeEnvelope(opts, config) {
485
169
  * derived from the `Finding[]` returned by the adapter (no separate
486
170
  * severity field on the runner result).
487
171
  *
488
- * Story #2839 (Epic #2815) — accepts a parameterized scope envelope
489
- * so the standalone Story closer can request a Story-scope review
490
- * against `main`, post the structured findings comment to the PR
491
- * (via `commentTargetId`), and surface critical findings to the
492
- * caller as `halted: true`. Lifecycle bus emits are confined to
493
- * `scope: 'epic'` because the `code-review.end` schema requires
494
- * `epicId` and the ledger only spans Epic lifecycles.
172
+ * Story #2839 (Epic #2815) — the Story closer requests a Story-scope
173
+ * review against `main`, posts the structured findings comment to the PR
174
+ * (via `commentTargetId`), and surfaces critical findings to the caller
175
+ * as `halted: true`.
495
176
  *
496
- * Argument shape (parameterized, Epic or Story):
497
- * `{ scope, ticketId, baseRef, headRef, [commentTargetId],
498
- * provider, bus }`
499
- * `scope` defaults to `'epic'`; `baseRef` defaults to the project base
500
- * branch and (Epic scope only) `headRef` defaults to `epic/<ticketId>`.
501
- * For `scope === 'story'`, `commentTargetId` overrides the post
502
- * target (e.g. PR number) while `ticketId` continues to label the
503
- * rendered header ("Story #N").
177
+ * Argument shape:
178
+ * `{ ticketId, baseRef, headRef, [commentTargetId], provider }`
179
+ * `baseRef` defaults to the project base branch; `headRef` is required.
180
+ * `commentTargetId` overrides the post target (e.g. PR number) while
181
+ * `ticketId` continues to label the rendered header ("Story #N").
504
182
  *
505
183
  * @param {{
506
- * scope?: 'epic'|'story',
184
+ * scope?: 'story',
507
185
  * ticketId: number,
508
186
  * baseRef?: string|null,
509
187
  * headRef?: string|null,
510
188
  * commentTargetId?: number|null,
511
189
  * provider: object,
512
190
  * logger?: { info?: Function, warn?: Function, error?: Function, fatal?: Function, createProgress?: Function },
513
- * planningRisk?: { overallLevel?: ('low'|'medium'|'high'), axes?: Array<{ axis?: string, level?: string }> }|null,
191
+ * changedFiles?: string[]|null,
514
192
  * changedFileCount?: number|null,
515
193
  * storyId?: number|null,
516
- * bus?: object|null,
517
- * now?: () => number,
518
194
  * reviewProvider?: { runReview: Function },
519
195
  * gitSpawnFn?: typeof gitSpawn,
520
196
  * resolveConfigFn?: typeof resolveConfig,
@@ -535,44 +211,47 @@ function resolveScopeEnvelope(opts, config) {
535
211
  */
536
212
  /**
537
213
  * Resolve the human-facing provider name from the resolved code-review
538
- * config. Chain configs render as `chain[a,b,...]`; a single-provider
539
- * config renders its `provider` string; everything else falls back to
540
- * `'native'`. Story #4075 extracted from `runCodeReview`.
214
+ * config. Multi-entry chains render as `chain[a,b,...]`; a single-entry
215
+ * chain (including the unset/empty default) renders that entry's name;
216
+ * everything else falls back to `'native'`.
541
217
  */
542
218
  function resolveProviderName(codeReviewConfig) {
543
- const isChainConfig =
544
- codeReviewConfig &&
545
- Array.isArray(codeReviewConfig.providers) &&
546
- codeReviewConfig.providers.length > 0;
547
- if (isChainConfig) {
548
- return `chain[${codeReviewConfig.providers
549
- .map((p) => p?.name ?? '?')
550
- .join(',')}]`;
219
+ const providers =
220
+ codeReviewConfig && Array.isArray(codeReviewConfig.providers)
221
+ ? codeReviewConfig.providers
222
+ : [];
223
+ if (providers.length === 1) {
224
+ return providers[0]?.name ?? 'native';
551
225
  }
552
- return (
553
- (codeReviewConfig && typeof codeReviewConfig.provider === 'string'
554
- ? codeReviewConfig.provider
555
- : null) ?? 'native'
556
- );
226
+ if (providers.length > 1) {
227
+ return `chain[${providers.map((p) => p?.name ?? '?').join(',')}]`;
228
+ }
229
+ return 'native';
557
230
  }
558
231
 
559
232
  /**
560
233
  * Build the provider `runReview` input, resolving the review depth from the
561
- * judged risk envelope's `overallLevel` and the mechanical changed-file
562
- * count of the diff under review (Story #3876 / #3938). The depth is an
563
- * input-only signal (light → standard → deep) and never touches the output
564
- * envelope or the posted comment. Absent risk envelope + unknown width →
565
- * `standard`. Story #4075 — extracted from `runCodeReview`.
234
+ * diff under review: its changed files derive the change level (sensitive path
235
+ * touched or not Story #4542) and their count supplies the width. The depth
236
+ * is an input-only signal (light → standard → deep) and never touches the
237
+ * output envelope or the posted comment. An unenumerable diff `standard`.
238
+ * Story #4075 — extracted from `runCodeReview`.
566
239
  */
567
- function buildReviewInput({ opts, config, scope, ticketId, baseRef, headRef }) {
240
+ function buildReviewInput({ opts, scope, ticketId, baseRef, headRef }) {
241
+ const changedFiles = Array.isArray(opts.changedFiles)
242
+ ? opts.changedFiles
243
+ : listChangedFiles({ baseRef, headRef, gitSpawnFn: opts.gitSpawnFn });
568
244
  const changedFileCount =
569
245
  typeof opts.changedFileCount === 'number'
570
246
  ? opts.changedFileCount
571
- : countChangedFiles({ baseRef, headRef, gitSpawnFn: opts.gitSpawnFn });
247
+ : (changedFiles?.length ?? null);
248
+ // v2 Stage 2: review depth uses DEFAULT_DIFF_WIDTH (mechanical file count
249
+ // of the diff under review). It is deliberately decoupled from the
250
+ // planning model-capacity advisory (`DEFAULT_MODEL_CAPACITY`).
251
+ const { level } = deriveChangeLevel({ changedFiles });
572
252
  const depth = resolveDepth({
573
- overallLevel: opts.planningRisk?.overallLevel,
253
+ derivedLevel: level,
574
254
  changedFileCount,
575
- sizing: resolveTaskSizing(config),
576
255
  });
577
256
  return {
578
257
  scope,
@@ -665,12 +344,11 @@ async function executeReviewPipeline({ opts, config, envelope }) {
665
344
  injectedReviewProvider ?? createReviewProviderFn(codeReviewConfig);
666
345
 
667
346
  logger?.info?.(
668
- `[code-review] Running ${providerName} adapter for ${scope === 'epic' ? 'Epic' : 'Story'} #${ticketId} (${baseRef}...${headRef})...`,
347
+ `[code-review] Running ${providerName} adapter for Story #${ticketId} (${baseRef}...${headRef})...`,
669
348
  );
670
349
 
671
350
  const reviewInput = buildReviewInput({
672
351
  opts,
673
- config,
674
352
  scope,
675
353
  ticketId,
676
354
  baseRef,
@@ -725,49 +403,13 @@ async function executeReviewPipeline({ opts, config, envelope }) {
725
403
  }
726
404
 
727
405
  export async function runCodeReview(opts = {}) {
728
- const { bus, now = Date.now, resolveConfigFn = resolveConfig } = opts;
406
+ const { resolveConfigFn = resolveConfig } = opts;
729
407
 
730
408
  const config = resolveConfigFn();
731
409
  const envelope = resolveScopeEnvelope(opts, config);
732
- const { scope } = envelope;
733
-
734
- // Epic-scope lifecycle ledger requires `bus`; Story-scope sits outside
735
- // the Epic lifecycle so the bus is optional there. A caller without a
736
- // bus on the Story path still gets the full review semantics — only the
737
- // `code-review.start`/`.end` events are suppressed.
738
- if (scope === 'epic' && (!bus || typeof bus.emit !== 'function')) {
739
- throw new TypeError('runCodeReview: bus is required (object with emit()).');
740
- }
741
- const ledgerEnabled =
742
- scope === 'epic' && bus && typeof bus.emit === 'function';
743
-
744
- const startedAt = typeof now === 'function' ? now() : Date.now();
745
- // Emit the matched `code-review.end` boundary; the ledger must always
746
- // show a start/end pair (even on adapter throw, where `result` is the
747
- // canonical `{ status: 'invalid' }`).
748
- const emitEnd = async (result) => {
749
- if (!ledgerEnabled) return;
750
- const endedAt = typeof now === 'function' ? now() : Date.now();
751
- await bus.emit(
752
- 'code-review.end',
753
- buildCodeReviewEndPayload({
754
- epicId: envelope.epicIdForLedger,
755
- result,
756
- durationMs: Math.max(0, endedAt - startedAt),
757
- }),
758
- );
759
- };
760
-
761
- if (ledgerEnabled) {
762
- await bus.emit('code-review.start', { epicId: envelope.epicIdForLedger });
763
- }
764
410
 
765
- try {
766
- const result = await executeReviewPipeline({ opts, config, envelope });
767
- await emitEnd(result);
768
- return result;
769
- } catch (err) {
770
- await emitEnd({ status: 'invalid' });
771
- throw err;
772
- }
411
+ // No lifecycle-bus emit: the `code-review.start` / `.end` ledger pair was
412
+ // Epic-scoped (its schema requires `epicId`), and v2.0.0 removed the Epic
413
+ // tier. Story-scope review sits outside the lifecycle ledger entirely.
414
+ return executeReviewPipeline({ opts, config, envelope });
773
415
  }
@@ -28,7 +28,7 @@
28
28
  * Located at `lib/orchestration/column-sync.js` (Story #2548) so the
29
29
  * canonical state mutator `transitionTicketState`
30
30
  * (`lib/orchestration/ticketing/state.js`) can invoke it without an
31
- * upward dependency into `epic-runner/`. Prior to #2548 this module
31
+ * upward dependency into the deleted `epic-runner/` tree. Prior to #2548 this module
32
32
  * lived under `epic-runner/` and was only wired against the Epic
33
33
  * ticket — Stories and Tasks never updated their Projects v2 Status
34
34
  * column on label flips.