@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,4 +1,5 @@
1
1
  import { issue_number_shape } from '#scripts/issue/issue-number-shape'
2
+ import { lane_child_mark_keys } from './lane-child-mark-keys'
2
3
  import { lane_paths } from './lane-paths'
3
4
 
4
5
  // The mark a dispatched lane child carries, so the pre-gate cut and a resume are decided from the
@@ -17,7 +18,7 @@ import { lane_paths } from './lane-paths'
17
18
  // equals the lane's own issue, so a leaked mark for another issue is read as absent. The name, the
18
19
  // meaning and the lifetime are documented once in
19
20
  // `.claude/skills/workflow-commands/pre-gate-cut.md`.
20
- const KEY = 'JOSH_LANE_CHILD'
21
+ const { KEY, OVERRUN_KEY } = lane_child_mark_keys
21
22
 
22
23
  // **A dispatched child also asks for the five-minute prompt-cache TTL**. A
23
24
  // headless `claude -p` session on a subscription defaults to the one-hour TTL, whose writes bill at 2x
@@ -28,6 +29,11 @@ const KEY = 'JOSH_LANE_CHILD'
28
29
  const CACHE_TTL_KEY = 'CLAUDE_CODE_PROMPT_CACHE_TTL'
29
30
  const CACHE_TTL = '5m'
30
31
 
32
+ // **An overrun investigation also carries its own mark** (joshuafolkken/kit#4880): it runs as the
33
+ // lane's child, so `issue:file` reads this one to record its filings as the investigation's rather than
34
+ // the child's. The launcher sets it, so the record never rests on the model passing an argument.
35
+ const OVERRUN_VALUE = '1'
36
+
31
37
  type MarkerSource = Readonly<Record<string, string | undefined>>
32
38
 
33
39
  // The environment fragment that marks a child dispatched for `#<issue>`. Composed from a digits-only
@@ -50,6 +56,16 @@ function marked_issue(source: MarkerSource = process.env): string | undefined {
50
56
  return issue_number_shape.ISSUE_NUMBER_PATTERN.test(value) ? value : undefined
51
57
  }
52
58
 
59
+ // The environment of the overrun investigation of `#<issue>`'s lane: the child's, plus its own mark.
60
+ function overrun_environment_for(issue: string): Record<string, string> {
61
+ return { ...environment_for(issue), [OVERRUN_KEY]: OVERRUN_VALUE }
62
+ }
63
+
64
+ // Read only beside a valid child mark, so a mark leaked without one is read as absent.
65
+ function is_overrun(source: MarkerSource = process.env): boolean {
66
+ return source[OVERRUN_KEY] === OVERRUN_VALUE && marked_issue(source) !== undefined
67
+ }
68
+
53
69
  // True when this session is a dispatched lane child for the checkout it is running in: the mark is
54
70
  // present and names this lane's own issue, read from the checkout path. A numeric mark naming a
55
71
  // *different* issue leaked in from a parent session into a checkout it does not belong to, so it is
@@ -63,8 +79,11 @@ function is_child_of(directory: string, source: MarkerSource = process.env): boo
63
79
 
64
80
  const lane_child_marker = {
65
81
  KEY,
82
+ OVERRUN_KEY,
66
83
  env_for: environment_for,
84
+ overrun_env_for: overrun_environment_for,
67
85
  is_child_of,
86
+ is_overrun,
68
87
  marked_issue,
69
88
  }
70
89
 
