mandrel 2.59.0 → 2.61.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 (678) hide show
  1. package/.agents/README.md +21 -19
  2. package/.agents/agents/acceptance-critic.md +24 -43
  3. package/.agents/agents/story-worker.md +20 -21
  4. package/.agents/docs/agentrc-reference.json +5 -84
  5. package/.agents/docs/configuration.md +48 -132
  6. package/.agents/docs/workflows.md +2 -2
  7. package/.agents/instructions.md +5 -8
  8. package/.agents/rules/ci-remediation.md +41 -8
  9. package/.agents/rules/gherkin-standards.md +4 -0
  10. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  11. package/.agents/schemas/agentrc.schema.json +16 -496
  12. package/.agents/schemas/story-deliver-terminal.schema.json +13 -3
  13. package/.agents/schemas/validation-evidence.schema.json +2 -1
  14. package/.agents/scripts/README.md +23 -13
  15. package/.agents/scripts/acceptance-eval.js +35 -169
  16. package/.agents/scripts/agents-bootstrap-github.js +27 -129
  17. package/.agents/scripts/apply-quality-bootstrap.js +4 -40
  18. package/.agents/scripts/audit-baselines.js +6 -27
  19. package/.agents/scripts/audit-labels-bootstrap.js +5 -29
  20. package/.agents/scripts/audit-to-stories.js +91 -361
  21. package/.agents/scripts/boot-sweep.js +19 -72
  22. package/.agents/scripts/bootstrap.js +74 -395
  23. package/.agents/scripts/ceremony-derive.js +10 -41
  24. package/.agents/scripts/check-arch-cycles.js +14 -64
  25. package/.agents/scripts/check-baselines.js +8 -48
  26. package/.agents/scripts/check-context-budget.js +105 -311
  27. package/.agents/scripts/check-cyclomatic.js +12 -44
  28. package/.agents/scripts/check-dead-exports.js +13 -64
  29. package/.agents/scripts/check-doc-links.js +38 -186
  30. package/.agents/scripts/check-gherkin-corpus.js +24 -127
  31. package/.agents/scripts/check-test-temp-hygiene.js +28 -169
  32. package/.agents/scripts/coverage-capture.js +34 -98
  33. package/.agents/scripts/deliver-light.js +25 -171
  34. package/.agents/scripts/deliver-recover.js +6 -42
  35. package/.agents/scripts/deliver-run.js +534 -0
  36. package/.agents/scripts/diagnose-friction.js +24 -116
  37. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  38. package/.agents/scripts/evidence-gate.js +23 -85
  39. package/.agents/scripts/file-ci-gap.js +57 -49
  40. package/.agents/scripts/generate-config-docs.js +30 -170
  41. package/.agents/scripts/generate-lens-checklists.js +8 -52
  42. package/.agents/scripts/generate-skills-index.js +14 -112
  43. package/.agents/scripts/generate-workflows-doc.js +10 -70
  44. package/.agents/scripts/git-cleanup.js +2 -34
  45. package/.agents/scripts/lib/Graph.js +24 -81
  46. package/.agents/scripts/lib/ITicketingProvider.js +47 -143
  47. package/.agents/scripts/lib/Logger.js +14 -76
  48. package/.agents/scripts/lib/audit-baselines/engine.js +11 -31
  49. package/.agents/scripts/lib/audit-baselines/gate-surface.js +3 -17
  50. package/.agents/scripts/lib/audit-baselines/headroom.js +4 -20
  51. package/.agents/scripts/lib/audit-baselines/hotspots.js +3 -15
  52. package/.agents/scripts/lib/audit-baselines/kinds.js +23 -89
  53. package/.agents/scripts/lib/audit-baselines/outliers.js +6 -23
  54. package/.agents/scripts/lib/audit-baselines/read.js +3 -16
  55. package/.agents/scripts/lib/audit-baselines/staleness.js +7 -26
  56. package/.agents/scripts/lib/audit-baselines/surface-entry.js +7 -28
  57. package/.agents/scripts/lib/audit-baselines/trend.js +7 -20
  58. package/.agents/scripts/lib/audit-baselines/weights.js +9 -37
  59. package/.agents/scripts/lib/audit-suite/audit-rules-reader.js +3 -18
  60. package/.agents/scripts/lib/audit-suite/checklist-threading.js +26 -124
  61. package/.agents/scripts/lib/audit-suite/dispatch-checklist.js +14 -45
  62. package/.agents/scripts/lib/audit-suite/findings.js +12 -52
  63. package/.agents/scripts/lib/audit-suite/frontmatter.js +5 -29
  64. package/.agents/scripts/lib/audit-suite/index.js +1 -15
  65. package/.agents/scripts/lib/audit-suite/lens-checklist.js +10 -45
  66. package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +11 -76
  67. package/.agents/scripts/lib/audit-suite/runner.js +13 -43
  68. package/.agents/scripts/lib/audit-suite/selector.js +49 -349
  69. package/.agents/scripts/lib/audit-suite/substitutions.js +12 -40
  70. package/.agents/scripts/lib/audit-suite/workflow-loader.js +3 -15
  71. package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +11 -73
  72. package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +8 -37
  73. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +25 -143
  74. package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +14 -80
  75. package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +4 -18
  76. package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +7 -40
  77. package/.agents/scripts/lib/audit-to-stories/group-findings.js +9 -39
  78. package/.agents/scripts/lib/audit-to-stories/issue-corpus.js +10 -66
  79. package/.agents/scripts/lib/audit-to-stories/issue-index.js +6 -30
  80. package/.agents/scripts/lib/audit-to-stories/issues-file.js +6 -36
  81. package/.agents/scripts/lib/audit-to-stories/ledger-commit.js +17 -69
  82. package/.agents/scripts/lib/audit-to-stories/ledger-pr.js +17 -85
  83. package/.agents/scripts/lib/audit-to-stories/ledger-record.js +10 -48
  84. package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +38 -146
  85. package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +7 -42
  86. package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +10 -57
  87. package/.agents/scripts/lib/baseline-loader.js +12 -51
  88. package/.agents/scripts/lib/baseline-schema-registry.js +5 -22
  89. package/.agents/scripts/lib/baselines/component-matcher.js +3 -12
  90. package/.agents/scripts/lib/baselines/components.js +10 -61
  91. package/.agents/scripts/lib/baselines/coverage-updater-cli.js +7 -36
  92. package/.agents/scripts/lib/baselines/crap-preview-incremental.js +7 -19
  93. package/.agents/scripts/lib/baselines/crap-preview-scan.js +19 -45
  94. package/.agents/scripts/lib/baselines/crap-updater-cli.js +16 -65
  95. package/.agents/scripts/lib/baselines/diff-scope-cli.js +5 -33
  96. package/.agents/scripts/lib/baselines/duplication-scanner.js +11 -60
  97. package/.agents/scripts/lib/baselines/env-overrides.js +12 -67
  98. package/.agents/scripts/lib/baselines/envelope.js +13 -129
  99. package/.agents/scripts/lib/baselines/exit-codes.js +6 -49
  100. package/.agents/scripts/lib/baselines/git-base.js +23 -142
  101. package/.agents/scripts/lib/baselines/kernel.js +11 -111
  102. package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +9 -47
  103. package/.agents/scripts/lib/baselines/kinds/_crap-read.js +8 -51
  104. package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +7 -62
  105. package/.agents/scripts/lib/baselines/kinds/bundle-size.js +8 -29
  106. package/.agents/scripts/lib/baselines/kinds/coverage.js +3 -15
  107. package/.agents/scripts/lib/baselines/kinds/crap.js +94 -415
  108. package/.agents/scripts/lib/baselines/kinds/duplication.js +4 -30
  109. package/.agents/scripts/lib/baselines/kinds/kind-factory.js +7 -53
  110. package/.agents/scripts/lib/baselines/kinds/maintainability.js +15 -80
  111. package/.agents/scripts/lib/baselines/kinds/mutation.js +12 -72
  112. package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +4 -11
  113. package/.agents/scripts/lib/baselines/merge-envelopes.js +30 -146
  114. package/.agents/scripts/lib/baselines/path-canon.js +19 -128
  115. package/.agents/scripts/lib/baselines/preview-gates.js +8 -37
  116. package/.agents/scripts/lib/baselines/reader.js +14 -107
  117. package/.agents/scripts/lib/baselines/refresh-service.js +35 -252
  118. package/.agents/scripts/lib/baselines/scope.js +11 -135
  119. package/.agents/scripts/lib/baselines/writer.js +16 -149
  120. package/.agents/scripts/lib/bdd-runner-detect.js +18 -113
  121. package/.agents/scripts/lib/bdd-scenario-budget.js +9 -36
  122. package/.agents/scripts/lib/bdd-scenario-scanner.js +11 -73
  123. package/.agents/scripts/lib/bdd-step-index.js +26 -100
  124. package/.agents/scripts/lib/bootstrap/baseline-merge-driver.js +23 -103
  125. package/.agents/scripts/lib/bootstrap/branch-protection.js +2 -5
  126. package/.agents/scripts/lib/bootstrap/commit-push.js +12 -50
  127. package/.agents/scripts/lib/bootstrap/gh-preflight.js +14 -101
  128. package/.agents/scripts/lib/bootstrap/hitl-confirm.js +5 -30
  129. package/.agents/scripts/lib/bootstrap/install-ledger.js +17 -73
  130. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +17 -121
  131. package/.agents/scripts/lib/bootstrap/manifest.js +15 -86
  132. package/.agents/scripts/lib/bootstrap/merge-methods.js +4 -33
  133. package/.agents/scripts/lib/bootstrap/preflight.js +12 -61
  134. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +34 -235
  135. package/.agents/scripts/lib/bootstrap/prompt.js +21 -129
  136. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +27 -141
  137. package/.agents/scripts/lib/bootstrap/summary.js +1 -8
  138. package/.agents/scripts/lib/bootstrap/workflow-audit.js +11 -84
  139. package/.agents/scripts/lib/branch-name-guard.js +4 -23
  140. package/.agents/scripts/lib/changed-files.js +39 -121
  141. package/.agents/scripts/lib/checks/core-bare-clean.js +4 -24
  142. package/.agents/scripts/lib/checks/index.js +18 -101
  143. package/.agents/scripts/lib/checks/loop-health.js +11 -53
  144. package/.agents/scripts/lib/checks/state.js +16 -91
  145. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +10 -61
  146. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +14 -83
  147. package/.agents/scripts/lib/child-exec.js +39 -108
  148. package/.agents/scripts/lib/cli/standard-args.js +9 -116
  149. package/.agents/scripts/lib/cli-args.js +31 -146
  150. package/.agents/scripts/lib/cli-usage.js +5 -27
  151. package/.agents/scripts/lib/cli-utils.js +2 -12
  152. package/.agents/scripts/lib/close-validation/commands.js +13 -76
  153. package/.agents/scripts/lib/close-validation/gates.js +92 -331
  154. package/.agents/scripts/lib/close-validation/process.js +121 -151
  155. package/.agents/scripts/lib/close-validation/projections/advisories.js +5 -31
  156. package/.agents/scripts/lib/close-validation/projections/crap.js +19 -67
  157. package/.agents/scripts/lib/close-validation/projections/head-sha.js +1 -17
  158. package/.agents/scripts/lib/close-validation/projections/inputs.js +4 -34
  159. package/.agents/scripts/lib/close-validation/projections/maintainability.js +11 -58
  160. package/.agents/scripts/lib/close-validation/runner.js +53 -110
  161. package/.agents/scripts/lib/command-header.js +6 -28
  162. package/.agents/scripts/lib/config/acceptance-eval.js +4 -30
  163. package/.agents/scripts/lib/config/baselines.js +3 -14
  164. package/.agents/scripts/lib/config/ci.js +8 -38
  165. package/.agents/scripts/lib/config/commands.js +1 -15
  166. package/.agents/scripts/lib/config/defaults.js +4 -33
  167. package/.agents/scripts/lib/config/delivery-routing.js +6 -34
  168. package/.agents/scripts/lib/config/explain.js +10 -83
  169. package/.agents/scripts/lib/config/gates/coverage.schema.js +0 -12
  170. package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +3 -31
  171. package/.agents/scripts/lib/config/gates/crap.schema.js +1 -34
  172. package/.agents/scripts/lib/config/gates/duplication.schema.js +1 -8
  173. package/.agents/scripts/lib/config/gates/index.js +2 -17
  174. package/.agents/scripts/lib/config/gates/maintainability.schema.js +1 -20
  175. package/.agents/scripts/lib/config/gates/mutation.schema.js +1 -7
  176. package/.agents/scripts/lib/config/gates/shared.js +4 -64
  177. package/.agents/scripts/lib/config/github.js +4 -22
  178. package/.agents/scripts/lib/config/limits.js +4 -57
  179. package/.agents/scripts/lib/config/paths.js +2 -21
  180. package/.agents/scripts/lib/config/qa.js +4 -38
  181. package/.agents/scripts/lib/config/quality.js +76 -432
  182. package/.agents/scripts/lib/config/runners.js +12 -56
  183. package/.agents/scripts/lib/config/runtime.js +13 -57
  184. package/.agents/scripts/lib/config/shared.js +2 -16
  185. package/.agents/scripts/lib/config/sync-agentrc.js +9 -50
  186. package/.agents/scripts/lib/config/temp-paths.js +40 -280
  187. package/.agents/scripts/lib/config/validate-orchestration.js +5 -17
  188. package/.agents/scripts/lib/config/worktree-isolation.js +9 -28
  189. package/.agents/scripts/lib/config-resolver.js +11 -52
  190. package/.agents/scripts/lib/config-schema-shared.js +1 -4
  191. package/.agents/scripts/lib/config-settings-schema-delivery.js +16 -291
  192. package/.agents/scripts/lib/config-settings-schema-quality.js +7 -219
  193. package/.agents/scripts/lib/config-settings-schema.js +37 -274
  194. package/.agents/scripts/lib/coverage-baseline.js +20 -110
  195. package/.agents/scripts/lib/coverage-capture-fullscope.js +18 -35
  196. package/.agents/scripts/lib/coverage-capture-incremental.js +15 -45
  197. package/.agents/scripts/lib/coverage-capture-usage.js +8 -25
  198. package/.agents/scripts/lib/coverage-capture.js +99 -224
  199. package/.agents/scripts/lib/coverage-utils.js +14 -79
  200. package/.agents/scripts/lib/cpu-pool.js +17 -123
  201. package/.agents/scripts/lib/crap-baseline-join.js +16 -88
  202. package/.agents/scripts/lib/crap-coordinates.js +6 -25
  203. package/.agents/scripts/lib/crap-engine.js +40 -153
  204. package/.agents/scripts/lib/crap-method-identity.js +16 -78
  205. package/.agents/scripts/lib/crap-utils.js +31 -155
  206. package/.agents/scripts/lib/cyclomatic-ceiling.js +14 -87
  207. package/.agents/scripts/lib/cyclomatic-scope.js +10 -50
  208. package/.agents/scripts/lib/dead-exports-knip.js +18 -56
  209. package/.agents/scripts/lib/dead-exports-mode.js +5 -24
  210. package/.agents/scripts/lib/degraded-mode.js +3 -26
  211. package/.agents/scripts/lib/dependency-parser.js +8 -40
  212. package/.agents/scripts/lib/dependency-version.js +13 -35
  213. package/.agents/scripts/lib/detect-package-manager.js +6 -36
  214. package/.agents/scripts/lib/doc-tiers.js +22 -124
  215. package/.agents/scripts/lib/duplicate-search.js +8 -72
  216. package/.agents/scripts/lib/env-loader.js +5 -27
  217. package/.agents/scripts/lib/error-redactor.js +6 -31
  218. package/.agents/scripts/lib/errors/index.js +2 -22
  219. package/.agents/scripts/lib/escomplex-ast-compat.js +22 -163
  220. package/.agents/scripts/lib/escomplex-kernel.js +21 -123
  221. package/.agents/scripts/lib/feedback-loop/graduator-core.js +94 -419
  222. package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +20 -98
  223. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +27 -149
  224. package/.agents/scripts/lib/findings/audit-ledger.js +23 -97
  225. package/.agents/scripts/lib/findings/classify-finding.js +14 -69
  226. package/.agents/scripts/lib/findings/promote-finding.js +14 -112
  227. package/.agents/scripts/lib/findings/provenance-field.js +11 -52
  228. package/.agents/scripts/lib/findings/route-finding.js +37 -255
  229. package/.agents/scripts/lib/findings/semantic-issue-search.js +14 -59
  230. package/.agents/scripts/lib/findings/severity.js +18 -104
  231. package/.agents/scripts/lib/format-generated-json.js +12 -44
  232. package/.agents/scripts/lib/full-suite-lock.js +160 -429
  233. package/.agents/scripts/lib/full-suite-queue.js +213 -0
  234. package/.agents/scripts/lib/gates/baseline-store.js +5 -9
  235. package/.agents/scripts/lib/gates/friction.js +1 -3
  236. package/.agents/scripts/lib/generated/agentrc-validator.js +2 -2
  237. package/.agents/scripts/lib/gh-exec.js +123 -191
  238. package/.agents/scripts/lib/git/cached-fetch.js +9 -52
  239. package/.agents/scripts/lib/git/sync-from-base.js +15 -107
  240. package/.agents/scripts/lib/git-branch-cleanup.js +14 -61
  241. package/.agents/scripts/lib/git-branch-lifecycle.js +16 -87
  242. package/.agents/scripts/lib/git-utils.js +37 -161
  243. package/.agents/scripts/lib/github/framework-repo.js +8 -71
  244. package/.agents/scripts/lib/github-url.js +2 -17
  245. package/.agents/scripts/lib/import-graph.js +11 -38
  246. package/.agents/scripts/lib/install-cmd-parser.js +4 -13
  247. package/.agents/scripts/lib/json-utils.js +3 -18
  248. package/.agents/scripts/lib/label-constants.js +16 -111
  249. package/.agents/scripts/lib/label-taxonomy.js +4 -30
  250. package/.agents/scripts/lib/maintainability-engine.js +12 -80
  251. package/.agents/scripts/lib/maintainability-unscorable.js +5 -25
  252. package/.agents/scripts/lib/maintainability-utils.js +16 -92
  253. package/.agents/scripts/lib/mandrel-catalog.js +12 -70
  254. package/.agents/scripts/lib/notifications/notifier.js +13 -38
  255. package/.agents/scripts/lib/npm-scripts.js +4 -23
  256. package/.agents/scripts/lib/observability/metrics-ledger.js +16 -76
  257. package/.agents/scripts/lib/observability/runtime-friction.js +44 -286
  258. package/.agents/scripts/lib/observability/signal-validator.js +5 -37
  259. package/.agents/scripts/lib/observability/signals-writer.js +11 -121
  260. package/.agents/scripts/lib/observability/source-classifier.js +22 -203
  261. package/.agents/scripts/lib/observability/terse-result.js +14 -47
  262. package/.agents/scripts/lib/onboard/init-tail.js +13 -74
  263. package/.agents/scripts/lib/onboard/scaffold-docs.js +11 -34
  264. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +25 -139
  265. package/.agents/scripts/lib/orchestration/auto-merge-cwd.js +11 -66
  266. package/.agents/scripts/lib/orchestration/behind-recovery.js +10 -55
  267. package/.agents/scripts/lib/orchestration/ceremony-routing.js +28 -156
  268. package/.agents/scripts/lib/orchestration/change-set.js +7 -36
  269. package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +9 -46
  270. package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +11 -44
  271. package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +5 -24
  272. package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +3 -12
  273. package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +5 -38
  274. package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +3 -8
  275. package/.agents/scripts/lib/orchestration/check-baselines/phases/refresh-ack.js +28 -136
  276. package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +3 -13
  277. package/.agents/scripts/lib/orchestration/check-state.js +92 -0
  278. package/.agents/scripts/lib/orchestration/ci-gap-intake.js +37 -144
  279. package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +121 -157
  280. package/.agents/scripts/lib/orchestration/code-review.js +24 -128
  281. package/.agents/scripts/lib/orchestration/column-sync.js +23 -111
  282. package/.agents/scripts/lib/orchestration/complexity-gate.js +118 -462
  283. package/.agents/scripts/lib/orchestration/deliver-recover.js +36 -168
  284. package/.agents/scripts/lib/orchestration/dependency-analyzer.js +4 -35
  285. package/.agents/scripts/lib/orchestration/dependency-candidates.js +9 -41
  286. package/.agents/scripts/lib/orchestration/diff-magnitude.js +25 -115
  287. package/.agents/scripts/lib/orchestration/doc-reader.js +2 -6
  288. package/.agents/scripts/lib/orchestration/docs-digest.js +13 -51
  289. package/.agents/scripts/lib/orchestration/epic-candidates.js +13 -53
  290. package/.agents/scripts/lib/orchestration/epic-checklist.js +9 -33
  291. package/.agents/scripts/lib/orchestration/epic-container.js +41 -167
  292. package/.agents/scripts/lib/orchestration/epic-expansion.js +10 -40
  293. package/.agents/scripts/lib/orchestration/epic-rollup.js +55 -207
  294. package/.agents/scripts/lib/orchestration/file-assumption-enum.js +2 -22
  295. package/.agents/scripts/lib/orchestration/file-assumptions.js +45 -253
  296. package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-detect.js +9 -46
  297. package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +7 -57
  298. package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +21 -126
  299. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +2 -6
  300. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +1 -4
  301. package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +1 -5
  302. package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +9 -34
  303. package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +41 -190
  304. package/.agents/scripts/lib/orchestration/git-cleanup/phases/merged-tip.js +9 -45
  305. package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +1 -4
  306. package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +19 -85
  307. package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +3 -17
  308. package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +1 -5
  309. package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +16 -100
  310. package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +1 -4
  311. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +16 -67
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +9 -33
  313. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +8 -29
  314. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +15 -68
  315. package/.agents/scripts/lib/orchestration/light-backstop.js +11 -49
  316. package/.agents/scripts/lib/orchestration/light-escalation.js +21 -89
  317. package/.agents/scripts/lib/orchestration/light-suitability.js +37 -307
  318. package/.agents/scripts/lib/orchestration/merge-block-class.js +39 -216
  319. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -377
  320. package/.agents/scripts/lib/orchestration/pinned-identifier-lint.js +17 -57
  321. package/.agents/scripts/lib/orchestration/plan-context.js +55 -318
  322. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +22 -79
  323. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +5 -31
  324. package/.agents/scripts/lib/orchestration/plan-metrics.js +29 -108
  325. package/.agents/scripts/lib/orchestration/plan-navigation.js +8 -27
  326. package/.agents/scripts/lib/orchestration/plan-persist/acceptance-handle-repair.js +12 -49
  327. package/.agents/scripts/lib/orchestration/plan-persist/audit-provenance.js +18 -73
  328. package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +16 -78
  329. package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +6 -30
  330. package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +14 -65
  331. package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +21 -76
  332. package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +6 -43
  333. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +14 -68
  334. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +9 -41
  335. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +71 -289
  336. package/.agents/scripts/lib/orchestration/plan-persist/soft-findings.js +2 -12
  337. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +96 -362
  338. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +9 -39
  339. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +60 -186
  340. package/.agents/scripts/lib/orchestration/plan-persist/wave-collision-gate.js +9 -49
  341. package/.agents/scripts/lib/orchestration/plan-persist/wave-serialisation.js +7 -28
  342. package/.agents/scripts/lib/orchestration/plan-reachability.js +13 -42
  343. package/.agents/scripts/lib/orchestration/plan-run-labels/reap.js +16 -91
  344. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +16 -54
  345. package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +10 -52
  346. package/.agents/scripts/lib/orchestration/planning/authoring-context.js +14 -109
  347. package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +11 -83
  348. package/.agents/scripts/lib/orchestration/pr-watch.js +48 -306
  349. package/.agents/scripts/lib/orchestration/project-meta-cache.js +15 -80
  350. package/.agents/scripts/lib/orchestration/project-meta-resolver.js +10 -51
  351. package/.agents/scripts/lib/orchestration/reassert-status-column.js +12 -76
  352. package/.agents/scripts/lib/orchestration/remote-verifier.js +12 -36
  353. package/.agents/scripts/lib/orchestration/resolve-stories.js +33 -164
  354. package/.agents/scripts/lib/orchestration/retro-proposals.js +66 -361
  355. package/.agents/scripts/lib/orchestration/review-base-ref.js +9 -43
  356. package/.agents/scripts/lib/orchestration/review-depth.js +12 -91
  357. package/.agents/scripts/lib/orchestration/review-providers/codex.js +10 -111
  358. package/.agents/scripts/lib/orchestration/review-providers/degraded-gates.js +13 -71
  359. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +7 -51
  360. package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +8 -53
  361. package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -214
  362. package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +7 -52
  363. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +4 -33
  364. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +11 -71
  365. package/.agents/scripts/lib/orchestration/review-providers/scoped-lint.js +19 -131
  366. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +6 -89
  367. package/.agents/scripts/lib/orchestration/review-providers/types.js +26 -56
  368. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +3 -46
  369. package/.agents/scripts/lib/orchestration/run-epilogue.js +245 -326
  370. package/.agents/scripts/lib/orchestration/run-scoped-config.js +55 -159
  371. package/.agents/scripts/lib/orchestration/single-story-close/close-note.js +7 -34
  372. package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +16 -89
  373. package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +18 -109
  374. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +83 -239
  375. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +20 -82
  376. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +103 -97
  377. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +8 -64
  378. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +136 -486
  379. package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +30 -134
  380. package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +96 -0
  381. package/.agents/scripts/lib/orchestration/single-story-close/phases/lock-wait-pending.js +49 -0
  382. package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +13 -86
  383. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +20 -95
  384. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +46 -203
  385. package/.agents/scripts/lib/orchestration/single-story-close/phases/pre-gate-steps.js +8 -50
  386. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +12 -83
  387. package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -39
  388. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +1 -6
  389. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-outcome.js +4 -28
  390. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +6 -51
  391. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +6 -34
  392. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +23 -121
  393. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +180 -273
  394. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +15 -69
  395. package/.agents/scripts/lib/orchestration/story-body-gate.js +4 -23
  396. package/.agents/scripts/lib/orchestration/story-close/baseline-upward-writeback.js +50 -179
  397. package/.agents/scripts/lib/orchestration/story-close/context-budget-writeback.js +11 -41
  398. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +23 -311
  399. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +22 -147
  400. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +16 -67
  401. package/.agents/scripts/lib/orchestration/story-deliver-terminal-schema.js +12 -68
  402. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +42 -200
  403. package/.agents/scripts/lib/orchestration/story-follow-ups.js +167 -252
  404. package/.agents/scripts/lib/orchestration/story-init-envelope.js +52 -0
  405. package/.agents/scripts/lib/orchestration/story-init-remote.js +2 -6
  406. package/.agents/scripts/lib/orchestration/story-reachability.js +3 -23
  407. package/.agents/scripts/lib/orchestration/task-body-validator.js +12 -135
  408. package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -131
  409. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +15 -149
  410. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +5 -33
  411. package/.agents/scripts/lib/orchestration/ticket-validator.js +63 -344
  412. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +51 -244
  413. package/.agents/scripts/lib/orchestration/ticketing/reads.js +39 -261
  414. package/.agents/scripts/lib/orchestration/ticketing/state.js +14 -68
  415. package/.agents/scripts/lib/orchestration/ticketing/transition.js +46 -263
  416. package/.agents/scripts/lib/orchestration/ticketing.js +2 -26
  417. package/.agents/scripts/lib/orchestration/verify-credit.js +18 -79
  418. package/.agents/scripts/lib/orchestration/worktree-dirty.js +5 -30
  419. package/.agents/scripts/lib/path-security.js +3 -6
  420. package/.agents/scripts/lib/plan-phase-cleanup.js +9 -49
  421. package/.agents/scripts/lib/preflight-runner.js +13 -69
  422. package/.agents/scripts/lib/process-group.js +143 -0
  423. package/.agents/scripts/lib/project-root.js +2 -8
  424. package/.agents/scripts/lib/provider-factory.js +2 -25
  425. package/.agents/scripts/lib/qa/console-allowlist.js +10 -59
  426. package/.agents/scripts/lib/qa/qa-session.js +15 -69
  427. package/.agents/scripts/lib/qa/redact-evidence.js +18 -129
  428. package/.agents/scripts/lib/qa/resolve-qa-contract.js +26 -135
  429. package/.agents/scripts/lib/qa/resolve-selection.js +16 -84
  430. package/.agents/scripts/lib/reserved-test-ids.js +9 -47
  431. package/.agents/scripts/lib/runtime-deps/dep-resolution.js +13 -53
  432. package/.agents/scripts/lib/runtime-deps/ensure-installed.js +10 -44
  433. package/.agents/scripts/lib/runtime-deps/manifest.js +10 -30
  434. package/.agents/scripts/lib/runtime-deps/parser-major.js +15 -51
  435. package/.agents/scripts/lib/runtime-deps/preflight.js +4 -22
  436. package/.agents/scripts/lib/runtime-deps/scan-imports.js +11 -55
  437. package/.agents/scripts/lib/signals/detectors/common.js +12 -38
  438. package/.agents/scripts/lib/signals/index.js +2 -19
  439. package/.agents/scripts/lib/signals/schema.js +14 -109
  440. package/.agents/scripts/lib/signals/write.js +2 -11
  441. package/.agents/scripts/lib/single-story/confirm-merge.js +31 -72
  442. package/.agents/scripts/lib/single-story/story-merged-notify.js +8 -49
  443. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +4 -26
  444. package/.agents/scripts/lib/single-story-sweep/protection.js +13 -100
  445. package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +60 -258
  446. package/.agents/scripts/lib/single-story-sweep.js +14 -97
  447. package/.agents/scripts/lib/skills/parse-skill.js +13 -59
  448. package/.agents/scripts/lib/skills/skills-index.js +8 -29
  449. package/.agents/scripts/lib/skills/walk-skill-files.js +17 -78
  450. package/.agents/scripts/lib/source-extensions.js +11 -42
  451. package/.agents/scripts/lib/source-text/strip-js-comments.js +8 -41
  452. package/.agents/scripts/lib/stdio-flush.js +9 -36
  453. package/.agents/scripts/lib/story-adjacency.js +8 -40
  454. package/.agents/scripts/lib/story-body/body-format-lints.js +51 -66
  455. package/.agents/scripts/lib/story-body/footer-block.js +11 -44
  456. package/.agents/scripts/lib/story-body/story-body.js +123 -344
  457. package/.agents/scripts/lib/temp-retention.js +42 -143
  458. package/.agents/scripts/lib/templates/decomposer-prompts.js +18 -80
  459. package/.agents/scripts/lib/test-env.js +12 -65
  460. package/.agents/scripts/lib/test-run-credit.js +10 -65
  461. package/.agents/scripts/lib/test-runner-contract.js +19 -74
  462. package/.agents/scripts/lib/test-temp.js +38 -184
  463. package/.agents/scripts/lib/test-tiers.js +12 -96
  464. package/.agents/scripts/lib/ticket-body-sections.js +21 -96
  465. package/.agents/scripts/lib/transpile.js +15 -74
  466. package/.agents/scripts/lib/util/concurrent-map.js +6 -25
  467. package/.agents/scripts/lib/util/parse-id-list.js +8 -34
  468. package/.agents/scripts/lib/util/poll-loop.js +8 -28
  469. package/.agents/scripts/lib/util/with-timeout.js +2 -11
  470. package/.agents/scripts/lib/validation-evidence.js +21 -96
  471. package/.agents/scripts/lib/wave-runner/footprint.js +17 -70
  472. package/.agents/scripts/lib/wave-runner/live-probe.js +67 -209
  473. package/.agents/scripts/lib/wave-runner/ready-set.js +72 -301
  474. package/.agents/scripts/lib/workers/crap-worker.js +11 -64
  475. package/.agents/scripts/lib/workers/maintainability-report-worker.js +8 -45
  476. package/.agents/scripts/lib/workers/maintainability-worker.js +5 -21
  477. package/.agents/scripts/lib/workers/serve-worker-messages.js +2 -18
  478. package/.agents/scripts/lib/workflow-closure.js +22 -105
  479. package/.agents/scripts/lib/workspace-provisioner.js +16 -54
  480. package/.agents/scripts/lib/worktree/git-hooks.js +15 -60
  481. package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +20 -60
  482. package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +10 -62
  483. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +22 -86
  484. package/.agents/scripts/lib/worktree/lifecycle/reap.js +24 -126
  485. package/.agents/scripts/lib/worktree/lifecycle-manager.js +2 -20
  486. package/.agents/scripts/lib/worktree/node-modules-strategy.js +46 -180
  487. package/.agents/scripts/lib/worktree-manager.js +15 -40
  488. package/.agents/scripts/lint-issue-body.js +12 -68
  489. package/.agents/scripts/mandrel-update-preflight.js +10 -70
  490. package/.agents/scripts/merge-baseline.js +30 -105
  491. package/.agents/scripts/nav-registry-diff.js +22 -108
  492. package/.agents/scripts/notify.js +12 -69
  493. package/.agents/scripts/plan-context.js +97 -92
  494. package/.agents/scripts/plan-critics.js +12 -66
  495. package/.agents/scripts/plan-persist.js +71 -137
  496. package/.agents/scripts/plan-run-epilogue.js +20 -43
  497. package/.agents/scripts/pr-watch-with-update.js +79 -263
  498. package/.agents/scripts/providers/github/auth.js +3 -8
  499. package/.agents/scripts/providers/github/blocked-by-add.js +14 -61
  500. package/.agents/scripts/providers/github/board-add.js +5 -21
  501. package/.agents/scripts/providers/github/branch-protection.js +11 -43
  502. package/.agents/scripts/providers/github/cache.js +2 -14
  503. package/.agents/scripts/providers/github/comments.js +7 -40
  504. package/.agents/scripts/providers/github/compose.js +3 -19
  505. package/.agents/scripts/providers/github/errors.js +22 -125
  506. package/.agents/scripts/providers/github/issues.js +31 -123
  507. package/.agents/scripts/providers/github/labels.js +24 -124
  508. package/.agents/scripts/providers/github/mappers.js +5 -27
  509. package/.agents/scripts/providers/github/merge-methods.js +3 -22
  510. package/.agents/scripts/providers/github/project-board.js +2 -17
  511. package/.agents/scripts/providers/github/projects-v2-graphql.js +3 -6
  512. package/.agents/scripts/providers/github/request-helpers.js +5 -32
  513. package/.agents/scripts/providers/github/search-budget.js +9 -39
  514. package/.agents/scripts/providers/github/search-query.js +5 -26
  515. package/.agents/scripts/providers/github/sub-issue-add.js +15 -65
  516. package/.agents/scripts/providers/github/sub-issues.js +7 -36
  517. package/.agents/scripts/providers/github/tickets.js +32 -134
  518. package/.agents/scripts/providers/github.js +18 -59
  519. package/.agents/scripts/prune-plan-run-labels.js +12 -46
  520. package/.agents/scripts/quality-preview.js +35 -220
  521. package/.agents/scripts/resolve-doc-tiers.js +3 -26
  522. package/.agents/scripts/resolve-stories.js +16 -67
  523. package/.agents/scripts/resync-status-column.js +6 -25
  524. package/.agents/scripts/run-tests.js +29 -104
  525. package/.agents/scripts/single-story-close.js +23 -135
  526. package/.agents/scripts/single-story-confirm-merge.js +32 -139
  527. package/.agents/scripts/single-story-init.js +47 -259
  528. package/.agents/scripts/stories-wave-tick.js +179 -415
  529. package/.agents/scripts/sync-agentrc.js +3 -21
  530. package/.agents/scripts/sync-claude-agents.js +9 -55
  531. package/.agents/scripts/sync-claude-commands.js +20 -110
  532. package/.agents/scripts/test-wrapper.js +6 -43
  533. package/.agents/scripts/update-coverage-baseline.js +5 -22
  534. package/.agents/scripts/update-crap-baseline.js +7 -30
  535. package/.agents/scripts/update-duplication-baseline.js +16 -92
  536. package/.agents/scripts/update-maintainability-baseline.js +8 -62
  537. package/.agents/scripts/update-ticket-state.js +1 -7
  538. package/.agents/scripts/validate-skills.js +6 -26
  539. package/.agents/skills/core/gates-and-baselines/reference.md +0 -1
  540. package/.agents/skills/skills.index.json +2 -2
  541. package/.agents/skills/stack/qa/playwright/SKILL.md +26 -0
  542. package/.agents/templates/agent-protocol.md +2 -2
  543. package/.agents/templates/docs/audit-sweep-runbook.md +3 -4
  544. package/.agents/workflows/audit-accessibility.md +4 -7
  545. package/.agents/workflows/audit-adrs.md +3 -6
  546. package/.agents/workflows/audit-architecture.md +3 -11
  547. package/.agents/workflows/audit-baselines.md +6 -9
  548. package/.agents/workflows/audit-clean-code.md +8 -12
  549. package/.agents/workflows/audit-data-model.md +3 -7
  550. package/.agents/workflows/audit-dependencies.md +4 -7
  551. package/.agents/workflows/audit-devops.md +4 -8
  552. package/.agents/workflows/audit-documentation.md +1 -4
  553. package/.agents/workflows/audit-mobile.md +4 -7
  554. package/.agents/workflows/audit-navigability.md +3 -6
  555. package/.agents/workflows/audit-performance.md +2 -4
  556. package/.agents/workflows/audit-privacy.md +4 -7
  557. package/.agents/workflows/audit-quality.md +4 -7
  558. package/.agents/workflows/audit-security.md +4 -7
  559. package/.agents/workflows/audit-seo.md +4 -7
  560. package/.agents/workflows/audit-sre.md +4 -7
  561. package/.agents/workflows/audit-to-stories.md +17 -30
  562. package/.agents/workflows/audit-ux-ui.md +4 -7
  563. package/.agents/workflows/helpers/acceptance-self-eval.md +84 -157
  564. package/.agents/workflows/helpers/audit-lens-core.md +1 -1
  565. package/.agents/workflows/helpers/code-quality-guardrails.md +12 -15
  566. package/.agents/workflows/helpers/code-review.md +4 -2
  567. package/.agents/workflows/helpers/deliver-digest.md +37 -28
  568. package/.agents/workflows/helpers/deliver-light.md +92 -101
  569. package/.agents/workflows/helpers/deliver-reference.md +162 -220
  570. package/.agents/workflows/helpers/deliver-story-reference.md +197 -607
  571. package/.agents/workflows/helpers/deliver-story.md +17 -18
  572. package/.agents/workflows/helpers/plan-reference.md +125 -167
  573. package/.agents/workflows/helpers/qa-core.md +12 -0
  574. package/.agents/workflows/mandrel-deliver.md +47 -31
  575. package/.agents/workflows/mandrel-plan.md +22 -21
  576. package/.agents/workflows/mandrel-update.md +36 -21
  577. package/.agents/workflows/memory-consolidate.md +1 -1
  578. package/.agents/workflows/qa-assist.md +27 -71
  579. package/.agents/workflows/qa-explore.md +19 -59
  580. package/.agents/workflows/qa-run.md +11 -33
  581. package/README.md +1 -1
  582. package/bin/mandrel.js +5 -46
  583. package/bin/postinstall.js +18 -107
  584. package/docs/CHANGELOG.md +60 -0
  585. package/lib/cli/doctor.js +11 -71
  586. package/lib/cli/init.js +26 -165
  587. package/lib/cli/migrate.js +5 -64
  588. package/lib/cli/registry.js +84 -467
  589. package/lib/cli/sync-agents.js +4 -64
  590. package/lib/cli/sync-commands.js +11 -64
  591. package/lib/cli/sync.js +34 -213
  592. package/lib/cli/uninstall.js +40 -219
  593. package/lib/cli/update.js +326 -523
  594. package/lib/cli/version-check.js +8 -72
  595. package/lib/cli/version-helpers.js +14 -87
  596. package/lib/migrations/helpers/retire-agentrc-key.js +11 -52
  597. package/lib/migrations/index.js +17 -92
  598. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +2 -15
  599. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +1 -13
  600. package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +2 -15
  601. package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +9 -38
  602. package/lib/migrations/steps/2.20.0-retire-codebase-snapshot.js +1 -13
  603. package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +2 -27
  604. package/lib/migrations/steps/2.57.0-retire-delivery-limit-knobs.js +2 -23
  605. package/lib/migrations/steps/2.57.0-retire-planning-limit-knobs.js +2 -27
  606. package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +21 -0
  607. package/lib/migrations/steps/strip-removed-agentrc-keys.js +333 -0
  608. package/package.json +17 -14
  609. package/.agents/docs/SDLC.md +0 -590
  610. package/.agents/docs/quality-gates.md +0 -1179
  611. package/.agents/rules/known-tooling-behavior.md +0 -150
  612. package/.agents/rules/orchestration-error-handling.md +0 -61
  613. package/.agents/rules/test-seams.md +0 -59
  614. package/.agents/schemas/baselines/lighthouse.schema.json +0 -59
  615. package/.agents/schemas/baselines/lint.schema.json +0 -47
  616. package/.agents/schemas/model-attribution.schema.json +0 -53
  617. package/.agents/scripts/check-action-pinning.js +0 -260
  618. package/.agents/scripts/check-audit-attribution.js +0 -302
  619. package/.agents/scripts/check-baseline-drift.js +0 -211
  620. package/.agents/scripts/check-baseline-scope.js +0 -362
  621. package/.agents/scripts/check-generated-validator.js +0 -202
  622. package/.agents/scripts/check-knip-entries.js +0 -159
  623. package/.agents/scripts/check-lifecycle-lint.js +0 -294
  624. package/.agents/scripts/check-pinned-override-notes.js +0 -102
  625. package/.agents/scripts/check-schema-references.js +0 -366
  626. package/.agents/scripts/check-test-portability.js +0 -512
  627. package/.agents/scripts/check-workflow-citations.js +0 -332
  628. package/.agents/scripts/check-workflow-cli-lint.js +0 -299
  629. package/.agents/scripts/check-workflow-timeouts.js +0 -291
  630. package/.agents/scripts/install-matrix-assert.js +0 -326
  631. package/.agents/scripts/lib/audit-advisories.js +0 -195
  632. package/.agents/scripts/lib/audit-attribution.js +0 -134
  633. package/.agents/scripts/lib/baselines/drift-detector.js +0 -351
  634. package/.agents/scripts/lib/baselines/kinds/lighthouse.js +0 -87
  635. package/.agents/scripts/lib/baselines/kinds/lint.js +0 -184
  636. package/.agents/scripts/lib/baselines/orphan-pruner.js +0 -233
  637. package/.agents/scripts/lib/baselines/scope-assert.js +0 -223
  638. package/.agents/scripts/lib/baselines/scope-inventory.js +0 -314
  639. package/.agents/scripts/lib/c8-cli-path.js +0 -21
  640. package/.agents/scripts/lib/config/gates/lighthouse.schema.js +0 -51
  641. package/.agents/scripts/lib/config/gates/lint.schema.js +0 -18
  642. package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +0 -70
  643. package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +0 -284
  644. package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +0 -80
  645. package/.agents/scripts/lib/dynamic-workflow/degraded-coverage.js +0 -81
  646. package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +0 -87
  647. package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +0 -74
  648. package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +0 -90
  649. package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +0 -43
  650. package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +0 -83
  651. package/.agents/scripts/lib/fs-walk.js +0 -52
  652. package/.agents/scripts/lib/knip-config-resolver.js +0 -181
  653. package/.agents/scripts/lib/knip-entry-sync.js +0 -452
  654. package/.agents/scripts/lib/orchestration/model-attribution.js +0 -418
  655. package/.agents/scripts/lib/orchestration/story-plan-state.js +0 -33
  656. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +0 -67
  657. package/.agents/scripts/lib/pinned-override-notes.js +0 -88
  658. package/.agents/scripts/lib/pinned-override-resolve.js +0 -212
  659. package/.agents/scripts/lib/test-isolate/cli-options.js +0 -93
  660. package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +0 -52
  661. package/.agents/scripts/lib/test-isolate/list-files.js +0 -90
  662. package/.agents/scripts/lib/test-isolate/parse-tap.js +0 -75
  663. package/.agents/scripts/lib/test-isolate/progress-log.js +0 -45
  664. package/.agents/scripts/lib/test-isolate/render-report.js +0 -97
  665. package/.agents/scripts/lib/test-isolate/run-isolate.js +0 -87
  666. package/.agents/scripts/lib/test-isolate/runner.js +0 -483
  667. package/.agents/scripts/lib/test-profile/parse-tap.js +0 -136
  668. package/.agents/scripts/lib/test-profile/render-report.js +0 -45
  669. package/.agents/scripts/lint-label-vocabulary.js +0 -214
  670. package/.agents/scripts/post-structured-comment.js +0 -127
  671. package/.agents/scripts/provision-git-hooks.js +0 -85
  672. package/.agents/scripts/prune-baseline-orphans.js +0 -181
  673. package/.agents/scripts/run-coverage.js +0 -197
  674. package/.agents/scripts/run-lint.js +0 -133
  675. package/.agents/scripts/run-test-profile.js +0 -129
  676. package/.agents/scripts/run-verify.js +0 -118
  677. package/.agents/scripts/test-isolate.js +0 -55
  678. package/.agents/scripts/update-dead-exports-baseline.js +0 -321
