@joshuafolkken/kit 1.1784.0 → 1.2114.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 (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +59 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +415 -389
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +15 -8
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env tsx
2
+ import { fileURLToPath } from 'node:url'
3
+ import { PROJECT_ROOT } from '#scripts/init/init-paths'
4
+ import { stamp_file } from '#scripts/josh/stamp-file'
5
+ import { lint_related_scope } from '#scripts/lint/lint-related-scope'
6
+ import { review_record_pinned } from '#scripts/review/review-record-pinned'
7
+ import { execa } from 'execa'
8
+ import run_parallel from 'run-parallel'
9
+ import { check_related_pinned } from './check-related-pinned'
10
+ import { check_related_reuse } from './check-related-reuse'
11
+ import { check_related_section, type CheckResult } from './check-related-section'
12
+ import { check_related_unplanned } from './check-related-unplanned'
13
+ import { gate_labels } from './gate-labels'
14
+ import { gate_log } from './gate-log'
15
+ import { metrics_totals } from './metrics-totals'
16
+ import { verification_tail } from './verification-tail'
17
+
18
+ const COMMAND = 'check:related'
19
+ // One file per checkout beside the gate's own log, overwritten by each run.
20
+ const LOG_PATH = stamp_file.stamp_path(
21
+ 'josh-check-related-log-',
22
+ PROJECT_ROOT,
23
+ gate_log.GATE_LOG_SUFFIX,
24
+ )
25
+ const LINT_RELATED = 'lint:related'
26
+ // The verdict `lint:related` itself prints last, under its own label.
27
+ const LINT_PASSED = verification_tail.format_verdict(lint_related_scope.COMMAND_LABEL, [])
28
+ const CHECKS: ReadonlyArray<string> = [
29
+ LINT_RELATED,
30
+ 'test:related',
31
+ gate_labels.TYPE_CHECK_TARGET,
32
+ 'cspell:dot',
33
+ ]
34
+ const REUSED = 'reused'
35
+ const METRICS_STOP =
36
+ '`josh ship`\'s pre-detach stops on the metrics notice above unless the branch approval already names the total; settle it first (`pnpm josh metrics --accept --reason "<why>"`); the accept needs no `check:related` re-run, as the notice changed no exit code'
37
+
38
+ type CheckExecutor = (command: string) => Promise<CheckResult>
39
+ type ProcessRunner = (
40
+ file: string,
41
+ args: Array<string>,
42
+ options: { all: true; reject: false },
43
+ ) => Promise<{ all: string | null; exitCode?: number }>
44
+
45
+ async function run_execa(
46
+ file: string,
47
+ args: Array<string>,
48
+ options: { all: true; reject: false },
49
+ ): Promise<{ all: string | null; exitCode?: number }> {
50
+ return await execa(file, args, options)
51
+ }
52
+
53
+ function failed_result(command: string, error: unknown): CheckResult {
54
+ return {
55
+ command,
56
+ exit_code: 1,
57
+ output: error instanceof Error ? error.message : String(error),
58
+ }
59
+ }
60
+
61
+ async function execute_check(
62
+ command: string,
63
+ run: ProcessRunner = run_execa,
64
+ ): Promise<CheckResult> {
65
+ try {
66
+ const result = await run('pnpm', ['josh', command], { all: true, reject: false })
67
+
68
+ return { command, exit_code: result.exitCode ?? 1, output: result.all ?? '' }
69
+ } catch (error) {
70
+ return failed_result(command, error)
71
+ }
72
+ }
73
+
74
+ async function start_check(
75
+ command: string,
76
+ execute: CheckExecutor,
77
+ complete: run_parallel.TaskCallback<CheckResult>,
78
+ ): Promise<void> {
79
+ try {
80
+ const result = await execute(command)
81
+
82
+ // eslint-disable-next-line unicorn/no-null -- run-parallel requires null for successful tasks.
83
+ complete(null, result)
84
+ } catch (error) {
85
+ // eslint-disable-next-line unicorn/no-null -- run-parallel requires null for successful tasks.
86
+ complete(null, failed_result(command, error))
87
+ }
88
+ }
89
+
90
+ async function run_checks(
91
+ execute: CheckExecutor = execute_check,
92
+ commands: ReadonlyArray<string> = CHECKS,
93
+ ): Promise<Array<CheckResult>> {
94
+ const tasks = commands.map((command): run_parallel.Task<CheckResult> => {
95
+ return (complete): void => {
96
+ void start_check(command, execute, complete)
97
+ }
98
+ })
99
+
100
+ return await new Promise<Array<CheckResult>>((resolve): void => {
101
+ run_parallel(tasks, (_error, results): void => {
102
+ resolve(results)
103
+ })
104
+ })
105
+ }
106
+
107
+ function failed_commands(results: ReadonlyArray<CheckResult>): ReadonlyArray<string> {
108
+ return results.filter((result) => result.exit_code !== 0).map((result) => result.command)
109
+ }
110
+
111
+ // The verdict is the last line, as every josh check prints it, so a reader of the tail sees every
112
+ // check that failed rather than only the section that finished last (joshuafolkken/kit#4940).
113
+ function checks_line(results: ReadonlyArray<CheckResult>): string {
114
+ return verification_tail.format_verdict(COMMAND, failed_commands(results))
115
+ }
116
+
117
+ // Each failed check and the command that reproduces it alone, above the log notice (joshuafolkken/kit#5162).
118
+ function failure_lines(results: ReadonlyArray<CheckResult>): string {
119
+ const failed = failed_commands(results)
120
+ if (failed.length === 0) return ''
121
+
122
+ const lines = failed.map((command) =>
123
+ verification_tail.format_rerun(command, `pnpm josh ${command}`),
124
+ )
125
+
126
+ return `${COMMAND} — next:\n${lines.join('\n')}\n`
127
+ }
128
+
129
+ // Every check's whole output, kept where the console's size limit cannot reach, as `josh gate` keeps its own.
130
+ function write_log(results: ReadonlyArray<CheckResult>, target: string): string | undefined {
131
+ const entries = results.map((result) => ({
132
+ header: `${result.command}: ${check_related_section.result_status(result)}`,
133
+ output: result.output,
134
+ }))
135
+
136
+ return gate_log.write_gate_log(entries, target)
137
+ }
138
+
139
+ function reused_suffix(reused: ReadonlySet<string>): string {
140
+ return reused.size === 0 ? '' : ` (reused: ${[...reused].join(', ')})`
141
+ }
142
+
143
+ // A notice is never a failure, so a passing verdict line alone hid it from a reader of the last lines,
144
+ // and the ship's pre-detach stopped on it (joshuafolkken/kit#4987).
145
+ function verdict_line(
146
+ results: ReadonlyArray<CheckResult>,
147
+ has_metrics_notice: boolean,
148
+ reused: ReadonlySet<string>,
149
+ ): string {
150
+ const line = `${checks_line(results)}${reused_suffix(reused)}`
151
+
152
+ return has_metrics_notice ? `${line} — ${METRICS_STOP}` : line
153
+ }
154
+
155
+ // `josh lint:related` ends its section with the metrics growth notice, which the sections after it
156
+ // bury; it is repeated above the verdict so the tail still carries what stops `josh ship`
157
+ // (joshuafolkken/kit#4939).
158
+ function metrics_notice(results: ReadonlyArray<CheckResult>): string | undefined {
159
+ const output = results.find((result) => result.command === LINT_RELATED)?.output ?? ''
160
+ const start = output.indexOf(metrics_totals.NOTICE_HEADING)
161
+
162
+ if (start === -1) return undefined
163
+
164
+ // The lint's own verdict closes its section; it is not part of the notice.
165
+ return output.slice(start).replace(LINT_PASSED, '').trimEnd()
166
+ }
167
+
168
+ function report_reused(reused: ReadonlySet<string>): void {
169
+ for (const command of reused) {
170
+ process.stdout.write(`\n=== ${command}: ${REUSED} ===\n`)
171
+ }
172
+ }
173
+
174
+ interface ReportOptions {
175
+ pinned_notice?: string | undefined
176
+ unplanned_notice?: string | undefined
177
+ reused?: ReadonlySet<string>
178
+ log_target?: string
179
+ is_full?: boolean
180
+ }
181
+
182
+ function report_notices(notices: ReadonlyArray<string | undefined>): void {
183
+ for (const notice of notices) {
184
+ if (notice !== undefined) process.stdout.write(`\n${notice}\n`)
185
+ }
186
+ }
187
+
188
+ function report_results(results: ReadonlyArray<CheckResult>, options: ReportOptions = {}): void {
189
+ const { is_full, log_target = LOG_PATH, pinned_notice, reused = new Set<string>() } = options
190
+
191
+ report_reused(reused)
192
+
193
+ for (const result of results) {
194
+ process.stdout.write(check_related_section.format_section(result, is_full))
195
+ }
196
+
197
+ const metrics = metrics_notice(results)
198
+
199
+ report_notices([metrics, pinned_notice, options.unplanned_notice])
200
+
201
+ const log = { path: write_log(results, log_target) }
202
+ const verdict = verdict_line(results, metrics !== undefined, reused)
203
+
204
+ process.stdout.write(
205
+ `\n${verification_tail.format_tail({ failures: failure_lines(results), log, verdict })}`,
206
+ )
207
+ }
208
+
209
+ function exit_code(results: ReadonlyArray<CheckResult>): number {
210
+ return results.every((result: CheckResult): boolean => result.exit_code === 0) ? 0 : 1
211
+ }
212
+
213
+ // **The first check of a round-1 fix starts `josh test:pinned` again on the fixed tree**
214
+ // (joshuafolkken/kit#4948): left to `josh review:record`, the restart came minutes before the ship, and
215
+ // its pre-detach waited out a whole run. Started here, the check runs beside these four; a tree that did
216
+ // not move, or a run outside a lane child, starts nothing. A verdict that check already reached on this
217
+ // tree is printed above the verdict line, waited for when this run started it (`check-related-pinned.ts`).
218
+ // A check whose green record still holds is not run (`check-related-reuse.ts`).
219
+ async function run_all(
220
+ root?: string,
221
+ execute: CheckExecutor = execute_check,
222
+ is_full = false,
223
+ ): Promise<number> {
224
+ const is_started = await review_record_pinned.restart_in_lane(root)
225
+ const tree = await check_related_reuse.read_tree()
226
+ const reused = await check_related_reuse.reusable(CHECKS, tree)
227
+ const results = await run_checks(
228
+ execute,
229
+ CHECKS.filter((command) => !reused.has(command)),
230
+ )
231
+
232
+ await check_related_reuse.record(results, tree)
233
+ report_results(results, {
234
+ is_full,
235
+ pinned_notice: await check_related_pinned.notice(root, is_started),
236
+ unplanned_notice: await check_related_unplanned.notice(),
237
+ reused,
238
+ })
239
+
240
+ return exit_code(results)
241
+ }
242
+
243
+ const check_related = {
244
+ CHECKS,
245
+ METRICS_STOP,
246
+ REUSED,
247
+ execute_check,
248
+ exit_code,
249
+ report_results,
250
+ run_all,
251
+ run_checks,
252
+ }
253
+
254
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
255
+ process.exitCode = await check_related.run_all(
256
+ undefined,
257
+ execute_check,
258
+ check_related_section.is_full_requested(process.argv),
259
+ )
260
+ }
261
+
262
+ export type { CheckExecutor }
263
+ export { check_related }
264
+
265
+ export { type CheckResult } from './check-related-section'
@@ -186,7 +186,7 @@ function runs_multi_worker_eslint(
186
186
  )
