@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
@@ -1,18 +1,19 @@
1
1
  import { randomUUID } from 'node:crypto'
2
2
  import { mkdirSync, readFileSync, rmSync, unlinkSync } from 'node:fs'
3
3
  import path from 'node:path'
4
- import { setTimeout as sleep } from 'node:timers/promises'
5
4
  import { git_common_directory } from '#scripts/git/git-common-directory'
6
5
  import { issue_cite } from '#scripts/issue/issue-cite'
7
6
  import { stamp_file } from '#scripts/josh/stamp-file'
8
7
  import { atomic_write } from '#scripts/lib/atomic-write'
9
8
  import { json_value } from '#scripts/lib/json-value'
9
+ import { poll } from '#scripts/lib/poll'
10
10
  import { run_event_stream } from '#scripts/run/event/run-event-stream'
11
11
  import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
12
12
  import { z } from 'zod'
13
13
  import { lane_broker_server, type BrokerServer } from './lane-broker-server'
14
14
  import type { LaneInfo } from './lane-registry'
15
15
  import { lane_session_action, type BrokerAction, type BrokerAnswer } from './lane-session-action'
16
+ import { lane_session_reread } from './lane-session-reread'
16
17
 
17
18
  // The sessions a lane child's detached `josh ship` cannot start itself, started for it by a process
18
19
  // that can: the round-1 and round-2 reviewer, and the fresh child a stopped ship hands back to. An
@@ -38,9 +39,7 @@ const REQUEST_LIMIT_MINUTES: Readonly<Record<BrokerAction['kind'], number>> = {
38
39
  review: 30,
39
40
  relaunch: 2,
40
41
  }
41
- const request_schema = z
42
- .object({ session: z.uuid(), nonce: z.uuid(), action: lane_session_action.action_schema })
43
- .strict()
42
+ const { request_schema } = lane_session_action
44
43
  // **A request this broker cannot read is still answered**: the supervisor reloads on new code only at
45
44
  // its next pass boundary (`run-wake-code.ts`), so until then a lane's ship can run a newer main than
46
45
  // the broker's, and a field the ship added made the request unreadable and
@@ -49,6 +48,15 @@ const request_schema = z
49
48
  // broker's schema had never learned even on one main (joshuafolkken/kit#4489).
50
49
  const envelope_schema = z.looseObject({ session: z.uuid(), nonce: z.uuid() })
51
50
  const UNREADABLE_REASON = 'the broker could not read the request'
51
+ // **A refused request is read as a version difference, never dropped silently** (joshuafolkken/kit#4714):
52
+ // the refusal marks the supervisor's code as suspect, so its next pass re-hashes the code even where the
53
+ // commit did not move or the hash at its start could not be read, and reloads when it differs. Only the
54
+ // `run:wake` supervisor takes the mark: an OpenAI lane's own supervisor never re-checks its code.
55
+ // **Before it is refused, the code on disk reads it** (`lane-session-reread.ts`), so a schema main widened
56
+ // since the supervisor started is answered now rather than after the reload (joshuafolkken/kit#4732).
57
+ const VERSION_NOTE =
58
+ "the broker's code differs from the ship's; a run:wake supervisor re-checks its code at its next pass"
59
+ const refusal = { is_pending: false }
52
60
  const response_schema = z
