@joshuafolkken/kit 1.1784.0 → 1.2116.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +60 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +386 -360
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +16 -9
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -0,0 +1,197 @@
1
+ import { issue_cite } from '#scripts/issue/issue-cite'
2
+
3
+ // The notes an overrun investigation leaves on the run's event stream (joshuafolkken/kit#4751): every
4
+ // merged lane's net time, at or under the threshold or over it, or why there is none
5
+ // (joshuafolkken/kit#4818); an overrun's start, naming the session's pid and start time; and its end —
6
+ // the session's result or the launch's failure. `lane-overrun.ts` writes them and `run:board` reads them
7
+ // back, both through this module, so the two never spell them differently.
8
+
9
+ // What a note says of the investigation of `issue`. `start` is the session's `process_identity` start
10
+ // token, which tells the session from a later process holding its pid; a launcher that could not read it
11
+ // leaves it off. A start note that launched no session is a failure with its minutes.
12
+ type OverrunNote =
13
+ | { kind: 'within'; issue: number; minutes: number }
14
+ | { kind: 'skipped'; issue: number; reason: string }
15
+ | {
16
+ kind: 'started'
17
+ issue: number
18
+ minutes: number
19
+ pid: number
20
+ start: string | undefined
21
+ longest: Longest | undefined
22
+ }
23
+ | { kind: 'ended'; issue: number; result: string }
24
+ | { kind: 'failed'; issue: number; minutes: number | undefined }
25
+
26
+ // The lane's longest stage in whole minutes (joshuafolkken/kit#4995, `lane-breakdown.ts`); a start note
27
+ // written before it was carried has none.
28
+ interface Longest {
29
+ name: string
30
+ minutes: number
31
+ }
32
+
33
+ type Groups = Partial<Record<string, string>>
34
+
35
+ const WITHIN_PATTERN = /^#(?<issue>\d+) net: (?<minutes>\d+) min$/u
36
+ const SKIPPED_PATTERN = /^#(?<issue>\d+) overrun skipped: (?<reason>.+)$/u
37
+ const OVERRAN_PATTERN =
38
+ /^#(?<issue>\d+) overran: (?<minutes>\d+) min net(?:, longest (?<stage>.+?) (?<stage_minutes>\d+) min)? — (?<outcome>.*)$/u
39
+ const INVESTIGATING_PATTERN = /^investigating in pid (?<pid>\d+)(?: started (?<start>.+))?$/u
40
+ const ENDED_PATTERN = /^#(?<issue>\d+) overrun: (?<result>.*)$/u
41
+ const FAILED_PATTERN = /^#(?<issue>\d+) overrun investigation failed: /u
42
+
43
+ // Why an overrun was skipped with the switch off (joshuafolkken/kit#5044); the board draws it only
44
+ // once the switch is on, hiding every merged row's minutes and skip while it stays off
45
+ // (joshuafolkken/kit#5132, joshuafolkken/kit#5194).
46
+ const DISABLED_REASON = 'disabled (JOSH_LANE_INVESTIGATION is not on)'
47
+ // The result an investigation that filed records; the board shows the filings themselves.
48
+ const FILED_RESULT = 'filed'
49
+ const NONE_LEAD = 'none: '
50
+ // What a result ends with for the stages the investigation judged not reducible (joshuafolkken/kit#4995).
51
+ const NOT_REDUCIBLE_LEAD = '; not reducible: '
52
+ const RECURRED_PATTERN = /^recurred #(?<number>\d+)/u
53
+ // The result of an investigation that appended causes to open Issues, which file no new one
54
+ // (joshuafolkken/kit#4858); any it filed besides show as filings.
55
+ const FOLDED_LEAD = 'folded '
56
+ const FOLDED_SEPARATOR = ','
57
+ const FOLDED_PATTERN = /^folded (?<list>#\d+(?:,#\d+)*)/u
58
+ const NUMBER_PATTERN = /#(?<number>\d+)/gu
59
+
60
+ function started_text(issue: number, minutes: number, outcome: string, longest?: Longest): string {
61
+ const stage =
62
+ longest === undefined ? '' : `, longest ${longest.name} ${String(longest.minutes)} min`
63
+
64
+ return `${issue_cite.plain(issue)} overran: ${String(minutes)} min net${stage} — ${outcome}`
65
+ }
66
+
67
+ function within_text(issue: number, minutes: number): string {
68
+ return `${issue_cite.plain(issue)} net: ${String(minutes)} min`
69
+ }
70
+
71
+ function skipped_text(issue: number, reason: string): string {
72
+ return `${issue_cite.plain(issue)} overrun skipped: ${reason}`
73
+ }
74
+
75
+ // The start note's outcome for a launched session.
76
+ function investigating(pid: number, start: string | undefined): string {
77
+ const outcome = `investigating in pid ${String(pid)}`
78
+
79
+ return start === undefined ? outcome : `${outcome} started ${start}`
80
+ }
81
+
82
+ function ended_text(issue: number, result: string): string {
83
+ return `${issue_cite.plain(issue)} overrun: ${result}`
84
+ }
85
+
86
+ function failed_text(issue: number, note: string): string {
87
+ return `${issue_cite.plain(issue)} overrun investigation failed: ${note}`
88
+ }
89
+
90
+ function none_result(reason: string): string {
91
+ return `${NONE_LEAD}${reason}`
92
+ }
93
+
94
+ function recurred_result(issue: number | string): string {
95
+ return `recurred ${issue_cite.plain(issue)}`
96
+ }
97
+
98
+ // The issue a `recurred #N` result commented on.
99
+ function recurred_of(result: string): number | undefined {
100
+ const number = RECURRED_PATTERN.exec(result)?.groups?.['number']
101
+
102
+ return number === undefined ? undefined : Number(number)
103
+ }
104
+
105
+ function folded_result(issues: ReadonlyArray<number | string>): string {
106
+ return `${FOLDED_LEAD}${issues.map((issue) => issue_cite.plain(issue)).join(FOLDED_SEPARATOR)}`
107
+ }
108
+
109
+ // The Issues a `folded #A,#B` result appended to, else none; any text after the list is not read.
110
+ function folded_of(result: string): ReadonlyArray<number> {
111
+ const list = FOLDED_PATTERN.exec(result)?.groups?.['list'] ?? ''
112
+
113
+ return [...list.matchAll(NUMBER_PATTERN)].map((match) => Number(match.groups?.['number']))
114
+ }
115
+
116
+ // The reason a `none: <reason>` result gives, else the result as it is — its stages not reducible left
117
+ // out.
118
+ function reason_of(result: string): string {
119
+ const [lead = ''] = result.split(NOT_REDUCIBLE_LEAD)
120
+
121
+ return lead.startsWith(NONE_LEAD) ? lead.slice(NONE_LEAD.length) : lead
122
+ }
123
+
124
+ function longest_of(groups: Groups): Longest | undefined {
125
+ const name = groups['stage']
126
+
127
+ return name === undefined ? undefined : { name, minutes: Number(groups['stage_minutes']) }
128
+ }
129
+
130
+ function overran(groups: Groups): OverrunNote {
131
+ const issue = Number(groups['issue'])
132
+ const minutes = Number(groups['minutes'])
133
+ const launched = INVESTIGATING_PATTERN.exec(groups['outcome'] ?? '')?.groups
134
+
135
+ if (launched === undefined) return { kind: 'failed', issue, minutes }
136
+
137
+ const pid = Number(launched['pid'])
138
+ const longest = longest_of(groups)
139
+
140
+ return { kind: 'started', issue, minutes, pid, start: launched['start'], longest }
141
+ }
142
+
143
+ function within(groups: Groups): OverrunNote {
144
+ return { kind: 'within', issue: Number(groups['issue']), minutes: Number(groups['minutes']) }
145
+ }
146
+
147
+ function skipped(groups: Groups): OverrunNote {
148
+ return { kind: 'skipped', issue: Number(groups['issue']), reason: groups['reason'] ?? '' }
149
+ }
150
+
151
+ function failed(groups: Groups): OverrunNote {
152
+ return { kind: 'failed', issue: Number(groups['issue']), minutes: undefined }
153
+ }
154
+
155
+ function ended(groups: Groups): OverrunNote {
156
+ return { kind: 'ended', issue: Number(groups['issue']), result: groups['result'] ?? '' }
157
+ }
158
+
159
+ const READERS: ReadonlyArray<readonly [RegExp, (groups: Groups) => OverrunNote]> = [
160
+ [WITHIN_PATTERN, within],
161
+ [SKIPPED_PATTERN, skipped],
162
+ [OVERRAN_PATTERN, overran],
163
+ [FAILED_PATTERN, failed],
164
+ [ENDED_PATTERN, ended],
165
+ ]
166
+
167
+ function parse(text: string): OverrunNote | undefined {
168
+ for (const [pattern, read] of READERS) {
169
+ const groups = pattern.exec(text)?.groups
170
+
171
+ if (groups !== undefined) return read(groups)
172
+ }
173
+
174
+ return undefined
175
+ }
176
+
177
+ const run_event_overrun = {
178
+ DISABLED_REASON,
179
+ ended_text,
180
+ failed_text,
181
+ FILED_RESULT,
182
+ folded_of,
183
+ folded_result,
184
+ investigating,
185
+ none_result,
186
+ NOT_REDUCIBLE_LEAD,
187
+ parse,
188
+ reason_of,
189
+ recurred_of,
190
+ recurred_result,
191
+ skipped_text,
192
+ started_text,
193
+ within_text,
194
+ }
195
+
196
+ export { run_event_overrun }
197
+ export type { Longest, OverrunNote }
@@ -25,6 +25,7 @@ const KIND_LABELS: Readonly<Record<EventKind, KindLabel>> = {
25
25
  park: { ja: '保留', en: 'parked' },
26
26
  split: { ja: '分割', en: 'split' },
27
27
  outage: { ja: '障害', en: 'outage' },
28
+ 'usage-limit': { ja: '利用上限', en: 'usage limit' },
28
29
  cut: { ja: 'セッション交代', en: 'session cut' },
29
30
  resume: { ja: '実装を再開', en: 'implementation resumed' },
30
31
  restart: { ja: '止めて出し直し', en: 'restarted' },
@@ -40,6 +41,7 @@ const KIND_LABELS: Readonly<Record<EventKind, KindLabel>> = {
40
41
  heartbeat: { ja: '生存確認', en: 'heartbeat' },
41
42
  'ship-launch': { ja: '出荷を開始', en: 'ship launched' },
42
43
  'ship-stop': { ja: '出荷が停止', en: 'ship stopped' },
44
+ 'relaunch-failed': { ja: '再起動に失敗', en: 'relaunch failed' },
43
45
  filed: { ja: '起票', en: 'filed' },
44
46
  note: { ja: '意見', en: 'note' },
45
47
  'lane-phase': { ja: 'レーンの段階', en: 'lane phase' },
@@ -50,6 +52,8 @@ const KIND_LABELS: Readonly<Record<EventKind, KindLabel>> = {
50
52
  'idle-notice': { ja: '待機の通知', en: 'idle notice' },
51
53
  'lane-state': { ja: 'レーンの状態', en: 'lane state' },
52
54
  'paused-notice': { ja: '一時停止の通知', en: 'paused notice' },
55
+ measured: { ja: '計測で完了', en: 'measured' },
56
+ sleep: { ja: 'ホストのスリープ', en: 'host sleep' },
53
57
  }
54
58
 
55
59
  const LABELS_BY_KIND: ReadonlyMap<string, KindLabel> = new Map(Object.entries(KIND_LABELS))
@@ -1,4 +1,5 @@
1
1
  import { repository_lock } from '#scripts/git/repository-lock'
2
+ import { durable_state } from '#scripts/josh/durable-state'
2
3
  import { stamp_file } from '#scripts/josh/stamp-file'
3
4
  import { json_value } from '#scripts/lib/json-value'
4
5
  import { run_ship_stage } from '#scripts/run/ship/run-ship-stage'
@@ -24,7 +25,7 @@ import { z } from 'zod'
24
25
  // must never fail the work it reports on, so `run-event-stream-emit.ts` wraps
25
26
  // every append in a swallow; this module is free to throw on a genuinely broken write.
26
27
 
27
- const EVENT_PREFIX = 'josh-run-events-'
28
+ const EVENT_PREFIX = durable_state.PREFIX.EVENTS
28
29
  // `.jsonl` rather than `.json`: the file is one JSON event per line, appended to, and the suffix tells
29
30
  // every reader — a person, an editor — that it is a line stream rather than a single document, the same
30
31
  // distinction the ambient `.log` draws.
@@ -56,6 +57,10 @@ const EVENT_KIND = {
56
57
  PARK: 'park',
57
58
  SPLIT: 'split',
58
59
  OUTAGE: 'outage',
60
+ // A Claude usage limit stopped a lane child (joshuafolkken/kit#4745). Its text names the reset time,
61
+ // which `backlog:drive` reads to hold launches until then; it counts against no streak, so it is not an
62
+ // `OUTAGE`.
63
+ USAGE_LIMIT: 'usage-limit',
59
64
  CUT: 'cut',
60
65
  // A fresh session adopted an implementation cut — `run:cut --resume` answered `resume-impl`. The
61
66
  // resume clears the cut record, so without this the `cut` would stay the newest position and
@@ -116,6 +121,11 @@ const EVENT_KIND = {
116
121
  // The position that hands control back: `run:step` prints the command that
117
122
  // shows the stopped report, so the agent fixes it and relaunches rather than rebuilding the context.
118
123
  SHIP_STOP: 'ship-stop',
124
+ // The relaunch meant to answer a `SHIP_STOP` started nothing — the broker refused it, or the direct
125
+ // spawn failed (joshuafolkken/kit#4765). `run:merge` reads it, not the transcript's mtime, to tell the
126
+ // stop went unanswered, and a re-dispatch cap's park names its reason. A trace: the stop stays the
127
+ // position `run:step` answers.
128
+ RELAUNCH_FAILED: 'relaunch-failed',
119
129
  // An Issue the run filed on its way, written by `issue:file`, so a run started from the command line
120
130
  // still surfaces what it found — `run:board`'s findings section reads it.
121
131
  FILED: 'filed',
@@ -157,6 +167,14 @@ const EVENT_KIND = {
157
167
  // silent window (joshuafolkken/kit#4270). Emitted once per pause episode (`emit_once_since_with`,
158
168
  // reset by `LANE_STATE`), it is the dedup marker for the one paused-lane Telegram. A trace.
159
169
  PAUSED_NOTICE: 'paused-notice',
170
+ // `backlog:drive` ran a due issue's measurement declaration itself, found it within its bound and
171
+ // closed the issue through `issue:measured` — no lane was launched for it (joshuafolkken/kit#4621).
172
+ // `run:board` draws it merged. A trace: the parent's position is the drive's, not this close.
173
+ MEASURED: 'measured',
174
+ // The host slept while `backlog:drive` sampled its load (joshuafolkken/kit#5032): the sampler's timer
175
+ // ran late by more than a few intervals. `at` is the wake and `elapsed_ms` how long the sleep
176
+ // lasted; every lane's net time takes it out (`lane-sleep.ts`). A trace.
177
+ SLEEP: 'sleep',
160
178
  } as const
161
179
 
162
180
  type EventKind = (typeof EVENT_KIND)[keyof typeof EVENT_KIND]
@@ -179,6 +197,9 @@ const TRACE_KINDS: ReadonlySet<string> = new Set([
179
197
  EVENT_KIND.IDLE_NOTICE,
180
198
  EVENT_KIND.LANE_STATE,
181
199
  EVENT_KIND.PAUSED_NOTICE,
200
+ EVENT_KIND.MEASURED,
201
+ EVENT_KIND.RELAUNCH_FAILED,
202
+ EVENT_KIND.SLEEP,
182
203
  ])
183
204
 
184
205
  // The trace kinds that say only that the run was alive, so the bound rolls them off first. A `filed` or
@@ -199,7 +220,8 @@ const event_schema = z.object({
199
220
  kind: z.string(),
200
221
  text: z.string(),
201
222
  // The child's time on a lane, recorded once by the writer of an ending (joshuafolkken/kit#4481), so a
202
- // reader never has to find its launch again. An event written before it has none.
223
+ // reader never has to find its launch again. An event written before it has none. A `sleep` event
224
+ // carries the sleep's length here.
203
225
  elapsed_ms: z.number().optional(),
204
226
  })
205
227
 
@@ -224,7 +246,7 @@ function is_event_kind(value: string): value is EventKind {
224
246
  // The stream's path, keyed on the run's identity the caller resolved. `.jsonl` so the append surface is
225
247
  // named for what it is.
226
248
  function target_of(repository: string): string {
227
- return stamp_file.stamp_path(EVENT_PREFIX, repository, EVENT_SUFFIX)
249
+ return durable_state.path(EVENT_PREFIX, repository, EVENT_SUFFIX)
228
250
  }
229
251
 
230
252
  function is_present(event: RunEvent | undefined): event is RunEvent {
@@ -3,6 +3,7 @@ import { git_gh_pr_read } from '#scripts/gh/git-gh-pr-read'
3
3
  import { git_gh_repo } from '#scripts/gh/git-gh-repo'
4
4
  import { git_command } from '#scripts/git/git-command'
5
5
  import { issue_cite } from '#scripts/issue/issue-cite'
6
+ import { shell_quote } from '#scripts/lib/shell-quote'
6
7
  import { stdout_on_stderr } from '#scripts/lib/stdout-on-stderr'
7
8
  import { telegram_test } from '#scripts/notify/telegram-test'
8
9
  import type { CliValues } from '#scripts/notify/telegram-test-logic'
@@ -22,9 +23,6 @@ const TITLE_PLACEHOLDER = '<title>'
22
23
  const PR_PLACEHOLDER = '<pr-url>'
23
24
  const HALFRUN = 'halfrun'
24
25
  const PRRUN = 'prrun'
25
- // Single quotes expand nothing, so a title stays one argument whatever it carries; its own `'` closes
26
- // the quote, emits an escaped one and reopens.
27
- const QUOTE = "'"
28
26
 
29
27
  interface StopFacts {
30
28
  issue: string
@@ -38,17 +36,14 @@ interface Composed {
38
36
  title: string | undefined
39
37
  }
40
38
 
41
- function single_quoted(text: string): string {
42
- return QUOTE + text.replaceAll(QUOTE, String.raw`'\''`) + QUOTE
43
- }
44
-
45
39
  // Plain, not linked: every line is a command a person copies out of the Telegram.
46
40
  function reference_of(facts: StopFacts): string {
47
41
  return issue_cite.plain(facts.issue)
48
42
  }
49
43
 
50
44
  function commit_title(facts: StopFacts): string {
51
- return single_quoted(`${facts.title ?? TITLE_PLACEHOLDER} ${reference_of(facts)}`)
45
+ // Single quotes expand nothing, so a title stays one argument whatever it carries.
46
+ return shell_quote.single_quoted(`${facts.title ?? TITLE_PLACEHOLDER} ${reference_of(facts)}`)
52
47
  }
53
48
 
54
49
  function with_urls(values: CliValues, facts: StopFacts): CliValues {
@@ -0,0 +1,57 @@
1
+ import { run_event_scope } from '#scripts/run/event/run-event-scope'
2
+ import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
3
+ import { run_stalled, type StallCause } from '#scripts/run/park/run-stalled'
4
+ import { run_merge_ship } from './run-merge-ship'
5
+
6
+ // Why a child the per-child re-dispatch cap stopped is parked (joshuafolkken/kit#4765). The cap turns a
7
+ // re-dispatchable ending into `failed`, and the park then named only the ship's stop — never that the cap
8
+ // was reached, how often the child was re-dispatched, or why its last relaunch started nothing.
9
+
10
+ type Events = ReadonlyArray<RunEvent>
11
+
12
+ const NO_RELAUNCH_FAILURE = 'none was recorded'
13
+
14
+ function is_own(event: RunEvent, kind: string, child: string): boolean {
15
+ return event.kind === kind && run_event_scope.issue_named(event) === child
16
+ }
17
+
18
+ // Every re-dispatch `child` was counted for, across the run.
19
+ function outages(events: Events, child: string): number {
20
+ return events.filter((event) => is_own(event, run_event_stream.EVENT_KIND.OUTAGE, child)).length
21
+ }
22
+
23
+ function last_relaunch_failure(events: Events, child: string): string {
24
+ const kind = run_event_stream.EVENT_KIND.RELAUNCH_FAILED
25
+ const failed = events.findLast((event) => is_own(event, kind, child))
26
+
27
+ return failed === undefined ? NO_RELAUNCH_FAILURE : failed.text
28
+ }
29
+
30
+ // The cap's line, put before what the park judged.
31
+ function note_of(events: Events, child: string, limit: number): string {
32
+ const count = outages(events, child)
33
+ const failure = last_relaunch_failure(events, child)
34
+
35
+ return `it reached the re-dispatch cap (${String(limit)}) after ${String(count)} re-dispatches; the last failed relaunch: ${failure}.`
36
+ }
37
+
38
+ // What a failed child is parked for: the caller's cause, else its ended ship's, else the unfinished
39
+ // session — led by the cap's line where the cap stopped its re-dispatch. A caller's cause parked the
40
+ // child on its own path, so the cap's line stays off it.
41
+ function park_cause(
42
+ child: string,
43
+ cause: StallCause | undefined,
44
+ note: string | undefined,
45
+ ): StallCause {
46
+ if (cause !== undefined) return cause
47
+
48
+ const judged = run_merge_ship.cause(child) ?? run_stalled.SESSION_UNFINISHED
49
+
50
+ if (note === undefined) return judged
51
+
52
+ return { short: judged.short, why: `${note} ${judged.why}` }
53
+ }
54
+
55
+ const run_merge_cap = { note_of, outages, park_cause }
56
+
57
+ export { run_merge_cap }
@@ -1,10 +1,11 @@
1
- import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-threshold'
2
1
  import { issue_cite } from '#scripts/issue/issue-cite'
3
2
  import { RUN_STALLED_LABEL } from '#scripts/issue/issue-labels'
4
3
  import { issue_number_shape } from '#scripts/issue/issue-number-shape'
5
4
  import { issue_state_cli } from '#scripts/issue/issue-state-cli'
5
+ import { lane_baseline } from '#scripts/lane/lane-baseline'
6
6
  import { lane_handoff } from '#scripts/lane/lane-handoff'
7
- import { lane_ledger } from '#scripts/lane/lane-ledger'
7
+ import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
8
+ import { lane_overrun } from '#scripts/lane/lane-overrun'
8
9
  import { cli_flags } from '#scripts/lib/cli-flags'
9
10
  import { run_carry, type CarryOwner, type RunCarry } from '#scripts/run/carry/run-carry'
10
11
  import { run_event_stream } from '#scripts/run/event/run-event-stream'
@@ -16,6 +17,8 @@ import { run_merge_driver } from './run-merge-driver'
16
17
  import { run_merge_signals } from './run-merge-signals'
17
18
  import { run_merge_steps, type FailedResult, type MergeContext } from './run-merge-steps'
18
19
  import { run_merge_token, type MergeToken } from './run-merge-token'
20
+ import { run_merge_usage_limit } from './run-merge-usage-limit'
21
+ import { run_merge_withdrawn, type Collected } from './run-merge-withdrawn'
19
22
 
20
23
  // `josh run:merge <N>` — one composite command for a `backlogrun` merge event. The parent's context is
21
24
  // the largest and its per-turn cost the highest, so it calls this once at a child's return and reads
@@ -128,8 +131,8 @@ function valid_child(parsed: ParsedArguments): string | undefined {
128
131
  }
129
132
 
130
133
  // `backlog:drive` has no context to cut, so its merge is never handed back `over`.
131
- function threshold_of(values: ParsedArguments['values']): number | undefined {
132
- return values.driver === true ? undefined : CONTEXT_CUT_THRESHOLD
134
+ function cut_check_of(values: ParsedArguments['values']): true | undefined {
135
+ return values.driver === true ? undefined : true
133
136
  }
134
137
 
135
138
  function to_context(parsed: ParsedArguments): MergeContext | undefined {
@@ -149,7 +152,7 @@ function to_context(parsed: ParsedArguments): MergeContext | undefined {
149
152
  child,
150
153
  epic: valid_epic(parsed.values.epic),
151
154
  repo: valid_repo(parsed.values.repo),
152
- over: threshold_of(parsed.values),
155
+ over: cut_check_of(parsed.values),
153
156
  owner,
154
157
  output: parsed.values.output,
155
158
  }
@@ -205,22 +208,32 @@ function report_count_refused(carry: RunCarry | undefined): MergeVerdict {
205
208
  return emit(MERGE_TOKEN.BUSY, FAILURE_EXIT_CODE)
206
209
  }
207
210
 
208
- // A merged child counted and its lane closed, the merge put on the stream and in the ledger. Returns the
211
+ async function is_on_record(text: string): Promise<boolean> {
212
+ const events = await run_event_stream_emit.invocation_or_all_events()
213
+
214
+ return events.some(
215
+ (event) => event.kind === run_event_stream.EVENT_KIND.MERGE && event.text === text,
216
+ )
217
+ }
218
+
219
+ // **Put on record once, dated to the merge's confirmation**: a pass that collects a child already on
220
+ // record — `run:carry --end` after `run:merge` — writes neither again.
221
+ async function put_merge_on_record(child: string, at: Date): Promise<void> {
222
+ const text = `${issue_cite.plain(child)} merged`
223
+
224
+ if (await is_on_record(text)) return
225
+
226
+ await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.MERGE, text, at)
227
+ await lane_ledger_write.record_merge(Number(child), at)
228
+ }
229
+
230
+ // A merged child counted and its lane closed, the merge put on the stream and in the ledger ahead of the
231
+ // lane close, dated to the ownership check rather than to the end of the sync (joshuafolkken/kit#4734). Returns the
209
232
  // carry when the ownership check refused it, `undefined` once recorded. `run:carry --end` records the
210
233
  // merges a run ended with through it too (`run-merge-collect.ts`). The lane's `ended` record is
211
234
  // `lane:close`'s alone: an `incomplete` close leaves the lane open on it (joshuafolkken/kit#4300).
212
235
  async function record_merged(ctx: MergeContext): Promise<RunCarry | undefined> {
213
- const refused = await run_merge_steps.do_merged(ctx)
214
-
215
- if (refused !== undefined) return refused
216
-
217
- await run_event_stream_emit.emit(
218
- run_event_stream.EVENT_KIND.MERGE,
219
- `${issue_cite.plain(ctx.child)} merged`,
220
- )
221
- await lane_ledger.record_merge(Number(ctx.child))
222
-
223
- return undefined
236
+ return await run_merge_steps.do_merged(ctx, put_merge_on_record)
224
237
  }
225
238
 
226
239
  // A merge is the only outcome that asks the hand-off check, because it is the only one that returned
@@ -230,6 +243,9 @@ async function on_merged(ctx: MergeContext): Promise<MergeVerdict> {
230
243
 
231
244
  if (refused !== undefined) return report_count_refused(refused)
232
245
 
246
+ await lane_overrun.investigate(Number(ctx.child))
247
+ await lane_baseline.investigate(Number(ctx.child))
248
+
233
249
  if (await run_merge_steps.is_over_budget(ctx.over)) {
234
250
  return emit(MERGE_TOKEN.OVER, SUCCESS_EXIT_CODE)
235
251
  }
@@ -308,6 +324,14 @@ async function on_unauthenticated(ctx: MergeContext): Promise<MergeVerdict> {
308
324
  return emit(MERGE_TOKEN.ENVIRONMENT, SUCCESS_EXIT_CODE)
309
325
  }
310
326
 
327
+ // A child a usage limit stopped: released uncounted, its reset recorded (`run-merge-usage-limit.ts`).
328
+ async function on_usage_limit(ctx: MergeContext): Promise<MergeVerdict> {
329
+ await run_merge_steps.release_child(ctx.child)
330
+ await run_merge_usage_limit.record(ctx.child, ctx.resume_ms ?? Date.now())
331
+
332
+ return await offered(ctx)
333
+ }
334
+
311
335
  // A child that ended its session with a cut no successor adopted: its successor is relaunched,
312
336
  // nothing is counted and nothing is parked, and `resumed` tells the parent to await the same lane
313
337
  // again rather than dispatch into it. A successor that could not be started — or a cut the
@@ -356,13 +380,29 @@ async function on_skipped(ctx: MergeContext): Promise<MergeVerdict> {
356
380
  return await offered(ctx)
357
381
  }
358
382
 
359
- // A child a person withdrew with `lane:withdraw`: the withdrawal already stopped it, closed its lane
360
- // and put itself on the stream, leaving its issue open for the next run, so nothing is counted or
361
- // written here and its seat goes to the next child.
362
- async function on_withdrawn(ctx: MergeContext): Promise<MergeVerdict> {
383
+ // The seat of a child whose lane was collected goes to the next child — or a retry, where the
384
+ // withdrawal could not read the child.
385
+ async function on_collected(ctx: MergeContext, collected: Collected): Promise<MergeVerdict> {
386
+ if (collected.note !== undefined) console.error(collected.note)
387
+ if (collected.is_retry) return emit(MERGE_TOKEN.RETRY, FAILURE_EXIT_CODE)
388
+
363
389
  return await offered(ctx)
364
390
  }
365
391
 
392
+ // A child a person withdrew with `lane:withdraw`, or whose issue closed without a merge: nothing is
393
+ // counted and no merge is put on record, and its lane is withdrawn unless a person already did
394
+ // (`run-merge-withdrawn.ts`).
395
+ async function on_withdrawn(ctx: MergeContext): Promise<MergeVerdict> {
396
+ return await on_collected(ctx, await run_merge_withdrawn.collect(ctx.child))
397
+ }
398
+
399
+ // A child that gave its lane back on its `lane:plan` (`lane-yield.ts`): its lane is closed the same way,
400
+ // but the issue stays in the run — `backlog:drive` does not exclude a `yielded` child, and its kept
401
+ // plan holds it back until the holder ends.
402
+ async function on_yielded(ctx: MergeContext): Promise<MergeVerdict> {
403
+ return await on_collected(ctx, await run_merge_withdrawn.collect_yield(ctx.child))
404
+ }
405
+
366
406
  // The child's own ending: it stopped before its commit for a person to look at, so nothing is counted
367
407
  // and no next child is offered.
368
408
  async function on_human_review(): Promise<MergeVerdict> {
@@ -385,11 +425,13 @@ const HANDLERS: Readonly<Record<ChildOutcome, (ctx: MergeContext) => Promise<Mer
385
425
  merged: on_merged,
386
426
  outage: on_outage,
387
427
  unauthenticated: on_unauthenticated,
428
+ 'usage-limit': on_usage_limit,
388
429
  parked: on_parked,
389
430
  split: on_skipped,
390
431
  unresolved: on_unresolved,
391
432
  shipping: on_shipping,
392
433
  withdrawn: on_withdrawn,
434
+ yielded: on_yielded,
393
435
  }
394
436
 
395
437
  // The whole merge event for one returned child: read its state, classify it, and run the handler.
@@ -404,9 +446,10 @@ async function merge_child(ctx: MergeContext): Promise<MergeResult> {
404
446
  const signals = await run_merge_signals.read_signals(ctx, read)
405
447
  const outcome = run_merge_signals.outcome_of(read, signals)
406
448
 
407
- const { merged_pr, is_streak_exempt } = signals
449
+ const { merged_pr, is_streak_exempt, capped_note, resume_ms } = signals
450
+ const handled = { ...ctx, merged_pr, is_streak_exempt, capped_note, resume_ms }
408
451
 
409
- return { outcome, ...(await HANDLERS[outcome]({ ...ctx, merged_pr, is_streak_exempt })) }
452
+ return { outcome, ...(await HANDLERS[outcome](handled)) }
410
453
  }
411
454
 
412
455
  async function run(argv: ReadonlyArray<string>): Promise<number> {
@@ -4,12 +4,14 @@
4
4
  const CHILD_OUTCOMES = [
5
5
  'merged',
6
6
  'withdrawn',
7
+ 'yielded',
7
8
  'human-review',
8
9
  'parked',
9
10
  'split',
10
11
  'cut',
11
12
  'outage',
12
13
  'unauthenticated',
14
+ 'usage-limit',
13
15
  'failed',
14
16
  'unresolved',
15
17
  'shipping',
@@ -75,19 +75,29 @@ function cause(child: string, directory: string = process.cwd()): StallCause | u
75
75
  return cause_of(run_ship_detach.read_result(repository, child), events, child)
76
76
  }
77
77
 
78
+ function is_relaunch_failed(event: RunEvent): boolean {
79
+ return event.kind === run_event_stream.EVENT_KIND.RELAUNCH_FAILED
80
+ }
81
+
78
82
  // Whether the ended ship was never answered: a session relaunched to fix a stop writes to the
79
83
  // transcript after it, so a transcript last written before the newest stop means no fix-up ran — its
80
- // broker or relaunch could not start. A ship with no stop at all ended abnormally only when its supervisor
81
- // died before reaching a stage.
84
+ // broker or relaunch could not start. **A `relaunch-failed` after the stop reads it unanswered whatever the
85
+ // mtime says** (joshuafolkken/kit#4765): the dispatch log's header is written before a spawn that may fail.
86
+ // A ship with no stop at all ended abnormally only when its supervisor died before reaching a stage.
82
87
  function is_stop_unanswered(
83
88
  ending: ShipEnding,
84
89
  attempt: Events,
85
90
  written_at: number | undefined,
86
91
  ): boolean {
87
- const stop = attempt.findLast((event) => event.kind === run_event_stream.EVENT_KIND.SHIP_STOP)
92
+ const index = attempt.findLastIndex(
93
+ (event) => event.kind === run_event_stream.EVENT_KIND.SHIP_STOP,
94
+ )
95
+ const stop = attempt[index]
88
96
 
89
97
  if (stop === undefined) return ending?.result === 'abnormal'
90
98
 
99
+ if (attempt.slice(index + 1).some((event) => is_relaunch_failed(event))) return true
100
+
91
101
  return written_at !== undefined && written_at < Date.parse(stop.at)
92
102
  }
93
103