@@ -1,79 +1,64 @@
1
1
  /**
2
- * full-suite-lock.js — serialize the framework's full-suite spawns across
3
- * concurrent processes on one host (Story #5173).
2
+ * full-suite-lock.js — serialize full-suite spawns across one host's
3
+ * worktrees (they contend for cores and a shared coverage artifact), over
4
+ * the `sweep-lock.js` primitive.
4
5
  *
5
- * A full `npm test` / `npm run test:coverage` is the most expensive thing this
6
- * framework causes, and a multi-Story delivery runs several of them from
7
- * sibling worktrees of the same checkout. Two suites racing on one host do not
8
- * merely take twice as long — they contend for the same cores, and the
9
- * coverage artifact they both write is a single shared path per worktree, so
10
- * the loser's run is wasted work. This module makes the second spawn wait for
11
- * the first instead.
12
- *
13
- * **It reuses the shipped advisory-lock primitive**
14
- * (`single-story-sweep/sweep-lock.js`) rather than authoring a second
15
- * lockfile: pid+mtime identity, stale takeover, heartbeat and owner-checked
16
- * release are all already solved there, and a second implementation would be a
17
- * second set of those bugs. `phases/post-land.js` is the other consumer.
18
- *
19
- * **Posture: best-effort, never load-bearing.** Failing to acquire — a
20
- * contended wait that expires, an I/O error, an unresolvable lock home —
21
- * falls through to spawning the suite anyway. The lock is a collision damper,
22
- * not mutual exclusion; turning it load-bearing would let a stale lockfile
23
- * fail a delivery, which is strictly worse than the contention it prevents.
24
- *
25
- * **It covers only the spawn.** Callers acquire immediately around the child
26
- * process, never around the freshness/digest checks that precede it, so a
27
- * capture that is already credited never waits.
6
+ * Best-effort: any failure to acquire spawns anyway — a stale lockfile must
7
+ * never fail a delivery. Only close opts in to defer on an expired wait
8
+ * ({@link LOCK_WAIT_EXPIRED_EXIT_CODE}). Waits are async so the holder's
9
+ * heartbeat and signal release keep working, and FIFO via
10
+ * `full-suite-queue.js`. The lock covers only the spawn, never the
11
+ * freshness checks before it.
28
12
  */
