@joshuafolkken/kit 1.1784.0 → 1.2116.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 +60 -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 +386 -360
  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 +16 -9
  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,46 @@
1
+ // **The gate's check names, in a module that imports nothing** (joshuafolkken/kit#5177). Most readers of
2
+ // `gate-plan.ts` wanted only these strings, and importing the plan for them tied every such reader into
3
+ // the plan's own imports — so a change to the plan reached most of the test suite. The plan builds its
4
+ // checks from these; a reader that needs only a name imports this leaf.
5
+
6
+ const LINT_LABEL = 'lint'
7
+ const TYPE_CHECK_LABEL = 'check'
8
+ // The `josh` command the gate's type check runs, shared with `check:related` so the scoped check runs the same one.
9
+ const TYPE_CHECK_TARGET = 'check'
10
+ const SPELL_CHECK_LABEL = 'cspell'
11
+ const SPELL_CHECK_TARGET = 'cspell:dot'
12
+ const UNIT_LABEL = 'test:unit'
13
+ const UNIT_TARGET = 'test:related'
14
+ // **The gate's unit leg runs the whole suite for a changed file every test imports**
15
+ // (joshuafolkken/kit#5122), which every other `josh test:related` narrows to its direct importers.
16
+ const KEEP_WHOLE_SUITE_FLAG = '--keep-whole-suite'
17
+ const BEHAVIOR_LABEL = 'behavior'
18
+ const METRICS_LABEL = 'metrics'
19
+ const EXPORTS_LABEL = 'exports'
20
+ const LOCKFILE_LABEL = 'lockfile'
21
+
22
+ // The checks whose warnings must survive the green record: eslint (the `lint` step) and svelte-check
23
+ // (the `check` step) both exit 0 while reporting per-tree warnings a developer needs to see again, so
24
+ // reusing a record taken from such a run would hide them. Every other step's
25
+ // warning-shaped output — a Vite config deprecation printed by `test:unit`, say — is not a per-tree
26
+ // finding and repeats every run, so it must not withhold the record. `has_checker_warning` narrows
27
+ // the withholding path down to these.
28
+ const WARNING_CHECKER_LABELS: ReadonlyArray<string> = [LINT_LABEL, TYPE_CHECK_LABEL]
29
+
30
+ const gate_labels = {
31
+ BEHAVIOR_LABEL,
32
+ EXPORTS_LABEL,
33
+ KEEP_WHOLE_SUITE_FLAG,
34
+ LINT_LABEL,
35
+ LOCKFILE_LABEL,
36
+ METRICS_LABEL,
37
+ SPELL_CHECK_LABEL,
38
+ SPELL_CHECK_TARGET,
39
+ TYPE_CHECK_LABEL,
40
+ TYPE_CHECK_TARGET,
41
+ UNIT_LABEL,
42
+ UNIT_TARGET,
43
+ WARNING_CHECKER_LABELS,
44
+ }
45
+
46
+ export { gate_labels }
@@ -1,9 +1,11 @@
1
1
  import { process_identity } from '#scripts/josh/process-identity'
2
- import { lane_ledger, type GateCheckRecord } from '#scripts/lane/lane-ledger'
2
+ import type { GateCheckRecord } from '#scripts/lane/lane-ledger-schema'
3
+ import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
4
+ import { lane_paths } from '#scripts/lane/lane-paths'
3
5
  import { related_scope } from '#scripts/test/test-related-scope'
4
6
  import { core_admission } from './core-admission'
5
7
  import { core_budget } from './core-budget'
6
- import { gate_plan } from './gate-plan'
8
+ import { gate_labels } from './gate-labels'
7
9
  import { gate_report, type GateStepResult } from './gate-report'
8
10
  import { machine_capacity } from './machine-capacity'
9
11
 
@@ -96,7 +98,7 @@ async function start(ledger_path: string | undefined): Promise<GateLedgerStart>
96
98
  // The unit leg's own facts: the whole-suite fallback it took, or the since-green no-op that ran no
97
99
  // test (joshuafolkken/kit#4457) — the two `josh lane:stats` must not time as an ordinary run.