@@ -0,0 +1,73 @@
1
+ import { lane_check_stats } from './lane-check-stats'
2
+ import { lane_ledger, type LedgerEntry, type StageEntry } from './lane-ledger'
3
+ import { lane_ledger_write } from './lane-ledger-write'
4
+ import { lane_stats, type StatsWindow } from './lane-stats'
5
+
6
+ // The followup's critical path (joshuafolkken/kit#5295): over the period's `ci-wait` rows, which check
7
+ // settled last — how often, and the median and maximum of when it settled into the wait — printed by
8
+ // `josh lane:stats`. A row from before the field, or a wait no check was seen to settle in, names none
9
+ // and is left out.
10
+
11
+ const COLUMNS = ['followup critical path', 'runs', 'median (s)', 'max (s)'] as const
12
+
13
+ interface LastCheck {
14
+ name: string
15
+ elapsed_ms: number
16
+ }
17
+
18
+ function settled({ last_check, check_ms }: StageEntry): LastCheck | undefined {
19
+ if (last_check === undefined) return undefined
20
+
21
+ const elapsed_ms = check_ms?.[last_check]
22
+
23
+ return elapsed_ms === undefined ? undefined : { name: last_check, elapsed_ms }
24
+ }
25
+
26
+ function last_check_of(entry: LedgerEntry): LastCheck | undefined {
27
+ if (entry.kind !== lane_ledger.KIND.STAGE || entry.stage !== lane_ledger_write.CI_WAIT_STAGE) {
28
+ return undefined
29
+ }
30
+
31
+ return settled(entry)
32
+ }
33
+
34
+ function name_row(name: string, lasts: ReadonlyArray<LastCheck>): string {
35
+ const elapsed = lasts.filter((last) => last.name === name).map((last) => last.elapsed_ms)
36
+
37
+ return lane_stats.to_row([
38
+ name,
39
+ String(elapsed.length),
40
+ lane_check_stats.cell(lane_stats.median(elapsed)),
41
+ lane_check_stats.cell(lane_stats.peak(elapsed)),
42
+ ])
43
+ }
44
+
45
+ // The period's table: `entries` is the whole ledger, filtered here to `window`.
46
+ function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
47
+ const lasts = lane_stats
48
+ .in_window(entries, window)
49
+ .map((entry) => last_check_of(entry))
50
+ .filter((last) => last !== undefined)
51
+ const names = [...new Set(lasts.map((last) => last.name))]
52
+
53
+ return [...lane_check_stats.header(COLUMNS), ...names.map((name) => name_row(name, lasts))].join(
54
+ '\n',
55
+ )
56
+ }
57
+
58
+ // `issue`'s followup line detail for `lane:breakdown`: the last check its latest `ci-wait` row names,
59
+ // `''` where none does.
60
+ function last_check_text(entries: ReadonlyArray<LedgerEntry>, issue: number): string {
61
+ const last = entries
62
+ .filter((entry) => entry.kind === lane_ledger.KIND.STAGE && entry.issue === issue)
63
+ .map((entry) => last_check_of(entry))
64
+ .findLast((found) => found !== undefined)
65
+
66
+ return last === undefined
67
+ ? ''
68
+ : ` (last check: ${last.name} ${lane_check_stats.cell(last.elapsed_ms)}s)`
69
+ }
70
+
71
+ const lane_ci_path_stats = { last_check_text, table }
72
+
73
+ export { lane_ci_path_stats }
@@ -0,0 +1,84 @@
1
+ import { MS_PER_SECOND } from '#scripts/lib/timeouts'
2
+ import { lane_ledger, type GateCheckRecord, type GateEntry, type LedgerEntry } from './lane-ledger'
3
+ import { lane_stage_stats } from './lane-stage-stats'
4
+ import { lane_stats, type StatsWindow } from './lane-stats'
5
+ import { lane_tail_stats } from './lane-tail-stats'
6
+
7
+ // What each gate check claimed from the core budget against what it used (joshuafolkken/kit#5138): one
8
+ // period's per-check rows reduced to one row per check — the median cores requested, then the cores it
9
+ // kept busy (`cpu_ms ÷ elapsed_ms`) as a median, a 90th percentile and a maximum, and the seconds its
10
+ // claims waited. The weights in `scripts/gate/core-weights.ts` are changed from this table, never by it.
11
+ //
12
+ // **Only a measured run is counted**: a reused check started no process, and a check with no `cpu_ms`
13
+ // was recorded before the field existed, so neither says how many cores the check used.
14
+
15
+ const DECIMALS = 1
16
+ const COLUMNS = [
17
+ 'check',
18
+ 'claim',
19
+ 'runs',
20
+ 'cores median',
21
+ 'cores p90',
22
+ 'cores max',
23
+ 'wait (s)',
24
+ ] as const
25
+ const { NOT_MEASURED } = lane_stage_stats
26
+
27
+ interface MeasuredCheck {
28
+ label: string
29
+ elapsed_ms: number
30
+ cpu_ms: number
31
+ claim?: GateCheckRecord['claim']
32
+ }
33
+
34
+ function is_gate(entry: LedgerEntry): entry is GateEntry {
35
+ return entry.kind === lane_ledger.KIND.GATE
36
+ }
37
+
38
+ function is_measured(check: GateCheckRecord): check is GateCheckRecord & MeasuredCheck {
39
+ return check.is_reused !== true && check.cpu_ms !== undefined && check.elapsed_ms > 0
40
+ }
41
+
42
+ function number_cell(value: number | undefined): string {
43
+ return value === undefined ? NOT_MEASURED : value.toFixed(DECIMALS)
44
+ }
45
+
46
+ function seconds_cell(milliseconds: number | undefined): string {
47
+ return number_cell(milliseconds === undefined ? undefined : milliseconds / MS_PER_SECOND)
48
+ }
49
+
50
+ function total(values: ReadonlyArray<number>): number {
51
+ return values.reduce((sum, value) => sum + value, 0)
52
+ }
53
+
54
+ function check_row(label: string, checks: ReadonlyArray<MeasuredCheck>): string {
55
+ const runs = checks.filter((check) => check.label === label)
56
+ const cores = runs.map((check) => check.cpu_ms / check.elapsed_ms)
57
+ const claims = runs.map((check) => check.claim).filter((claim) => claim !== undefined)
58
+ const requested = claims.map((claim) => claim.requested)
59
+ const waited_ms = claims.length === 0 ? undefined : total(claims.map((claim) => claim.waited_ms))
60
+
61
+ return lane_stats.to_row([
62
+ label,
63
+ number_cell(lane_stats.median(requested)),
64
+ String(runs.length),
65
+ number_cell(lane_stats.median(cores)),
66
+ number_cell(lane_tail_stats.tail_minutes(cores)),
67
+ number_cell(lane_stats.peak(cores)),
68
+ seconds_cell(waited_ms),
69
+ ])
70
+ }
71
+
72
+ // The period's table: `entries` is the whole ledger, filtered here to `window`.
73
+ function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
74
+ const gates = lane_stats.in_window(entries, window).filter(is_gate)
75
+ const checks = gates.flatMap((gate) => gate.checks ?? []).filter(is_measured)
76
+ const labels = [...new Set(checks.map((check) => check.label))]
77
+ const header = [lane_stats.to_row(COLUMNS), lane_stats.to_row(COLUMNS.map(() => '---'))]
78
+
79
+ return [...header, ...labels.map((label) => check_row(label, checks))].join('\n')
80
+ }
81
+
82
+ const lane_claim_stats = { table }
83
+
84
+ export { lane_claim_stats }
@@ -3,6 +3,7 @@ import { git_command } from '#scripts/git/git-command'
3
3
  import { git_worktree } from '#scripts/git/git-worktree'
