@joshuafolkken/kit 1.1784.0 → 1.2114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +59 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +415 -389
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +15 -8
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -0,0 +1,112 @@
1
+ import { git_gh_command } from '#scripts/gh/git-gh-command'
2
+ import { issue_cite } from '#scripts/issue/issue-cite'
3
+ import { issue_measured_close } from '#scripts/issue/issue-measured-close'
4
+ import {
5
+ measure_declaration,
6
+ type MeasureDeclaration,
7
+ type MeasureVerdict,
8
+ } from '#scripts/issue/measure-declaration'
9
+ import { trusted_measure, type CommandRun } from '#scripts/issue/trusted-measure'
10
+ import { error_text } from '#scripts/lib/error-message'
11
+ import { run_event_stream } from '#scripts/run/event/run-event-stream'
12
+ import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
13
+
14
+ // joshuafolkken/kit#4621: the drive runs a due issue's measurement declaration (`measure-declaration.ts`)
15
+ // before it opens a lane. A value within the bound closes the issue the way `issue:measured` does — the
16
+ // result comment, the `measured` label, the close and the epic's progress — and puts a `measured` event
17
+ // on the stream, so no lane is spent. Anything else — no declaration, an untrusted body, a value out of
18
+ // bound, a failed command, output that is not one number — launches the lane as before; where a
19
+ // command ran, its result is commented first, so the child starts from the measurement, not a re-run.
20
+
21
+ const FENCE = '```'
22
+ const VERDICT_WORDS: Readonly<Record<MeasureVerdict['kind'], string>> = {
23
+ pass: 'within the bound, so the issue is closed without a lane.',
24
+ fail: 'out of the bound, so the issue goes to a lane.',
25
+ unreadable: 'no value could be read from the output, so the issue goes to a lane.',
26
+ }
27
+
28
+ interface Measurement {
29
+ declaration: MeasureDeclaration
30
+ run: CommandRun
31
+ verdict: MeasureVerdict
32
+ }
33
+
34
+ async function declared(issue: string): Promise<MeasureDeclaration | undefined> {
35
+ const read = await trusted_measure.read_trusted_body(issue)
36
+
37
+ return read.kind === 'trusted' ? measure_declaration.parse(read.body) : undefined
38
+ }
39
+
40
+ function measured(declaration: MeasureDeclaration): Measurement {
41
+ const run = trusted_measure.run_command(declaration.command)
42
+ const verdict: MeasureVerdict =
43
+ run.kind === 'ok' ? measure_declaration.judge(declaration, run.output) : { kind: 'unreadable' }
44
+
45
+ return { declaration, run, verdict }
46
+ }
47
+
48
+ function value_words(verdict: MeasureVerdict): string {
49
+ return verdict.kind === 'unreadable' ? 'unreadable' : String(verdict.value)
50
+ }
51
+
52
+ // The result comment: the declaration, the value read, what follows and the command's own output.
53
+ // Script-emitted, so English (`run-merge.ts` → `park_comment`).
54
+ function report(measurement: Measurement): string {
55
+ const { declaration, run, verdict } = measurement
56
+
57
+ return [
58
+ '`backlog:drive` ran the measurement declaration.',
59
+ '',
60
+ `- Declaration: ${measure_declaration.format(declaration)}`,
61
+ `- Value: ${value_words(verdict)}`,
62
+ `- Verdict: ${VERDICT_WORDS[verdict.kind]}`,
63
+ '',
64
+ FENCE,
65
+ trusted_measure.text_of(run),
66
+ FENCE,
67
+ ].join('\n')
68
+ }
69
+
70
+ async function close_passed(issue: string, measurement: Measurement): Promise<boolean> {
71
+ const is_closed = await issue_measured_close.close(issue, report(measurement))
72
+ const value = value_words(measurement.verdict)
73
+ const bound = `${measurement.declaration.operator} ${String(measurement.declaration.threshold)}`
74
+
75
+ if (is_closed) {
76
+ await run_event_stream_emit.emit(
77
+ run_event_stream.EVENT_KIND.MEASURED,
78
+ `${issue_cite.plain(issue)} measured by backlog:drive: ${value} ${bound}`,
79
+ )
80
+ }
81
+
82
+ return is_closed
83
+ }
84
+
85
+ // The result handed to the lane on the issue itself, which the child reads with its comments. A comment
86
+ // that cannot be posted still launches the lane: the child re-runs the declaration.
87
+ async function hand_over(issue: string, measurement: Measurement): Promise<false> {
88
+ try {
89
+ await git_gh_command.issue_comment(issue, report(measurement))
90
+ } catch (error) {
91
+ console.error(`Measurement result not posted: ${error_text.message_of(error)}`)
92
+ }
93
+
94
+ return false
95
+ }
96
+
97
+ // Whether the drive closed the issue by its declaration; `false` launches its lane.
98
+ async function closed(issue: string): Promise<boolean> {
99
+ const declaration = await declared(issue)
100
+
101
+ if (declaration === undefined) return false
102
+
103
+ const measurement = measured(declaration)
104
+
105
+ return measurement.verdict.kind === 'pass'
106
+ ? await close_passed(issue, measurement)
107
+ : await hand_over(issue, measurement)
108
+ }
109
+
110
+ const backlog_measure_close = { closed }
111
+
112
+ export { backlog_measure_close }
@@ -1,7 +1,9 @@
1
- import { auto_ok_cli, type OptedInRead, type TrackingRead } from '#scripts/auto-ok/auto-ok-cli'
1
+ import { auto_ok_author } from '#scripts/auto-ok/auto-ok-author'
2
+ import { auto_ok_cli, type OptedInRead } from '#scripts/auto-ok/auto-ok-cli'
2
3
  import { repo_discovery } from '#scripts/discovery/repo-discovery'
