mandrel 1.93.0 → 2.0.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 (463) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/acceptance-critic.md +129 -0
  3. package/.agents/agents/story-worker.md +161 -0
  4. package/.agents/docs/SDLC.md +489 -1285
  5. package/.agents/docs/agentrc-reference.json +177 -67
  6. package/.agents/docs/configuration.md +108 -136
  7. package/.agents/docs/execution-reference.md +44 -22
  8. package/.agents/docs/quality-gates.md +13 -19
  9. package/.agents/docs/workflows.md +3 -3
  10. package/.agents/instructions.md +107 -108
  11. package/.agents/rules/ci-remediation.md +8 -12
  12. package/.agents/rules/git-conventions-reference.md +224 -0
  13. package/.agents/rules/git-conventions.md +42 -223
  14. package/.agents/rules/security-baseline.md +5 -0
  15. package/.agents/rules/testing-standards.md +106 -13
  16. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  17. package/.agents/schemas/agentrc.schema.json +71 -201
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  20. package/.agents/schemas/risk-verdict.schema.json +0 -13
  21. package/.agents/scripts/acceptance-eval.js +62 -18
  22. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  23. package/.agents/scripts/analyze-execution.js +1 -1
  24. package/.agents/scripts/audit-to-stories.js +7 -7
  25. package/.agents/scripts/boot-sweep.js +1 -1
  26. package/.agents/scripts/check-context-budget.js +62 -5
  27. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  28. package/.agents/scripts/check-prepush-recovery.js +1 -1
  29. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  30. package/.agents/scripts/diagnose-friction.js +0 -6
  31. package/.agents/scripts/lib/Logger.js +6 -10
  32. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  33. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  34. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  35. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  36. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  37. package/.agents/scripts/lib/baselines/reader.js +1 -6
  38. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  39. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  40. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  41. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  42. package/.agents/scripts/lib/checks/index.js +2 -1
  43. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  44. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  45. package/.agents/scripts/lib/cli-args.js +16 -7
  46. package/.agents/scripts/lib/close-validation/gates.js +160 -22
  47. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  48. package/.agents/scripts/lib/config/ci.js +6 -31
  49. package/.agents/scripts/lib/config/delivery-routing.js +103 -0
  50. package/.agents/scripts/lib/config/explain.js +57 -36
  51. package/.agents/scripts/lib/config/limits.js +17 -58
  52. package/.agents/scripts/lib/config/paths.js +0 -2
  53. package/.agents/scripts/lib/config/quality.js +1 -1
  54. package/.agents/scripts/lib/config/runners.js +17 -50
  55. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  56. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  57. package/.agents/scripts/lib/config-resolver.js +3 -8
  58. package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
  59. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
  60. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  61. package/.agents/scripts/lib/dependency-parser.js +3 -2
  62. package/.agents/scripts/lib/doc-tiers.js +39 -4
  63. package/.agents/scripts/lib/duplicate-search.js +211 -41
  64. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  66. package/.agents/scripts/lib/framework-version.js +2 -3
  67. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  68. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  69. package/.agents/scripts/lib/git-utils.js +32 -6
  70. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  71. package/.agents/scripts/lib/label-constants.js +10 -23
  72. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  73. package/.agents/scripts/lib/observability/active-story-env.js +112 -3
  74. package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
  75. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  76. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  77. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  78. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  79. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  80. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  81. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
  82. package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
  83. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  84. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  85. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  86. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  87. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  88. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  89. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  90. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  91. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  92. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  93. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  94. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  95. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  96. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  97. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  98. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  99. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  100. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  102. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  103. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  104. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  105. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  106. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  107. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  108. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
  109. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  110. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  111. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  112. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  113. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  114. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  115. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  116. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  118. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  119. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  120. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  121. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  122. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  124. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  131. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  132. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  134. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  135. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  136. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  137. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  138. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  139. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  140. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  141. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  142. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  143. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  144. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  145. package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
  146. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  147. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  148. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  149. package/.agents/scripts/lib/planning-corpus.js +16 -11
  150. package/.agents/scripts/lib/preflight-runner.js +2 -2
  151. package/.agents/scripts/lib/provider-factory.js +1 -1
  152. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  153. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  154. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  155. package/.agents/scripts/lib/story-adjacency.js +11 -14
  156. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  157. package/.agents/scripts/lib/story-plan.js +2 -4
  158. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  159. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  160. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  161. package/.agents/scripts/lib/validation-evidence.js +1 -1
  162. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  163. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  164. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  165. package/.agents/scripts/lint-issue-body.js +71 -40
  166. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  167. package/.agents/scripts/notify.js +4 -3
  168. package/.agents/scripts/plan-context.js +64 -74
  169. package/.agents/scripts/plan-persist.js +121 -280
  170. package/.agents/scripts/plan-run-epilogue.js +97 -0
  171. package/.agents/scripts/post-structured-comment.js +38 -0
  172. package/.agents/scripts/providers/github/issues.js +17 -33
  173. package/.agents/scripts/providers/github/mappers.js +0 -12
  174. package/.agents/scripts/providers/github/tickets.js +2 -5
  175. package/.agents/scripts/resolve-plan-run.js +117 -0
  176. package/.agents/scripts/signals-view.js +24 -19
  177. package/.agents/scripts/single-story-close.js +11 -14
  178. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  179. package/.agents/scripts/single-story-init.js +29 -20
  180. package/.agents/scripts/stories-wave-tick.js +6 -6
  181. package/.agents/scripts/story-plan.js +26 -47
  182. package/.agents/scripts/sync-claude-agents.js +165 -0
  183. package/.agents/scripts/update-ticket-state.js +37 -15
  184. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  185. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  186. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  187. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  188. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  189. package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
  190. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  191. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  192. package/.agents/skills/skills.index.json +8 -418
  193. package/.agents/starter-agentrc.json +0 -5
  194. package/.agents/templates/agent-protocol.md +9 -10
  195. package/.agents/workflows/audit-architecture.md +3 -3
  196. package/.agents/workflows/audit-clean-code.md +3 -3
  197. package/.agents/workflows/audit-dependencies.md +3 -3
  198. package/.agents/workflows/audit-devops.md +3 -3
  199. package/.agents/workflows/audit-documentation.md +5 -5
  200. package/.agents/workflows/audit-lighthouse.md +3 -3
  201. package/.agents/workflows/audit-navigability.md +3 -2
  202. package/.agents/workflows/audit-performance.md +3 -3
  203. package/.agents/workflows/audit-privacy.md +3 -3
  204. package/.agents/workflows/audit-quality.md +3 -3
  205. package/.agents/workflows/audit-security.md +3 -3
  206. package/.agents/workflows/audit-seo.md +3 -3
  207. package/.agents/workflows/audit-sre.md +3 -3
  208. package/.agents/workflows/audit-to-stories.md +20 -20
  209. package/.agents/workflows/audit-ux-ui.md +3 -3
  210. package/.agents/workflows/deliver.md +122 -131
  211. package/.agents/workflows/git-cleanup.md +3 -4
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
  214. package/.agents/workflows/helpers/code-review.md +70 -193
  215. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  216. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  217. package/.agents/workflows/helpers/diagnose.md +10 -10
  218. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  219. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  220. package/.agents/workflows/helpers/signals.md +16 -16
  221. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  222. package/.agents/workflows/mandrel-update.md +3 -2
  223. package/.agents/workflows/plan.md +112 -145
  224. package/.agents/workflows/qa-assist.md +24 -30
  225. package/.agents/workflows/qa-explore.md +29 -38
  226. package/.agents/workflows/qa-run.md +2 -2
  227. package/README.md +9 -8
  228. package/docs/CHANGELOG.md +46 -0
  229. package/lib/cli/registry.js +95 -0
  230. package/lib/migrations/index.js +6 -5
  231. package/package.json +5 -3
  232. package/.agents/personas/architect.md +0 -113
  233. package/.agents/personas/devops-engineer.md +0 -38
  234. package/.agents/personas/engineer-mobile.md +0 -120
  235. package/.agents/personas/engineer-web.md +0 -111
  236. package/.agents/personas/engineer.md +0 -119
  237. package/.agents/personas/product.md +0 -94
  238. package/.agents/personas/project-manager.md +0 -114
  239. package/.agents/personas/qa-engineer.md +0 -95
  240. package/.agents/personas/refactorer.md +0 -113
  241. package/.agents/personas/security-engineer.md +0 -112
  242. package/.agents/personas/sre.md +0 -86
  243. package/.agents/personas/technical-writer.md +0 -101
  244. package/.agents/personas/ux-designer.md +0 -95
  245. package/.agents/schemas/dispatch-manifest.json +0 -232
  246. package/.agents/schemas/epic-spec.schema.json +0 -153
  247. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  248. package/.agents/scripts/dispatcher.js +0 -295
  249. package/.agents/scripts/epic-audit-prepare.js +0 -497
  250. package/.agents/scripts/epic-audit-recheck.js +0 -274
  251. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  252. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  253. package/.agents/scripts/epic-deliver-prepare.js +0 -590
  254. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  255. package/.agents/scripts/epic-plan-clarity.js +0 -211
  256. package/.agents/scripts/epic-plan-decompose.js +0 -54
  257. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  258. package/.agents/scripts/epic-plan-spec.js +0 -64
  259. package/.agents/scripts/epic-reconcile.js +0 -625
  260. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  261. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  262. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  263. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  264. package/.agents/scripts/lib/config/preflight.js +0 -58
  265. package/.agents/scripts/lib/config/retro.js +0 -77
  266. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  267. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  268. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  269. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
  270. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  271. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  272. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  273. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  274. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  275. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  276. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  277. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  278. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  279. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  280. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  281. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  282. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  283. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  284. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  285. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  286. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  287. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  288. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
  289. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  290. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  291. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  292. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  293. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  294. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  295. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  296. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  297. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  298. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  299. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  300. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  301. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  302. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  303. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  304. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  305. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  306. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  307. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  308. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  309. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  310. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  311. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  313. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
  314. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  315. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  316. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  317. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
  318. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  319. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  320. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  321. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  322. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  323. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  324. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  325. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  326. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  327. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  328. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  329. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  330. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  331. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  332. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  333. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  334. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  335. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  336. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  337. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  338. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  339. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  340. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  341. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  342. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  343. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  344. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  345. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  346. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  347. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  348. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  349. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  350. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  351. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  352. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  353. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  354. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  355. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  356. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  357. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  358. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  359. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  360. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  361. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
  362. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  363. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  364. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  365. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  366. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  367. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  368. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  369. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  370. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  371. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  372. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  373. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  374. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  375. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  376. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  377. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  378. package/.agents/scripts/lib/spec/index.js +0 -36
  379. package/.agents/scripts/lib/spec/loader.js +0 -425
  380. package/.agents/scripts/lib/spec/state.js +0 -208
  381. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  382. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  383. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  384. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  385. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  386. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  387. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  388. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  389. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  390. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  391. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  392. package/.agents/scripts/lifecycle-emit.js +0 -510
  393. package/.agents/scripts/plan-critics.js +0 -199
  394. package/.agents/scripts/retro-run.js +0 -218
  395. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  396. package/.agents/scripts/story-close.js +0 -294
  397. package/.agents/scripts/story-init.js +0 -599
  398. package/.agents/scripts/story-phase.js +0 -369
  399. package/.agents/scripts/wave-tick.js +0 -335
  400. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  401. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  402. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  403. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  404. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  405. package/.agents/skills/core/context-engineering/examples.md +0 -58
  406. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  407. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  408. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  409. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  410. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  411. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  412. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  413. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
  414. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  415. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  416. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  417. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  418. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  419. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  420. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  421. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  422. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  423. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  424. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  425. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  426. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  427. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  428. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  429. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  430. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  431. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  432. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  433. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  434. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  435. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  436. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  437. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  438. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  439. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  440. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  441. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  442. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  443. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  444. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  445. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  446. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  447. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  448. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  449. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  450. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  451. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  452. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
  453. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
  454. package/.agents/workflows/helpers/deliver-epic.md +0 -955
  455. package/.agents/workflows/helpers/deliver-stories.md +0 -440
  456. package/.agents/workflows/helpers/epic-audit.md +0 -189
  457. package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
  458. package/.agents/workflows/helpers/epic-testing.md +0 -125
  459. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  460. package/.agents/workflows/helpers/plan-epic.md +0 -351
  461. package/.agents/workflows/helpers/plan-story.md +0 -251
  462. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  463. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,747 +0,0 @@