187
187
  }
188
188
 
189
- const command_memory = { estimated_memory_mb, runs_multi_worker_eslint, tool_calls_of }
189
+ const command_memory = { estimated_memory_mb, runs_multi_worker_eslint, tool_calls_of, workers_of }
190
190
 
191
191
  export { command_memory }
192
192
  export type { ToolCall }
@@ -1,4 +1,5 @@
1
1
  import { MS_PER_SECOND } from '#scripts/lib/timeouts'
2
+ import { core_budget_timing } from './core-budget-timing'
2
3
  import type { LedgerLoad, MachineBudget } from './machine-capacity'
3
4
 
4
5
  // The ledger's admission arithmetic, kept apart from the markers `core-budget.ts` reads and writes so
@@ -16,6 +17,11 @@ const RAMP_UP_MS = 30_000
16
17
  // enough for the related checks an edit triggers together, short enough that a heavy claim waits only
17
18
  // for the claims already in flight.
18
19
  const BYPASS_WINDOW_MS = 30_000
20
+ // How long after a heavier waiting claim a lighter one may still pass it: half the wait cap
21
+ // (`core-budget-timing.ts`), so the heavier claim still has the cap's second half to find its room before
22
+ // it starts narrowed or past the budget.
23
+ const WAIT_CAP_SHARE = 0.5
24
+ const HEAVIER_BYPASS_WINDOW_MS = core_budget_timing.WAIT_CAP_MS * WAIT_CAP_SHARE
19
25
  // A narrowed unit claim still runs one worker: zero would run no test and report the suite green.