3
4
  import { epic_bundle_gaps } from '#scripts/epic/epic-bundle-gaps'
4
5
  import { epic_busy } from '#scripts/epic/epic-busy'
6
+ import type { Classification } from '#scripts/epic/epic-classify'
5
7
  import type { EpicChild } from '#scripts/epic/epic-graph'
6
8
  import { epic_index } from '#scripts/epic/epic-index'
7
9
  import { epic_next } from '#scripts/epic/epic-next'
@@ -15,12 +17,11 @@ import { PROJECT_ROOT } from '#scripts/init/init-paths'
15
17
  import { issue_not_before } from '#scripts/issue/issue-not-before'
16
18
  import { issue_not_before_label } from '#scripts/issue/issue-not-before-label'
17
19
  import { session_cite } from '#scripts/issue/session-cite'
18
- import { lane_state } from '#scripts/lane/lane-state'
19
20
  import { issue_citation } from '#scripts/rules/issue-citation'
20
21
  import { backlog_defect_priority } from './backlog-defect-priority'
21
- import { backlog_overlap } from './backlog-overlap'
22
+ import { backlog_gate_scope, type OptedIn, type PoolContext } from './backlog-gate-scope'
22
23
  import { backlog_pool } from './backlog-pool'
23
- import { backlog_rank, type GateScope } from './backlog-rank'
24
+ import { backlog_rank } from './backlog-rank'
24
25
  import { backlog_wait_cause } from './backlog-wait-cause'
25
26
 
26
27
  // `josh backlog:next` — what the whole opted-in backlog may run next.
@@ -84,17 +85,6 @@ const VERDICT_TOKENS: Readonly<Record<BacklogVerdict, string>> = {
84
85
  wait: 'wait',
85
86
  }
86
87
 
87
- type OptedIn = Extract<OptedInRead, { kind: 'read' }>
88
- type Tracking = Extract<TrackingRead, { kind: 'read' }>
89
-
90
- // Everything the answer is assembled from, read once and passed down rather than re-fetched.
91
- interface PoolContext {
92
- opted_in: OptedIn
93
- tracking: Tracking
94
- repo: string
95
- exclude: ReadonlyArray<number>
96
- }
97
-
98
88
  // One token per line on standard output: the runnable issue numbers of **this** repository, in the
99
89
  // order they may be started, or the single verdict word when there is nothing to offer here. Every
100
90
  // explanation is on standard error, so `answers=$(pnpm josh backlog:next)` captures something a loop