98
100
  function unit_facts(result: GateStepResult): Pick<GateCheckRecord, 'fallback' | 'is_unmoved'> {
99
- if (result.label !== gate_plan.UNIT_LABEL) return {}
101
+ if (result.label !== gate_labels.UNIT_LABEL) return {}
100
102
 
101
103
  return {
102
104
  fallback: related_scope.fallback_kind(result.output),
@@ -120,7 +122,12 @@ function check_records(results: ReadonlyArray<GateStepResult>): Array<GateCheckR
120
122
  async function record_reused(ledger_path: string | undefined, elapsed_ms: number): Promise<void> {
121
123
  if (ledger_path === undefined) return
122
124
 
123
- await lane_ledger.record_gate(ledger_path, { elapsed_ms, is_passed: true, is_reused: true })
125
+ await lane_ledger_write.record_gate(ledger_path, {
126
+ elapsed_ms,
127
+ is_passed: true,
128
+ is_reused: true,
129
+ issue: lane_paths.issue_here(),
130
+ })
124
131
  }
125
132
 
126
133
  // The caller measures the elapsed time before this, so the end's reading is never part of it.
@@ -133,14 +140,15 @@ async function record(
133
140
 
134
141
  if (begun.ledger_path === undefined) return
135
142
 
136
- const unit_ms = results.find((result) => result.label === gate_plan.UNIT_LABEL)?.elapsed_ms
143
+ const unit_ms = results.find((result) => result.label === gate_labels.UNIT_LABEL)?.elapsed_ms
137
144
  const external_cores = peak([...begun.readings, await read_external_cores()])
138
145
 
139
- await lane_ledger.record_gate(begun.ledger_path, {
146
+ await lane_ledger_write.record_gate(begun.ledger_path, {
140
147
  ...outcome,
141
148
  unit_ms,
142
149
  external_cores,
143
150
  checks: check_records(results),
151
+ issue: lane_paths.issue_here(),
144
152
  })
145
153
  }
146
154
 
@@ -1,7 +1,8 @@
1
1
  import { availableParallelism } from 'node:os'
2
2
  import { josh_verdict } from '#scripts/josh/josh-verdict'
3
3
  import { unit_worker_share } from '#scripts/test/unit-worker-share'
4
- import { core_budget } from './core-budget'
4
+ import { core_weights } from './core-weights'
5
+ import { gate_labels } from './gate-labels'
5
6
 
6
7
  // How many of the gate's checks run at once, and how wide the one elastic check may fan out —
7
8
  // both derived from the machine rather than fixed at four.
@@ -36,7 +37,7 @@ interface GateCheck {
36
37
  // The unit suite reserves nothing: it sizes its own pool from the machine, so it is capped
37
38
  // instead of reserved, and counting it here would reserve cores against itself.
38
39
  reserved_cores: number
39
- // The memory this check holds while it runs, `core_budget.MEMORY_MB`'s measured peak; none declared is
40
+ // The memory this check holds while it runs, `core_weights.MEMORY_MB`'s measured peak; none declared is
40
41
  // none waited for. The unit suite's is per worker, so it is derived instead.
41
42
  memory_mb?: number
42
43
  // A check whose `josh` command is kit-only, so a consumer's gate leaves it out rather than running
@@ -46,21 +47,20 @@ interface GateCheck {
46
47
  is_kit_only?: boolean
47
48
  }
48
49
 
49
- const LINT_LABEL = 'lint'
50
- const TYPE_CHECK_LABEL = 'check'
51
- const UNIT_LABEL = 'test:unit'
52
- const UNIT_TARGET = 'test:related'
53
- const BEHAVIOR_LABEL = 'behavior'
54
- const METRICS_LABEL = 'metrics'
55
- const EXPORTS_LABEL = 'exports'
56
-
57
- // The checks whose warnings must survive the green record: eslint (the `lint` step) and svelte-check
58
- // (the `check` step) both exit 0 while reporting per-tree warnings a developer needs to see again, so
59
- // reusing a record taken from such a run would hide them. Every other step's
60
- // warning-shaped output — a Vite config deprecation printed by `test:unit`, say — is not a per-tree
61
- // finding and repeats every run, so it must not withhold the record. `has_checker_warning` narrows
62
- // the withholding path down to these.
63
- const WARNING_CHECKER_LABELS: ReadonlyArray<string> = [LINT_LABEL, TYPE_CHECK_LABEL]
50
+ const {
51
+ BEHAVIOR_LABEL,
52
+ EXPORTS_LABEL,
53
+ KEEP_WHOLE_SUITE_FLAG,
54
+ LINT_LABEL,
55
+ LOCKFILE_LABEL,
56
+ METRICS_LABEL,
57
+ SPELL_CHECK_LABEL,
58
+ SPELL_CHECK_TARGET,
59
+ TYPE_CHECK_LABEL,
60
+ TYPE_CHECK_TARGET,
61
+ UNIT_LABEL,
62
+ UNIT_TARGET,
63
+ } = gate_labels
64
64
 
65
65
  // The checks that do not fan out across every core, in the order their output is printed. They are
66
66
  // named apart from the unit suite because CI runs them on their own runner:
@@ -74,14 +74,14 @@ const WARNING_CHECKER_LABELS: ReadonlyArray<string> = [LINT_LABEL, TYPE_CHECK_LA
74
74
  // `--no-unit` set stays "the whole gate minus the unit suite", and a CI runner — which has no recorded
75
75
  // transcripts — runs it as a trivial green rather than skipping it.
76
76
  //
77
- // **The three reserving weights are `core_budget.CORE_WEIGHTS`**, the same
77
+ // **The three reserving weights are `core_weights.CORE_WEIGHTS`**, the same
78
78
  // numbers the `josh lint`, `josh check` and `josh cspell:dot` commands claim when run directly.
79
79
  //
80
80
  // **The two zero weights are measured, and they stay zero.** These are warm runs on the 11-core
81
81
  // machine. `behavior` took 0.6s of wall for 0.7s of CPU, which
82
82
  // is node starting up. `exports:unused` took 5.5s of wall for 9.0s of CPU, about 1.6 cores. Rounded
83
83
  // up, that would be two cores, but a reservation lasts the whole gate's plan, not the check's five
84
- // seconds. It would raise `RESERVED_CORES` from 6 to 8 and cut the solo unit cap from 5 workers to 3
84
+ // seconds. It would raise `RESERVED_CORES` from 5 to 7 and cut the solo unit cap from 6 workers to 4
85
85
  // for the full length of the unit suite, to cover a burst that ends before lint does. Nothing has measured
86
86
  // that trade, so the measured shape stays.
87
87
  const STATIC_CHECKS: ReadonlyArray<GateCheck> = [
@@ -91,20 +91,20 @@ const STATIC_CHECKS: ReadonlyArray<GateCheck> = [
91
91
  label: LINT_LABEL,
92
92
  target: 'lint',
93
93
  args: ['--changed'],
94
- reserved_cores: core_budget.CORE_WEIGHTS.lint,
95
- memory_mb: core_budget.MEMORY_MB.lint,
94
+ reserved_cores: core_weights.CORE_WEIGHTS.lint,
95
+ memory_mb: core_weights.MEMORY_MB.lint,
96
96
  },
97
97
  {
98
98
  label: TYPE_CHECK_LABEL,
99
- target: 'check',
100
- reserved_cores: core_budget.CORE_WEIGHTS.type_check,
101
- memory_mb: core_budget.MEMORY_MB.type_check,
99
+ target: TYPE_CHECK_TARGET,
100
+ reserved_cores: core_weights.CORE_WEIGHTS.type_check,
101
+ memory_mb: core_weights.MEMORY_MB.type_check,
102
102
  },
103
103
  {
104
- label: 'cspell',
105
- target: 'cspell:dot',
106
- reserved_cores: core_budget.CORE_WEIGHTS.spell_check,
107
- memory_mb: core_budget.MEMORY_MB.spell_check,
104
+ label: SPELL_CHECK_LABEL,
105
+ target: SPELL_CHECK_TARGET,
106
+ reserved_cores: core_weights.CORE_WEIGHTS.spell_check,
107
+ memory_mb: core_weights.MEMORY_MB.spell_check,
108
108
  },
109
109
  { label: BEHAVIOR_LABEL, target: BEHAVIOR_LABEL, reserved_cores: 0 },
110
110
  // **The unused-member check reserves no core**: it builds one TypeScript
@@ -121,13 +121,13 @@ const STATIC_CHECKS: ReadonlyArray<GateCheck> = [
121
121
  target: METRICS_LABEL,
122
122
  args: ['--no-startup'],
123
123
  reserved_cores: 0,
124
- memory_mb: core_budget.MEMORY_MB.eslint_scan,
124
+ memory_mb: core_weights.MEMORY_MB.metrics,
125
125
  is_kit_only: true,
126
126
  },
127
127
  // The lockfile policy check is network-bound and usually instant: it verifies only when the
128
128
  // lockfile or `pnpm-workspace.yaml` moved from the merge-base (joshuafolkken/kit#4090), so it
129
129
  // reserves no core. Kit's own until a consumer's private-registry entries are known to verify.
130
- { label: 'lockfile', target: 'lockfile:policy', reserved_cores: 0, is_kit_only: true },
130
+ { label: LOCKFILE_LABEL, target: 'lockfile:policy', reserved_cores: 0, is_kit_only: true },
131
131
  ]
132
132
 
133
133
  // The checks, in the order their output is printed — the static set, then the unit suite last (the
@@ -140,7 +140,7 @@ const STATIC_CHECKS: ReadonlyArray<GateCheck> = [
140
140
  // sharded suite regardless.
141
141
  const GATE_CHECKS: ReadonlyArray<GateCheck> = [
142
142
  ...STATIC_CHECKS,
143
- { label: UNIT_LABEL, target: UNIT_TARGET, reserved_cores: 0 },
143
+ { label: UNIT_LABEL, target: UNIT_TARGET, args: [KEEP_WHOLE_SUITE_FLAG], reserved_cores: 0 },
144
144
  ]
145
145
 
146
146
  // **Selecting is not skipping, and the difference is where the unit suite runs rather than whether
@@ -166,7 +166,7 @@ function has_unit_check(checks: ReadonlyArray<GateCheck>): boolean {
166
166
  return checks.some((check) => check.label === UNIT_LABEL)
167
167
  }
168
168
 
169
- // What the non-elastic checks hold between them: 2 + 2 + 2. Reduced over `STATIC_CHECKS`
169
+ // What the non-elastic checks hold between them: 2 + 2 + 1. Reduced over `STATIC_CHECKS`
170
170
  // rather than over every check, because that is the set the sentence above names: `resolve_unit_worker_cap`
171
171
  // spends this as the cores the unit suite must leave to its siblings, so summing the unit check into
172
172
  // it would have the suite subtract its own reservation from its own budget the day that reservation
@@ -223,6 +223,15 @@ interface GatePlan {
223
223
  // the exact opposite of what this function is for. `bounded-pool.ts` closes the same hole for the
224
224
  // same reason. A count below one is nonsense too and is read as one run, which is the direction
225
225
  // that leaves behavior where it was rather than throttling a gate on a bad input.
226
+ // The order the gate both counts and starts its checks in. `toSorted` is stable, so checks of one
227
+ // weight keep their declaration order.
228
+ function lightest_first<Item>(
229
+ items: ReadonlyArray<Item>,
230
+ reserved_cores_of: (item: Item) => number,
231
+ ): Array<Item> {
232
+ return items.toSorted((left, right) => reserved_cores_of(left) - reserved_cores_of(right))
233
+ }
234
+
226
235
  function shared_cores(available_cores: number, concurrent_runs: number): number {
227
236
  const runs = Number.isFinite(concurrent_runs)
228
237
  ? Math.max(unit_worker_share.SOLO_RUNS, concurrent_runs)
@@ -231,9 +240,9 @@ function shared_cores(available_cores: number, concurrent_runs: number): number
231
240
  return Math.max(MIN_SHARED_CORES, Math.floor(available_cores / runs))
232
241
  }
233
242
 
234
- // Admit checks in declaration order while the running set's reserved cores still fit **this run's
243
+ // Admit checks, lightest first, while the running set's reserved cores still fit **this run's
235
244
  // share** of the machine. On a machine running one gate that share is the machine, so this bites
236
- // only below six cores — the three reserving checks want six between them — and there it is the
245
+ // only below five cores — the three reserving checks want five between them — and there it is the
237
246
  // difference between two checks sharing a core and four fighting over it.
238
247
  //
239
248
  // **Under concurrency it is the only lever there is, and that is a measurement rather than a
@@ -250,16 +259,23 @@ function shared_cores(available_cores: number, concurrent_runs: number): number
250
259
  // the gate still reports every failure in one pass — `bounded_pool` queues what it does not start,
251
260
  // and no check ever rejects (see `run_gate_steps`). What changes is how many are in flight at
252
261
  // once, which is scheduling and never coverage.
262
+ //
263
+ // **The checks are counted lightest first, and `run_gate_steps` starts them in the same order**
264
+ // (joshuafolkken/kit#4609). Counted in declaration order, the first check over the share ended the
265
+ // count, so on CI's four cores lint and the type check filled it and every zero-weight check after
266
+ // the spell check queued behind a check that was only waiting for cores. Lightest first, the `break`
267
+ // is exact: once one check does not fit, no heavier one after it can.
253
268
  function resolve_concurrency(
254
269
  available_cores: number,
255
270
  concurrent_runs: number = unit_worker_share.SOLO_RUNS,
256
271
  checks: ReadonlyArray<GateCheck> = GATE_CHECKS,
257
272
  ): number {
258
273
  const share = shared_cores(available_cores, concurrent_runs)
274
+ const ordered = lightest_first(checks, (check) => check.reserved_cores)
259
275
  let admitted = 0
260
276
  let reserved = 0
261
277
 
262
- for (const check of checks) {
278
+ for (const check of ordered) {
263
279
  reserved += check.reserved_cores
264
280
 
265
281
  if (reserved > share) break
@@ -283,8 +299,8 @@ function resolve_concurrency(
283
299
  //
284
300
  // **The shared branch drops `RESERVED_CORES`, knowingly, and it is not a strict improvement.** Each
285
301
  // concurrent gate still runs lint, the type check and the spell check beside its unit step, and the
286
- // share below does not subtract them: on 12 cores a solo gate takes 8 unit workers plus 3 siblings —
287
- // 11 processes for 12 cores — while two concurrent gates take 6 each plus 3 siblings each, which is 18.
302
+ // share below does not subtract them: on 12 cores a solo gate takes 7 unit workers plus 3 siblings —
303
+ // 10 processes for 12 cores — while two concurrent gates take 6 each plus 3 siblings each, which is 18.
288
304
  // The obvious correction, `⌊(cores − RESERVED_CORES × runs) ÷ runs⌋`, is **not** applied because
289
305
  // nothing has measured it: it hands two gates on an 11-core machine one worker apiece, against the
290
306
  // 11.7s-at-8-workers / 16.7s-at-4 curve the table above was built from, and trading a measured
@@ -323,8 +339,8 @@ function solo_unit_weight(available_cores: number): number {
323
339
  // once**: no second set of weights is introduced, so a change to the measured reservation moves the
324
340
  // admission with it.
325
341
  //
326
- // **A solo gate's four weights sum to exactly the core count** — `reserved(2 + 2 + 2) +
327
- // unit_cap(cores - 6)` is `cores` — which is what lets every check of a lone gate on a machine with room
342
+ // **A solo gate's four weights sum to exactly the core count** — `reserved(2 + 2 + 1) +
343
+ // unit_cap(cores - 5)` is `cores` — which is what lets every check of a lone gate on a machine with room
328
344
  // (its busy cores within what the ledger holds, `core-budget.ts`) be admitted at once,
329
345
  // its concurrency unchanged. A machine below the measured one leaves the unit suite uncapped and reads
330
346
  // its weight from the same identity, `cores - RESERVED_CORES` clamped at zero, so the sum is the core
@@ -336,7 +352,7 @@ function check_weight(check: GateCheck, plan: GatePlan, available_cores: number)
336
352
  }
337
353
 
338
354
  function unit_memory(workers: number): number {
339
- return workers * core_budget.MEMORY_MB.unit_worker
355
+ return workers * core_weights.MEMORY_MB.unit_worker
340
356
  }
341
357
 
342
358
  // The memory a check holds: its declared figure, or for the unit suite one
@@ -347,34 +363,66 @@ function check_memory(check: GateCheck, plan: GatePlan, available_cores: number)
347
363
  return unit_memory(check_weight(check, plan, available_cores))
348
364
  }
349
365
 
366
+ // The workers a lone direct run opens below the gate's solo weight: vitest's own default, one per core
367
+ // but one, bounded by the gate's solo workers on the measured machine. **A direct run has no siblings**,
368
+ // so subtracting `RESERVED_CORES` for them sized a four-core CI runner to zero and its suite to one
369
+ // worker (joshuafolkken/kit#4607); vitest's default is what that runner ran before the claim bounded it.
370
+ // The bound keeps a mid-sized machine from claiming more than the measured one does.
371
+ function direct_solo_workers(available_cores: number): number {
372
+ const vitest_default = available_cores - unit_worker_share.MAIN_PROCESS_CORES
373
+ const floor = Math.min(vitest_default, solo_unit_weight(MEASURED_CORES))
374
+
375
+ return Math.max(solo_unit_weight(available_cores), floor)
376
+ }
377
+
350
378
  // The cores a unit run started directly reserves: the share it will pass to
351
- // vitest while other runs are live, and otherwise the gate's own solo unit weight. **Not the whole
352
- // machine**, though a lone vitest sizes its own pool: FIFO admission lets a claim of every core in only
379
+ // vitest while other runs are live, and otherwise `direct_solo_workers`. **Not the whole
380
+ // machine where there is room to leave**: FIFO admission lets a claim of every core in only
353
381
  // once the ledger is empty, so a one-file `josh test:related` would wait out every other lane's gate
354
- // and hold every later claim behind it. One weight for the suite however it is started. **Floored at one
355
- // worker**: on a machine the static checks fill, a four-core CI runner among them, the gate's solo
356
- // weight is zero because its siblings hold every core — a direct run has no siblings, and vitest still
357
- // occupies a core. **Plus vitest's own process** (joshuafolkken/kit#4362): the workers are the share,
358
- // and the claim holds the process that drives them on top (`unit_worker_share.cap_to_claim` takes it
359
- // back off).
382
+ // and hold every later claim behind it — the solo bound stops below the core count from seven cores up.
383
+ // One weight for the suite however it is started. **Plus vitest's own process** (joshuafolkken/kit#4362):
384
+ // the workers are the share, and the claim holds the process that drives them on top
385
+ // (`unit_worker_share.cap_to_claim` takes it back off).
360
386
  function direct_unit_weight(
361
387
  available_cores: number = availableParallelism(),
362
388
  live_runs: number = unit_worker_share.live_run_count(),
363
389
  ): number {
364
390
  const workers =
365
- unit_worker_share.current_share(available_cores, live_runs) ?? solo_unit_weight(available_cores)
391
+ unit_worker_share.current_share(available_cores, live_runs) ??
392
+ direct_solo_workers(available_cores)
366
393
 
367
394
  return Math.max(unit_worker_share.MIN_WORKERS, workers) + unit_worker_share.MAIN_PROCESS_CORES
368
395
  }
369
396
 
397
+ // The related files one vitest worker clears in about 30 seconds: `tools/test/unit-durations.json`'s
398
+ // median file takes 105 ms (2077 files), and 30 000 ÷ 105 ≈ 285 (joshuafolkken/kit#5135).
399
+ const FILES_PER_WORKER = 285
400
+
401
+ // The cores a narrowed `josh test:related` reserves once its scope is known: one worker for each
402
+ // `FILES_PER_WORKER` related files, at least `MIN_WORKERS` and at most the share `direct_unit_weight`
403
+ // gives the whole suite, plus vitest's own process. **A small scope no longer claims the whole width**,
404
+ // so the other lanes' unit claims stop waiting behind a twenty-second run (joshuafolkken/kit#5135).
405
+ function scoped_unit_weight(
406
+ files: number,
407
+ available_cores: number = availableParallelism(),
408
+ live_runs: number = unit_worker_share.live_run_count(),
409
+ ): number {
410
+ const { MAIN_PROCESS_CORES, MIN_WORKERS } = unit_worker_share
411
+ const share = direct_unit_weight(available_cores, live_runs) - MAIN_PROCESS_CORES
412
+ const wanted = Math.max(MIN_WORKERS, Math.ceil(files / FILES_PER_WORKER))
413
+
414
+ return Math.min(wanted, share) + MAIN_PROCESS_CORES
415
+ }
416
+
370
417
  // What a unit run started directly holds: one worker's peak for each core `direct_unit_weight` gives
371
418
  // it, vitest's own process counted as one more.
372
419
  function direct_unit_memory(): number {
373
420
  return unit_memory(direct_unit_weight())
374
421
  }
375
422
 
376
- // The claim every unit run started directly declares — `josh test:unit`, `josh test:related` and the
377
- // pre-push hook — declared once so the three cannot drift apart.
423
+ // The claim every unit run started directly declares — `josh test:unit` and the pre-push hook —
424
+ // declared once so the two cannot drift apart. `josh test:related` claims in its body instead, once
425
+ // its scope is known (`scoped_unit_weight`).
378
426
  const DIRECT_UNIT_CLAIM = {
379
427
  core_weight: direct_unit_weight,
380
428
  memory_mb: direct_unit_memory,
@@ -468,28 +516,25 @@ function format_gate_plan(
468
516
 
469
517
  const gate_plan = {
470
518
  DIRECT_UNIT_CLAIM,
471
- EXPORTS_LABEL,
519
+ FILES_PER_WORKER,
472
520
  GATE_CHECKS,
473
- LINT_LABEL,
474
521
  MEASURED_CORES,
475
- METRICS_LABEL,
476
522
  RESERVED_CORES,
477
523
  STATIC_CHECKS,
478
- TYPE_CHECK_LABEL,
479
- UNIT_LABEL,
480
- UNIT_TARGET,
481
- WARNING_CHECKER_LABELS,
482
524
  check_memory,
483
525
  check_weight,
484
526
  direct_unit_weight,
485
527
  format_gate_plan,
486
528
  format_machine,
487
529
  has_unit_check,
530
+ lightest_first,
488
531
  plan_of,
489
532
  resolve_concurrency,
490
533
  resolve_gate_plan,
491
534
  resolve_unit_worker_cap,
535
+ scoped_unit_weight,
492
536
  select_gate_checks,
537
+ unit_memory,
493
538
  }
494
539
 
495
540
  export type { GateCheck, GatePlan }
@@ -5,8 +5,9 @@ import { status_icons } from '#scripts/lib/status-icons'
5
5
  import { MS_PER_SECOND } from '#scripts/lib/timeouts'
6
6
  import { NOT_USED_MARKER, NOTHING_TO_CHECK_MARKER } from '#scripts/test/skip-marker'
7
7
  import { test_unit_guard } from '#scripts/test/test-unit-guard'
8
+ import { gate_labels } from './gate-labels'
8
9
  import { gate_log } from './gate-log'
9
- import { gate_plan } from './gate-plan'
10
+ import { verification_tail } from './verification-tail'
10
11
 
11
12
  // The gate's console reporting, split out of `verification-gate.ts` so that file stays under its line
12
13
  // ceiling while it grows the scoped pre-check and the failure summary. Nothing
@@ -98,7 +99,7 @@ function checker_lines(result: GateStepResult): ReadonlyArray<string> {
98
99
  }
99
100
 
100
101
  function has_checker_warning(result: GateStepResult): boolean {
101
- if (!gate_plan.WARNING_CHECKER_LABELS.includes(result.label)) return false
102
+ if (!gate_labels.WARNING_CHECKER_LABELS.includes(result.label)) return false
102
103
 
103
104
  return checker_lines(result).some((line) =>
104
105
  WARNING_MARKERS.some((marker) => line.includes(marker)),
@@ -201,15 +202,16 @@ function print_gate_step(result: GateStepResult, is_verbose: boolean): void {
201
202
  function format_failure_actions(failed: ReadonlyArray<GateStepResult>): string {
202
203
  if (failed.length === 0) return ''
203
204
 
204
- const lines = failed.map(
205
- (result) => ` ${FAIL_ICON} ${result.label} — re-run: pnpm ${result.command}`,
205
+ const lines = failed.map((result) =>
206
+ verification_tail.format_rerun(result.label, `pnpm ${result.command}`),
206
207
  )
207
208
 
208
209
  return `${GATE_COMMAND} — next:\n${lines.join('\n')}\n`
209
210
  }
210
211
 
211
212
  // **A check that started past the core budget is said in the summary, not only in the log**.
212
- // The wait cap admits a check that waited two minutes whatever the budget says,
213
+ // The wait cap admits a check that waited two minutes whatever the budget says — sooner where outside
214
+ // load holds it and does not ease —
213
215
  // so a gate that ran over-subscribed would otherwise look exactly like one that fitted.
214
216
  function format_budget_notes(results: ReadonlyArray<GateStepResult>): string {
215
217
  const lines = results.flatMap((result) =>
@@ -255,10 +257,10 @@ function print_gate_summary(
255
257
  failed.length === 0
256
258
  ? format_green_verdict(results, total)
257
259
  : josh_verdict.format_gate_failed(failed.map((result) => result.label).join(', '), total)
258
- const notes = format_budget_notes(results)
260
+ const failures = `${format_budget_notes(results)}${format_failure_actions(failed)}`
259
261
 
260
262
  process.stdout.write(
261
- `\n${notes}${format_failure_actions(failed)}${gate_log.format_log_notice(log_path)}${verdict}\n`,
263
+ `\n${verification_tail.format_tail({ failures, log: { path: log_path }, verdict })}`,
262
264
  )
263
265
  }
264
266
 
@@ -5,6 +5,7 @@ import { unit_worker_share } from '#scripts/test/unit-worker-share'
5
5
  import { check_cpu, type CheckCpu } from './check-cpu'
6
6
  import { core_budget, type Admission } from './core-budget'
7
7
  import { free_cores } from './free-cores'
8
+ import { gate_labels } from './gate-labels'
8
9
  import { gate_plan, type GatePlan } from './gate-plan'
9
10
  import type { CheckClaim, GateStep, GateStepResult } from './gate-report'
10
11
  import { build_gate_step, with_granted_workers } from './gate-steps'
@@ -61,6 +62,8 @@ function default_budget(): BudgetContext {
61
62
  interface ReservedStep {
62
63
  step: GateStep
63
64
  weight: number
65
+ // The check's own `reserved_cores`, the key `gate_plan.lightest_first` orders the pool's queue by.
66
+ reserved_cores: number
64
67
  memory_mb: number
65
68
  // The plan's `--maxWorkers` for the unit suite, the width the free memory bounds once it is admitted.
66
69
  worker_cap: number | undefined
@@ -80,6 +83,7 @@ async function build_reserved_steps(
80
83
  plan.checks.map(async (check) => ({
81
84
  step: await build_gate_step(check, process.cwd(), plan),
82
85
  weight: gate_plan.check_weight(check, plan, available_cores),
86
+ reserved_cores: check.reserved_cores,
83
87
  memory_mb: gate_plan.check_memory(check, plan, available_cores),
84
88
  worker_cap: plan.unit_worker_cap,
85
89
  reused_at: reused.get(check.label),
@@ -119,7 +123,7 @@ async function admitted_step(
119
123
  admission: Admission,
120
124
  available_cores: number,
121
125
  ): Promise<GateStep> {
122
- if (reserved.step.label !== gate_plan.UNIT_LABEL) return reserved.step
126
+ if (reserved.step.label !== gate_labels.UNIT_LABEL) return reserved.step
123
127
 
124
128
  const { memory_workers } = await free_cores.read({ available_cores })
125
129
  const asked = admission.granted ?? reserved.worker_cap
@@ -155,11 +159,30 @@ async function run_reserved_step(
155
159
  budget: budget.available_cores,
156
160
  memory_mb: reserved.memory_mb,
157
161
  command: `gate ${reserved.step.label}`,
158
- is_unit: reserved.step.label === gate_plan.UNIT_LABEL,
162
+ is_unit: reserved.step.label === gate_labels.UNIT_LABEL,
159
163
  },
160
164
  )
161
165
  }
162
166
 
167
+ // The pool's queue in the order `resolve_concurrency` counted it (joshuafolkken/kit#4609), so the
168
+ // checks its width admitted are the ones that start, and one over the share waits for a slot rather
169
+ // than taking one ahead of a zero-weight check. Each result goes back to its check's declaration
170
+ // position, so the printed sections keep their order.
171
+ async function run_lightest_first(
172
+ reserved: ReadonlyArray<ReservedStep>,
173
+ concurrency: number,
174
+ run: (entry: ReservedStep) => Promise<GateStepResult>,
175
+ ): Promise<ReadonlyArray<GateStepResult>> {
176
+ const indexed = reserved.map((entry, index) => ({ entry, index }))
177
+ const queue = gate_plan.lightest_first(indexed, ({ entry }) => entry.reserved_cores)
178
+ const finished = await bounded_pool.bounded_map(queue, concurrency, async ({ entry, index }) => ({
179
+ index,
180
+ result: await run(entry),
181
+ }))
182
+
183
+ return finished.toSorted((left, right) => left.index - right.index).map(({ result }) => result)
184
+ }
185
+
163
186
  // `bounded_pool` rather than a bare `Promise.all`, so the plan's `concurrency` is what decides how
164
187
  // many run at once. **The all-failures-in-one-pass property survives the
165
188
  // change** because no check ever rejects: `buffered_process` reports a non-zero exit as a value, so
@@ -181,7 +204,7 @@ async function run_gate_steps(
181
204
  // sets the mark too, since its checks are covered by the outer gate's reservation.
182
205
  return await core_budget.with_held_mark(
183
206
  async () =>
184
- await bounded_pool.bounded_map(
207
+ await run_lightest_first(
185
208
  reserved,
186
209
  plan.concurrency,
187
210
  async (entry) => await run_reserved_step(entry, budget, cpu),
@@ -1,4 +1,4 @@
1
- import type { FileMapStamp } from '#scripts/josh/file-map-stamp'
1
+ import { file_map_stamp, type FileMapStamp } from '#scripts/josh/file-map-stamp'
2
2
  import { review_brief } from '#scripts/review/review-brief'
3
3
  import { review_stamps } from '#scripts/review/review-stamps'
4
4
 
@@ -64,11 +64,15 @@ const FORCE_FLAG = '--force'
64
64
  // rewritten by the hook's own install each cost minutes before anyone could tell them apart.
65
65
  type GateReuse = { stamp: FileMapStamp } | { miss: string }
66
66
 
67
+ const NO_BASE = 'the merge base could not be read'
68
+ const NO_CHANGE = 'no file differs from the merge base'
69
+
67
70
  // The fingerprint of every declared check's tools and environment (`verification-inputs.ts`).
68
71
  const INPUTS_MOVED = 'a checked tool or environment variable changed since the green gate'
72
+ const BASE_MOVED = 'the merge base moved since the green gate'
69
73
 
70
74
  function base_moved(recorded: string | undefined, base: string): string {
71
- return `the merge base moved since the green gate (${recorded ?? 'none'} → ${base})`
75
+ return `${BASE_MOVED} (${recorded ?? 'none'} → ${base})`
72
76
  }
73
77
 
74
78
  function stamp_miss(stamp: FileMapStamp, base: string): string | undefined {
@@ -77,23 +81,57 @@ function stamp_miss(stamp: FileMapStamp, base: string): string | undefined {
77
81
  return review_stamps.gate_stamp.describes_inputs(stamp) ? undefined : INPUTS_MOVED
78
82
  }
79
83
 
84
+ const NO_MATCHING_RECORD = 'no green gate record matches the changed files'
85
+
86
+ // joshuafolkken/kit#5214: a record that exists but covers other files is told apart from no record
87
+ // at all, with the sizes of the two maps, so a log shows how far the tree had moved past it.
88
+ function record_miss(recorded: FileMapStamp | undefined, tree: Record<string, string>): string {
89
+ if (recorded === undefined) return NO_MATCHING_RECORD
90
+
91
+ const changed = String(Object.keys(tree).length)
92
+ const covered = String(Object.keys(recorded.files).length)
93
+ const differing = String(file_map_stamp.changed_since(recorded, tree).length)
94
+
95
+ return `${NO_MATCHING_RECORD} (${changed} changed, record covers ${covered}, ${differing} differ)`
96
+ }
97
+
80
98
  function gate_reuse(
81
99
  tree: Record<string, string>,
82
100
  base: string | undefined,
83
101
  source?: string,
84
102
  ): GateReuse {
85
- if (base === undefined) return { miss: 'the merge base could not be read' }
86
- if (Object.keys(tree).length === 0) return { miss: 'no file differs from the merge base' }
103
+ if (base === undefined) return { miss: NO_BASE }
104
+ if (Object.keys(tree).length === 0) return { miss: NO_CHANGE }
87
105
 
88
- const stamp = review_brief.matching_stamp(review_stamps.gate_stamp.read(source), tree)
106
+ const recorded = review_stamps.gate_stamp.read(source)
107
+ const stamp = review_brief.matching_stamp(recorded, tree)
89
108
 
90
- if (stamp === undefined) return { miss: 'no green gate record matches the changed files' }
109
+ if (stamp === undefined) return { miss: record_miss(recorded, tree) }
91
110
 
92
111
  const miss = stamp_miss(stamp, base)
93
112
 
94
113
  return miss === undefined ? { stamp } : { miss }
95
114
  }
96
115
 
116
+ // joshuafolkken/kit#5234: the kind of a miss, read off the sentence `gate_reuse` wrote, so a ledger
117
+ // counts the reasons without a second wording of them. A record that covers other files is checked
118
+ // before no record at all, since its sentence starts with the other's. A miss no prefix names is
119
+ // `other`; a hook's own refusals are told apart first, by `hook_gate_reuse.miss_kind`.
120
+ const MISS_KINDS: ReadonlyArray<readonly [string, string]> = [
121
+ [NO_BASE, 'no-base'],
122
+ [NO_CHANGE, 'no-change'],
123
+ [`${NO_MATCHING_RECORD} (`, 'record-differs'],
124
+ [NO_MATCHING_RECORD, 'no-record'],
125
+ [BASE_MOVED, 'base-moved'],
126
+ [INPUTS_MOVED, 'inputs-moved'],
127
+ ]
128
+
129
+ const OTHER_MISS = 'other'
130
+
131
+ function miss_kind(miss: string): string {
132
+ return MISS_KINDS.find(([prefix]) => miss.startsWith(prefix))?.[1] ?? OTHER_MISS
133
+ }
134
+
97
135
  function stamp_of(reuse: GateReuse): FileMapStamp | undefined {
98
136
  return 'stamp' in reuse ? reuse.stamp : undefined
99
137
  }
@@ -153,6 +191,7 @@ const gate_skip = {
153
191
  format_reuse_notice,
154
192
  format_skip,
155
193
  gate_reuse,
194
+ miss_kind,
156
195
  reusable_green_gate,
157
196
  stamp_of,
158
197
  }