20
26
  const MIN_GRANT = 1
21
27
  // A unit claim narrowed to less than its asked weight over this waits rather than starts (`is_too_narrow`).
@@ -128,15 +134,26 @@ function first_waiter_limit(budget: MachineBudget): LedgerLoad {
128
134
  return { cores: budget.cores + (budget.busy_excess ?? 0), memory_mb: budget.memory_mb }
129
135
  }
130
136
 
137
+ // Whether `own` may pass one waiter ahead: any waiter claimed within the window before it, and a heavier
138
+ // one within the longer window (joshuafolkken/kit#4595) — a two-core `lint:related` queued for most of the
139
+ // cap behind a unit claim of five cores that the running claims had no room for.
140
+ function may_pass_waiter(own: LedgerReservation, waiter: LedgerReservation): boolean {
141
+ const since_ms = own.claimed_at - waiter.claimed_at
142
+
143
+ if (since_ms < BYPASS_WINDOW_MS) return true
144
+
145
+ return waiter.weight > own.weight && since_ms < HEAVIER_BYPASS_WINDOW_MS
146
+ }
147
+
131
148
  // **A light claim passes a waiting one only within a window of that one's claim** (#4313). A claim that
132
149
  // fits the room the running claims leave runs instead of queueing behind a heavier claim that does not