53
61
  .object({
54
62
  session: z.uuid(),
@@ -103,15 +111,31 @@ function refused_field(issue: z.core.$ZodIssue): ReadonlyArray<string> {
103
111
  function unreadable(error: z.ZodError): BrokerAnswer {
104
112
  const fields = error.issues.flatMap((issue) => refused_field(issue))
105
113
 
106
- return failure(`${UNREADABLE_REASON} — ${fields.join('; ')}`)
114
+ return failure(`${UNREADABLE_REASON} — ${VERSION_NOTE} — ${fields.join('; ')}`)
115
+ }
116
+
117
+ // The answer of a broker on code older than the request, which the ship can still fall back from.
118
+ function is_unreadable(answer: BrokerAnswer): boolean {
119
+ return !answer.is_success && answer.reason.includes(UNREADABLE_REASON)
107
120
  }
108
121
 
109
122
  async function answer_request(lane: LaneInfo, received: BrokerEnvelope): Promise<BrokerAnswer> {
110
123
  const parsed = request_schema.safeParse(received)
124
+ if (parsed.success) return await lane_session_action.answer(lane, parsed.data.action)
111
125
 
112
- return parsed.success
113
- ? await lane_session_action.answer(lane, parsed.data.action)
114
- : unreadable(parsed.error)
126
+ refusal.is_pending = true
127
+
128
+ return (await lane_session_reread.reread(lane.issue, received)) ?? unreadable(parsed.error)
129
+ }
130
+
131
+ // Whether a request was refused since the supervisor last asked, clearing the mark — the supervisor
132
+ // re-checks its code on it (`run-wake-code.ts`).
133
+ function take_refusal(): boolean {
134
+ const { is_pending } = refusal
135
+
136
+ refusal.is_pending = false
137
+
138
+ return is_pending
115
139
  }
116
140
 
117
141
  // The requests this process's servers are answering now — what the supervisor's reload waits out
@@ -152,21 +176,23 @@ async function serve(
152
176
  response: string,
153
177
  state: { is_running: boolean; current: BrokerResponse },
154
178
  ): Promise<void> {
155
- let last_nonce = ''
179
+ const served = { nonce: '' }
156
180
  const target = request_path(lane.directory, lane.issue)
157
181
 
158
- while (state.is_running) {
182
+ // Requests are served one at a time, in arrival order: a pass ends only once its request is answered.
183
+ async function serve_pass(): Promise<true | undefined> {
184
+ if (!state.is_running) return true
159
185
  const received = read_record(target, envelope_schema)
160
186
 
161
- if (received?.session === session && received.nonce !== last_nonce) {
162
- last_nonce = received.nonce
163
- // eslint-disable-next-line no-await-in-loop -- requests are served one at a time, in arrival order
187
+ if (received?.session === session && received.nonce !== served.nonce) {
188
+ served.nonce = received.nonce
164
189
  await process_request(lane, response, received, state)
165
190
  }
166
191
 
167
- // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
168
- await sleep(POLL_MS)
192
+ return undefined
169
193
  }
194
+
195
+ await poll.wait_for(serve_pass, { interval_ms: POLL_MS })
170
196
  }
171
197
 
172
198
  // The server record is written before the response, so a ship that finds the response finds it too.
@@ -291,15 +317,15 @@ async function wait_response(
291
317
  const limit_minutes = REQUEST_LIMIT_MINUTES[kind]
292
318
  const deadline = Date.now() + limit_minutes * MINUTE_MS
293
319
 
294
- while (Date.now() < deadline) {
295
- const verdict = response_verdict(target, session, nonce)
296
- if (verdict !== undefined) return verdict
320
+ function verdict_by_deadline(): BrokerAnswer | undefined {
321
+ if (Date.now() >= deadline) {
322
+ return failure(`the broker gave no answer within ${String(limit_minutes)} minutes`)
323
+ }
297
324
 
298
- // eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
299
- await sleep(POLL_MS)
325
+ return response_verdict(target, session, nonce)
300
326
  }
301
327
 
302
- return failure(`the broker gave no answer within ${String(limit_minutes)} minutes`)
328
+ return await poll.wait_for(verdict_by_deadline, { interval_ms: POLL_MS })
303
329
  }
304
330
 
305
331
  function live_response(target: string): BrokerResponse | undefined {
@@ -374,11 +400,13 @@ async function request(
374
400
  const lane_session_broker = {
375
401
  is_answering,
376
402
  is_serving,
403
+ is_unreadable,
377
404
  request,
378
405
  request_path,
379
406
  response_path,
380
407
  review_paths: lane_session_action.review_paths,
381
408
  serving_session,
409
+ take_refusal,
382
410
  with_server,
383
411
  }
384
412
 
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env tsx
2
+ import { fileURLToPath } from 'node:url'
3
+ import { lane_session_reread } from './lane-session-reread'
4
+
5
+ // The fresh process a lane broker starts for a request its own code refused (`lane-session-reread.ts`):
6
+ // `<issue> <request JSON>` in, the answer's JSON out, exit 1 where it read nothing.
7
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
8
+ const ARGV_OFFSET = 2
9
+ const [issue = '', text = ''] = process.argv.slice(ARGV_OFFSET)
10
+ const answer = await lane_session_reread.answer_text(issue, text)
11
+
12
+ if (answer === undefined) process.exitCode = 1
13
+ else process.stdout.write(`${JSON.stringify(answer)}\n`)
14
+ }
@@ -0,0 +1,51 @@
1
+ import { fileURLToPath } from 'node:url'
2
+ import { json_value } from '#scripts/lib/json-value'
3
+ import { execa } from 'execa'
4
+ import { z } from 'zod'
5
+ import { lane_registry } from './lane-registry'
6
+ import { lane_session_action, type BrokerAnswer } from './lane-session-action'
7
+
8
+ // **A request the supervisor's loaded code refuses is read again by the code on disk**
9
+ // (joshuafolkken/kit#4732): the `run:wake` supervisor reloads only at a pass boundary, so a schema main
10
+ // widened after it started refused the request a stopped ship sent, and the lane it should have
11
+ // relaunched was parked instead. A fresh process of this file's sibling entry reads the request with
12
+ // the schema main has now and performs the action; it prints the answer only when it read the request,
13
+ // so a disk as old as the supervisor leaves the refusal to the broker.
14
+
15
+ const ENTRY = fileURLToPath(new URL('lane-session-reread-main.ts', import.meta.url))
16
+ const answer_schema = z.discriminatedUnion('is_success', [
17
+ z.object({ is_success: z.literal(true) }).strict(),
18
+ z.object({ is_success: z.literal(false), reason: z.string() }).strict(),
19
+ ])
20
+
21
+ // The fresh process's side: the answer to a request read with the schema on disk, or `undefined` where
22
+ // the request is unreadable or no open lane carries the issue.
23
+ async function answer_text(issue: string, text: string): Promise<BrokerAnswer | undefined> {
24
+ const request = json_value.parse_with(text, lane_session_action.request_schema)
25
+ if (request === undefined) return undefined
26
+
27
+ const lane = await lane_registry.find_open_lane(issue)
28
+ if (lane === undefined) return undefined
29
+
30
+ return await lane_session_action.answer(lane, request.action)
31
+ }
32
+
33
+ function last_line(text: string): string {
34
+ return text.trimEnd().split('\n').at(-1) ?? ''
35
+ }
36
+
37
+ // The supervisor's side: the fresh process's answer, or `undefined` where it read nothing.
38
+ async function reread(issue: string, received: unknown): Promise<BrokerAnswer | undefined> {
39
+ const result = await execa(
40
+ process.execPath,
41
+ [...process.execArgv, ENTRY, issue, JSON.stringify(received)],
42
+ { reject: false, stderr: 'inherit' },
43
+ )
44
+ if (result.exitCode !== 0) return undefined
45
+
46
+ return json_value.parse_with(last_line(result.stdout), answer_schema)
47
+ }
48
+
49
+ const lane_session_reread = { answer_text, reread }
50
+
51
+ export { lane_session_reread }
@@ -0,0 +1,74 @@
1
+ import { lane_check_stats } from './lane-check-stats'
2
+ import { lane_ledger, type LedgerEntry, type ShipLapEntry } from './lane-ledger'
3
+ import { lane_stage_stats } from './lane-stage-stats'
4
+ import { lane_stats, type StatsWindow } from './lane-stats'
5
+
6
+ // What the ship stages spent their time on (joshuafolkken/kit#5294): one period's `ship-lap` entries
7
+ // reduced to one row per stage and inner step — median, maximum and runs — printed by `josh lane:stats`
8
+ // under the stage table. The rows follow the stages' running order, a stage's steps longest first.
9
+ //
10
+ // **A row's first cell names both, `<stage>: <step>`**: `lane:value cell` finds a row by its first
11
+ // cell alone, and a stage records several steps while a step (`scoped pair`) runs in several stages.
12
+
13
+ const COLUMNS = ['ship step', 'median (min)', 'max (min)', 'runs'] as const
14
+ const STAGE_ORDER: ReadonlyArray<string> = lane_stage_stats.STAGES
15
+
16
+ interface Group {
17
+ stage: string
18
+ step: string
19
+ elapsed: ReadonlyArray<number>
20
+ }
21
+
22
+ function is_ship_lap(entry: LedgerEntry): entry is ShipLapEntry {
23
+ return entry.kind === lane_ledger.KIND.SHIP_LAP
24
+ }
25
+
26
+ function groups_of(laps: ReadonlyArray<ShipLapEntry>): Array<Group> {
27
+ const keys = [...new Map(laps.map((lap) => [`${lap.stage}\n${lap.step}`, lap])).values()]
28
+
29
+ return keys.map(({ stage, step }) => ({
30
+ stage,
31
+ step,
32
+ elapsed: laps
33
+ .filter((lap) => lap.stage === stage && lap.step === step)
34
+ .map((lap) => lap.elapsed_ms),
35
+ }))
36
+ }
37
+
38
+ // A stage `STAGES` does not name sorts after every stage it does.
39
+ function stage_rank(stage: string): number {
40
+ const index = STAGE_ORDER.indexOf(stage)
41
+
42
+ return index === -1 ? STAGE_ORDER.length : index
43
+ }
44
+
45
+ function compare(left: Group, right: Group): number {
46
+ const by_stage = stage_rank(left.stage) - stage_rank(right.stage)
47
+
48
+ if (by_stage !== 0) return by_stage
49
+
50
+ return (lane_stats.median(right.elapsed) ?? 0) - (lane_stats.median(left.elapsed) ?? 0)
51
+ }
52
+
53
+ function row_of(group: Group): string {
54
+ return lane_stats.to_row([
55
+ `${group.stage}: ${group.step}`,
56
+ lane_stage_stats.cell(lane_stats.median(group.elapsed)),
57
+ lane_stage_stats.cell(lane_stats.peak(group.elapsed)),
58
+ String(group.elapsed.length),
59
+ ])
60
+ }
61
+
62
+ // The period's table: `entries` is the whole ledger, filtered here to `window`.
63
+ function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
64
+ const laps = lane_stats.in_window(entries, window).filter(is_ship_lap)
65
+ const rows = groups_of(laps)
66
+ .toSorted(compare)
67
+ .map((group) => row_of(group))
68
+
69
+ return [...lane_check_stats.header(COLUMNS), ...rows].join('\n')
70
+ }
71
+
72
+ const lane_ship_lap_stats = { table }
73
+
74
+ export { lane_ship_lap_stats }
@@ -0,0 +1,58 @@
1
+ import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
2
+ import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
3
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
4
+ import type { LaneSpan } from './lane-net-time'
5
+
6
+ // The host's sleep (joshuafolkken/kit#5032): a closed lid stops every lane, yet no park, outage or
7
+ // usage-limit event says so, and its minutes read as work. The load sampler's timer does not fire while
8
+ // the host sleeps, so a tick later than a few intervals is the sign: the wall clock past the tick that
9
+ // was due is recorded as one `sleep` event, and every lane's net time takes it out (`lane-net-time.ts`).
10
+ // A tick merely slowed by load runs well inside the threshold, so a busy host is not read as asleep.
11
+
12
+ const { EVENT_KIND } = run_event_stream
13
+
14
+ const GAP_INTERVALS = 3
15
+
16
+ /** The sleep between two ticks `interval_ms` apart, or `undefined` when the later one was on time. */
17
+ function gap_of(last_ms: number, now_ms: number, interval_ms: number): LaneSpan | undefined {
18
+ if (now_ms - last_ms <= interval_ms * GAP_INTERVALS) return undefined
19
+
20
+ return { from_ms: last_ms + interval_ms, to_ms: now_ms }
21
+ }
22
+
23
+ function event_of(span: LaneSpan): Omit<RunEvent, 'pos'> {
24
+ const elapsed_ms = span.to_ms - span.from_ms
25
+ const minutes = (elapsed_ms / MS_PER_MINUTE).toFixed(1)
26
+
27
+ // Stamped at the wake, when it is appended: a stream reader takes its newest line for the newest time.
28
+ return {
29
+ at: new Date(span.to_ms).toISOString(),
30
+ kind: EVENT_KIND.SLEEP,
31
+ text: `host slept ${minutes} min`,
32
+ elapsed_ms,
33
+ }
34
+ }
35
+
36
+ /** Append `span` as a `sleep` event to `events_path`, or to this checkout's run stream when absent. */
37
+ async function record(span: LaneSpan, events_path?: string): Promise<void> {
38
+ const target = events_path ?? (await run_event_stream_emit.stream_target())
39
+
40
+ if (target === undefined) return
41
+
42
+ run_event_stream.append_event(target, event_of(span))
43
+ }
44
+
45
+ // Every sleep on `events`, oldest first.
46
+ function spans(events: ReadonlyArray<RunEvent>): Array<LaneSpan> {
47
+ return events
48
+ .filter((event) => event.kind === EVENT_KIND.SLEEP)
49
+ .map((event) => {
50
+ const to_ms = Date.parse(event.at)
51
+
52
+ return { from_ms: to_ms - (event.elapsed_ms ?? 0), to_ms }
53
+ })
54
+ }
55
+
56
+ const lane_sleep = { gap_of, record, spans }
57
+
58
+ export { lane_sleep }
@@ -203,7 +203,7 @@ function idle_lanes(
203
203
  return issues_traced(traced_of(lanes, probes), PROCESS_NONE)
204
204
  }
205
205
 
206
- const lane_spent = { idle_lanes, kept_reason, lanes_in_use, sort_lanes }
206
+ const lane_spent = { idle_lanes, kept_reason, lanes_in_use, read_unpushed_commits, sort_lanes }
207
207
 
208
208
  export type { KeptLane, LaneUse, SpentProbes, SpentSort }
209
209
  export { lane_spent }
@@ -0,0 +1,28 @@
1
+ import { split_resolution } from '#scripts/split/split-resolution'
2
+ import type { LedgerEntry } from './lane-ledger'
3
+ import { lane_stats, type StatsWindow } from './lane-stats'
4
+
5
+ // Whether the split notice works: the lanes the notice reached in one period, and how many of them
6
+ // filed a split child, printed by `josh lane:stats` so the notice's effect is read off the ledger
7
+ // rather than searched for in lane transcripts (joshuafolkken/kit#4695). A split child counts
8
+ // whenever it was filed, since a lane may carve the rest out before the notice reaches it.
9
+
10
+ const COLUMNS = ['noticed lanes', 'split'] as const
11
+
12
+ // The period's table: `entries` is the whole ledger; the notices are filtered here to `window`.
13
+ function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
14
+ const in_period = split_resolution.notices(lane_stats.in_window(entries, window))
15
+ const noticed = new Set(in_period.map((entry) => entry.issue))
16
+ const split = split_resolution.split_issues(entries)
17
+ const split_count = [...noticed].filter((issue) => split.has(issue)).length
18
+
19
+ return [
20
+ lane_stats.to_row(COLUMNS),
21
+ lane_stats.to_row(COLUMNS.map(() => '---')),
22
+ lane_stats.to_row([String(noticed.size), String(split_count)]),
23
+ ].join('\n')
24
+ }
25
+
26
+ const lane_split_stats = { table }
27
+
28
+ export { lane_split_stats }
@@ -1,6 +1,12 @@
1
1
  import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
2
2
  import { run_ship_stage } from '#scripts/run/ship/run-ship-stage'
3
- import { lane_ledger, type DispatchEntry, type LedgerEntry, type StageEntry } from './lane-ledger'
3
+ import {
4
+ lane_ledger,
5
+ type DispatchEntry,
6
+ type LedgerEntry,
7
+ type MergeEntry,
8
+ type StageEntry,
9
+ } from './lane-ledger'
4
10
  import { lane_stats, type StatsWindow } from './lane-stats'
5
11
 
6
12
  // Where a lane's time goes: the ledger's `stage` and `dispatch` entries of one period reduced to one
@@ -37,6 +43,7 @@ const STAGES = [
37
43
  lane_ledger.CI_WAIT_STAGE,
38
44
  lane_ledger.CODERABBIT_WAIT_STAGE,
39
45
  lane_ledger.CODERABBIT_RATE_LIMIT_STAGE,
46
+ lane_ledger.CODERABBIT_RETRIGGER_STAGE,
40
47
  STAGE.REPORT,
41
48
  ] as const
42
49
 
@@ -53,6 +60,10 @@ function is_dispatch(entry: LedgerEntry): entry is DispatchEntry {
53
60
  return entry.kind === lane_ledger.KIND.DISPATCH
54
61
  }
55
62
 
63
+ function is_merge(entry: LedgerEntry): entry is MergeEntry {
64
+ return entry.kind === lane_ledger.KIND.MERGE
65
+ }
66
+
56
67
  function is_number(value: number | undefined): value is number {
57
68
  return value !== undefined
58
69
  }
@@ -154,6 +165,7 @@ const lane_stage_stats = {
154
165
  STAGES,
155
166
  cell,
156
167
  is_dispatch,
168
+ is_merge,
157
169
  is_number,
158
170
  is_stage,
159
171
  medians,
@@ -2,6 +2,7 @@ import { readdirSync } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { repository_lock } from '#scripts/git/repository-lock'
4
4
  import { session_cite } from '#scripts/issue/session-cite'
5
+ import { durable_state } from '#scripts/josh/durable-state'
5
6
  import { stamp_file } from '#scripts/josh/stamp-file'
6
7
  import { figure_format } from '#scripts/lib/figure-format'
7
8
  import { json_value } from '#scripts/lib/json-value'
@@ -12,10 +13,10 @@ import { z } from 'zod'
12
13
  // the lane commands (joshuafolkken/kit#4268), so a reader asks the record rather than guessing from
13
14
  // the `.env` mtime, the event stream or the `ps` state.
14
15
  //
15
- // **It is a `stamp_path` keyed on the common git directory**, beside the carry record and the event
16
- // stream and outside every work tree, so it is the same file from the main checkout and from inside
17
- // the lane, it outlives `lane:close`'s removal of the lane, and `JOSH_TEMP_ROOT` moves it with every
18
- // other record the run keeps.
16
+ // **It is a `durable_state` path keyed on the common git directory**, in
17
+ // `<common git dir>/josh/run-state` beside the carry record and the event stream and outside every
18
+ // work tree, so it is the same file from the main checkout and from inside the lane, it outlives
19
+ // `lane:close`'s removal of the lane, and a reboot does not clear it.
19
20
  //
20
21
  // **The write is `stamp_file.replace_stamp`'s** — a temporary file beside the target, renamed over it —
21
22
  // so two commands writing the same lane at once leave one whole record, never a torn one. **The read,
@@ -26,7 +27,7 @@ import { z } from 'zod'
26
27
  // warned about and the command carries on, as it does when the record cannot be written at all — the
27
28
  // record never fails the command that keeps it.
28
29
 
29
- const STATE_PREFIX = 'josh-lane-state-'
30
+ const STATE_PREFIX = durable_state.PREFIX.LANE_STATE
30
31
  const STATE_SUFFIX = '.json'
31
32
  const LOCK_SUFFIX = '.lock'
32
33
  // A change holds the lock for one read and one rename; a wait this long means a holder is stuck.
@@ -85,7 +86,7 @@ type RecordOutcome =
85
86
  { kind: 'written'; record: LaneStateRecord } | { kind: 'skipped'; reason: string }
86
87
 
87
88
  function state_path(directory: string, issue: string): string {
88
- return stamp_file.stamp_path(STATE_PREFIX, directory, `-${issue}${STATE_SUFFIX}`)
89
+ return durable_state.path(STATE_PREFIX, directory, `-${issue}${STATE_SUFFIX}`)
89
90
  }
90
91
 
91
92
  function is_allowed(from: LaneState | undefined, to: LaneState): boolean {
@@ -180,9 +181,10 @@ async function outcome_of(change: LaneChange, options: StateOptions): Promise<Re
180
181
  return apply(change, directory, options.now ?? new Date())
181
182
  }
182
183
 
183
- async function settled_outcome(change: LaneChange, options: StateOptions): Promise<RecordOutcome> {
184
+ // A write that threw is a write skipped for that reason, never an error out of the lane command.
185
+ async function settled(write: () => Promise<RecordOutcome>): Promise<RecordOutcome> {
184
186
  try {
185
- return await outcome_of(change, options)
187
+ return await write()
186
188
  } catch (error: unknown) {
187
189
  return { kind: 'skipped', reason: error instanceof Error ? error.message : String(error) }
188
190
  }
@@ -192,7 +194,7 @@ async function record_change(
192
194
  change: LaneChange,
193
195
  options: StateOptions = {},
194
196
  ): Promise<RecordOutcome> {
195
- const outcome = await settled_outcome(change, options)
197
+ const outcome = await settled(async () => await outcome_of(change, options))
196
198
 
197
199
  if (outcome.kind === 'skipped') warn(change, outcome.reason)
198
200
 
@@ -255,6 +257,35 @@ async function record_stuck(
255
257
  return locked(root, issue, () => stuck_held(issue, stuck, root))
256
258
  }
257
259
 
260
+ function adopted_held(change: LaneChange, directory: string, now: Date): RecordOutcome {
261
+ if (read_record(directory, change.issue) !== undefined) {
262
+ return { kind: 'skipped', reason: 'a record exists' }
263
+ }
264
+
265
+ return apply_held(change, directory, now)
266
+ }
267
+
268
+ /**
269
+ * Write `change` for a lane that has no record, and only then: a record that appeared since the caller
270
+ * read none is the lane command's, and is never overwritten (`lane:adopt`).
271
+ */
272
+ async function adopted_outcome(change: LaneChange, options: StateOptions): Promise<RecordOutcome> {
273
+ const directory = await resolve_directory(options.directory)
274
+
275
+ if (directory === undefined) return NO_DIRECTORY
276
+
277
+ const now = options.now ?? new Date()
278
+
279
+ return locked(directory, change.issue, () => adopted_held(change, directory, now))
280
+ }
281
+
282
+ async function record_adopted(
283
+ change: LaneChange,
284
+ options: StateOptions = {},
285
+ ): Promise<RecordOutcome> {
286
+ return await settled(async () => await adopted_outcome(change, options))
287
+ }
288
+
258
289
  /** Each of `issues`' records, by issue; an issue with none is left out. */
259
290
  async function read_states(
260
291
  issues: ReadonlyArray<string>,
@@ -293,6 +324,7 @@ const lane_state = {
293
324
  read_records,
294
325
  read_state,
295
326
  read_states,
327
+ record_adopted,
296
328
  record_change,
297
329
  record_stuck,
298
330
  state_path,
@@ -0,0 +1,58 @@
1
+ import type { RunEvent } from '#scripts/run/event/run-event-stream'
2
+ import { lane_check_stats } from './lane-check-stats'
3
+ import { lane_ci_path_stats } from './lane-ci-path-stats'
4
+ import { lane_claim_stats } from './lane-claim-stats'
5
+ import { lane_core_wait_stats } from './lane-core-wait-stats'
6
+ import { lane_gap_stats } from './lane-gap-stats'
7
+ import { lane_held_stats } from './lane-held-stats'
8
+ import { lane_implement_stats } from './lane-implement-stats'
9
+ import type { lane_ledger } from './lane-ledger'
10
+ import { lane_paused_spans } from './lane-paused-spans'
11
+ import { lane_process_stats } from './lane-process-stats'
12
+ import { lane_round_one_stats } from './lane-round-one-stats'
13
+ import { lane_round_two_stats } from './lane-round-two-stats'
14
+ import { lane_ship_lap_stats } from './lane-ship-lap-stats'
15
+ import { lane_split_stats } from './lane-split-stats'
16
+ import { lane_stage_stats } from './lane-stage-stats'
17
+ import type { StatsWindow } from './lane-stats'
18
+ import { lane_stop_stats } from './lane-stop-stats'
19
+ import { lane_test_related_stats } from './lane-test-related-stats'
20
+ import type { ToolCall } from './lane-transcript-calls'
21
+ import { lane_transcript_stats } from './lane-transcript-stats'
22
+
23
+ // The tables `josh lane:stats` prints under the period's row — the single source `josh lane:value
24
+ // cell` reads one cell of (joshuafolkken/kit#5144), so a measurement never copies an aggregation.
25
+
26
+ interface PeriodRecords {
27
+ entries: ReturnType<typeof lane_ledger.read_entries>
28
+ events: ReadonlyArray<RunEvent>
29
+ calls: ReadonlyArray<ToolCall>
30
+ }
31
+
32
+ // The tables under the period's row, in the order `lane:stats` prints them.
33
+ function tables_of({ entries, events, calls }: PeriodRecords, window: StatsWindow): Array<string> {
34
+ return [
35
+ lane_stage_stats.table(entries, window),
36
+ lane_ship_lap_stats.table(entries, window),
37
+ lane_ci_path_stats.table(entries, window),
38
+ lane_implement_stats.table(calls, window, lane_paused_spans.by_lane(entries)),
39
+ lane_stop_stats.table(entries, window, events),
40
+ lane_gap_stats.table(entries, window, events),
41
+ lane_round_one_stats.table(entries, window),
42
+ lane_round_two_stats.table(entries, window),
43
+ lane_split_stats.table(entries, window),
44
+ lane_held_stats.table(entries, window),
45
+ lane_core_wait_stats.table(entries, window),
46
+ lane_process_stats.table(entries, window),
47
+ lane_check_stats.table(entries, window),
48
+ lane_claim_stats.table(entries, window),
49
+ lane_test_related_stats.table(entries, window),
50
+ lane_test_related_stats.trigger_table(entries, window),
51
+ lane_transcript_stats.table(calls, window),
52
+ ]
53
+ }
54
+
55
+ const lane_stats_tables = { tables_of }
56
+
57
+ export type { PeriodRecords }
58
+ export { lane_stats_tables }
@@ -2,6 +2,7 @@ import { machine_capacity } from '#scripts/gate/machine-capacity'
2
2
  import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
3
3
  import type { DispatchEntry, GateEntry, LedgerEntry, LoadEntry, MergeEntry } from './lane-ledger'
4
4
  import { lane_sampler } from './lane-sampler'
5
+ import { lane_tail_stats } from './lane-tail-stats'
5
6
 
6
7
  // The lane-limit measurement's one table row: the ledger entries of one period
7
8
  // reduced to throughput, gate duration and machine load, in the column order
@@ -41,6 +42,8 @@ const COLUMNS = [
41
42
  'merges / hour',
42
43
  'effective lanes',
43
44
  'lane median (min)',
45
+ `lanes over ${String(lane_tail_stats.OVERRUN_LANE_MINUTES)} min`,
46
+ 'lane p90 (min)',
44
47
  'gate median (min)',
45
48
  'gate max (min)',
46
49
  'load peak',
@@ -236,17 +239,30 @@ function lane_minutes(
236
239
 
237
240
  // One merge's lane time runs from the latest dispatch of its issue — looked up in the whole ledger,
238
241
  // since a lane may start before the window — to the merge. A merge no dispatch preceded is skipped.
239
- function lane_cell(
242
+ function merge_minutes(
240
243
  entries: ReadonlyArray<LedgerEntry>,
241
244
  period: ReadonlyArray<LedgerEntry>,
242
- ): string {
245
+ ): Array<number> {
243
246
  const dispatches = entries.filter(is_dispatch)
244
- const minutes = period
247
+
248
+ return period
245
249
  .filter((entry) => is_merge(entry))
246
250
  .map((merge) => lane_minutes(dispatches, merge))
247
251
  .filter(is_number)
252
+ }
248
253
 
249
- return cell(median(minutes))
254
+ // The median lane, then its tail (`lane-tail-stats.ts`).
255
+ function lane_cells(
256
+ entries: ReadonlyArray<LedgerEntry>,
257
+ period: ReadonlyArray<LedgerEntry>,
258
+ ): Array<string> {
259
+ const minutes = merge_minutes(entries, period)
260
+
261
+ return [
262
+ cell(median(minutes)),
263
+ String(lane_tail_stats.overrun_count(minutes)),
264
+ cell(lane_tail_stats.tail_minutes(minutes)),
265
+ ]
250
266
  }
251
267
 
252
268
  // A reused gate ran no check, so its few milliseconds would pull the median toward a gate that never ran.
@@ -301,7 +317,7 @@ function row(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow, label: Ro
301
317
  label.limit,
302
318
  String(label.period_days),
303
319
  ...throughput_cells(period),
304
- lane_cell(entries, period),
320
+ ...lane_cells(entries, period),
305
321
  ...gate_cells(period),
306
322
  ...load_cells(period.filter(is_load)),
307
323
  ])