4
4
  import { error_text } from '#scripts/lib/error-message'
5
5
  import { lane_paths } from './lane-paths'
6
+ import { lane_plan } from './lane-plan'
6
7
  import { lane_reap } from './lane-reap'
7
8
  import { lane_reap_settle } from './lane-reap-settle'
8
9
  import { lane_registry, type LaneInfo } from './lane-registry'
@@ -160,6 +161,12 @@ async function left_behind_of(issue: string, targets: LaneTargets): Promise<Arra
160
161
  return [...(await residue(targets)), ...survivors]
161
162
  }
162
163
 
164
+ // An ended lane's cleared plan goes with it; a plan its lane yielded on stays (`lane_plan.release`).
165
+ async function record_end(issue: string): Promise<void> {
166
+ await lane_state.record_change({ issue, state: 'ended', command: 'lane:close' })
167
+ lane_plan.release(Number(issue), process.cwd())
168
+ }
169
+
163
170
  async function close_lane(issue: string): Promise<CloseOutcome> {
164
171
  const { existing, targets } = await resolve_lane(issue)
165
172
  const did_exist = existing !== undefined || existsSync(targets.directory)
@@ -174,9 +181,7 @@ async function close_lane(issue: string): Promise<CloseOutcome> {
174
181
  const left_behind = await left_behind_of(issue, targets)
175
182
  const kind = close_kind(did_exist, left_behind)
176
183
 
177
- if (await is_ending(issue, kind)) {
178
- await lane_state.record_change({ issue, state: 'ended', command: 'lane:close' })
179
- }
184
+ if (await is_ending(issue, kind)) await record_end(issue)
180
185
 
181
186
  return { issue, kind, left_behind, reaped, residents }
182
187
  }
@@ -1,11 +1,11 @@
1
- import { stamp_file } from '#scripts/josh/stamp-file'
1
+ import { durable_state } from '#scripts/josh/durable-state'
2
2
  import type { LaneInfo } from './lane-registry'
3
3
 
4
- const LOG_PREFIX = 'josh-lane-dispatch-'
4
+ const LOG_PREFIX = durable_state.PREFIX.LANE_DISPATCH
5
5
  const LOG_SUFFIX = '.log'
6
6
 
7
7
  function default_log_path(lane: LaneInfo): string {
8
- return stamp_file.stamp_path(`${LOG_PREFIX}${lane.issue}-`, lane.directory, LOG_SUFFIX)
8
+ return durable_state.path(`${LOG_PREFIX}${lane.issue}-`, lane.directory, LOG_SUFFIX)
9
9
  }
10
10
 
11
11
  const lane_dispatch_log = { default_log_path }
@@ -16,7 +16,7 @@ import { run_label } from '#scripts/run/run-label'
16
16
  import { lane_child_invocation } from './lane-child-invocation'
17
17
  import { lane_child_marker } from './lane-child-marker'
18
18
  import { lane_dispatch_log } from './lane-dispatch-log'
19
- import { lane_ledger } from './lane-ledger'
19
+ import { lane_ledger_write } from './lane-ledger-write'
20
20
  import { lane_output } from './lane-output'
21
21
  import { lane_registry, type LaneInfo } from './lane-registry'
22
22
  import { lane_resume, type ResumePlan } from './lane-resume'
@@ -345,7 +345,7 @@ async function record_started(issue: string, start: DispatchStart): Promise<void
345
345
  `${issue_cite.plain(issue)} dispatched`,
346
346
  now,
347
347
  )