133
- // fit it; a claim made more than the window after a waiter queues behind it, so a waiter is passed by a
134
- // bounded set of claims and is never starved.
150
+ // fit it; a claim made more than the window after a waiter — the heavier window after a heavier one
151
+ // (`may_pass_waiter`) — queues behind it, so a waiter is passed by a bounded set of claims and is never
152
+ // starved.
135
153
  function may_pass({ own, ahead, running }: Placement, budget: MachineBudget): boolean {
136
- const latest = own.reservation.claimed_at - BYPASS_WINDOW_MS
137
- const is_recent = ahead.every((entry) => entry.reservation.claimed_at > latest)
154
+ const is_passable = ahead.every((entry) => may_pass_waiter(own.reservation, entry.reservation))
138
155
 
139
- return is_recent && fits([...running, own], budget)
156
+ return is_passable && fits([...running, own], budget)
140
157
  }
141
158
 
142
159
  function fits_in_order({ own, ahead, running }: Placement, budget: MachineBudget): boolean {
@@ -252,7 +269,7 @@ function total_weight(reservations: ReadonlyArray<LedgerEntry>): number {
252
269
  return sum_load(reservations).cores
253
270
  }
254
271
 
255
- // **The weight a unit claim admitted past the wait cap may take: the cores the admitted claims leave
272
+ // **The weight a unit claim admitted past its wait (the cap, or outside load that does not ease) may take: the cores the admitted claims leave
256
273
  // free, never below one worker and never above what it asked for.** Admitting it at full width put the
257
274
  // ledger past the machine (joshuafolkken/kit#4235); a unit suite is the one tool whose width follows a
258
275
  // number, so it narrows instead. `undefined` for any other claim, and for one that fits as asked.
@@ -335,6 +352,7 @@ function describe_overflow(admission: Admission): string | undefined {
335
352
 
336
353
  const core_admission = {
337
354
  BYPASS_WINDOW_MS,
355
+ HEAVIER_BYPASS_WINDOW_MS,
338
356
  RAMP_UP_MS,
339
357
  admitted_keys,
340
358
  admitted_load,
@@ -6,14 +6,21 @@ const POLL_INTERVAL_MS = 50
6
6
  // for good. Two minutes is well past a unit suite's worst measured time under six-way load. A claim a
7
7
  // swap stall holds is the exception (`core_admission.is_swap_held`).
8
8
  const WAIT_CAP_MS = 120_000
9
+ // How long the load may go without easing before a held reservation is admitted at minimum width ahead
10
+ // of the cap (`busy_average.is_unrelieved`): ten of the busy average's windows.
11
+ const EASE_WINDOW_MS = 30_000
12
+
13
+ interface Cadence {
14
+ poll_interval_ms: number
15
+ wait_cap_ms: number
16
+ ease_window_ms: number
17
+ }
9
18
 
10
19
  // The clock and cadence a wait runs on, resolved apart from the ledger fields so `reserve` stays under
11
20
  // the complexity limit — each default is a branch.
12
- interface TimingConfig {
21
+ interface TimingConfig extends Cadence {
13
22
  now: () => number
14
23
  sleep: (ms: number) => Promise<void>
15
- poll_interval_ms: number
16
- wait_cap_ms: number
17
24
  }
18
25
 
19
26
  async function default_sleep(ms: number): Promise<void> {
@@ -22,16 +29,23 @@ async function default_sleep(ms: number): Promise<void> {
22
29
  })
23
30
  }
24
31
 
32
+ function resolve_cadence(options: Partial<Cadence>): Cadence {
33
+ return {
34
+ poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS,
35
+ wait_cap_ms: options.wait_cap_ms ?? WAIT_CAP_MS,
36
+ ease_window_ms: options.ease_window_ms ?? EASE_WINDOW_MS,
37
+ }
38
+ }
39
+
25
40
  function resolve_timing(options: Partial<TimingConfig>): TimingConfig {
26
41
  return {
27
42
  now: options.now ?? Date.now,
28
43
  sleep: options.sleep ?? default_sleep,
29
- poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS,
30
- wait_cap_ms: options.wait_cap_ms ?? WAIT_CAP_MS,
44
+ ...resolve_cadence(options),
31
45
  }
32
46
  }
33
47
 
34
- const core_budget_timing = { resolve_timing }
48
+ const core_budget_timing = { WAIT_CAP_MS, resolve_timing }
35
49
 
36
50
  export type { TimingConfig }
37
51
  export { core_budget_timing }
@@ -9,7 +9,7 @@ import { stamp_file } from '#scripts/josh/stamp-file'
9
9
  import { json_value } from '#scripts/lib/json-value'
10
10
  import { unit_worker_share } from '#scripts/test/unit-worker-share'
11
11
  import { z } from 'zod'
12
- import { busy_average, type BusySample } from './busy-average'
12
+ import { busy_average, type BusySample, type LoadEase } from './busy-average'
13
13
  import { core_admission, type Admission, type LedgerEntry, type Overflow } from './core-admission'
14
14
  import { core_budget_timing, type TimingConfig } from './core-budget-timing'
15
15
  import { core_wait, type BudgetWait, type WaitReason } from './core-wait'
@@ -29,7 +29,7 @@ import { machine_capacity, type MachineBudget, type MachineReading } from './mac
29
29
  //
30
30
  // **A solo run is bit-for-bit unchanged, and that is arithmetic rather than a branch.** The gate's
31
31
  // weights are its `reserved_cores` (the static checks) and its `unit_worker_cap` (the unit suite), and
32
- // `reserved(2 + 2 + 2) + unit_cap(cores - 6)` is exactly `cores` — so a single gate's four claims sum
32
+ // `reserved(2 + 2 + 1) + unit_cap(cores - 5)` is exactly `cores` — so a single gate's four claims sum
33
33
  // to the whole budget and, while the busy cores stay within what the ledger holds, every one is
34
34
  // admitted the instant it is made, with no poll and no wait. Under
35
35
  // concurrency the same weights sum past the budget and the ledger is what holds the machine down.
@@ -53,7 +53,7 @@ const MIN_BUDGET = 1
53
53
  // declared memory, and it counts as load from outside the ledger until it is gone.
54
54
  // `command`, `checkout`, `lane`, `lanes_root` and `wait_reason` name a waiting claim on `run:board`
55
55
  // (`core-wait.ts`). `is_unit` marks a unit suite's claim, which may be admitted narrowed to `granted`
56
- // past the wait cap (`core_admission.narrowed_weight`).
56
+ // past the wait cap, or once outside load holding it does not ease (`core_admission.narrowed_weight`).
57
57
  const reservation_schema = process_owner_schema.extend({
58
58
  weight: z.number(),
59
59
  claimed_at: z.number(),
@@ -86,6 +86,7 @@ interface ReserveOptions {
86
86
  report?: (line: string) => void
87
87
  read_machine?: () => Promise<MachineReading>
88
88
  wait_cap_ms?: number
89
+ ease_window_ms?: number
89
90
  poll_interval_ms?: number
90
91
  directory?: string
91
92
  now?: () => number
@@ -188,6 +189,8 @@ interface WaitContext extends TimingConfig {
188
189
  deadline: number
189
190
  fields: ReservationFields
190
191
  busy_samples: Array<BusySample>
192
+ // Unset until the first reading of the machine (`busy_average.with_ease`).
193
+ ease?: LoadEase | undefined
191
194
  }
192
195
 
193
196
  // **A claim alone in the ledger reads the machine too** (joshuafolkken/kit#4238): load outside the
@@ -211,6 +214,8 @@ async function current_budget(
211
214
 
212
215
  const mean = busy_average.averaged(reading, context.busy_samples, ledger.cores)
213
216
 
217
+ context.ease = busy_average.with_ease(context.ease, mean.busy_cores, context.now())
218
+
214
219
  return machine_capacity.machine_budget(context.budget, mean, ledger)
215
220
  }
216
221
 
@@ -250,21 +255,37 @@ function mark_waiting(context: WaitContext, reason: WaitReason): void {
250
255
  if (previous === undefined) context.report(core_wait.wait_line(context.fields.command, reason))
251
256
  }
252
257
 
258
+ // Past the cap a held claim runs regardless, and so does one only load outside the ledger holds once
259
+ // that load has not eased for a window of the wait — waiting on gains it nothing. A claim a swap stall
260
+ // holds is the exception to both.
261
+ function is_wait_spent(
262
+ context: WaitContext,
263
+ reservations: ReadonlyArray<LiveReservation>,
264
+ budget: MachineBudget,
265
+ ): boolean {
266
+ if (core_admission.is_swap_held(context.key, reservations, budget)) return false
267
+
268
+ const now = context.now()
269
+
270
+ if (now >= context.deadline) return true
271
+
272
+ return (
273
+ busy_average.is_unrelieved(context.ease, now, context.ease_window_ms) &&
274
+ core_wait.is_outside_held(context.key, reservations, budget)
275
+ )
276
+ }
277
+
253
278
  async function poll_admission(context: WaitContext): Promise<Admission | undefined> {
254
279
  const reservations = live_reservations(context.directory)
255
280
  const budget = await current_budget(context, reservations)
256
281
  // A unit claim is admitted at the room the budget leaves rather than at full width — the first
257
- // waiter, which load outside the ledger does not hold, as well as one past the wait cap.
282
+ // waiter, which load outside the ledger does not hold, as well as one whose wait is spent.
258
283
  const granted = core_admission.narrowed_weight(context.key, reservations, budget.cores)
259
284
  const reason = core_wait.hold_reason(context.key, reservations, budget, granted)
260
285
 
261
286
  if (reason === undefined) return admit(context, undefined, granted)
262
287
 
263
- // Past the cap a held claim runs regardless, except one a swap stall holds.
264
- if (
265
- context.now() >= context.deadline &&
266
- !core_admission.is_swap_held(context.key, reservations, budget)
267
- ) {
288
+ if (is_wait_spent(context, reservations, budget)) {
268
289
  const held = core_admission.with_grant(context.key, reservations, granted)
269
290
 
270
291
  return admit(context, overflow_of(context, held, budget), granted)
@@ -275,7 +296,8 @@ async function poll_admission(context: WaitContext): Promise<Admission | undefin
275
296
  return undefined
276
297
  }
277
298
 
278
- // Poll the ledger until this reservation is admitted, or until the wait cap admits it at minimum width.
299
+ // Poll the ledger until this reservation is admitted, or until the wait cap — or, for a claim only load
300
+ // outside the ledger holds, that load not easing — admits it at minimum width.
279
301
  // A solo run is admitted on the first read — its own claim is the ledger's head — so the loop body never
280
302
  // runs and the wait costs nothing.
281
303
  async function await_admission(context: WaitContext): Promise<Admission> {
@@ -370,6 +392,12 @@ async function with_core_reservation<T>(
370
392
  }
371
393
  }
372
394
 
395
+ // Whether a parent's claim already covers this process — a held parent command, or a unit suite this
396
+ // runs inside — so a command claims nothing, and one that sizes its claim need not size it.
397
+ function is_covered(): boolean {
398
+ return held_mark.is_held() || unit_worker_share.is_nested_run()
399
+ }
400
+
373
401
  // **A command's reservation: the gate's claim, unless a parent already holds the cores**
374
402
  // `josh-logic.ts` calls this around every command that declares a weight.
375
403
  // Each command then only declares its weight, and no command carries a copy of the claim, run and
@@ -381,7 +409,7 @@ async function with_command_reservation<T>(
381
409
  run: () => Promise<T>,
382
410
  options: ReserveOptions = {},
383
411
  ): Promise<T> {
384
- if (held_mark.is_held() || unit_worker_share.is_nested_run()) return await run()
412
+ if (is_covered()) return await run()
385
413
 
386
414
  return await with_core_reservation(
387
415
  weight,
@@ -413,6 +441,7 @@ const core_budget = {
413
441
  budget_waits,
414
442
  describe_overflow: core_admission.describe_overflow,
415
443
  held_unit_claim,
444
+ is_covered,
416
445
  is_held: held_mark.is_held,
417
446
  live_reservations,
418
447
  release,
@@ -1,4 +1,5 @@
1
- import { lane_ledger, type CoreWaitRecord } from '#scripts/lane/lane-ledger'
1
+ import type { CoreWaitRecord } from '#scripts/lane/lane-ledger-schema'
2
+ import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
2
3
 
3
4
  // How long a claim waited for the core budget, written to the lane ledger once it is admitted, so
4
5
  // `josh lane:stats` can split a lane's time into work and waiting (joshuafolkken/kit#4382). The
@@ -21,7 +22,7 @@ interface AdmittedClaim {
21
22
  type WaitSink = (wait: CoreWaitRecord) => Promise<void>
22
23
 
23
24
  async function to_ledger(wait: CoreWaitRecord): Promise<void> {
24
- await lane_ledger.record_core_wait(wait)
25
+ await lane_ledger_write.record_core_wait(wait)
25
26
  }
26
27
 
27
28
  function wait_of(claim: AdmittedClaim, now: number): CoreWaitRecord | undefined {
@@ -95,6 +95,25 @@ function hold_reason(
95
95
  return core_admission.is_too_narrow(key, reservations, granted) ? 'cpu' : undefined
96
96
  }
97
97
 
98
+ // **Whether only load from outside the ledger holds the claim** (joshuafolkken/kit#4982): with that load
99
+ // gone — its busy cores handed back and no run-queue overload — the claim would be admitted at a width
100
+ // that is not too narrow. A claim the ledger or memory holds is not, and waits for its room to come back.
101
+ function is_outside_held(
102
+ key: string,
103
+ reservations: ReadonlyArray<LedgerEntry>,
104
+ budget: MachineBudget,
105
+ ): boolean {
106
+ const unloaded = {
107
+ ...budget,
108
+ cores: budget.cores + (budget.busy_excess ?? 0),
109
+ busy_excess: 0,
110
+ is_overloaded: false,
111
+ }
112
+ const granted = core_admission.narrowed_weight(key, reservations, unloaded.cores)
113
+
114
+ return hold_reason(key, reservations, unloaded, granted) === undefined
115
+ }
116
+
98
117
  // The line a waiting command prints once, when its wait starts.
99
118
  function wait_line(command: string | undefined, reason: WaitReason): string {
100
119
  return `⏳ ${command ?? 'a step'} waits for the core budget — ${REASON_TEXT[reason]}`
@@ -102,10 +121,13 @@ function wait_line(command: string | undefined, reason: WaitReason): string {
102
121
 
103
122
  // The lanes root a checkout belongs to: a lane's parent, or the root beside a main checkout. Two
104
123
  // checkouts of one repository share it; the ledger is machine-wide, so another repository's do not.
124
+ // A Claude Code worktree under a checkout reads as that checkout (`lane_paths.checkout_of`).
105
125
  function lanes_root_of(checkout: string): string {
106
- if (lane_paths.lane_issue_of(checkout) === undefined) return lane_paths.lane_root(checkout)
126
+ const resolved = lane_paths.checkout_of(path.resolve(checkout))
127
+
128
+ if (lane_paths.lane_issue_of(resolved) === undefined) return lane_paths.lane_root(resolved)
107
129
 
108
- return path.dirname(path.resolve(checkout))
130
+ return path.dirname(resolved)
109
131
  }
110
132
 
111
133
  // Where a claim runs, read by the claimer under its own environment: `JOSH_LANE_ROOT` is a
@@ -152,6 +174,7 @@ function waits_of(
152
174
  const core_wait = {
153
175
  WAIT_REASONS,
154
176
  hold_reason,
177
+ is_outside_held,
155
178
  wait_line,
156
179
  wait_reason,
157
180
  waits_of,
@@ -10,15 +10,19 @@ interface Measurement {
10
10
  // **What each heavy tool was measured at, on the 11-core machine.** The whole-tree eslint scan behind
11
11
  // `josh lines` and `josh refactor:scan`, cold on 2026-10-06. eslint over 40 staged files
12
12
  // (`pre-commit-lint.ts`), which the gate's lint also runs beside its sibling linters, so it is the
13
- // lint's floor; whole runs were observed at 124–147% CPU. The type check and the spell check with
14
- // `/usr/bin/time -l` on 2026-10-21 under a load average of 14. `prettier --check` over 40 staged
15
- // files, `josh retrospective` and a fresh lane's `pnpm install --frozen-lockfile` with
16
- // `/usr/bin/time -l` on 2026-10-17 under a load average of 16. The gate ledger records each check's
17
- // CPU beside its duration (`check-cpu.ts`), so these can be re-measured from it.
13
+ // lint's floor; whole runs were observed at 124–147% CPU. The type check with `/usr/bin/time -l` on
14
+ // 2026-10-21 under a load average of 14. `prettier --check` over 40 staged files, `josh retrospective`
15
+ // and a fresh lane's `pnpm install --frozen-lockfile` with `/usr/bin/time -l` on 2026-10-17 under a
16
+ // load average of 16. The gate ledger records each check's CPU beside its duration (`check-cpu.ts`),
17
+ // so these can be re-measured from it. The spell check was re-measured from it
18
+ // (joshuafolkken/kit#5140): its median CPU and median wall over the lane ledger's 413 gate `cspell`
19
+ // runs that were not reused, from 2026-10-24 to 2026-10-27, whose per-run cores had a median of 0.91
20
+ // and a p90 of 1.31 — one core rounded up, where the single 2026-10-21 run of 6.0s over 5.6s had
21
+ // rounded up to two.
18
22
  const MEASURED = {
19
23
  lint: { cpu_s: 16.9, wall_s: 14 },
20
24
  type_check: { cpu_s: 31.2, wall_s: 27.3 },
21
- spell_check: { cpu_s: 6, wall_s: 5.6 },
25
+ spell_check: { cpu_s: 5.7, wall_s: 6.2 },
22
26
  eslint_scan: { cpu_s: 113, wall_s: 98 },
23
27
  format: { cpu_s: 2.1, wall_s: 1.7 },
24
28
  retrospective: { cpu_s: 16.5, wall_s: 19.8 },
@@ -57,9 +61,13 @@ const CORE_WEIGHTS = {
57
61
  // On 2026-10-17: prettier 260 MB, the retrospective 862 MB and a lane install 65 MB. On 2026-10-22
58
62
  // (joshuafolkken/kit#4528) the whole suite, 1,830 files at `--maxWorkers=3` beside four lanes, sampled
59
63
  // each worker's resident size once a second: the largest peaked at 381 MB, so the 54-file
60
- // measurement had read a worker short of the files it lives through.
64
+ // measurement had read a worker short of the files it lives through. On 2026-10-23
65
+ // (joshuafolkken/kit#4595) `josh metrics`, its process tree sampled four times a second, peaked at
66
+ // 1,176 MB on a merge-base cache hit and 1,851 MB on a miss, where its own untyped `max-lines`-only
67
+ // eslint pass still holds its heap beside the `--json` child measuring the merge-base. It takes the miss.
61
68
  const MEMORY_MB = {
62
69
  lint: 2400,
70
+ metrics: 1900,
63
71
  type_check: 1300,
64
72
  spell_check: 350,
65
73
  eslint_scan: 2400,