@@ -193,14 +183,27 @@ function running_of(
193
183
  // The two halves as one result. The epic half is already classified by `epic:next`; the standalone
194
184
  // half is classified here; the verdict is decided from the merge, so a backlog with a runnable epic
195
185
  // child and nothing else says `run` exactly as one with a runnable standalone issue does.
196
- function combine(views: ReadonlyArray<EpicView>, context: PoolContext): EpicNextResult {
197
- const graphs = views.map((view) => view.snapshot.children)
198
- const standalone = backlog_pool.standalone_rows(context.opted_in.issues)
199
- const from_epics = backlog_pool.drop_excluded(
200
- backlog_pool.epic_classification(views),
186
+ // `untrusted` is the epic children an author without write access filed (joshuafolkken/kit#4633).
187
+ function epic_half(
188
+ views: ReadonlyArray<EpicView>,
189
+ context: PoolContext,
190
+ untrusted: ReadonlySet<string>,
191
+ ): Classification {
192
+ return backlog_pool.drop_excluded(
193
+ backlog_pool.epic_classification(views, untrusted),
201
194
  context.exclude,
202
195
  context.repo,
203
196
  )
197
+ }
198
+
199
+ function combine(
200
+ views: ReadonlyArray<EpicView>,
201
+ context: PoolContext,
202
+ untrusted: ReadonlySet<string>,
203
+ ): EpicNextResult {
204
+ const graphs = views.map((view) => view.snapshot.children)
205
+ const standalone = backlog_pool.standalone_rows(context.opted_in.issues)
206
+ const from_epics = epic_half(views, context, untrusted)
204
207
  const from_standalone = backlog_pool.classify_standalone(standalone, {
205
208
  tracked: epic_index.withheld_children(context.tracking.index, context.opted_in.issues),
206
209
  exclude: context.exclude,
@@ -245,10 +248,17 @@ function settled_views(
245
248
  //
246
249
  // The running set covers the standalone rows as well as every read graph, so an epic child waiting on
247
250
  // an opted-in standalone issue waits rather than stops.
248
- function views_from(reads: ReadonlyArray<EpicRead>, context: PoolContext): ReadonlyArray<EpicView> {
251
+ function views_from(
252
+ reads: ReadonlyArray<EpicRead>,
253
+ context: PoolContext,
254
+ untrusted: ReadonlySet<string>,
255
+ ): ReadonlyArray<EpicView> {
249
256
  if (reads.length === 0) return []
250
257
 
251
- const graphs = reads.map((read) => read.snapshot.children)
258
+ const graphs = backlog_pool.trusted_graphs(
259
+ reads.map((read) => read.snapshot.children),
260
+ untrusted,
261
+ )
252
262
 
253
263
  return settled_views(
254
264
  reads,
@@ -277,11 +287,15 @@ async function resolve(context: PoolContext): Promise<EpicNextResult | undefined
277
287
  return undefined
278
288
  }
279
289
 
290
+ const untrusted = await auto_ok_author.untrusted_child_keys(
291
+ reads.flatMap((read) => read.snapshot.children),
292
+ context.repo,
293
+ )
280
294
  // The defect priority and the ranking keys are applied here rather than when printing, so
281
295
  // `backlog:plan` shows the order the run takes. The
282
296
  // ranking goes last: its sort is stable, so the defect order survives as its final key.
283
297
  const ordered = await backlog_defect_priority.prioritize(
284
- combine(views_from(reads, context), context),
298
+ combine(views_from(reads, context, untrusted), context, untrusted),
285
299
  context.repo,
286
300
  )
287
301
 
@@ -318,29 +332,6 @@ function report_retry(context: PoolContext): number {
318
332
  return SUCCESS_EXIT_CODE
319
333
  }
320
334
 
321
- // The rows the offer's cap bounds — the standalone half.
322
- function standalone_keys(context: PoolContext): ReadonlySet<string> {
323
- return backlog_pool.standalone_keys(context.opted_in.issues, {
324
- tracked: epic_index.withheld_children(context.tracking.index, context.opted_in.issues),
325
- exclude: context.exclude,
326
- repo: context.repo,
327
- })
328
- }
329
-
330
- // The running lanes still carry the pickup label, so the opted-in listing holds their bodies too —
331
- // which is what lets a candidate be held back from a path a running lane already declares.
332
- // `backlog:plan --waves` reads the same scope, so its first wave is this offer. Their lane state
333
- // records name a paused holder in the wait it causes (joshuafolkken/kit#4270); they are local files.
334
- async function gate_scope(context: PoolContext): Promise<GateScope> {
335
- const { issues } = context.opted_in
336
-
337
- return {
338
- standalone: standalone_keys(context),
339
- declared: backlog_overlap.declared_of(issues),
340
- lanes: await lane_state.read_states(issues.map((issue) => String(issue.number))),
341
- }
342
- }
343
-
344
335
  // The `run:solo` gate is applied here rather than in `resolve`, because `backlog:plan` shares
345
336
  // `resolve` and a plan made before the run lists everything. The holders are
346
337
  // read only on a `run` answer — the one answer the gate can change. The cap follows the gate
@@ -356,7 +347,7 @@ async function gate_solo(result: EpicNextResult, context: PoolContext): Promise<
356
347
 
357
348
  if (notice !== undefined) console.error(notice)
358
349
 
359
- const gated = backlog_rank.gate(result, read, repo, await gate_scope(context))
350
+ const gated = backlog_rank.gate(result, read, repo, await backlog_gate_scope.gate_scope(context))
360
351
 
361
352
  if (gated.notice !== undefined) console.error(gated.notice)
362
353
 
@@ -470,10 +461,9 @@ const backlog_next = {
470
461
  READ_FAILURES,
471
462
  VERDICT_TOKENS,
472
463
  resolve,
473
- gate_scope,
474
464
  context_of,
475
465
  run,
476
466
  }
477
467
 
478
468
  export { backlog_next }
479
- export type { BacklogVerdict, OptedIn, PoolContext }
469
+ export type { BacklogVerdict }
@@ -27,8 +27,8 @@ import type { LaneRecords } from '#scripts/lane/lane-state'
27
27
  // child ended at the hand-off, and while `josh followup` runs the supervisor only polls CI, CodeRabbit
28
28
  // and the merge, so the slot is free for the next launch while every merge check still runs. The wait is
29
29
  // unmarked while the followup stage merges and gates again (`run-ship-sync.ts`); a stop there counts
30
- // the lane again, and past the limit the supervisor waits for a place before it relaunches the child
31
- // (`run-ship-return.ts`). A named epic's offer discounts the same lanes (`epic-lane-offer.ts`).
30
+ // the lane again, and more than one lane past the limit the supervisor waits for a place before it
31
+ // relaunches the child (`run-ship-place.ts`). A named epic's offer discounts the same lanes (`epic-lane-offer.ts`).
32
32
 
33
33
  // The issues whose lane has no child working in it (`lane_spent.idle_lanes`).
34
34
  type IdleRead = (lanes: ReadonlyArray<LaneInfo>) => ReadonlyArray<string>
@@ -17,11 +17,16 @@ import { lane_state, type LaneRecords } from '#scripts/lane/lane-state'
17
17
  const CODE_SPAN = /`([^`\s]+)`/gu
18
18
  const LINE_SUFFIX = /:\d+(?:[-:]\d+)?$/u
19
19
  const FILE_EXTENSION = /\.[a-z]\w*$/iu
20
- const ROOT_FILE_EXTENSION = /\.(?:[cm]?[jt]sx?|svelte|jsonc?|md|ya?ml|css|html|sh|toml|txt)$/u
20
+ // `properties`: `sonar-project.properties`, which joshuafolkken/kit#5083 and its holder both named
21
+ // and neither declared (joshuafolkken/kit#5107).
22
+ const ROOT_FILE_EXTENSION =
23
+ /\.(?:[cm]?[jt]sx?|svelte|jsonc?|md|ya?ml|css|html|sh|toml|txt|properties)$/u
21
24
  const GLOB = '*'
22
25
  const ISSUE_MARK = '#'
23
26
  const SEPARATOR = '/'
24
27
  const MIN_DIRECTORY_DEPTH = 2
28
+ const DOCS_DIRECTORY = 'docs/'
29
+ const MARKDOWN = '.md'
25
30
 
26
31
  // The paths each issue declares, by issue number. A directory ends in `/`; anything else is a file.
27
32
  type Declared = ReadonlyMap<number, ReadonlySet<string>>
@@ -52,9 +57,8 @@ function claim_of(path: string): string | undefined {
52
57
  return is_file(path) ? path : undefined
53
58
  }
54
59
 
55
- // The backticked files and directories `body` declares.
56
- function declared_paths(body: string): ReadonlySet<string> {
57
- const tokens = [...body.matchAll(CODE_SPAN)].map((match) => match[1] ?? '')
60
+ // The files and directories `tokens` claim — a body's code spans, or the paths a lane plans to edit.
61
+ function path_claims(tokens: ReadonlyArray<string>): ReadonlySet<string> {
58
62
  const paths = tokens
59
63
  .filter((token) => !token.includes(ISSUE_MARK))
60
64
  .map((token) => claim_of(without_glob(token.replace(LINE_SUFFIX, ''))))
@@ -62,6 +66,11 @@ function declared_paths(body: string): ReadonlySet<string> {
62
66
  return new Set(paths.filter((path) => path !== undefined))
63
67
  }
64
68
 
69
+ // The backticked files and directories `body` declares.
70
+ function declared_paths(body: string): ReadonlySet<string> {
71
+ return path_claims([...body.matchAll(CODE_SPAN)].map((match) => match[1] ?? ''))
72
+ }
73
+
65
74
  function declared_of(issues: ReadonlyArray<DeclaringIssue>): Declared {
66
75
  return new Map(issues.map((issue) => [issue.number, declared_paths(issue.body ?? '')]))
67
76
  }
@@ -70,7 +79,17 @@ function contains(outer: string, inner: string): boolean {
70
79
  return outer.endsWith(SEPARATOR) ? inner.startsWith(outer) : outer === inner
71
80
  }
72
81
 
82
+ // A document under `docs/` — a Markdown file or a directory of them. Nearly every issue edits one
83
+ // (`docs/josh-commands-run.md`), and the lane's sync with main resolves the overlap, so holding a lane
84
+ // back for it cost a whole lane each (joshuafolkken/kit#4926). `prompts/` and `.claude/` are the rules
85
+ // themselves and still count.
86
+ function is_shared_document(path: string): boolean {
87
+ return path.startsWith(DOCS_DIRECTORY) && (path.endsWith(SEPARATOR) || path.endsWith(MARKDOWN))
88
+ }
89
+
73
90
  function overlaps(left: string, right: string): boolean {
91
+ if (is_shared_document(left) || is_shared_document(right)) return false
92
+
74
93
  return contains(left, right) || contains(right, left)
75
94
  }
76
95
 
@@ -125,12 +144,19 @@ interface Holding {
125
144
  repo: string
126
145
  }
127
146
 
147
+ // The path of `paths` that one of `holders` already declares — what `lane:plan` yields on.
148
+ function path_clash(
149
+ paths: ReadonlySet<string>,
150
+ declared: Declared,
151
+ holders: ReadonlyArray<number>,
152
+ ): Clash | undefined {
153
+ return clash_of(claims_of(declared, holders), paths)
154
+ }
155
+
128
156
  // The path `child` declares that one of the running `holders` already declares — the clash `separate`
129
157
  // withholds a candidate on, for a reader that names the running issues itself (`run:board`).
130
158
  function running_clash(child: EpicChild, declared: Declared, holding: Holding): Clash | undefined {
131
- const claims = claims_of(declared, holding.holders)
132
-
133
- return clash_of(claims, paths_of(child, declared, holding.repo))
159
+ return path_clash(paths_of(child, declared, holding.repo), declared, holding.holders)
134
160
  }
135
161
 
136
162
  // Whether `waiting` declares a path `holder` declares — the overlap `separate` withholds it on.
@@ -207,7 +233,15 @@ function separate(
207
233
  return { offered: walk.offered, withheld, ...(notice !== undefined && { notice }) }
208
234
  }
209
235
 
210
- const backlog_overlap = { declared_of, declared_paths, holds, running_clash, separate }
236
+ const backlog_overlap = {
237
+ declared_of,
238
+ declared_paths,
239
+ holds,
240
+ path_claims,
241
+ path_clash,
242
+ running_clash,
243
+ separate,
244
+ }
211
245
 
212
246
  export { backlog_overlap }
213
247
  export type { Clash, Declared }
@@ -6,6 +6,7 @@ import { backlog_named } from './backlog-named'
6
6
  import { backlog_next } from './backlog-next'
7
7
  import { backlog_plan, type NamedPlan } from './backlog-plan'
8
8
  import { backlog_plan_read, type OpenListing, type Plan } from './backlog-plan-read'
9
+ import { backlog_rank } from './backlog-rank'
9
10
  import { backlog_scope } from './backlog-scope'
10
11
  import { backlog_waves } from './backlog-waves'
11
12
 
@@ -105,7 +106,9 @@ function print_plan(plan: Plan, listing: OpenListing, view: PlanView): void {
105
106
  const scope = { repo: plan.repo, exclude: plan.exclude, tracked: plan.tracked }
106
107
  const rows = backlog_scope.out_of_scope(listing.rows, plan.result, scope)
107
108
 
108
- console.info(backlog_plan.format_plan(plan.result, rows, context, view.named))
109
+ const ordered = backlog_rank.offer_order(plan.result, plan.repo, plan.scope.yielded)
110
+
111
+ console.info(backlog_plan.format_plan(ordered, rows, context, view.named))
109
112
  }
110
113
 
111
114
  async function report(plan: Plan, view: PlanView): Promise<number> {
@@ -0,0 +1,81 @@
1
+ import { git_gh_issue_read } from '#scripts/gh/git-gh-issue-read'
2
+ import { has_any_label, PLANNED_LABEL } from '#scripts/issue/issue-labels'
3
+ import { issue_read, type IssueComment } from '#scripts/issue/issue-read'
4
+ import { markdown_section } from '#scripts/issue/markdown-section'
5
+ import { plan_consumers_section } from '#scripts/issue/plan-consumers-section'
6
+ import { lane_plan } from '#scripts/lane/lane-plan'
7
+ import { bounded_pool } from '#scripts/lib/bounded-pool'
8
+ import { backlog_overlap, type Declared } from './backlog-overlap'
9
+
10
+ // The paths a pool issue declares — the plan a running lane recorded with `lane:plan`, else the plan
11
+ // `issue:plan` posted as a comment, else its body.
12
+ //
13
+ // **A plan replaces the body**: a body cites paths as evidence (joshuafolkken/kit#4937). A plan naming
14
+ // no path leaves the body.
15
+ //
16
+ // **A plan posted as a comment declares paths too.** joshuafolkken/kit#4910's body named none of the
17
+ // files its plan comment did, so dispatch saw no overlap with joshuafolkken/kit#4911 and
18
+ // joshuafolkken/kit#4907, and the lane sat in `lane:plan`'s `wait` for 23 minutes
19
+ // (joshuafolkken/kit#4923). Only a `run:planned` issue is read, so an unplanned pool costs no request,
20
+ // and only a trusted author's comment counts — the same trust `issue:read` applies. A plan is the
21
+ // comment carrying the consumers section `issue:plan` refuses a plan without; the latest one wins.
22
+ // A listing that cannot be read leaves the body alone — the scope dispatch gated on before — and
23
+ // `lane:plan` still holds the lane at its first edit.
24
+
25
+ const PLANNED: ReadonlySet<string> = new Set([PLANNED_LABEL])
26
+ const READ_CONCURRENCY = 8
27
+
28
+ interface PoolIssue {
29
+ number: number
30
+ body?: string | undefined
31
+ labels?: ReadonlyArray<{ name: string }> | undefined
32
+ }
33
+
34
+ function is_plan(comment: IssueComment): boolean {
35
+ return (
36
+ comment.is_trusted === true &&
37
+ markdown_section.has_line(comment.body, plan_consumers_section.HEADING)
38
+ )
39
+ }
40
+
41
+ // The latest trusted plan among `comments`, less its consumers section — whose entries are readers,
42
+ // not edited files — or `undefined` when none is one.
43
+ function plan_of(comments: ReadonlyArray<IssueComment>): string | undefined {
44
+ const plan = comments.findLast((comment) => is_plan(comment))?.body
45
+
46
+ return plan === undefined ? undefined : plan_consumers_section.without(plan)
47
+ }
48
+
49
+ // The plan comment `issue` carries, or `undefined` when none does or the listing could not be read.
50
+ async function read_plan(issue: number): Promise<string | undefined> {
51
+ const json = await git_gh_issue_read.issue_list_comments(String(issue))
52
+ const comments = await issue_read.parse_comments(json)
53
+
54
+ return comments === undefined ? undefined : plan_of(comments)
55
+ }
56
+
57
+ // The paths `issue`'s plan comment declares — what `lane:plan` is handed before the first edit.
58
+ async function plan_paths(issue: number): Promise<ReadonlyArray<string>> {
59
+ return [...backlog_overlap.declared_paths((await read_plan(issue)) ?? '')]
60
+ }
61
+
62
+ async function with_plan(issue: PoolIssue): Promise<PoolIssue> {
63
+ if (!has_any_label(issue.labels, PLANNED)) return issue
64
+
65
+ const plan = await read_plan(issue.number)
66
+
67
+ if (plan === undefined || backlog_overlap.declared_paths(plan).size === 0) return issue
68
+
69
+ return { ...issue, body: plan }
70
+ }
71
+
72
+ // What each of `issues` declares, read from `directory`'s lane plans — the scope dispatch gates on.
73
+ async function declared_of(issues: ReadonlyArray<PoolIssue>, directory: string): Promise<Declared> {
74
+ const planned = await bounded_pool.bounded_map(issues, READ_CONCURRENCY, with_plan)
75
+
76
+ return lane_plan.with_plans(backlog_overlap.declared_of(planned), directory)
77
+ }
78
+
79
+ const backlog_plan_comment = { declared_of, plan_of, plan_paths }
80
+
81
+ export { backlog_plan_comment }
@@ -4,8 +4,10 @@ import type { EpicNextResult } from '#scripts/epic/epic-report'
4
4
  import { git_gh_command } from '#scripts/gh/git-gh-command'
5
5
  import { open_issue_schema, type OpenIssueData } from '#scripts/git/git-schemas'
6
6
  import { read_json_listing } from '#scripts/git/parse-json-array'
7
- import { issue_sample_gate } from '#scripts/issue/issue-sample-gate'
8
- import { backlog_next, type OptedIn } from './backlog-next'
7
+ import { issue_sample_prime } from '#scripts/issue/issue-sample-prime'
8
+ import { lane_capacity } from '#scripts/lane/lane-capacity'
9
+ import { backlog_gate_scope, type OptedIn } from './backlog-gate-scope'
10
+ import { backlog_next } from './backlog-next'
9
11
  import type { PlanContext } from './backlog-plan'
10
12
  import type { GateScope } from './backlog-rank'
11
13
  import { backlog_scope } from './backlog-scope'
@@ -24,8 +26,8 @@ interface Plan {
24
26
  // past the listing cap. Carrying the *whole* index here instead would move that misreport rather
25
27
  // than remove it: the sentence would name an epic that is withholding nothing.
26
28
  tracked: ReadonlyMap<number, number>
27
- // The rows the offer's cap bounds and the paths each issue declares, so `--waves` cuts each
28
- // wave where `backlog:next` does.
29
+ // The rows the offer's cap bounds and the paths each issue declares, so `--waves` separates each
30
+ // wave as `backlog:next` does — and the lane limit it cuts each wave at.
29
31
  scope: GateScope
30
32
  }
31
33
 
@@ -42,6 +44,14 @@ interface PlanRead {
42
44
  listing: OpenListing
43
45
  }
44
46
 
47
+ // The lane limit a wave is cut at, capped at the port seats as a launch is; `undefined` when the
48
+ // limit cannot be read, so the plan stays drawable and says it is uncapped.
49
+ async function read_wave_limit(): Promise<number | undefined> {
50
+ const choice = await lane_capacity.lane_limit()
51
+
52
+ return choice.kind === 'limit' ? lane_capacity.seated_limit(choice.limit) : undefined
53
+ }
54
+
45
55
  // The same reads and the same classification `backlog:next` makes, through the same two functions.
46
56
  // `undefined` is a failure it has already reported.
47
57
  async function classify(
@@ -61,7 +71,10 @@ async function classify(
61
71
  repo: context.repo,
62
72
  exclude,
63
73
  tracked: epic_index.withheld_children(context.tracking.index, context.opted_in.issues),
64
- scope: await backlog_next.gate_scope(context),
74
+ scope: {
75
+ ...(await backlog_gate_scope.gate_scope(context)),
76
+ wave_limit: await read_wave_limit(),
77
+ },
65
78
  }
66
79
  }
67
80
 
@@ -76,7 +89,7 @@ async function fetch_open(): Promise<OpenListing | undefined> {
76
89
  const read = read_json_listing(json, open_issue_schema)
77
90
 
78
91
  if (read.kind !== 'read') return undefined
79
- await issue_sample_gate.prime(read.rows.map((row) => row.body))
92
+ await issue_sample_prime.prime(read.rows.map((row) => row.body))
80
93
 
81
94
  return { rows: read.rows, is_capped }
82
95
  }
@@ -1,3 +1,4 @@
1
+ import { auto_ok_author } from '#scripts/auto-ok/auto-ok-author'
1
2
  import { auto_ok_cli } from '#scripts/auto-ok/auto-ok-cli'
2
3
  import type { Classification } from '#scripts/epic/epic-classify'
3
4
  import { epic_graph, type EpicChild, type GraphAnomaly } from '#scripts/epic/epic-graph'
@@ -61,13 +62,19 @@ function waits_outside(issue: OpenIssueData, running: ReadonlySet<string>, repo:
61
62
  .some((blocker) => blocker.state === 'OPEN' && !running.has(epic_graph.blocker_key(blocker)))
62
63
  }
63
64
 
64
- function needs_person(issue: OpenIssueData, context: StandaloneContext): boolean {
65
+ // An issue whose author lacks write access waits on a person too: only they can vouch for its body.
66
+ function is_stuck(issue: OpenIssueData, running: ReadonlySet<string>, repo: string): boolean {
65
67
  return (
68
+ !auto_ok_author.is_author_trusted(issue) ||
66
69
  has_any_label(issue.labels, DECISION_LABELS) ||
67
- waits_outside(issue, context.running, context.repo)
70
+ waits_outside(issue, running, repo)
68
71
  )
69
72
  }
70
73
 
74
+ function needs_person(issue: OpenIssueData, context: StandaloneContext): boolean {
75
+ return is_stuck(issue, context.running, context.repo)
76
+ }
77
+
71
78
  // Each open epic's key, read off the tracking index — child number to the epics listing it.
72
79
  function epic_keys_of(tracking: TrackingIndex, repo: string): ReadonlySet<string> {
73
80
  return new Set([...tracking.values()].flat().map((number) => epic_graph.key_of({ repo, number })))
@@ -102,10 +109,6 @@ function rooted(
102
109
  return with_tracking_epics(members, tracking, repo)
103
110
  }
104
111
 
105
- function is_stuck(issue: OpenIssueData, running: ReadonlySet<string>, repo: string): boolean {
106
- return has_any_label(issue.labels, DECISION_LABELS) || waits_outside(issue, running, repo)
107
- }
108
-
109
112
  // The running set with every standalone row a person has to resolve taken out, repeated until a pass
110
113
  // removes nothing — a row waiting on such a row waits on that person too, however long the chain.
111
114
  function settle_standalone(
@@ -293,6 +296,29 @@ function keys_of(children: ReadonlyArray<EpicChild>): Set<string> {
293
296
  return new Set(children.map((child) => epic_graph.key_of(child)))
294
297
  }
295
298
 
299
+ // The graphs with every untrusted child taken out before the running set is built from them, so a row
300
+ // blocked by one — standalone or in another epic — waits on a person rather than on time.
301
+ function trusted_graphs(
302
+ graphs: ReadonlyArray<ReadonlyArray<EpicChild>>,
303
+ untrusted: ReadonlySet<string>,
304
+ ): Array<Array<EpicChild>> {
305
+ return graphs.map((children) => without(children, untrusted))
306
+ }
307
+
308
+ function waits_on(child: EpicChild, held: ReadonlySet<string>): boolean {
309
+ return child.blocked_by.some((blocker) => held.has(epic_graph.blocker_key(blocker)))
310
+ }
311
+
312
+ // The held keys and, however long the chain, every child waiting on one of them.
313
+ function with_dependants(
314
+ children: ReadonlyArray<EpicChild>,
315
+ held: ReadonlySet<string>,
316
+ ): ReadonlySet<string> {
317
+ const grown = new Set([...held, ...keys_of(children.filter((child) => waits_on(child, held)))])
318
+
319
+ return grown.size === held.size ? held : with_dependants(children, grown)
320
+ }
321
+
296
322
  // The epic half, already classified. `epic:next` decided each of these — the `blocked-by` graph, the
297
323
  // wave, the anomalies — so this only flattens the per-repository bundles back into one list, in the
298
324
  // order the epics' own task lists gave them.
@@ -302,15 +328,26 @@ function keys_of(children: ReadonlyArray<EpicChild>): Set<string> {
302
328
  // `runnable` — and a child offered on standard output while standard error lists it as waiting is
303
329
  // work a loop would start against a dependency that is still standing. So `human` is settled first,
304
330
  // `time` next, and `runnable` keeps only what neither claimed.
305
- function epic_classification(views: ReadonlyArray<EpicView>): Classification {
306
- const human = unique_children(views.flatMap((view) => view.result.blocked_on_people))
307
- const time = without(
308
- unique_children(views.flatMap((view) => view.result.waiting)),
309
- keys_of(human),
310
- )
331
+ //
332
+ // `untrusted` names the children whose author lacks write access (`auto_ok_author.untrusted_child_keys`).
333
+ // Each waits on a person wherever `epic:next` put it, exactly as a standalone row's does in
334
+ // `needs_person`: only a person can vouch for its body (joshuafolkken/kit#4633). A sibling waiting on
335
+ // one waits on that person too — `epic:next` weighs a blocker in the same graph by its own category,
336
+ // never by the running set, so the untrusted child's absence from that set does not reach it.
337
+ function epic_classification(
338
+ views: ReadonlyArray<EpicView>,
339
+ untrusted: ReadonlySet<string>,
340
+ ): Classification {
341
+ const waiting = views.flatMap((view) => view.result.waiting)
311
342
  const offered = views.flatMap((view) =>
312
343
  view.result.candidates.flatMap((bundle) => bundle.children),
313
344
  )
345
+ const held = with_dependants(waiting, untrusted)
346
+ const human = unique_children([
347
+ ...views.flatMap((view) => view.result.blocked_on_people),
348
+ ...[...waiting, ...offered].filter((child) => held.has(epic_graph.key_of(child))),
349
+ ])
350
+ const time = without(unique_children(waiting), keys_of(human))
314
351
 
315
352
  return {
316
353
  runnable: without(unique_children(offered), keys_of([...human, ...time])),
@@ -378,6 +415,7 @@ const backlog_pool = {
378
415
  standalone_rows,
379
416
  to_child,
380
417
  to_children,
418
+ trusted_graphs,
381
419
  }
382
420
 
383
421
  export { backlog_pool }