348
- await lane_ledger.record_dispatch(Number(issue))
348
+ await lane_ledger_write.record_dispatch(Number(issue))
349
349
  await lane_state.record_change(
350
350
  {
351
351
  issue,
@@ -2,6 +2,7 @@ import { agent_role_profile } from '#scripts/agent/agent-role-profile'
2
2
  import { MS_PER_SECOND } from '#scripts/lib/timeouts'
3
3
  import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
4
4
  import { lane_ledger, type LedgerEntry, type MergeEntry } from './lane-ledger'
5
+ import { lane_net_time } from './lane-net-time'
5
6
  import { lane_spans, type Span } from './lane-spans'
6
7
  import { lane_stage_stats } from './lane-stage-stats'
7
8
  import { lane_stats, type StatsWindow } from './lane-stats'
@@ -17,6 +18,8 @@ import { lane_stop_stats } from './lane-stop-stats'
17
18
  // entry. A pool that stays full writes no line after its one `released`, and a driver handed back
18
19
  // writes none, so a gap over the offer interval is a full pool or no driver, never the hand-over
19
20
  // (joshuafolkken/kit#4410). The ship's cap park and the driver's collection of it are each timed.
21
+ // - `yield → redispatch`: a yield (`lane:plan` gave the seat back) until its issue's next `dispatch`, the
22
+ // wait `josh lane:net` takes out (`lane-net-time.ts`, joshuafolkken/kit#5216).
20
23
  // - `followup → merge`: the ship's last `followup` stage before the merge until the parent wrote the
21
24
  // `merge` line, the step that releases the slot. A merge with no `followup` stage has no start.
22
25
  //
@@ -26,10 +29,11 @@ const COLUMNS = ['gap', 'count', 'median (s)', 'max (s)', 'not ended'] as const
26
29
  const RELAUNCH = 'cut → resume'
27
30
  const OUTAGE = 'outage → relaunch'
28
31
  const PARK = 'park → offer'
32
+ const YIELD = 'yield → redispatch'
29
33
  const MERGE = 'followup → merge'
30
34
  const FOLLOWUP_STAGE = 'followup'
31
35
  const IMPLEMENTATION_CUT = `cut (${agent_role_profile.IMPLEMENTATION_PHASE})`
32
- const { NOT_MEASURED, is_dispatch, is_number, is_stage } = lane_stage_stats
36
+ const { NOT_MEASURED, is_dispatch, is_merge, is_number, is_stage } = lane_stage_stats
33
37
  const { EVENT_KIND } = run_event_stream
34
38
  // The offer answers that are not a dispatch: a free lane held, or the pool found full.
35
39
  const OFFER_ANSWERS: ReadonlySet<string> = new Set([
@@ -38,7 +42,7 @@ const OFFER_ANSWERS: ReadonlySet<string> = new Set([
38
42
  ])
39
43
 
40
44
  // Only an implementation cut appends a `resume` when it is adopted; a pre-gate resume appends nothing,
41
- // so its cut would read as never ended (`run-cut-cli.ts` → `emit_resume_event`).
45
+ // so its cut would read as never ended (`run-cut-resume.ts` → `emit_resume_event`).
42
46
  function implementation_cuts(events: ReadonlyArray<RunEvent>): Array<RunEvent> {
43
47
  return events.filter((event) => event.text.endsWith(IMPLEMENTATION_CUT))
44
48
  }
@@ -81,10 +85,6 @@ function park_spans(
81
85
  .map((park) => ({ from_ms: park.at_ms, end_ms: offers.find((at) => at > park.at_ms) }))
82
86
  }
83
87
 
84
- function is_merge(entry: LedgerEntry): entry is MergeEntry {
85
- return entry.kind === lane_ledger.KIND.MERGE
86
- }
87
-
88
88
  function is_followup_of(entry: LedgerEntry, merge: MergeEntry): boolean {
89
89
  return (
90
90
  is_stage(entry) &&
@@ -147,6 +147,7 @@ function table(
147
147
  gap_row(RELAUNCH, relaunch_spans(events), window),
148
148
  gap_row(OUTAGE, outage_spans(events), window),
149
149
  gap_row(PARK, park_spans(entries, events), window),
150
+ gap_row(YIELD, lane_net_time.yield_spans(entries, events), window),
150
151
  gap_row(MERGE, merge_spans(entries), window),
151
152
  ].join('\n')
152
153
  }
@@ -26,7 +26,7 @@ import { lane_child_marker, type MarkerSource } from './lane-child-marker'
26
26
  // The three ways a guard may behave in a lane child. Outside a lane child every
27
27
  // guard is `refuse`, which is why that is also the fail-safe default below.
28
28
  type LaneGuardMode = 'refuse' | 'notice' | 'off'
29
- type LaneGuardId = 'investigation' | 'batching' | 'rule' | 'duplicate-read'
29
+ type LaneGuardId = 'investigation' | 'batching' | 'search-batching' | 'rule' | 'duplicate-read'
30
30
 
31
31
  // The mode outside a lane child, and the fail-safe for a guard nobody enumerated: a denial, the same
32
32
  // direction `delegation-policy.ts` takes, because a silenced rule is the one mistake that ships unseen.
@@ -55,6 +55,12 @@ const LANE_GUARD_POLICY: ReadonlyArray<LaneGuardEntry> = [
55
55
  because:
56
56
  'a refusal ends a child turn and every advisory notice was measured not to move the call density, so the guard is off and the density stays readable through `josh time:density`',
57
57
  },
58
+ {
59
+ id: 'search-batching',
60
+ mode_in_lane_child: 'refuse',
61
+ because:
62
+ 'the largest share of single-call pairs in lane children is a search chain (`grep` / `sed` issued one per turn, about 10,600 pairs in 14 days), and a refusal re-fires only every third single-call search turn, so one refused round trip (about $0.036) is repaid once it folds two later searches into one turn',
63
+ },
58
64
  {
59
65
  id: 'duplicate-read',
60
66
  mode_in_lane_child: 'notice',
@@ -0,0 +1,207 @@
1
+ import { lane_implement_subagents, type ImplementLane } from './lane-implement-subagents'
2
+ import { lane_paused_spans, type PausedSpan, type PausedSpans } from './lane-paused-spans'
3
+ import { lane_stage_stats } from './lane-stage-stats'
4
+ import { lane_stats, type StatsWindow } from './lane-stats'
5
+ import type { ToolCall } from './lane-transcript-calls'
6
+ import { lane_transcript_stats } from './lane-transcript-stats'
7
+
8
+ // The implement stage broken down by what its time went on (joshuafolkken/kit#4887). The ledger's
9
+ // implement is one span per lane, dispatch to the ship's first stage (`lane-stage-stats.ts`); the lane's
10
+ // transcript holds every tool call inside it, so each call's span — from the latest end of the session's
11
+ // earlier calls to its own, the model's turn before it included — is put to one sub-stage, and `lane:stats` prints each one's
12
+ // median over the period's lanes.
13
+ //
14
+ // **A lane's implement ends at its first `josh ship` call**, so a lane that never shipped in the period
15
+ // has no implement here. **`review-fix` runs from `run:review` on** — the round's fixes and their scoped
16
+ // checks; before it, an edit is `edit`, a scoped check or gate is `check`, and any other call is `plan`
17
+ // before the first edit, `read` after it. **A session's first call spans its own duration**, so the gap
18
+ // between two sessions of one lane is nobody's. **Nor is the time the lane stood paused**: a
19
+ // `lane:pause` leaves the call in flight on the clock, so its overlap with the lane's paused spans is
20
+ // taken out (joshuafolkken/kit#5168).
21
+
22
+ const SUB_STAGES = ['plan', 'read', 'edit', 'check', 'review-fix'] as const
23
+ type SubStage = (typeof SUB_STAGES)[number]
24
+ const [PLAN, READ, EDIT, CHECK, REVIEW_FIX] = SUB_STAGES
25
+ type Totals = ReadonlyMap<SubStage, number>
26
+
27
+ const EDIT_TOOLS: ReadonlySet<string> = new Set(['Edit', 'MultiEdit', 'NotebookEdit', 'Write'])
28
+ const CHECK_COMMANDS: ReadonlySet<string> = new Set([
29
+ 'check:related',
30
+ 'cspell:dot',
31
+ 'gate',
32
+ 'lint:related',
33
+ 'metrics',
34
+ 'test:pinned',
35
+ 'test:related',
36
+ ])
37
+ const REVIEW_COMMANDS: ReadonlySet<string> = new Set(['review:brief', 'run:review'])
38
+ const SHIP_COMMANDS: ReadonlySet<string> = new Set(['ship'])
39
+ // `backgrounded` counts a subagent row's untimed calls (`lane-implement-subagents.ts`); a sub-stage has none.
40
+ const COLUMNS = [
41
+ 'implement sub-stage',
42
+ 'lanes',
43
+ 'median (min)',
44
+ 'max (min)',
45
+ 'backgrounded',
46
+ ] as const
47
+
48
+ interface Phase {
49
+ edited: boolean
50
+ reviewing: boolean
51
+ }
52
+
53
+ // The latest end of the calls seen so far in one session; calls run side by side overlap.
54
+ interface Reach {
55
+ session_id: ToolCall['session_id'] | undefined
56
+ end_ms: number
57
+ }
58
+
59
+ const NO_REACH: Reach = { session_id: undefined, end_ms: 0 }
60
+
61
+ function runs_any(call: ToolCall, names: ReadonlySet<string>): boolean {
62
+ return lane_transcript_stats.josh_commands(call.command).some((name) => names.has(name))
63
+ }
64
+
65
+ function is_edit(call: ToolCall): boolean {
66
+ return EDIT_TOOLS.has(call.tool ?? '')
67
+ }
68
+
69
+ // The phase once `call` ran: an edit, or a review started, holds for the rest of the lane.
70
+ function next_phase(call: ToolCall, phase: Phase): Phase {
71
+ return {
72
+ edited: phase.edited || is_edit(call),
73
+ reviewing: phase.reviewing || runs_any(call, REVIEW_COMMANDS),
74
+ }
75
+ }
76
+
77
+ function sub_stage_of(call: ToolCall, phase: Phase): SubStage {
78
+ if (phase.reviewing) return REVIEW_FIX
79
+ if (is_edit(call)) return EDIT
80
+ if (runs_any(call, CHECK_COMMANDS)) return CHECK
81
+
82
+ return phase.edited ? READ : PLAN
83
+ }
84
+
85
+ function end_ms(call: ToolCall): number {
86
+ return call.started_ms + (call.duration_ms ?? 0)
87
+ }
88
+
89
+ function span_ms(call: ToolCall, reach: Reach): number {
90
+ if (reach.session_id !== call.session_id) return call.duration_ms ?? 0
91
+
92
+ return Math.max(0, end_ms(call) - reach.end_ms)
93
+ }
94
+
95
+ function next_reach(call: ToolCall, reach: Reach): Reach {
96
+ const latest = reach.session_id === call.session_id ? reach.end_ms : 0
97
+
98
+ return { session_id: call.session_id, end_ms: Math.max(latest, end_ms(call)) }
99
+ }
100
+
101
+ // The call's span less the time its lane stood paused inside it.
102
+ function active_ms(call: ToolCall, reach: Reach, paused: ReadonlyArray<PausedSpan>): number {
103
+ const span = span_ms(call, reach)
104
+ const end = end_ms(call)
105
+
106
+ return span - lane_paused_spans.overlap_ms(paused, end - span, end)
107
+ }
108
+
109
+ // Each sub-stage's summed span over one lane's implement calls, oldest first.
110
+ function lane_totals(calls: ReadonlyArray<ToolCall>, paused: ReadonlyArray<PausedSpan>): Totals {
111
+ const totals = new Map<SubStage, number>(SUB_STAGES.map((stage) => [stage, 0]))
112
+ let phase: Phase = { edited: false, reviewing: false }
113
+ let reach = NO_REACH
114
+
115
+ for (const call of calls) {
116
+ phase = next_phase(call, phase)
117
+ const stage = sub_stage_of(call, phase)
118
+
119
+ totals.set(stage, (totals.get(stage) ?? 0) + active_ms(call, reach, paused))
120
+ reach = next_reach(call, reach)
121
+ }
122
+
123
+ return totals
124
+ }
125
+
126
+ // One lane's calls before its first ship, or `undefined` when it never shipped.
127
+ function implement_calls(calls: ReadonlyArray<ToolCall>): ReadonlyArray<ToolCall> | undefined {
128
+ const ship = calls.findIndex((call) => runs_any(call, SHIP_COMMANDS))
129
+
130
+ return ship === -1 ? undefined : calls.slice(0, ship)
131
+ }
132
+
133
+ function lanes_of(calls: ReadonlyArray<ToolCall>): Array<ReadonlyArray<ToolCall>> {
134
+ const lanes = [...new Set(calls.map((call) => call.lane))]
135
+
136
+ return lanes.map((lane) =>
137
+ calls
138
+ .filter((call) => call.lane === lane)
139
+ .toSorted((left, right) => left.started_ms - right.started_ms),
140
+ )
141
+ }
142
+
143
+ // One lane's implement calls and paused spans, or `undefined` when it never shipped.
144
+ function implement_lane(
145
+ lane: ReadonlyArray<ToolCall>,
146
+ paused: PausedSpans,
147
+ ): ImplementLane | undefined {
148
+ const implement = implement_calls(lane)
149
+ const spans = lane_paused_spans.of_lane(paused, lane[0]?.lane ?? '')
150
+
151
+ return implement === undefined ? undefined : { calls: implement, paused: spans }
152
+ }
153
+
154
+ // The implement calls and paused spans of each lane that shipped in `window`.
155
+ function implement_lanes(
156
+ calls: ReadonlyArray<ToolCall>,
157
+ window: StatsWindow,
158
+ paused: PausedSpans,
159
+ ): Array<ImplementLane> {
160
+ const lanes = lanes_of(lane_transcript_stats.in_period(calls, window))
161
+
162
+ return lanes.flatMap((lane) => implement_lane(lane, paused) ?? [])
163
+ }
164
+
165
+ // The sub-stage totals of each lane that shipped in `window`.
166
+ function lane_totals_in(
167
+ calls: ReadonlyArray<ToolCall>,
168
+ window: StatsWindow,
169
+ paused: PausedSpans,
170
+ ): Array<Totals> {
171
+ return implement_lanes(calls, window, paused).map((lane) => lane_totals(lane.calls, lane.paused))
172
+ }
173
+
174
+ function stage_row(stage: SubStage, totals: ReadonlyArray<Totals>): Array<string> {
175
+ const values = totals.map((lane) => lane.get(stage) ?? 0)
176
+
177
+ return [
178
+ stage,
179
+ String(values.length),
180
+ lane_stage_stats.cell(lane_stats.median(values)),
181
+ lane_stage_stats.cell(lane_stats.peak(values)),
182
+ '',
183
+ ]
184
+ }
185
+
186
+ // The period's table: `calls` is every lane session's calls, filtered here to `window`; `paused` is
187
+ // each lane's paused spans (`lane-paused-spans.ts`). The sub-stages, then the subagents by agent type
188
+ // (`lane-implement-subagents.ts`).
189
+ function table(calls: ReadonlyArray<ToolCall>, window: StatsWindow, paused: PausedSpans): string {
190
+ const lanes = implement_lanes(calls, window, paused)
191
+ const totals = lanes.map((lane) => lane_totals(lane.calls, lane.paused))
192
+ const rows = [
193
+ ...SUB_STAGES.map((stage) => stage_row(stage, totals)),
194
+ ...lane_implement_subagents.rows(lanes),
195
+ ]
196
+
197
+ return [
198
+ lane_stats.to_row(COLUMNS),
199
+ lane_stats.to_row(COLUMNS.map(() => '---')),
200
+ ...rows.map((row) => lane_stats.to_row(row)),
201
+ ].join('\n')
202
+ }
203
+
204
+ const lane_implement_stats = { SUB_STAGES, lane_totals_in, table }
205
+
206
+ export type { SubStage }
207
+ export { lane_implement_stats }
@@ -0,0 +1,90 @@
1
+ import { lane_paused_spans, type PausedSpan } from './lane-paused-spans'
2
+ import { lane_stage_stats } from './lane-stage-stats'
3
+ import { lane_stats } from './lane-stats'
4
+ import type { ToolCall } from './lane-transcript-calls'
5
+
6
+ // The implement's subagent time by the agent dispatched (joshuafolkken/kit#5297): one row per agent
7
+ // type under `lane:stats`'s implement sub-stages, over the lanes that dispatched it. **A row times the
8
+ // call's own duration**, less the time its lane stood paused inside it — the sub-stages above already
9
+ // put the same call's span to `plan`, `read` or `review-fix`, so the rows break those down rather than
10
+ // add to them. **A backgrounded call is counted, never timed**: its result line is the background
11
+ // notice (`lane-transcript-calls.ts`), so it adds to the row's `backgrounded` count alone — a lane
12
+ // whose calls of a type were all untimed is not among the lanes the median and max are taken over.
13
+ // **The first cell is the type alone**, so a `lane:value cell --row "subagent: <type>"` address holds
14
+ // from one period to the next.
15
+
16
+ // One lane's implement calls and the spans it stood paused (`lane-implement-stats.ts`).
17
+ interface ImplementLane {
18
+ calls: ReadonlyArray<ToolCall>
19
+ paused: ReadonlyArray<PausedSpan>
20
+ }
21
+
22
+ interface TypeTotal {
23
+ ms: number
24
+ timed: number
25
+ untimed: number
26
+ }
27
+
28
+ const NO_TOTAL: TypeTotal = { ms: 0, timed: 0, untimed: 0 }
29
+
30
+ function own_ms(call: ToolCall, paused: ReadonlyArray<PausedSpan>): number {
31
+ const duration = call.duration_ms ?? 0
32
+ const end = call.started_ms + duration
33
+
34
+ return duration - lane_paused_spans.overlap_ms(paused, call.started_ms, end)
35
+ }
36
+
37
+ function added(total: TypeTotal, call: ToolCall, paused: ReadonlyArray<PausedSpan>): TypeTotal {
38
+ return {
39
+ ms: total.ms + own_ms(call, paused),
40
+ timed: total.timed + (call.duration_ms === undefined ? 0 : 1),
41
+ untimed: total.untimed + (call.background ? 1 : 0),
42
+ }
43
+ }
44
+
45
+ // Each agent type's summed time and backgrounded count over one lane's implement calls.
46
+ function lane_types(lane: ImplementLane): ReadonlyMap<string, TypeTotal> {
47
+ const types = new Map<string, TypeTotal>()
48
+
49
+ for (const call of lane.calls) {
50
+ const type = call.subagent?.type
51
+
52
+ if (type !== undefined) types.set(type, added(types.get(type) ?? NO_TOTAL, call, lane.paused))
53
+ }
54
+
55
+ return types
56
+ }
57
+
58
+ // The type's row: its timed lanes, their median and max, and its backgrounded calls over every lane.
59
+ function type_row(type: string, totals: ReadonlyArray<TypeTotal>): Array<string> {
60
+ const values = totals.filter((total) => total.timed > 0).map((total) => total.ms)
61
+ const untimed = totals.reduce((sum, total) => sum + total.untimed, 0)
62
+
63
+ return [
64
+ `subagent: ${type}`,
65
+ String(values.length),
66
+ lane_stage_stats.cell(lane_stats.median(values)),
67
+ lane_stage_stats.cell(lane_stats.peak(values)),
68
+ String(untimed),
69
+ ]
70
+ }
71
+
72
+ // One row per agent type any lane dispatched, by name; its lanes are the lanes that dispatched it.
73
+ function rows(lanes: ReadonlyArray<ImplementLane>): Array<Array<string>> {
74
+ const per_lane = lanes.map((lane) => lane_types(lane))
75
+ const types = [...new Set(per_lane.flatMap((types_of) => [...types_of.keys()]))].toSorted(
76
+ (left, right) => left.localeCompare(right),
77
+ )
78
+
79
+ return types.map((type) =>
80
+ type_row(
81
+ type,
82
+ per_lane.flatMap((types_of) => types_of.get(type) ?? []),
83
+ ),
84
+ )
85
+ }
86
+
87
+ const lane_implement_subagents = { rows }
88
+
89
+ export type { ImplementLane }
90
+ export { lane_implement_subagents }
@@ -0,0 +1,16 @@
1
+ import { hook_decision } from '#scripts/josh/hook-decision'
2
+
3
+ // The switch the automatic lane investigations `run:merge` launches — the overrun's
4
+ // (`lane-overrun.ts`) and the baseline's (`lane-baseline.ts`) — share (joshuafolkken/kit#5044). It
5
+ // defaults off, so an unset variable launches no session; `run:merge` loads `.env`, where it is set.
6
+ // Not `JOSH_LANE_OVERRUN`, the mark an investigation session itself carries.
7
+ const INVESTIGATION_ENV_KEY = 'JOSH_LANE_INVESTIGATION'
8
+
9
+ // Read at call time, so a suite that switches the variable between cases is not answered from a cache.
10
+ function is_on(): boolean {
11
+ return hook_decision.is_switch_opt_in(INVESTIGATION_ENV_KEY)
12
+ }
13
+
14
+ const lane_investigation_switch = { is_on }
15
+
16
+ export { lane_investigation_switch }