29
13
  import fs from 'node:fs';
30
14
  import path from 'node:path';
31
- import { Worker } from 'node:worker_threads';
32
15
 
33
16
  import { mainCheckoutRoot } from './config/temp-paths.js';
34
- import {
35
- acquireLockWithWait,
36
- acquireSweepLock,
37
- readLockHolderPid,
38
- refreshLockSync,
39
- } from './single-story-sweep/sweep-lock.js';
17
+ import { isFirstInLine, waitInLine } from './full-suite-queue.js';
18
+ import { acquireSweepLock } from './single-story-sweep/sweep-lock.js';
40
19
 
41
20
  /** Environment escape hatch: set to `0`/`false`/`off`/`no` to disable. */
42
21
  export const FULL_SUITE_LOCK_ENV = 'MANDREL_FULL_SUITE_LOCK';
43
22
 
44
- /**
45
- * Lockfile name, resolved under the **git common dir's parent** so every
46
- * linked worktree of one checkout contends on one file — the whole point of a
47
- * host-level lock is that `.worktrees/story-A` and `.worktrees/story-B` must
48
- * not each get their own.
49
- */
23
+ /** Close sets it to `defer` on its gate children; nothing else does. */
24
+ export const FULL_SUITE_LOCK_EXPIRY_ENV = 'MANDREL_FULL_SUITE_LOCK_ON_EXPIRY';
25
+
26
+ /** `EX_TEMPFAIL`. */
27
+ export const LOCK_WAIT_EXPIRED_EXIT_CODE = 75;
28
+
29
+ /** Under the main checkout's `.git`, so every worktree shares one file. */
50
30
  const FULL_SUITE_LOCK_FILENAME = 'mandrel-full-suite.lock';
