@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
@@ -1,5 +1,8 @@
1
1
  import { issue_cite } from '#scripts/issue/issue-cite'
2
+ import { review_attest, type ReviewSlot } from '#scripts/review/review-attest'
2
3
  import { review_finding_ledger } from '#scripts/review/review-finding-ledger'
4
+ import { review_finding_text } from '#scripts/review/review-finding-text'
5
+ import { review_prior_findings } from '#scripts/review/review-prior-findings'
3
6
  import { review_record_cli } from '#scripts/review/review-record-cli'
4
7
 
5
8
  // The pure half of `josh ship --review`: the one-line prompts the supervised reviewers are launched
@@ -24,17 +27,14 @@ const HIGH = 'high'
24
27
  const MEDIUM = 'medium'
25
28
  const FIXED_PREFIX = 'fixed '
26
29
  const KIND_FIELDS = 2
27
- // What a finding line carries after its spec: one sentence saying what is wrong, so a stopped ship's
28
- // log tells the resumed lane child the defect rather than only its location.
29
- const DESCRIPTION_SEPARATOR = ' — '
30
- // Where the spec ends on read: a reviewer that types the dash as `-`, `--` or `–` still ends it there,
31
- // so its sentence never lands in the ledger's file field.
32
- const DESCRIPTION_BOUNDARY = / [—–-]{1,2} /u
33
- // Where a description's first sentence ends, and the cap that keeps a run-on one a line. Japanese
34
- // sets no space after `。`, so it ends a sentence on its own.
35
- const SENTENCE_END = /(?<=[.!?])\s|(?<=。)/u
36
- const SENTENCE_LIMIT = 200
37
- const ELLIPSIS = '…'
30
+ // `findings_path` is set only for a lane whose josh predates `review:submit`
31
+ // (`lane-session-action.ts`).
32
+ type PromptOf = (
33
+ brief_path: string,
34
+ slot: ReviewSlot,
35
+ issue: string,
36
+ findings_path?: string,
37
+ ) => string
38
38
 