1
- /**
2
- * auto-refresh-runner.js — bounded baseline auto-refresh at story-close
3
- * (Story #1398, Epic #1386; rerouted to `refreshBaseline()` by Story
4
- * #2205; collapsed onto the single `runRefreshCommit` funnel by Story
5
- * #4017).
6
- *
7
- * Runs *after* `runPreMergeGatesWithAttribution` returns `{ status: 'ok' }`
8
- * and *before* the merge into `epic/<id>`. For each baseline kind
9
- * (maintainability, crap) the runner:
10
- *
11
- * 1. Snapshots the prior on-disk envelope (so cap evaluation can compare
12
- * regenerated rows against the pre-refresh baseline).
13
- * 2. Delegates the refresh → stage → commit sequence to
14
- * `runRefreshCommit()` (`baseline-attribution/phases/refresh-commit.js`)
15
- * — the **single** story-close refresh funnel — injecting a `capCheck`
16
- * that re-reads the refreshed envelope and evaluates the row deltas
17
- * against the configured caps via {@link evaluateAutoRefresh}.
18
- *
19
- * - **Under-cap path** — the funnel emits one canonical commit
20
- * `chore(baselines): refresh <kind> for story-<id>` per kind that
21
- * actually drifted. NO `--amend`, NO `--allow-empty`.
22
- *
23
- * - **Over-cap path** — the funnel restores the kind's baseline file to
24
- * HEAD; the runner appends a single `baseline-refresh-regression`
25
- * friction signal to the per-Story NDJSON and returns
26
- * `{ status: 'refused', ... }`.
27
- *
28
- * - **Skipped paths** — `enabled: false` in `quality.autoRefresh`, or
29
- * no configured kind produced drift. The runner returns
30
- * `{ status: 'skipped', reason }` without touching the branch tip.
31
- *
32
- * Each-kind-once contract (Story #4017): the caller threads the close
33
- * cycle's shared `cycleState` (created in `runGatesAndRefresh`) into the
34
- * funnel, so a kind already refreshed by the gate-failure attribution
35
- * retry (`gate-failure.js` → `runRefreshCommit`) is **not re-scored or
36
- * re-committed** here — the funnel short-circuits on the idempotency
37
- * token. A clean close therefore computes each baseline kind exactly once
38
- * and emits at most one `chore(baselines): refresh` subject per kind.
39
- *
40
- * Dedup contract (AC3 — idempotent re-run):
41
- * On re-entry after an over-cap refusal, the runner scans the per-Story
42
- * `signals.ndjson` for any prior `baseline-refresh-regression` signal
43
- * tagged `source.tool === 'auto-refresh-runner'` and skips the append if
44
- * one exists. The on-disk friction-signal file therefore carries one row
45
- * per (story, refusal-cause) regardless of how many times story-close
46
- * runs.
47
- *
48
- * The runner is dependency-injection-friendly: every git invocation, every
49
- * fs touch, the refresh-service handle, the evaluator, and the signal
50
- * writer are injectable seams. Production callers omit the seams; tests
51
- * inject mocks.
52
- *
53
- * @see .agents/scripts/lib/baselines/refresh-service.js (the unified write path)
54
- * @see ./baseline-attribution/phases/refresh-commit.js (the commit funnel)
55
- */
56
-
57
- import fs from 'node:fs';
58
- import path from 'node:path';
59
- import { loadFile as defaultReaderLoadFile } from '../../baselines/reader.js';
60
- import { refreshBaseline as defaultRefreshBaseline } from '../../baselines/refresh-service.js';
61
- import {
62
- getBaselines as defaultGetBaselines,
63
- getQuality as defaultGetQuality,
64
- } from '../../config-resolver.js';
65
- import { gitSpawn as defaultGitSpawn } from '../../git-utils.js';
66
- import { Logger as DefaultLogger } from '../../Logger.js';
67
- import {
68
- appendSignal as defaultAppendSignal,
69
- forEachLine as defaultForEachLine,
70
- } from '../../observability/signals-writer.js';
71
- import {
72
- buildKindScorer,
73
- computeStoryDiffPaths,
74
- runRefreshCommit as defaultRunRefreshCommit,
75
- } from './baseline-attribution-wiring.js';
76
-
77
- const RUNNER_SOURCE_TOOL = 'auto-refresh-runner';
78
- const FRICTION_CATEGORY = 'baseline-refresh-regression';
79
-
80
- // ---------------------------------------------------------------------------
81
- // Pure delta-cap evaluator (Story #1398; folded in from the deleted
82
- // standalone evaluator module by Story #4017).
83
- // ---------------------------------------------------------------------------
84
-
85
- /**
86
- * Numeric guard — accepts finite numbers only. Strings, NaN, Infinity, null,
87
- * undefined all fail. The evaluator runs against scored rows produced by the
88
- * MI / CRAP scanners (which always emit numeric scores) and baseline rows
89
- * loaded from the on-disk JSON (which JSON-parses numeric fields), so a
90
- * non-finite value here signals upstream corruption — we exclude the row
91
- * conservatively rather than coercing.
92
- */
93
- function isFiniteNumber(value) {
94
- return typeof value === 'number' && Number.isFinite(value);
95
- }
96
-
97
- /**
98
- * Index `baseline.mi` rows by `path` for O(1) lookup. Bad rows (missing
99
- * `path`, non-string `path`, non-finite `mi`) are skipped — their absence
100
- * causes the matching scored row to be treated as "new", which never blocks
101
- * auto-refresh.
102
- */
103
- function indexMiBaseline(rows) {
104
- const byPath = new Map();
105
- if (!Array.isArray(rows)) return byPath;
106
- for (const row of rows) {
107
- if (!row || typeof row.path !== 'string' || row.path.length === 0) continue;
108
- if (!isFiniteNumber(row.mi)) continue;
109
- byPath.set(row.path, row);
110
- }
111
- return byPath;
112
- }
113
-
114
- /**
115
- * Index `baseline.crap` rows by `${file}::${method}` for O(1) lookup.
116
- * `startLine` is *not* part of the key — the scored row may have shifted
117
- * lines vs the baseline (legitimate refactor), and we want the closest match
118
- * by method name. When the same method appears multiple times in the same
119
- * file (e.g. nested helpers), we pick the closest startLine at lookup time.
120
- *
121
- * Bad rows (missing `file`/`method`, non-finite `crap`) are skipped — their
122
- * absence causes the matching scored row to be treated as "new".
123
- */
124
- function indexCrapBaseline(rows) {
125
- const byMethod = new Map();
126
- if (!Array.isArray(rows)) return byMethod;
127
- for (const row of rows) {
128
- if (!row || typeof row.file !== 'string' || row.file.length === 0) {
129
- continue;
130
- }
131
- if (typeof row.method !== 'string' || row.method.length === 0) continue;
132
- if (!isFiniteNumber(row.crap)) continue;
133
- const key = `${row.file}::${row.method}`;
134
- if (!byMethod.has(key)) byMethod.set(key, []);
135
- byMethod.get(key).push(row);
136
- }
137
- return byMethod;
138
- }
139
-
140
- /**
141
- * Pick the closest baseline candidate by `startLine` distance. When the
142
- * scored row's `startLine` is missing or all candidates have missing line
143
- * info, returns the first candidate — matches `baseline-attribution-wiring`'s
144
- * `diffCrapBaselines` resolution policy.
145
- */
146
- function pickClosestBaseline(candidates, scoredStartLine) {
147
- if (!Array.isArray(candidates) || candidates.length === 0) return null;
148
- if (candidates.length === 1) return candidates[0];
149
- const target = isFiniteNumber(scoredStartLine) ? scoredStartLine : 0;
150
- let best = candidates[0];
151
- let bestDist = Math.abs((best.startLine ?? 0) - target);
152
- for (let i = 1; i < candidates.length; i += 1) {
153
- const c = candidates[i];
154
- const dist = Math.abs((c?.startLine ?? 0) - target);
155
- if (dist < bestDist) {
156
- bestDist = dist;
157
- best = c;
158
- }
159
- }
160
- return best;
161
- }
162
-
163
- /**
164
- * Evaluate every MI scored row against the MI cap. Returns the over-cap
165
- * subset; rows under the cap (or new) are simply omitted from the result.
166
- *
167
- * MI is higher-is-better, so drift = baseline.mi − scored.mi. A positive
168
- * drift is a regression; a drift greater than `miDropCap` breaches the cap.
169
- */
170
- function evaluateMiRows({ scoredRows, baselineIndex, miDropCap }) {
171
- const overCap = [];
172
- if (!Array.isArray(scoredRows)) return overCap;
173
- for (const row of scoredRows) {
174
- if (!row || typeof row.path !== 'string' || row.path.length === 0) {
175
- continue;
176
- }
177
- if (!isFiniteNumber(row.mi)) continue;
178
- const baselineRow = baselineIndex.get(row.path);
179
- if (!baselineRow) continue; // new path — never breaches
180
- const drop = baselineRow.mi - row.mi;
181
- if (drop > miDropCap) {
182
- overCap.push({
183
- path: row.path,
184
- baseline: baselineRow.mi,
185
- scored: row.mi,
186
- delta: drop,
187
- });
188
- }
189
- }
190
- return overCap;
191
- }
192
-
193
- /**
194
- * Evaluate every CRAP scored row against the CRAP cap. Returns the over-cap
195
- * subset; rows under the cap (or new) are simply omitted from the result.
196
- *
197
- * CRAP is lower-is-better, so jump = scored.crap − baseline.crap. A positive
198
- * jump is a regression; a jump greater than `crapJumpCap` breaches the cap.
199
- */
200
- function evaluateCrapRows({ scoredRows, baselineIndex, crapJumpCap }) {
201
- const overCap = [];
202
- if (!Array.isArray(scoredRows)) return overCap;
203
- for (const row of scoredRows) {
204
- if (!row || typeof row.file !== 'string' || row.file.length === 0) {
205
- continue;
206
- }
207
- if (typeof row.method !== 'string' || row.method.length === 0) continue;
208
- if (!isFiniteNumber(row.crap)) continue;
209
- const candidates = baselineIndex.get(`${row.file}::${row.method}`);
210
- const baselineRow = pickClosestBaseline(candidates, row.startLine);
211
- if (!baselineRow) continue; // new method — never breaches
212
- const jump = row.crap - baselineRow.crap;
213
- if (jump > crapJumpCap) {
214
- overCap.push({
215
- file: row.file,
216
- method: row.method,
217
- startLine: row.startLine,
218
- baseline: baselineRow.crap,
219
- scored: row.crap,
220
- delta: jump,
221
- });
222
- }
223
- }
224
- return overCap;
225
- }
226
-
227
- /**
228
- * Build the human-readable refusal reasons array. Stable formatting so the
229
- * friction-signal renderer (and unit tests) can pin the strings exactly.
230
- *
231
- * Each reason names the kind, the file/path/method, and the absolute delta
232
- * vs the cap. Numbers are formatted to 3 decimal places to match the
233
- * baseline JSON's float precision without trailing-zero noise.
234
- */
235
- function buildRefusalReasons({ miOverCap, crapOverCap, caps }) {
236
- const reasons = [];
237
- for (const r of miOverCap) {
238
- reasons.push(
239
- `MI drop ${r.delta.toFixed(3)} > cap ${caps.miDropCap} on ${r.path} (baseline ${r.baseline.toFixed(3)} → scored ${r.scored.toFixed(3)})`,
240
- );
241
- }
242
- for (const r of crapOverCap) {
243
- reasons.push(
244
- `CRAP jump ${r.delta.toFixed(3)} > cap ${caps.crapJumpCap} on ${r.file}::${r.method} (baseline ${r.baseline.toFixed(3)} → scored ${r.scored.toFixed(3)})`,
245
- );
246
- }
247
- return reasons;
248
- }
249
-
250
- /**
251
- * Pure delta-cap evaluator. Decides whether the regenerated rows can be
252
- * silently committed (under-cap) or whether the close must refuse the
253
- * refresh and surface a `baseline-refresh-regression` friction signal
254
- * (over-cap).
255
- *
256
- * Cap semantics:
257
- *
258
- * - MI is "higher is better". A *drop* (baseline.mi − scored.mi) greater
259
- * than `miDropCap` breaches the cap. Improvements never breach.
260
- * - CRAP is "lower is better". A *jump* (scored.crap − baseline.crap)
261
- * greater than `crapJumpCap` breaches the cap. Improvements never
262
- * breach.
263
- * - Equality at the cap (delta === cap) is *under* the cap — the cap is
264
- * the maximum allowed delta, not the strict maximum.
265
- * - Missing baseline rows (path/method new in the scored set) never push
266
- * `canAutoRefresh` to `false` and are not surfaced in the over-cap
267
- * arrays.
268
- *
269
- * @param {object} input
270
- * @param {{
271
- * mi?: Array<{ path: string, mi: number }>,
272
- * crap?: Array<{ file: string, method: string, startLine?: number, crap: number }>,
273
- * }} input.scoredRows Just-regenerated rows for the Story diff.
274
- * @param {{
275
- * mi?: Array<{ path: string, mi: number }>,
276
- * crap?: Array<{ file: string, method: string, startLine?: number, crap: number }>,
277
- * }} input.baseline Previously committed rows.
278
- * @param {{ miDropCap: number, crapJumpCap: number }} input.caps
279
- * Bounded delta caps (defaults: miDropCap=1.5, crapJumpCap=5 — see
280
- * `.agents/docs/agentrc-reference.json` under `delivery.quality.autoRefresh`).
281
- * @returns {{
282
- * canAutoRefresh: boolean,
283
- * miOverCap: Array<{ path: string, baseline: number, scored: number, delta: number }>,
284
- * crapOverCap: Array<{ file: string, method: string, startLine?: number, baseline: number, scored: number, delta: number }>,
285
- * refusalReasons: string[],
286
- * }}
287
- */
288
- export function evaluateAutoRefresh({
289
- scoredRows = {},
290
- baseline = {},
291
- caps,
292
- } = {}) {
293
- if (
294
- !caps ||
295
- !isFiniteNumber(caps.miDropCap) ||
296
- !isFiniteNumber(caps.crapJumpCap)
297
- ) {
298
- throw new TypeError(
299
- 'evaluateAutoRefresh: caps.{miDropCap,crapJumpCap} must be finite numbers',
300
- );
301
- }
302
-
303
- const miBaselineIdx = indexMiBaseline(baseline?.mi);
304
- const crapBaselineIdx = indexCrapBaseline(baseline?.crap);
305
-
306
- const miOverCap = evaluateMiRows({
307
- scoredRows: scoredRows?.mi,
308
- baselineIndex: miBaselineIdx,
309
- miDropCap: caps.miDropCap,
310
- });
311
- const crapOverCap = evaluateCrapRows({
312
- scoredRows: scoredRows?.crap,
313
- baselineIndex: crapBaselineIdx,
314
- crapJumpCap: caps.crapJumpCap,
315
- });
316
-
317
- const canAutoRefresh = miOverCap.length === 0 && crapOverCap.length === 0;
318
- const refusalReasons = canAutoRefresh
319
- ? []
320
- : buildRefusalReasons({ miOverCap, crapOverCap, caps });
321
-
322
- return { canAutoRefresh, miOverCap, crapOverCap, refusalReasons };
323
- }
324
-
325
- // ---------------------------------------------------------------------------
326
- // Runner plumbing
327
- // ---------------------------------------------------------------------------
328
-
329
- /**
330
- * Load + parse the baseline envelope at `absPath` via the injected
331
- * reader. Returns `null` when the file is missing, unreadable, or fails
332
- * schema validation — the caller treats null as "no prior, every row is
333
- * new" (the cap evaluator handles missing-prior gracefully).
334
- */
335
- function readEnvelope({ absPath, kind, readerLoadFile }) {
336
- if (typeof absPath !== 'string' || absPath.length === 0) return null;
337
- try {
338
- const parsed = readerLoadFile(absPath, { kind });
339
- if (!parsed || !Array.isArray(parsed.rows)) return null;
340
- return { rows: parsed.rows };
341
- } catch {
342
- return null;
343
- }
344
- }
345
-
346
- /**
347
- * Adapt the writer's CRAP row shape (`{path, method, startLine, crap}`) to
348
- * the evaluator's expectation (`{file, method, startLine, crap}`). The MI
349
- * evaluator already keys on `path`, so no adapter is required for MI rows.
350
- *
351
- * Pure.
352
- */
353
- function adaptCrapRowsForEvaluator(rows) {
354
- return (rows ?? []).map((row) => {
355
- if (!row || typeof row !== 'object') return row;
356
- const { path: p, ...rest } = row;
357
- return typeof p === 'string' ? { ...rest, file: p } : { ...rest };
358
- });
359
- }
360
-
361
- /**
362
- * Filter rows to those whose path/file is in the Story's diff footprint.
363
- * Empty `storyDiffPaths` returns the input unchanged so interactive
364
- * re-runs (`story-close --skip-validation`) on already-merged branches
365
- * still evaluate every row.
366
- */
367
- function filterToStoryDiff({ miRows, crapRows, storyDiffPaths }) {
368
- if (!Array.isArray(storyDiffPaths) || storyDiffPaths.length === 0) {
369
- return { mi: miRows ?? [], crap: crapRows ?? [] };
370
- }
371
- const scope = new Set(storyDiffPaths);
372
- const mi = (miRows ?? []).filter((r) => scope.has(r.path));
373
- const crap = (crapRows ?? []).filter((r) => scope.has(r.file));
374
- return { mi, crap };
375
- }
376
-
377
- /**
378
- * Check whether a `baseline-refresh-regression` signal tagged with the
379
- * runner's `emitter.tool === 'auto-refresh-runner'` already exists in the
380
- * Story's signals stream. Backs the AC3 idempotent-re-run contract.
381
- */
382
- async function priorRefusalSignalExists({
383
- epicId,
384
- storyId,
385
- forEachLine = defaultForEachLine,
386
- }) {
387
- let found = false;
388
- await forEachLine(epicId, storyId, (record) => {
389
- if (
390
- record &&
391
- typeof record === 'object' &&
392
- record.kind === 'friction' &&
393
- record.category === FRICTION_CATEGORY &&
394
- record?.emitter?.tool === RUNNER_SOURCE_TOOL
395
- ) {
396
- found = true;
397
- }
398
- });
399
- return found;
400
- }
401
-
402
- /**
403
- * Compose the friction-signal record. Stable shape so the analyzer +
404
- * `diagnose-friction` pattern-matchers can pin against fixed inputs.
405
- */
406
- function buildRefusalSignal({
407
- epicId,
408
- storyId,
409
- miOverCap,
410
- crapOverCap,
411
- refusalReasons,
412
- caps,
413
- }) {
414
- return {
415
- kind: 'friction',
416
- ts: new Date().toISOString(),
417
- epicId,
418
- storyId,
419
- category: FRICTION_CATEGORY,
420
- emitter: { tool: RUNNER_SOURCE_TOOL },
421
- details: {
422
- message: `Auto-refresh refused: ${refusalReasons.length} row(s) breach configured caps (miDropCap=${caps.miDropCap}, crapJumpCap=${caps.crapJumpCap}).`,
423
- },
424
- refusalReasons,
425
- miOverCap,
426
- crapOverCap,
427
- caps: { miDropCap: caps.miDropCap, crapJumpCap: caps.crapJumpCap },
428
- };
429
- }
430
-
431
- function resolveBaselineAbs(cwd, p) {
432
- if (typeof p !== 'string' || p.length === 0) return null;
433
- return path.isAbsolute(p) ? p : path.resolve(cwd, p);
434
- }
435
-
436
- async function probeDedup({ epicId, storyId, forEachLine, logger }) {
437
- try {
438
- return await priorRefusalSignalExists({ epicId, storyId, forEachLine });
439
- } catch (err) {
440
- logger.warn?.(
441
- `[auto-refresh-runner] dedup probe failed: ${err?.message ?? err}`,
442
- );
443
- return false;
444
- }
445
- }
446
-
447
- async function maybeAppendRefusalSignal({
448
- dedup,
449
- epicId,
450
- storyId,
451
- verdict,
452
- caps,
453
- appendSignal,
454
- config,
455
- logger,
456
- }) {
457
- if (dedup) return false;
458
- const signal = buildRefusalSignal({
459
- epicId,
460
- storyId,
461
- miOverCap: verdict.miOverCap,
462
- crapOverCap: verdict.crapOverCap,
463
- refusalReasons: verdict.refusalReasons,
464
- caps,
465
- });
466
- try {
467
- return await appendSignal({ epicId, storyId, signal, config });
468
- } catch (err) {
469
- logger.warn?.(
470
- `[auto-refresh-runner] friction signal append failed: ${err?.message ?? err}`,
471
- );
472
- return false;
473
- }
474
- }
475
-
476
- function resolveAutoRefreshDeps(deps) {
477
- return {
478
- logger: deps.logger ?? DefaultLogger,
479
- getQuality: deps.getQuality ?? defaultGetQuality,
480
- getBaselines: deps.getBaselines ?? defaultGetBaselines,
481
- evaluateAutoRefresh: deps.evaluateAutoRefresh ?? evaluateAutoRefresh,
482
- refreshBaseline: deps.refreshBaseline ?? defaultRefreshBaseline,
483
- scorerBuilder: deps.scorerBuilder ?? buildKindScorer,
484
- runRefreshCommit: deps.runRefreshCommit ?? defaultRunRefreshCommit,
485
- gitRunner: deps.gitRunner ?? { gitSpawn: defaultGitSpawn },
486
- fsImpl: deps.fsImpl ?? fs,
487
- appendSignal: deps.appendSignal ?? defaultAppendSignal,
488
- forEachLine: deps.forEachLine ?? defaultForEachLine,
489
- computeDiffPaths: deps.computeStoryDiffPaths ?? computeStoryDiffPaths,
490
- readerLoadFile: deps.readerLoadFile ?? defaultReaderLoadFile,
491
- };
492
- }
493
-
494
- /**
495
- * Build the per-kind `capCheck` closure the funnel invokes after drift is
496
- * staged and before the commit lands. Re-reads the refreshed envelope,
497
- * narrows to the Story diff (unless `quality.autoRefresh.scope === 'full'`),
498
- * and evaluates the single kind's rows against the configured caps with the
499
- * prior (pre-refresh) snapshot as the baseline.
500
- */
501
- function buildCapCheck({
502
- kind,
503
- priorEnv,
504
- autoRefresh,
505
- caps,
506
- cwd,
507
- epicBranch,
508
- storyBranch,
509
- evaluate,
510
- gitRunner,
511
- computeDiffPaths,
512
- readerLoadFile,
513
- }) {
514
- return ({ writePath }) => {
515
- const finalEnv = readEnvelope({ absPath: writePath, kind, readerLoadFile });
516
- const isMi = kind === 'maintainability';
517
- const finalRows = isMi
518
- ? (finalEnv?.rows ?? [])
519
- : adaptCrapRowsForEvaluator(finalEnv?.rows ?? []);
520
- const priorRows = isMi
521
- ? (priorEnv?.rows ?? [])
522
- : adaptCrapRowsForEvaluator(priorEnv?.rows ?? []);
523
-
524
- let scoped;
525
- if ((autoRefresh.scope ?? 'diff') === 'full') {
526
- scoped = isMi ? { mi: finalRows } : { crap: finalRows };
527
- } else {
528
- const storyDiffPaths = computeDiffPaths({
529
- cwd,
530
- epicBranch,
531
- storyBranch,
532
- gitRunner,
533
- });
534
- const filtered = filterToStoryDiff({
535
- miRows: isMi ? finalRows : [],
536
- crapRows: isMi ? [] : finalRows,
537
- storyDiffPaths,
538
- });
539
- scoped = isMi ? { mi: filtered.mi } : { crap: filtered.crap };
540
- }
541
-
542
- return evaluate({
543
- scoredRows: scoped,
544
- baseline: isMi ? { mi: priorRows } : { crap: priorRows },
545
- caps,
546
- });
547
- };
548
- }
549
-
550
- /**
551
- * Map a funnel failure string back onto the runner's historical failure
552
- * vocabulary so `phases/refresh.js` keeps logging the same reason labels.
553
- */
554
- function classifyFunnelError(error) {
555
- return typeof error === 'string' && error.startsWith('refreshBaseline(')
556
- ? 'refresh-service-threw'
557
- : 'commit-failed';
558
- }
559
-
560
- /**
561
- * Aggregate per-kind refused verdicts into the single refusal envelope the
562
- * close pipeline consumes, appending the friction signal (dedup-aware,
563
- * AC3) as the publish step. The funnel already rolled the refused kinds'
564
- * files back to HEAD.
565
- */
566
- async function publishRefusal({
567
- refusedVerdicts,
568
- caps,
569
- epicId,
570
- storyId,
571
- appendSignal,
572
- forEachLine,
573
- config,
574
- logger,
575
- }) {
576
- const verdict = {
577
- miOverCap: refusedVerdicts.flatMap((v) => v.miOverCap ?? []),
578
- crapOverCap: refusedVerdicts.flatMap((v) => v.crapOverCap ?? []),
579
- refusalReasons: refusedVerdicts.flatMap((v) => v.refusalReasons ?? []),
580
- };
581
- const dedup = await probeDedup({ epicId, storyId, forEachLine, logger });
582
- const signalAppended = await maybeAppendRefusalSignal({
583
- dedup,
584
- epicId,
585
- storyId,
586
- verdict,
587
- caps,
588
- appendSignal,
589
- config,
590
- logger,
591
- });
592
- logger.info?.(
593
- `[auto-refresh-runner] refused — ${verdict.refusalReasons.length} cap breach(es); friction signal ${dedup ? 'already present (dedup)' : signalAppended ? 'appended' : 'append failed'}.`,
594
- );
595
- return {
596
- status: 'refused',
597
- refusalReasons: verdict.refusalReasons,
598
- signalAppended,
599
- dedup,
600
- miOverCap: verdict.miOverCap,
601
- crapOverCap: verdict.crapOverCap,
602
- };
603
- }
604
-
605
- /**
606
- * Bounded baseline auto-refresh. Delegates the per-kind refresh → stage →
607
- * commit mechanics to the single `runRefreshCommit` funnel; this function
608
- * owns only the config gating, the prior-envelope snapshot, the cap-check
609
- * closure, and the refusal publication.
610
- *
611
- * @param {object} args
612
- * @param {{ refreshedKinds?: Set<string>, lastRefreshSha?: string|null } | null} [args.cycleState]
613
- * The close cycle's shared idempotency token (Story #4017). When the
614
- * gate-failure attribution retry already refreshed a kind this cycle,
615
- * the funnel short-circuits and the kind is not re-scored here.
616
- * @returns {Promise<
617
- * | { status: 'committed', sha: string, files: string[], committed: Array<{ kind: string, sha: string }> }
618
- * | { status: 'refused', refusalReasons: string[], signalAppended: boolean, dedup: boolean, miOverCap: Array, crapOverCap: Array }
619
- * | { status: 'skipped', reason: string }
620
- * | { status: 'failed', reason: string, detail?: string }
621
- * >}
622
- */
623
- export async function runAutoRefresh({
624
- storyId,
625
- epicId,
626
- cwd,
627
- epicBranch,
628
- storyBranch,
629
- config,
630
- cycleState = null,
631
- deps = {},
632
- } = {}) {
633
- const resolved = resolveAutoRefreshDeps(deps);
634
- const {
635
- logger,
636
- getQuality,
637
- getBaselines,
638
- evaluateAutoRefresh: evaluate,
639
- refreshBaseline,
640
- scorerBuilder,
641
- runRefreshCommit,
642
- gitRunner,
643
- fsImpl,
644
- appendSignal,
645
- forEachLine,
646
- computeDiffPaths,
647
- readerLoadFile,
648
- } = resolved;
649
-
650
- const autoRefresh = getQuality(config)?.autoRefresh;
651
- if (!autoRefresh || autoRefresh.enabled === false) {
652
- return { status: 'skipped', reason: 'disabled' };
653
- }
654
- const caps = {
655
- miDropCap: autoRefresh.miDropCap,
656
- crapJumpCap: autoRefresh.crapJumpCap,
657
- };
658
-
659
- const baselines = getBaselines(config);
660
- const kinds = [
661
- {
662
- kind: 'maintainability',
663
- abs: resolveBaselineAbs(cwd, baselines?.maintainability?.path),
664
- },
665
- { kind: 'crap', abs: resolveBaselineAbs(cwd, baselines?.crap?.path) },
666
- ].filter((k) => k.abs);
667
-
668
- const committed = [];
669
- const refusedVerdicts = [];
670
- let lastSha = '';
671
-
672
- for (const { kind, abs } of kinds) {
673
- // Snapshot the prior envelope BEFORE the funnel's refreshBaseline()
674
- // overwrites it — the cap evaluator compares against the pre-refresh
675
- // rows. Reader-routed: schema-validated via `reader.loadFile`.
676
- const priorEnv = readEnvelope({ absPath: abs, kind, readerLoadFile });
677
- const capCheck = buildCapCheck({
678
- kind,
679
- priorEnv,
680
- autoRefresh,
681
- caps,
682
- cwd,
683
- epicBranch,
684
- storyBranch,
685
- evaluate,
686
- gitRunner,
687
- computeDiffPaths,
688
- readerLoadFile,
689
- });
690
-
691
- const res = await runRefreshCommit({
692
- cwd,
693
- kind,
694
- storyId,
695
- epicBranch,
696
- storyBranch,
697
- config,
698
- cycleState,
699
- capCheck,
700
- refreshBaseline,
701
- scorerBuilder,
702
- getBaselines,
703
- getQuality,
704
- fsImpl,
705
- gitRunner,
706
- logger,
707
- });
708
-
709
- if (res.ok !== true) {
710
- return {
711
- status: 'failed',
712
- reason: classifyFunnelError(res.error),
713
- detail: res.error,
714
- };
715
- }
716
- if (res.refused) {
717
- refusedVerdicts.push(res.verdict);
718
- continue;
719
- }
720
- if (!res.skipped && res.sha) {
721
- committed.push({ kind, sha: res.sha });
722
- lastSha = res.sha;
723
- }
724
- }
725
-
726
- if (refusedVerdicts.length > 0) {
727
- return publishRefusal({
728
- refusedVerdicts,
729
- caps,
730
- epicId,
731
- storyId,
732
- appendSignal,
733
- forEachLine,
734
- config,
735
- logger,
736
- });
737
- }
738
- if (committed.length === 0) {
739
- return { status: 'skipped', reason: 'no-baseline-drift' };
740
- }
741
- return {
742
- status: 'committed',
743
- sha: lastSha,
744
- files: kinds.map((k) => k.abs),
745
- committed,
746
- };
747
- }