51
31
 
52
- /** Stale-holder threshold. A suite legitimately runs for minutes. */
53
- const DEFAULT_STALE_MS = 15 * 60_000;
32
+ /** Well under close's ten-minute foreground ceiling. */
33
+ const DEFAULT_WAIT_MS = 300_000;
54
34
 
55
- /** Total bounded wait before giving up and spawning anyway. */
56
- const DEFAULT_WAIT_MS = 20 * 60_000;
35
+ /** Never above the wait budget. */
36
+ const DEFAULT_STALE_MS = 240_000;
57
37
 
58
- /** Poll interval while waiting. */
59
38
  const DEFAULT_POLL_MS = 2_000;
60
39
 
61
- /**
62
- * Mtime-refresh interval for the spawn heartbeat. A third of the staleness
63
- * window, matching the sweep primitive's own divisor: two consecutive missed
64
- * beats still leave a live holder looking live.
65
- */
66
- const DEFAULT_SPAWN_HEARTBEAT_MS = DEFAULT_STALE_MS / 3;
40
+ /** More than one poll under 30 s, so jitter never stretches a gap past 30 s. */
41
+ const DEFAULT_REPORT_MS = 25_000;
67
42
 
68
43
  const FALSEY = /^(0|false|off|no)$/i;
69
44
 