39
39
  const VERDICT = {
40
40
  CLEAN: 'clean',
@@ -78,24 +78,68 @@ const MISSING_NOTE = 'the reviewer wrote no findings file — the review did not
78
78
  const CLEAN_NOTE = 'review clean or Low-only — recorded; shipping on.'
79
79
  const FIXED_NOTE =
80
80
  'review fixes applied in place — recorded; the gate re-runs on the fixed tree and round 2 follows the commit.'
81
- const BLOCKING_NOTE =
82
- 'review found High/Medium it did not fix — recorded; fix them, then take the round-2 route (`chain-rule.md`).'
81
+ // Every stop that hands findings back for a fix: a fix of only the cited line left the same pattern
82
+ // beside it for the next round to stop on again (joshuafolkken/kit#4673).
83
+ const SWEEP_INSTRUCTION = [
84
+ 'Before fixing, sweep each finding for its other sites — the same file, the callers of the same',
85
+ 'function and a grep of the pattern — fix every site in one pass, and list each range searched on its',
86
+ 'own line in the Issue fix comment.',
87
+ ].join(' ')
88
+ const BLOCKING_NOTE = `review found High/Medium it did not fix — recorded. ${SWEEP_INSTRUCTION} Then take the round-2 route (\`chain-rule.md\`).`
83
89
  const UNVERIFIED_OUTCOME: RoundOutcome = {
84
90
  is_passing: false,
85
- note: 'review fixes did not pass the scoped checks — recorded as unfixed; fix them, then take the round-2 route (`chain-rule.md`).',
91
+ note: `review fixes did not pass the scoped checks — recorded as unfixed. ${SWEEP_INSTRUCTION} Then take the round-2 route (\`chain-rule.md\`).`,
86
92
  }
93
+ // The findings line is all a stopped ship hands the lane, so the other sites the rubric asks the
94
+ // reviewer to cite ride on it rather than in its prose report (joshuafolkken/kit#4673).
95
+ const OTHER_SITES_CLAUSE = '"other sites: <file>:<line>, …" for each other site of the same pattern'
87
96
  const ROUND_TWO_CLEAN_NOTE = 'round 2 clean or Low-only — recorded; shipping on.'
88
- const ROUND_TWO_BLOCKING_NOTE =
89
- 'round 2 found High/Medium or edited the tree — recorded; round 2 is final: fix, push and gate it, then run followup (`chain-rule.md` step 4).'
97
+ const SUBMIT_COMMAND = 'pnpm josh review:submit'
98
+ const ROUND_TWO_BLOCKING_NOTE = `round 2 found High/Medium or edited the tree — recorded; round 2 is final. ${SWEEP_INSTRUCTION} Then push and gate it, and run followup (\`chain-rule.md\` step 4).`
99
+
100
+ // **The reviewer hands its findings to a command, never to a path it copies** (joshuafolkken/kit#4799):
101
+ // a reviewer that copied the findings path matched the `josh-review-*` files beside it and dropped
102
+ // `ship-`, so the supervisor never read a review it had finished. `review:submit` knows the slot's path.
103
+ function submit_command(slot: ReviewSlot): string {
104
+ return slot === review_attest.REVIEW_SLOT.CODE
105
+ ? SUBMIT_COMMAND
106
+ : `${SUBMIT_COMMAND} --interaction`
107
+ }
108
+
109
+ // **A lane whose josh predates `review:submit` is handed the path**: the supervisor reloads onto main
110
+ // at its pass boundary (`run-wake-code.ts`), so it meets lanes branched before the command existed.
111
+ function sink_clauses(
112
+ slot: ReviewSlot,
113
+ findings_path: string | undefined,
114
+ ): readonly [string, string] {
115
+ if (findings_path !== undefined) {
116
+ return [
117
+ `Then write every finding to ${findings_path},`,
118
+ 'and an empty file when there is none.',
119
+ ]
120
+ }
121
+
122
+ return [
123
+ `Then pipe every finding on stdin to \`${submit_command(slot)}\` — never write a findings file yourself —`,
124
+ 'or run it with `--none` and no stdin when there is none; if it refuses a line, fix that line and run it again.',
125
+ ]
126
+ }
90
127
 
91
- function findings_instruction(findings_path: string, fixed_clause: string): string {
128
+ function findings_instruction(
129
+ slot: ReviewSlot,
130
+ fixed_clause: string,
131
+ findings_path: string | undefined,
132
+ ): string {
92
133
  const categories = review_finding_ledger.CATEGORIES.join(', ')
134
+ const [opening, closing] = sink_clauses(slot, findings_path)
93
135
 
94
136
  return [
95
- `Then write every finding to ${findings_path}, one per line as`,
96
- `<category>:<severity>:<file>[:<line>]${DESCRIPTION_SEPARATOR}<one sentence: what is wrong and why>`,
137
+ opening,
138
+ 'one per line as',
139
+ `<category>:<severity>:<file>[:<line>]${review_finding_text.DESCRIPTION_SEPARATOR}<one sentence: what is wrong and why>`,
97
140
  `(category one of ${categories}; severity high, medium or low)${fixed_clause},`,
98
- 'and an empty file when there is none.',
141
+ `a high or medium line ending with ${OTHER_SITES_CLAUSE},`,
142
+ closing,
99
143
  ].join(' ')
100
144
  }
101
145
 
@@ -109,56 +153,99 @@ function issue_read_instruction(issue: string): string {
109
153
  ].join(' ')
110
154
  }
111
155
 
156
+ // **The review runs in this session itself** (joshuafolkken/kit#4715): a reviewer that invoked the
157
+ // `/code-review` skill forked a second agent that read the same diff and brief again. The session is
158
+ // launched without the `Skill` and `Agent` tools (`claude-agent-argv.ts`), and the prompt says so.
159
+ const IN_SESSION_CLAUSE =
160
+ 'Review it yourself in this session — you carry no Skill or Agent tool, so never launch a second reviewer.'
161
+
162
+ function round_one_opening(brief_path: string): string {
163
+ return [
164
+ `Review this checkout as a /code-review: read the review brief at ${brief_path} and follow it exactly —`,
165
+ 'the level on its first line, the rubric it names, the checkout it pins and its review:attest step.',
166
+ IN_SESSION_CLAUSE,
167
+ ].join(' ')
168
+ }
169
+
112
170
  // One line, because `detached_launch` refuses an argument carrying a control character: the multi-line
113
171
  // brief travels by path, never inline.
114
- function reviewer_prompt(brief_path: string, findings_path: string, issue: string): string {
172
+ function reviewer_prompt(
173
+ brief_path: string,
174
+ slot: ReviewSlot,
175
+ issue: string,
176
+ findings_path?: string,
177
+ ): string {
115
178
  return [
116
- `Run a /code-review of this checkout: read the review brief at ${brief_path} and follow it exactly —`,
117
- 'the level on its first line, the rubric it names, the checkout it pins and its review:attest step.',
179
+ round_one_opening(brief_path),
118
180
  issue_read_instruction(issue),
181
+ ...review_prior_findings.prompt_clauses(issue),
119
182
  'Apply a fix only for a Medium finding whose fix is small and local — a one-function refactor, an',
120
183
  'added test, an added guard; never fix a High or a change that reaches beyond one place, and never',
121
184
  'commit, stage or push. After any fix, run `pnpm josh lint:related && pnpm josh test:related` and',
122
185
  'return only once both are green; revert a fix you cannot get green and report that finding unfixed.',
123
- findings_instruction(findings_path, `, prefixing a finding you fixed with "${FIXED_PREFIX}"`),
186
+ findings_instruction(
187
+ slot,
188
+ `, prefixing a finding you fixed with "${FIXED_PREFIX}"`,
189
+ findings_path,
190
+ ),
124
191
  ].join(' ')
125
192
  }
126
193
 
194
+ // The round-1 review run beside the code review: it reads only, so the two sessions never fix, verify
195
+ // and revert in the one shared checkout at once; its findings go to the lane's one fix pass.
196
+ function report_prompt(
197
+ brief_path: string,
198
+ slot: ReviewSlot,
199
+ issue: string,
200
+ findings_path?: string,
201
+ ): string {
202
+ return [
203
+ round_one_opening(brief_path),
204
+ 'Do not edit any file: the code review running beside this one fixes in this checkout.',
205
+ issue_read_instruction(issue),
206
+ ...review_prior_findings.prompt_clauses(issue),
207
+ findings_instruction(slot, '', findings_path),
208
+ ].join(' ')
209
+ }
210
+
211
+ // **One reviewer edits the checkout** (joshuafolkken/kit#4672): a slot reviewed beside the code slot
212
+ // reads only, and a slot reviewed alone takes the round's own prompt.
213
+ function slot_prompt(
214
+ round_prompt: PromptOf,
215
+ slot: ReviewSlot,
216
+ slots: ReadonlyArray<ReviewSlot>,
217
+ ): PromptOf {
218
+ if (slot === review_attest.REVIEW_SLOT.CODE || slots.length === 1) return round_prompt
219
+
220
+ return report_prompt
221
+ }
222
+
127
223
  // The round-2 verification pass: a fresh session over the round-1 fix delta, reading only.
128
- function verification_prompt(brief_path: string, findings_path: string, issue: string): string {
224
+ function verification_prompt(
225
+ brief_path: string,
226
+ slot: ReviewSlot,
227
+ issue: string,
228
+ findings_path?: string,
229
+ ): string {
129
230
  return [
130
- `Run a /code-review of this checkout — the round-2 verification pass over the round-1 fixes: read the`,
231
+ `Review this checkout as a /code-review — the round-2 verification pass over the round-1 fixes: read the`,
131
232
  `review brief at ${brief_path} and follow it exactly — the level on its first line, the rubric it`,
132
233
  'names, the checkout it pins and its review:attest step. Do not edit any file.',
234
+ IN_SESSION_CLAUSE,
133
235
  issue_read_instruction(issue),
134
- findings_instruction(findings_path, ''),
236
+ ...review_prior_findings.prompt_clauses(issue),
237
+ findings_instruction(slot, '', findings_path),
135
238
  ].join(' ')
136
239
  }
137
240
 
138
241
  // The spec is what `review:record` reads; the description after it travels in the stage output and,
139
242
  // for a finding that stopped the ship, its first sentence in the durable stop log.
140
- function split_description(unmarked: string): { spec: string; description: string } {
141
- const boundary = DESCRIPTION_BOUNDARY.exec(unmarked)
142
-
143
- if (boundary === null) return { spec: unmarked.trim(), description: '' }
144
-
145
- const rest = unmarked.slice(boundary.index + boundary[0].length)
146
-
147
- return { spec: unmarked.slice(0, boundary.index).trim(), description: rest.trim() }
148
- }
149
-
150
243
  function finding_of(line: string): Finding {
151
244
  const is_fixed = line.startsWith(FIXED_PREFIX)
152
245
 
153
- return { ...split_description(is_fixed ? line.slice(FIXED_PREFIX.length) : line), is_fixed, line }
154
- }
155
-
156
- function first_sentence(description: string): string {
157
- const [sentence = ''] = description.split(SENTENCE_END, 1)
246
+ const unmarked = is_fixed ? line.slice(FIXED_PREFIX.length) : line
158
247
 
159
- if (sentence.length <= SENTENCE_LIMIT) return sentence
160
-
161
- return `${sentence.slice(0, SENTENCE_LIMIT - ELLIPSIS.length)}${ELLIPSIS}`
248
+ return { ...review_finding_text.split_description(unmarked), is_fixed, line }
162
249
  }
163
250
 
164
251
  function spec_findings(text: string): ReadonlyArray<Finding> {
@@ -192,7 +279,11 @@ function kinds_of(findings: ReadonlyArray<Finding>): ReadonlyArray<string> {
192
279
  function stop_finding_of(finding: Finding): StopFinding {
193
280
  const location = review_record_cli.parse_finding(finding.spec)?.file ?? ''
194
281
 
195
- return { kind: kind_of(finding), location, sentence: first_sentence(finding.description) }
282
+ return {
283
+ kind: kind_of(finding),
284
+ location,
285
+ sentence: review_finding_text.first_sentence(finding.description),
286
+ }
196
287
  }
197
288
 
198
289
  // `bug-risks:medium` — each kind of finding that decided a stopped stage, once per kind (the stop
@@ -218,6 +309,14 @@ function blocking_details(text: string): ReadonlyArray<StopFinding> {
218
309
  return deciding_findings(text).map((finding) => stop_finding_of(finding))
219
310
  }
220
311
 
312
+ // The findings a passing round 1 fixed in place — the stop log's only chance to see them, since no stop
313
+ // follows (joshuafolkken/kit#4780); none for any other round.
314
+ function passing_fixes(verdict: ScoredVerdict, outcome: RoundOutcome): ReadonlyArray<StopFinding> {
315
+ if (!outcome.is_passing || verdict.kind !== VERDICT.FIXED) return []
316
+
317
+ return blocking_details(verdict.report.join('\n'))
318
+ }
319
+
221
320
  function scored_kind(findings: ReadonlyArray<Finding>): ScoredVerdict['kind'] {
222
321
  if (findings.some((finding) => is_blocking(finding))) return VERDICT.BLOCKING
223
322
 
@@ -225,9 +324,10 @@ function scored_kind(findings: ReadonlyArray<Finding>): ScoredVerdict['kind'] {
225
324
  }
226
325
 
227
326
  // Absent means the reviewer never finished; a line outside the grammar means its verdict cannot be
228
- // recorded — both stop the ship rather than read as clean. The specs are recorded without the `fixed`
229
- // mark: a fixed finding was still a finding of that round. The report keeps each line whole — mark and
230
- // description — for the stage output a resumed lane child reads.
327
+ // recorded — both stop the ship rather than read as clean. A fixed finding is recorded with its
328
+ // `fixed` mark, the disposition `review:record` keeps in the ledger and `review:round2` reads round 1's
329
+ // closure from (joshuafolkken/kit#5286). The report keeps each line whole — mark and description — for
330
+ // the stage output a resumed lane child reads.
231
331
  function read_verdict(text: string | undefined): ReviewVerdict {
232
332
  if (text === undefined) return { kind: VERDICT.INVALID, note: MISSING_NOTE }
233
333
 
@@ -240,11 +340,23 @@ function read_verdict(text: string | undefined): ReviewVerdict {
240
340
 
241
341
  return {
242
342
  kind: scored_kind(findings),
243
- specs: findings.map((finding) => finding.spec),
343
+ specs: findings.map((finding) =>
344
+ finding.is_fixed ? `${FIXED_PREFIX}${finding.spec}` : finding.spec,
345
+ ),
244
346
  report: findings.map((finding) => finding.line),
245
347
  }
246
348
  }
247
349
 
350
+ // The specs `review:record` is given: a stopped round's `fixed` marks are dropped, since a fix the scoped
351
+ // pair turned down, or one beside a finding still blocking, has not closed what it marks.
352
+ function recorded_specs(verdict: ScoredVerdict, outcome: RoundOutcome): ReadonlyArray<string> {
353
+ if (outcome.is_passing) return verdict.specs
354
+
355
+ return verdict.specs.map((spec) =>
356
+ spec.startsWith(FIXED_PREFIX) ? spec.slice(FIXED_PREFIX.length) : spec,
357
+ )
358
+ }
359
+
248
360
  // Round 1 passes clean or with every blocking finding fixed in place; round 2 follows the commit.
249
361
  function round_one_outcome(verdict: ScoredVerdict): RoundOutcome {
250
362
  if (verdict.kind === VERDICT.BLOCKING) return { is_passing: false, note: BLOCKING_NOTE }
@@ -279,18 +391,26 @@ function round_two_outcome(verdict: ScoredVerdict): RoundOutcome {
279
391
 
280
392
  const run_ship_review = {
281
393
  FIXED_PREFIX,
394
+ OTHER_SITES_CLAUSE,
395
+ SWEEP_INSTRUCTION,
282
396
  UNVERIFIED_OUTCOME,
283
397
  VERDICT,
284
398
  blocking_details,
285
399
  blocking_kinds,
286
400
  has_fixes,
287
401
  is_clean_round_one,
402
+ passing_fixes,
288
403
  read_verdict,
404
+ recorded_specs,
405
+ report_prompt,
289
406
  reviewer_prompt,
407
+ round_one_opening,
290
408
  round_one_outcome,
291
409
  round_two_outcome,
410
+ slot_prompt,
411
+ submit_command,
292
412
  verification_prompt,
293
413
  }
294
414
 
295
- export type { ReviewVerdict, RoundOutcome, ScoredVerdict, StopFinding }
415
+ export type { PromptOf, ReviewVerdict, RoundOutcome, ScoredVerdict, StopFinding }
296
416
  export { run_ship_review }
@@ -1,4 +1,4 @@
1
- import { agent_argv, type AgentArgv } from '#scripts/agent/agent-argv'
1
+ import { agent_argv, type AgentArgv, type AgentArgvResult } from '#scripts/agent/agent-argv'
2
2
  import { agent_role_profile, type AgentProfile } from '#scripts/agent/agent-role-profile'
3
3
  import { api_auth } from '#scripts/agent/api-auth'
4
4
  import { PROJECT_ROOT } from '#scripts/init/init-paths'
@@ -6,8 +6,10 @@ import { josh_command, type JoshResult } from '#scripts/josh/josh-run'
6
6
  import { stamp_file } from '#scripts/josh/stamp-file'
7
7
  import { lane_child_marker } from '#scripts/lane/lane-child-marker'
8
8
  import { lane_session_broker } from '#scripts/lane/lane-session-broker'
9
+ import { review_attest, type ReviewSlot } from '#scripts/review/review-attest'
9
10
  import { detached_launch } from '#scripts/run/detached-launch'
10
- import { run_ship_review } from './run-ship-review'
11
+ import { run_ship_brokered_review } from './run-ship-brokered-review'
12
+ import { run_ship_review, type PromptOf } from './run-ship-review'
11
13
  import type { Phase } from './run-ship-scoped'
12
14
  import { run_ship_stop_cause, type Cause } from './run-ship-stop-cause'
13
15
  import type { StepResult } from './run-ship-sync'
@@ -22,13 +24,24 @@ const should_forward_stderr = true
22
24
  const ATTEST_CHECK = ['review:attest', '--check']
23
25
  const KEPT_REVIEW_NOTE =
24
26
  'the reviewer wrote its findings before it failed — its review is kept; attest and record judge it.'
27
+ const MISSING_FINDINGS_NOTE = 'the reviewer submitted no findings; nothing is at the slot path:'
25
28
  type Round = '1' | '2'
26
29
 
27
30
  const ROUND_ONE: Round = '1'
28
31
  const ROUND_TWO: Round = '2'
29
- type PromptOf = (brief_path: string, findings_path: string, issue: string) => string
32
+
33
+ interface SlotOpen {
34
+ open: ReadonlyArray<string>
35
+ slot: ReviewSlot
36
+ }
37
+
38
+ interface Briefed {
39
+ brief: string
40
+ slot: ReviewSlot
41
+ }
30
42
 
31
43
  const { CAUSE } = run_ship_stop_cause
44
+ const { CODE } = review_attest.REVIEW_SLOT
32
45
 
33
46
  // **Every stop is tagged with the step's own cause**, so a round that stopped on a red join, a reviewer
34
47
  // that did not finish or a refused attestation is not booked as a finding (joshuafolkken/kit#4431).
@@ -44,8 +57,8 @@ function tagged_phase(cause: Cause, phase: Phase): Phase {
44
57
  return async () => tagged(cause, await phase())
45
58
  }
46
59
 
47
- function paths(): { brief: string; findings: string; log: string } {
48
- return lane_session_broker.review_paths(PROJECT_ROOT)
60
+ function paths(slot?: ReviewSlot): { brief: string; findings: string; log: string } {
61
+ return lane_session_broker.review_paths(PROJECT_ROOT, slot)
49
62
  }
50
63
 
51
64
  async function josh(argv: ReadonlyArray<string>): Promise<JoshResult> {
@@ -66,17 +79,39 @@ function exited_note(log_path: string): string {
66
79
  return `${api_auth.AUTH_FAILURE_NOTE}: ${exited}`
67
80
  }
68
81
 
69
- function current_verdict(): ReturnType<typeof run_ship_review.read_verdict> {
70
- return run_ship_review.read_verdict(stamp_file.read_stamp_text(paths().findings))
82
+ function current_verdict(slot?: ReviewSlot): ReturnType<typeof run_ship_review.read_verdict> {
83
+ return run_ship_review.read_verdict(stamp_file.read_stamp_text(paths(slot).findings))
84
+ }
85
+
86
+ // **A session that ended with no findings file names the slot's path** (joshuafolkken/kit#4774) — the
87
+ // one `review:submit` writes, or the one a lane predating it was told to write: a reviewer that never
88
+ // submitted otherwise stops the round later, on a join or a record that never says the file is missing.
89
+ function missing_findings(slots: ReadonlyArray<ReviewSlot>): string | undefined {
90
+ const missing = slots
91
+ .map((slot) => paths(slot).findings)
92
+ .filter((findings) => stamp_file.read_stamp_text(findings) === undefined)
93
+
94
+ return missing.length === 0 ? undefined : `${MISSING_FINDINGS_NOTE} ${missing.join(', ')}`
95
+ }
96
+
97
+ function finished_session(slots: ReadonlyArray<ReviewSlot>): JoshResult {
98
+ const missing = missing_findings(slots)
99
+
100
+ return missing === undefined
101
+ ? { code: SUCCESS_EXIT_CODE, out: '' }
102
+ : failure(missing, CAUSE.INFRA)
71
103
  }
72
104
 
73
105
  // **A session that ran and then failed keeps the review it wrote** (joshuafolkken/kit#4562). The
74
106
  // findings file is removed before the launch and written as the reviewer's last step, so a readable one
75
107
  // is this session's finished review — a late auth failure or a lost broker reply then costs nothing,
76
108
  // where a relaunch would review the whole change again. The attest and record phases still judge it.
77
- function ended_session(failed_note: string): JoshResult {
78
- if (current_verdict().kind === run_ship_review.VERDICT.INVALID) {
79
- return failure(failed_note, CAUSE.INFRA)
109
+ // A broker answers for every slot it ran at once, so each slot's file must be readable.
110
+ function ended_session(failed_note: string, slots: ReadonlyArray<ReviewSlot> = [CODE]): JoshResult {
111
+ if (slots.some((slot) => current_verdict(slot).kind === run_ship_review.VERDICT.INVALID)) {
112
+ const missing = missing_findings(slots)
113
+
114
+ return failure(missing === undefined ? failed_note : `${failed_note}\n${missing}`, CAUSE.INFRA)
80
115
  }
81
116
 
82
117
  note(`${failed_note}\n${KEPT_REVIEW_NOTE}`)
@@ -86,13 +121,15 @@ function ended_session(failed_note: string): JoshResult {
86
121
 
87
122
  // Under the round's reviewer profile — the same model and effort (`JOSH_REVIEWER_*` included) the
88
123
  // chain's subagent is given — and waited on, so the join below runs only once the review has finished.
89
- // Each call is its own process, so round 2 is a fresh session by construction.
124
+ // Each call is its own process, so round 2 is a fresh session by construction. A failed session is
125
+ // judged on its own slot's findings, not on a sibling's still being written.
90
126
  async function run_direct_session(
91
127
  argv: AgentArgv,
92
128
  profile: AgentProfile,
93
- log_path: string,
129
+ slot: ReviewSlot,
94
130
  round: Round,
95
131
  ): Promise<JoshResult> {
132
+ const log_path = paths(slot).log
96
133
  const request = { argv, cwd: PROJECT_ROOT, log_path, profile }
97
134
 
98
135
  note(agent_role_profile.describe_review(Number(round), profile))
@@ -102,9 +139,9 @@ async function run_direct_session(
102
139
  return failure(`reviewer could not start: ${result.note}`, CAUSE.INFRA)
103
140
  }
104
141
 
105
- if (result.exit_code !== SUCCESS_EXIT_CODE) return ended_session(exited_note(log_path))
142
+ if (result.exit_code !== SUCCESS_EXIT_CODE) return ended_session(exited_note(log_path), [slot])
106
143
 
107
- return { code: SUCCESS_EXIT_CODE, out: '' }
144
+ return finished_session([slot])
108
145
  }
109
146
 
110
147
  // A lane child's reviewer is started by the lane's broker: an OpenAI lane's always, since a nested Codex
@@ -117,77 +154,135 @@ function is_brokered(profile: AgentProfile, issue: string): boolean {
117
154
  return profile.provider === 'openai' || lane_session_broker.is_serving(PROJECT_ROOT, issue)
118
155
  }
119
156
 
120
- async function run_session(
121
- prompt: string,
122
- log_path: string,
157
+ interface SlotSession {
158
+ slot: ReviewSlot
159
+ built: AgentArgvResult
160
+ }
161
+
162
+ function session_for(
163
+ prompt_of: PromptOf,
123
164
  issue: string,
124
165
  round: Round,
125
- ): Promise<JoshResult> {
126
- const built = agent_argv.review_in(prompt, Number(round), PROJECT_ROOT)
166
+ slots: { slot: ReviewSlot; all: ReadonlyArray<ReviewSlot> },
167
+ ): SlotSession {
168
+ const { slot, all } = slots
169
+ const prompt = run_ship_review.slot_prompt(prompt_of, slot, all)(paths(slot).brief, slot, issue)
170
+
171
+ return { slot, built: agent_argv.review_in(prompt, Number(round), PROJECT_ROOT) }
172
+ }
173
+
174
+ async function run_slot(session: SlotSession, round: Round): Promise<JoshResult> {
175
+ const { built, slot } = session
127
176
 
128
177
  if (built.kind === 'rejected') {
129
178
  return failure(`reviewer profile rejected: ${built.note}`, CAUSE.INFRA)
130
179
  }
131
180
 
132
- if (!is_brokered(built.profile, issue)) {
133
- return await run_direct_session(built.argv, built.profile, log_path, round)
134
- }
181
+ return await run_direct_session(built.argv, built.profile, slot, round)
182
+ }
135
183
 
136
- const answer = await lane_session_broker.request(PROJECT_ROOT, issue, { kind: 'review', round })
184
+ async function run_brokered(
185
+ issue: string,
186
+ round: Round,
187
+ slots: ReadonlyArray<ReviewSlot>,
188
+ ): Promise<JoshResult> {
189
+ const answer = await run_ship_brokered_review.request(PROJECT_ROOT, issue, round, slots)
137
190
 
138
191
  return answer.is_success
139
- ? { code: SUCCESS_EXIT_CODE, out: '' }
140
- : ended_session(`isolated reviewer failed: ${answer.reason}`)
192
+ ? finished_session(slots)
193
+ : ended_session(`isolated reviewer failed: ${answer.reason}`, slots)
194
+ }
195
+
196
+ // **The slots' reviewers run side by side** (joshuafolkken/kit#4672), and the first failure among
197
+ // them is the result — each slot is launched through the same path a single review takes.
198
+ async function run_sessions(
199
+ prompt_of: PromptOf,
200
+ issue: string,
201
+ round: Round,
202
+ slots: ReadonlyArray<ReviewSlot>,
203
+ ): Promise<JoshResult> {
204
+ const sessions = slots.map((slot) => session_for(prompt_of, issue, round, { slot, all: slots }))
205
+ const [first] = sessions
206
+
207
+ if (first?.built.kind === 'argv' && is_brokered(first.built.profile, issue)) {
208
+ return await run_brokered(issue, round, slots)
209
+ }
210
+
211
+ const results = await Promise.all(sessions.map(async (session) => await run_slot(session, round)))
212
+
213
+ return (
214
+ results.find((result) => result.code !== SUCCESS_EXIT_CODE) ?? {
215
+ code: SUCCESS_EXIT_CODE,
216
+ out: '',
217
+ }
218
+ )
141
219
  }
142
220
 
143
221
  // The brief goes to a file and the previous round's findings are removed, so a reviewer that writes
144
222
  // nothing reads as unfinished rather than as the last round's verdict.
145
- async function launch_reviewer(
146
- brief: string,
223
+ async function launch_reviewers(
224
+ briefs: ReadonlyArray<Briefed>,
147
225
  prompt_of: PromptOf,
148
226
  issue: string,
149
227
  round: Round,
150
228
  ): Promise<JoshResult> {
151
- const target = paths()
229
+ for (const { brief, slot } of briefs) {
230
+ const target = paths(slot)
152
231
 
153
- stamp_file.write_text_stamp(target.brief, brief)
154
- stamp_file.remove_stamp(target.findings)
232
+ stamp_file.write_text_stamp(target.brief, brief)
233
+ stamp_file.remove_stamp(target.findings)
234
+ }
155
235
 
156
- return await run_session(
157
- prompt_of(target.brief, target.findings, issue),
158
- target.log,
236
+ return await run_sessions(
237
+ prompt_of,
159
238
  issue,
160
239
  round,
240
+ briefs.map(({ slot }) => slot),
161
241
  )
162
242
  }
163
243
 
164
244
  // A refused attestation — the issue changed after the brief, an update left unread, no attestation —
165
- // is no finding: the round read what it was briefed on.
245
+ // is no finding: the round read what it was briefed on. `review:attest --check` asks every slot.
166
246
  async function attest_phase(): Promise<StepResult> {
167
247
  return tagged(CAUSE.ATTEST, await josh(ATTEST_CHECK))
168
248
  }
169
249
 
170
- // A brief-minting command, then a reviewer handed what it printed.
171
- function reviewed(
172
- open: ReadonlyArray<string>,
250
+ // Each slot's brief-minting command in turn, then their reviewers side by side, each handed what its
251
+ // command printed. The slots are the ones asked for, not the ones whose command has run so far.
252
+ function reviewed_together(
253
+ opens: ReadonlyArray<SlotOpen>,
173
254
  prompt_of: PromptOf,
174
255
  issue: string,
175
256
  round: Round,
176
257
  ): ReadonlyArray<Phase> {
177
- const opened = { brief: '' }
258
+ const printed = new Map<ReviewSlot, string>()
259
+
260
+ function briefs(): ReadonlyArray<Briefed> {
261
+ return opens.map(({ slot }) => ({ brief: printed.get(slot) ?? '', slot }))
262
+ }
178
263
 
179
264
  return [
180
- async () => {
265
+ ...opens.map(({ open, slot }) => async () => {
181
266
  const result = await josh(open)
182
267
 
183
- opened.brief = result.out
268
+ printed.set(slot, result.out)
184
269
 
185
270
  return tagged(CAUSE.CHECK, result)
186
- },
187
- async () => await launch_reviewer(opened.brief, prompt_of, issue, round),
271
+ }),
272
+ async () => await launch_reviewers(briefs(), prompt_of, issue, round),
188
273
  ]
189
274
  }
190
275
 
276
+ // A brief-minting command, then a reviewer handed what it printed.
277
+ function reviewed(
278
+ open: ReadonlyArray<string>,
279
+ prompt_of: PromptOf,
280
+ issue: string,
281
+ round: Round,
282
+ ): ReadonlyArray<Phase> {
283
+ return reviewed_together([{ open, slot: CODE }], prompt_of, issue, round)
284
+ }
285
+
191
286
  const run_ship_reviewer = {
192
287
  attest_phase,
193
288
  current_verdict,
@@ -196,6 +291,7 @@ const run_ship_reviewer = {
196
291
  note,
197
292
  paths,
198
293
  reviewed,
294
+ reviewed_together,
199
295
  ROUND_ONE,
200
296
  ROUND_TWO,
201
297
  SUCCESS_EXIT_CODE,