45
+ const LOCK_TAG = '[full-suite-lock]';
46
+
47
+ const LOCK_DEFAULTS = Object.freeze({
48
+ enabled: true,
49
+ log: () => {},
50
+ waitMs: DEFAULT_WAIT_MS,
51
+ pollMs: DEFAULT_POLL_MS,
52
+ staleMs: DEFAULT_STALE_MS,
53
+ reportMs: DEFAULT_REPORT_MS,
54
+ fsImpl: fs,
55
+ nowFn: Date.now,
56
+ sleepFn: (ms) => defaultSleep(ms),
57
+ acquireOnceFn: (opts) => acquireSweepLock(opts),
58
+ });
59
+
70
60
  /**
71
- * Is the full-suite lock enabled for this process?
72
- *
73
- * The environment wins over config so an operator can disable it for one
74
- * invocation without editing `.agentrc.json`. Both hatches are one-way: they
75
- * only ever turn the lock **off**, because an operator disabling a
76
- * best-effort damper is always safe while forcing it on is not.
61
+ * Both hatches (env, then config) can only turn the lock off.
77
62
  *
78
63
  * @param {{ config?: object, env?: Record<string, string|undefined> }} [opts]
79
64
  * @returns {boolean}
@@ -85,11 +70,8 @@ export function isFullSuiteLockEnabled({ config, env = process.env } = {}) {
85
70
  }
86
71
 
87
72
  /**
88
- * Resolve the one lockfile path shared by a checkout and all of its linked
89
- * worktrees, or `null` when the checkout root cannot be resolved (not a git
90
- * repo, git unavailable). A `null` disables the lock for that call rather
91
- * than inventing a cwd-local path that would never actually collide with the
92
- * sibling it is meant to serialize against.
73
+ * `null` (no lock) when the root is unresolvable — a cwd-local path would
74
+ * never collide with its sibling.
93
75
  *
94
76
  * @param {{ cwd: string, mainCheckoutRootFn?: typeof mainCheckoutRoot }} opts
95
77
  * @returns {string|null}
@@ -105,238 +87,60 @@ export function resolveFullSuiteLockPath({
105
87
  }
106
88
 
107
89
  /**
108
- * Emit the operator-facing wait line. Naming the holding pid is what keeps a
109
- * multi-minute wait from reading as a hang — it is the difference between
110
- * "nothing is happening" and "pid 4711 is running the suite; mine is next".
90
+ * Uncontended fast path, skipped when waiters are queued (no overtaking).
111
91
  *
112
- * @param {(m: string) => void} log
113
- * @param {string} lockPath
114
- * @param {object} fsImpl
92
+ * @returns {{ lock: object|null, lockPath: string|null }} null `lock` with a
93
+ * `lockPath` means wait; both null means no lock.
115
94
  */
116
- function logWait(log, lockPath, fsImpl) {
117
- const pid = readLockHolderPid(lockPath, fsImpl);
118
- log(
119
- `[full-suite-lock] ⏳ another full suite is already running on this host (holding pid ${pid ?? 'unknown'}) — waiting for it to finish before spawning.`,
120
- );
121
- }
122
-
123
- /**
124
- * Shared preamble for both wrappers: decide whether to lock at all, take the
125
- * uncontended fast path, and emit the wait line when a wait is about to
126
- * happen.
127
- *
128
- * @returns {{ lock: object|null, lockPath: string|null }} `lock` is a held
129
- * lock when the fast path won, `null` when the caller must wait (or when
130
- * locking is off, in which case `lockPath` is `null` too).
131
- */
132
- function beginLock({
133
- cwd,
134
- enabled,
135
- log,
136
- staleMs,
137
- fsImpl,
138
- acquireOnceFn,
139
- lockPath: explicitLockPath,
140
- }) {
141
- if (!enabled) return { lock: null, lockPath: null };
142
- const lockPath = explicitLockPath ?? resolveFullSuiteLockPath({ cwd });
143
- if (lockPath === null) return { lock: null, lockPath: null };
95
+ function beginLock({ staleMs, fsImpl, acquireOnceFn, ...where }) {
96
+ const resolved = lockHome(where);
97
+ if (resolved === null) return NO_LOCK;
98
+ if (!isFirstInLine({ lockPath: resolved, ticket: null, staleMs, fsImpl })) {
99
+ return { lock: null, lockPath: resolved };
100
+ }
144
101
  const first = acquireOnceFn({
145
- lockPath,
102
+ lockPath: resolved,
146
103
  timeoutMs: staleMs,
147
104
  fsImpl,
148
105
  });
149
- if (first.acquired) return { lock: first, lockPath };
106
+ if (first.acquired) return { lock: first, lockPath: resolved };
150
107
  // A hard I/O error will not resolve by waiting — proceed unserialized.
151
- if (first.reason === 'error') return { lock: null, lockPath: null };
152
- logWait(log, lockPath, fsImpl);
153
- return { lock: null, lockPath };
154
- }
155
-
156
- /**
157
- * The heartbeat body, run on a worker thread (Story #5278).
158
- *
159
- * Sleeps in `Atomics.wait` slices and refreshes the lockfile's mtime between
160
- * them, stopping the moment the main thread flips the shared stop flag (and
161
- * `Atomics.notify`s it), the lockfile stops being ours, or any I/O fails.
162
- * Ownership is re-read from the file's first line on every beat for the same
163
- * reason the in-process heartbeat does it: after a steal the file belongs to
164
- * someone else, and bumping its mtime would keep *their* lock alive on our
165
- * behalf.
166
- *
167
- * Inline source rather than a module of its own: it is nine lines of loop
168
- * whose whole meaning is the lock it refreshes, and a separate worker entry
169
- * point would be a second file that no reader of this one can see.
170
- */
171
- const HEARTBEAT_WORKER_SOURCE = `
172
- const fs = require('node:fs');
173
- const { workerData } = require('node:worker_threads');
174
- const { lockPath, ownerId, intervalMs, stopBuffer } = workerData;
175
- const stop = new Int32Array(stopBuffer);
176
- while (Atomics.load(stop, 0) === 0) {
177
- Atomics.wait(stop, 0, 0, intervalMs);
178
- if (Atomics.load(stop, 0) !== 0) break;
179
- try {
180
- if (String(fs.readFileSync(lockPath, 'utf8')).split('\\n', 1)[0] !== ownerId) break;
181
- const now = new Date();
182
- fs.utimesSync(lockPath, now, now);
183
- } catch {
184
- break;
185
- }
108
+ return first.reason === 'error'
109
+ ? NO_LOCK
110
+ : { lock: null, lockPath: resolved };
186
111
  }
187
- `;
188
112
 
189
- /**
190
- * Keep a held lock's mtime advancing while this thread is blocked inside a
191
- * synchronous spawn (Story #5278).
192
- *
193
- * The primitive's own heartbeat is a `setInterval`, so it only fires when the
194
- * holder's event loop gets a turn. `runCapture` spawns the suite with
195
- * `spawnSync`: the loop stops turning for the entire run, the mtime freezes
196
- * at acquisition time, and a sibling reading that mtime concludes — correctly,
197
- * on the evidence available to it — that the holder died, breaks the lock, and
198
- * starts a second full suite beside the first. That is the exact collision
199
- * this lock exists to prevent, and it fires most reliably on the slowest
200
- * suites, where it costs the most.
201
- *
202
- * A worker thread has its own event loop, unaffected by the main thread's
203
- * blocking spawn, so it is the only place a refresh can happen at all here.
204
- *
205
- * **Best-effort, like everything else on this path.** A worker that cannot
206
- * start (a runtime with threads disabled, a resource limit) leaves the
207
- * pre-#5278 behaviour exactly as it was; it never throws and never delays the
208
- * spawn it guards.
209
- *
210
- * @param {{ lockPath: string|null, ownerId?: string, heartbeatMs: number }} opts
211
- * @returns {() => void} `stop()` — idempotent, safe when no worker started.
212
- */
213
- function startSpawnHeartbeat({ lockPath, ownerId, heartbeatMs }) {
214
- if (!(lockPath && typeof ownerId === 'string' && heartbeatMs > 0)) {
215
- return () => {};
216
- }
217
- let worker = null;
218
- let stop = null;
219
- try {
220
- const stopBuffer = new SharedArrayBuffer(4);
221
- stop = new Int32Array(stopBuffer);
222
- worker = new Worker(HEARTBEAT_WORKER_SOURCE, {
223
- eval: true,
224
- workerData: { lockPath, ownerId, intervalMs: heartbeatMs, stopBuffer },
225
- });
226
- // A heartbeat must never be the reason the process stays alive.
227
- worker.unref();
228
- worker.on('error', () => {});
229
- } catch {
230
- return () => {};
231
- }
232
- let stopped = false;
233
- return () => {
234
- if (stopped) return;
235
- stopped = true;
236
- try {
237
- Atomics.store(stop, 0, 1);
238
- Atomics.notify(stop, 0);
239
- worker.terminate();
240
- } catch {
241
- // Already gone.
242
- }
243
- };
244
- }
245
-
246
- /**
247
- * Start the spawn heartbeat without ever letting it become a reason the suite
248
- * does not run.
249
- *
250
- * The whole module's posture is that a lock defect may slow a suite down and
251
- * may never skip one, and a heartbeat is the least load-bearing thing on the
252
- * path — it exists only so a *rival* reads the mtime correctly. So a starter
253
- * that throws (an environment without worker threads, a resource limit, an
254
- * injected seam) resolves to "no heartbeat", never to a failed close.
255
- *
256
- * @param {Function} startFn
257
- * @param {{ lockPath: string|null, ownerId?: string, heartbeatMs: number }} opts
258
- * @returns {() => void}
259
- */
260
- function safeStartHeartbeat(startFn, opts) {
261
- try {
262
- return startFn(opts) ?? (() => {});
263
- } catch {
264
- return () => {};
265
- }
266
- }
113
+ const NO_LOCK = Object.freeze({ lock: null, lockPath: null });
267
114
 
268
115
  /**
269
- * Stamp a held lock as current immediately before its critical section
270
- * begins (Story #5278).
271
- *
272
- * A lock acquired at the end of a twenty-minute wait was created — or last
273
- * heartbeat-refreshed — long before the spawn it is about to guard, and the
274
- * synchronous caller's event loop is about to stop turning for the whole
275
- * duration of that spawn. Refreshing here is the last chance to put a current
276
- * mtime on the file.
277
- *
278
- * Routed through the primitive's own {@link refreshLockSync} rather than the
279
- * holder's `refresh()` so an injected `acquireOnceFn` seam that returns a
280
- * bare `{ acquired, release }` is refreshed identically to the real one.
281
- *
282
- * @param {{ ownerId?: string }|null} held
283
- * @param {string|null} lockPath
284
- * @param {object} fsImpl
116
+ * @param {{ enabled: boolean, cwd: string, lockPath?: string }} where
117
+ * @returns {string|null}
285
118
  */
286
- function refreshBeforeSpawn(held, lockPath, fsImpl) {
287
- if (!(held?.acquired && typeof held.ownerId === 'string' && lockPath)) return;
288
- refreshLockSync({ lockPath, ownerId: held.ownerId, fsImpl });
119
+ function lockHome({ enabled, cwd, lockPath }) {
120
+ if (!enabled) return null;
121
+ return lockPath ?? resolveFullSuiteLockPath({ cwd });
289
122
  }
290
123
 
291
124
  /**
292
- * The post-wait re-probe (Story #5278).
293
- *
294
- * Waiting for the lock is waiting for *someone else's* full suite against
295
- * this same checkout. By the time it finishes, the thing this caller was
296
- * about to spawn the suite to establish may already be true — the holder
297
- * deposited the stamp, or a sibling recorded the evidence. Spawning anyway
298
- * pays for a whole suite to re-derive a fact that is already on disk, which
299
- * is exactly the cost the lock exists to avoid.
300
- *
301
- * Consulted **only after a real wait**: an uncontended caller's freshness
302
- * probe ran moments ago and nothing has happened since, so re-running it
303
- * would be pure overhead on the hot path.
125
+ * Consulted only after a real wait: the suite we waited behind may already
126
+ * have established what we were about to spawn for.
304
127
  *
305
128
  * @template T
306
- * @param {(() => T|undefined)|undefined} skipIfSatisfied
307
- * @param {boolean} waited
129
+ * @param {(() => T|undefined)|undefined} probe
130
+ * @param {boolean} applies
308
131
  * @returns {{ satisfied: boolean, value?: T }}
309
132
  */
310
- function probeAlreadySatisfied(skipIfSatisfied, waited) {
311
- if (!(waited && typeof skipIfSatisfied === 'function')) {
312
- return { satisfied: false };
313
- }
314
- const value = skipIfSatisfied();
133
+ function consult(probe, applies) {
134
+ if (!(applies && typeof probe === 'function')) return { satisfied: false };
135
+ const value = probe();
315
136
  return value === undefined
316
137
  ? { satisfied: false }
317
138
  : { satisfied: true, value };
318
139
  }
319
140
 
320
141
  /**
321
- * Block a synchronous caller for `ms` without a timer. `runCapture` spawns the
322
- * suite with `spawnSync`, so its whole call stack is synchronous and there is
323
- * no event loop to yield to; `Atomics.wait` on a throwaway buffer is the
324
- * sanctioned way to sleep on that stack.
325
- *
326
- * @param {number} ms
327
- */
328
- function sleepSync(ms) {
329
- if (!(ms > 0)) return;
330
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
331
- }
332
-
333
- /**
334
- * Run `spawn` with the full-suite lock held, from a **synchronous** caller.
335
- *
336
- * Never throws on the lock's account and always runs `spawn` exactly once:
337
- * every lock outcome — disabled, acquired, contended past the wait budget,
338
- * I/O error — ends in the same call, so a lock defect can slow a suite down
339
- * but can never skip or duplicate it.
142
+ * Never throws on the lock's account and spawns at most once — a lock defect
143
+ * can slow a suite, never duplicate it.
340
144
  *
341
145
  * @template T
342
146
  * @param {{
@@ -346,192 +150,119 @@ function sleepSync(ms) {
346
150
  * waitMs?: number,
347
151
  * pollMs?: number,
348
152
  * staleMs?: number,
153
+ * reportMs?: number,
349
154
  * fsImpl?: object,
350
155
  * nowFn?: () => number,
351
- * sleepFn?: (ms: number) => void,
156
+ * sleepFn?: (ms: number) => Promise<void>,
352
157
  * acquireOnceFn?: typeof acquireSweepLock,
353
158
  * lockPath?: string,
354
159
  * skipIfSatisfied?: () => T|undefined,
355
- * spawnHeartbeatMs?: number,
356
- * startSpawnHeartbeatFn?: typeof startSpawnHeartbeat,
357
- * }} opts `skipIfSatisfied` is the post-wait re-probe (Story #5278): after a
358
- * contended wait it decides whether the thing this spawn would establish is
359
- * already true, and a non-`undefined` return is returned in the spawn's
360
- * place. Never consulted on the uncontended path.
361
- * @param {() => T} spawn
362
- * @returns {T}
160
+ * onWaitExpired?: () => T|undefined,
161
+ * }} opts A non-`undefined` return from either hook stands in for the spawn.
162
+ * @param {() => Promise<T>} spawn
163
+ * @returns {Promise<T>}
363
164
  */
364
- export function withFullSuiteLockSync(
365
- {
366
- cwd,
367
- enabled = true,
368
- log = () => {},
369
- waitMs = DEFAULT_WAIT_MS,
370
- pollMs = DEFAULT_POLL_MS,
371
- staleMs = DEFAULT_STALE_MS,
372
- fsImpl = fs,
373
- nowFn = Date.now,
374
- sleepFn = sleepSync,
375
- acquireOnceFn = acquireSweepLock,
376
- lockPath: explicitLockPath,
377
- skipIfSatisfied,
378
- spawnHeartbeatMs = DEFAULT_SPAWN_HEARTBEAT_MS,
379
- startSpawnHeartbeatFn = startSpawnHeartbeat,
380
- },
381
- spawn,
382
- ) {
383
- const { lock, lockPath } = beginLock({
384
- cwd,
385
- enabled,
386
- log,
387
- staleMs,
388
- fsImpl,
389
- acquireOnceFn,
390
- lockPath: explicitLockPath,
391
- });
392
- let held = lock;
393
- let waited = false;
394
- if (held === null && lockPath !== null) {
395
- const deadline = nowFn() + Math.max(0, waitMs);
396
- for (;;) {
397
- if (nowFn() >= deadline) break;
398
- waited = true;
399
- sleepFn(Math.max(0, pollMs));
400
- const attempt = acquireOnceFn({ lockPath, timeoutMs: staleMs, fsImpl });
401
- if (attempt.acquired) {
402
- held = attempt;
403
- break;
404
- }
405
- if (attempt.reason === 'error') break;
406
- }
407
- }
165
+ export async function withFullSuiteLockAsync(options, spawn) {
166
+ const opts = withDefaults(options);
167
+ const { lock, lockPath } = beginLock(opts);
168
+ const wait =
169
+ lock === null && lockPath !== null
170
+ ? await waitInLine({ ...opts, lockPath, expiryNote: expiryNote(opts) })
171
+ : { held: lock, expired: false, waited: false };
408
172
  try {
409
- const probe = probeAlreadySatisfied(skipIfSatisfied, waited);
410
- if (probe.satisfied) {
411
- log(
412
- '[full-suite-lock] ⏭ the run we waited for already covered this tree — skipping the spawn.',
413
- );
414
- return probe.value;
415
- }
416
- refreshBeforeSpawn(held, lockPath, fsImpl);
417
- // The main thread is about to stop turning for the whole spawn, so the
418
- // holder's own interval heartbeat cannot fire; this one runs off-thread.
419
- const stopHeartbeat = safeStartHeartbeat(startSpawnHeartbeatFn, {
420
- lockPath: held?.acquired ? lockPath : null,
421
- ownerId: held?.ownerId,
422
- heartbeatMs: spawnHeartbeatMs,
423
- });
424
- try {
425
- return spawn();
426
- } finally {
427
- stopHeartbeat();
428
- }
173
+ return await spawnOrStandIn(opts, wait, spawn);
429
174
  } finally {
430
- if (held?.acquired) held.release();
175
+ if (wait.held?.acquired) wait.held.release();
176
+ }
177
+ }
178
+
179
+ function withDefaults(options) {
180
+ const opts = { ...LOCK_DEFAULTS };
181
+ for (const [key, value] of Object.entries(options)) {
182
+ if (value !== undefined) opts[key] = value;
183
+ }
184
+ return opts;
185
+ }
186
+
187
+ function expiryNote({ onWaitExpired }) {
188
+ return typeof onWaitExpired === 'function'
189
+ ? 'not spawning; the caller reports the wait instead'
190
+ : 'spawning anyway';
191
+ }
192
+
193
+ async function spawnOrStandIn(opts, wait, spawn) {
194
+ const probe = consult(opts.skipIfSatisfied, wait.waited);
195
+ if (probe.satisfied) {
196
+ opts.log(
197
+ `${LOCK_TAG} ⏭ the run we waited for already covered this tree — skipping the spawn.`,
198
+ );
199
+ return probe.value;
431
200
  }
201
+ const deferred = consult(opts.onWaitExpired, wait.expired);
202
+ return deferred.satisfied ? deferred.value : await spawn();
432
203
  }
433
204
 
434
205
  /**
435
- * Decorate a capture runner so its spawn is serialized behind the host lock.
436
- *
437
- * The lock composes *over* `runCapture` rather than living inside it, for two
438
- * reasons. `runCapture` has no config in scope — it is reached from pre-push
439
- * and from unit tests as a pure spawn helper — and every decision that can
440
- * avoid the suite (the changed-file skip, the digest/mtime freshness probe)
441
- * happens in the capture paths *above* it. Wrapping the runner at the one
442
- * production call site therefore puts the lock exactly around the spawn: an
443
- * already-credited capture returns before the wrapper is ever invoked, so it
444
- * never waits (AC-9).
206
+ * @param {number} ms
207
+ * @returns {Promise<void>}
208
+ */
209
+ function defaultSleep(ms) {
210
+ return new Promise((resolve) => {
211
+ setTimeout(resolve, ms);
212
+ });
213
+ }
214
+
215
+ /**
216
+ * Serialize a capture runner's spawn. Wrapped at the one call site below
217
+ * every skip/freshness decision, so a credited capture never waits.
445
218
  *
446
- * @param {Function} runCaptureFn The runner to wrap (`runCapture`).
447
- * @param {object} [config] Resolved config; both escape hatches are read here.
448
- * @returns {Function} A runner with the same `(opts) => exitCode` contract.
219
+ * @param {Function} runCaptureFn
220
+ * @param {object} [config]
221
+ * @param {Record<string, string|undefined>} [env]
222
+ * @param {object} [lockOptions] Test seam only.
223
+ * @returns {(opts?: object) => Promise<number>}
449
224
  */
450
- export function lockedCapture(runCaptureFn, config) {
451
- const enabled = isFullSuiteLockEnabled({ config });
225
+ export function lockedCapture(
226
+ runCaptureFn,
227
+ config,
228
+ env = process.env,
229
+ lockOptions = {},
230
+ ) {
231
+ const policy = {
232
+ enabled: isFullSuiteLockEnabled({ config, env }),
233
+ onWaitExpired: deferredCaptureExit(env),
234
+ ...lockOptions,
235
+ };
452
236
  return (captureOpts = {}) =>
453
- withFullSuiteLockSync(
237
+ withFullSuiteLockAsync(
454
238
  {
239
+ ...policy,
455
240
  cwd: captureOpts.cwd,
456
241
  log: captureOpts.log,
457
- enabled,
458
- // Story #5278 — the capture path supplies its own freshness re-probe
459
- // per call, because only it knows which scope ('full' /
460
- // 'incremental') the stamp has to satisfy. A `true` means the suite
461
- // we queued behind already stamped this tree, so this caller reports
462
- // success (exit 0) without spawning a second one.
463
- skipIfSatisfied:
464
- typeof captureOpts.recheckFresh === 'function'
465
- ? () => (captureOpts.recheckFresh() ? 0 : undefined)
466
- : undefined,
242
+ skipIfSatisfied: freshnessProbe(captureOpts),
467
243
  },
468
244
  () => runCaptureFn(captureOpts),
469
245
  );
470
246
  }
471
247
 
472
248
  /**
473
- * Run `spawn` with the full-suite lock held, from an **async** caller.
474
- *
475
- * Same contract as {@link withFullSuiteLockSync}, but it waits on the shipped
476
- * promise-based `acquireLockWithWait` so it never blocks the event loop — the
477
- * close-validation gate runner drives sibling gates on that loop, and a
478
- * blocking wait there would stall them behind this one.
249
+ * @param {Record<string, string|undefined>} env
250
+ * @returns {(() => number)|undefined}
251
+ */
252
+ function deferredCaptureExit(env) {
253
+ return env[FULL_SUITE_LOCK_EXPIRY_ENV] === 'defer'
254
+ ? () => LOCK_WAIT_EXPIRED_EXIT_CODE
255
+ : undefined;
256
+ }
257
+
258
+ /**
259
+ * A fresh recheck means exit 0 without spawning.
479
260
  *
480
- * @template T
481
- * @param {Parameters<typeof withFullSuiteLockSync>[0] & {
482
- * acquireWithWaitFn?: typeof acquireLockWithWait,
483
- * }} opts `skipIfSatisfied` behaves exactly as in the sync wrapper.
484
- * @param {() => Promise<T>} spawn
485
- * @returns {Promise<T>}
261
+ * @param {{ recheckFresh?: () => boolean }} captureOpts
262
+ * @returns {(() => number|undefined)|undefined}
486
263
  */
487
- export async function withFullSuiteLockAsync(
488
- {
489
- cwd,
490
- enabled = true,
491
- log = () => {},
492
- waitMs = DEFAULT_WAIT_MS,
493
- pollMs = DEFAULT_POLL_MS,
494
- staleMs = DEFAULT_STALE_MS,
495
- fsImpl = fs,
496
- acquireOnceFn = acquireSweepLock,
497
- acquireWithWaitFn = acquireLockWithWait,
498
- lockPath: explicitLockPath,
499
- skipIfSatisfied,
500
- },
501
- spawn,
502
- ) {
503
- const { lock, lockPath } = beginLock({
504
- cwd,
505
- enabled,
506
- log,
507
- staleMs,
508
- fsImpl,
509
- acquireOnceFn,
510
- lockPath: explicitLockPath,
511
- });
512
- let held = lock;
513
- let waited = false;
514
- if (held === null && lockPath !== null) {
515
- waited = true;
516
- const attempt = await acquireWithWaitFn({
517
- lockPath,
518
- waitMs,
519
- pollMs,
520
- timeoutMs: staleMs,
521
- fsImpl,
522
- });
523
- if (attempt.acquired) held = attempt;
524
- }
525
- try {
526
- const probe = probeAlreadySatisfied(skipIfSatisfied, waited);
527
- if (probe.satisfied) {
528
- log(
529
- '[full-suite-lock] ⏭ the run we waited for already covered this tree — skipping the spawn.',
530
- );
531
- return probe.value;
532
- }
533
- return await spawn();
534
- } finally {
535
- if (held?.acquired) held.release();
536
- }
264
+ function freshnessProbe({ recheckFresh }) {
265
+ return typeof recheckFresh === 'function'
266
+ ? () => (recheckFresh() ? 0 : undefined)
267
+ : undefined;
537
268
  }