@joshuafolkken/kit 1.1784.0 → 1.2116.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +60 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +386 -360
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +16 -9
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -1,16 +1,24 @@
1
- import { git_gh_issue_write } from '#scripts/gh/git-gh-issue-write'
2
1
  import { issue_number_shape } from '#scripts/issue/issue-number-shape'
2
+ import { lane_child_marker } from '#scripts/lane/lane-child-marker'
3
3
  import { cli_flags } from '#scripts/lib/cli-flags'
4
4
  import { observation_ledger_home } from '#scripts/observations/observation-ledger-home'
5
- import { review_comment_round } from './review-comment-round'
5
+ import type { StopFinding } from '#scripts/run/ship/run-ship-review'
6
+ import { review_comment_carry } from './review-comment-carry'
6
7
  import { review_finding_ledger, type Finding, type LineKind } from './review-finding-ledger'
8
+ import { review_finding_text } from './review-finding-text'
7
9
  import { review_interaction } from './review-interaction'
10
+ import { review_lane_handover } from './review-lane-handover'
8
11
  import { review_record, type RecordVerdict } from './review-record'
12
+ import { review_record_code_round } from './review-record-code-round'
13
+ import { review_record_comment } from './review-record-comment'
14
+ import { review_record_interaction } from './review-record-interaction'
15
+ import type { ReuseAnswer } from './review-round-reuse'
16
+ import { review_stop_log } from './review-stop-log'
9
17
 
10
18
  // `josh review:record --issue <N> [<category>:<severity>:<file> ...]` — the one write path for a
11
- // `/code-review` round's findings. It appends a `- rf:` line per finding to
19
+ // `/code-review` round's findings. It appends a `- rb:` round boundary and a `- rf:` line per finding to
12
20
  // the issue's own file of the observation ledger, which the run's commit carries like any other
13
- // ledger change. **A call with no findings is a zero-finding round, and it still writes one line** — so the
21
+ // ledger change. **A call with no findings is a zero-finding round, and it still writes one `- rf:` line** — so the
14
22
  // round that found nothing is recorded rather than mistaken for a round nobody reviewed.
15
23
  //
16
24
  // **`--comment` records a round that ran after the pull request opened**: the same lines go to the
@@ -21,26 +29,50 @@ import { review_record, type RecordVerdict } from './review-record'
21
29
  //
22
30
  // `josh review:record --check --issue <N>` is the read half `pnpm josh followup` runs before it
23
31
  // merges: `ok` / `not-required` exit zero, `missing` exits non-zero so the
24
- // merge is refused until the round is recorded. It mirrors `josh review:attest --check`.
32
+ // merge is refused until the round is recorded. It mirrors `josh review:attest --check`. A recorded
33
+ // code round adds whether the ship reuses it (`review-round-reuse.ts`); the exit code does not change.
25
34
  //
26
35
  // **`--interaction` records and checks the interaction review's pass instead** (`review-interaction.ts`):
27
36
  // the same grammar under `- ri:`. It takes no `--comment` — the pass runs before the pull request, and
28
37
  // a pass kept only on the issue would leave the merge gate reading it as missing.
38
+ //
39
+ // **A finding written with its reason — `<spec> — <sentence>` — also lands in the durable stop log**,
40
+ // marked fixed (joshuafolkken/kit#4817). The ledger keeps the spec alone, as it always has; the stop
41
+ // log is the one record that keeps a finding's location and reason, so a lane's own round reaches the
42
+ // next stop's fix and the next review (`review-prior-findings.ts`) the way a ship's round already does.
29
43
 
30
44
  const FAILURE_EXIT_CODE = 1
31
45
  const USAGE =
32
- 'Usage: josh review:record --issue <N> [--comment | --interaction] [<category>:<severity>:<file> ...] | josh review:record --check [--interaction] --issue <N>'
46
+ 'Usage: josh review:record --issue <N> [--comment | --interaction] [[<disposition> ]<category>:<severity>:<file>[ — <reason>] ...] | josh review:record --check [--interaction] --issue <N>'
33
47
  const FILE_HINT = ' <file>: the cited path, optionally with :line'
48
+ const DISPOSITION_HINT =
49
+ ' <disposition>: optional — fixed | false-positive | filed:#<M> | deferred:#<M>; josh review:round2 skips only when every High/Medium is fixed or false-positive'
50
+ const REASON_HINT =
51
+ ' <reason>: optional, one sentence on what was wrong, kept for the lane’s next review and fix — pass each finding with its reason as one single-quoted argument'
52
+ const RECORD_STAGE = 'review:record'
34
53
  const CHECK_USAGE = 'Usage: josh review:record --check [--interaction] --issue <N>'
35
54
  const RECORDED_LINE = 'Recorded: the review round for this issue is in the ledger.'
55
+ const REUSED_LINE =
56
+ 'Reused: josh ship takes this round as its round 1 — the files this round covers hold still since the record. A default branch the ship’s sync merges in moves them only where it changed a file this round covers, and the ship then reviews round 1 again itself.'
57
+ const DELTA_LINE =
58
+ 'Reused, delta to round 2: josh ship takes this round as its round 1 and does not review it again — every file moved since the record is one round 2 reads after the commit, or the ship’s own round 1 stopped on it.'
59
+
60
+ // The condition that re-runs round 1, and the path that met it, named rather than listed among every
61
+ // condition that could (joshuafolkken/kit#4941).
62
+ function review_again_line(cause = 'the reuse question gave no reason'): string {
63
+ return `Not reused: josh ship reviews round 1 again — ${cause}. Run \`pnpm josh run:review\` and the round-1 \`/code-review\` here (chain-rule.md step 0).`
64
+ }
65
+
66
+ function reuse_line(answer: ReuseAnswer): string {
67
+ if (answer.reuse === 'again') return review_again_line(answer.cause)
68
+
69
+ return answer.reuse === 'delta' ? DELTA_LINE : REUSED_LINE
70
+ }
71
+
36
72
  const NOT_REQUIRED_LINE =
37
73
  'No review-finding ledger is kept in this checkout, so there is nothing to check.'
38
- const INTERACTION_NOT_REQUIRED_LINE =
39
- 'No interaction review is due: the change touches no run tooling, or this checkout keeps no ledger.'
40
- const CARRIED_LINE =
41
- 'review-finding line(s) recorded on closed issues after their pull requests opened into the ledger.'
42
- const CARRY_FAILED_LINE =
43
- 'Could not carry the closed issues’ comment rounds into the ledger; the next round retries:'
74
+ const LANE_CARRY_LINE =
75
+ 'Not carrying the closed issues’ comment rounds: a lane child leaves them to `pnpm josh observations:flush`.'
44
76
  const OPTIONS = {
45
77
  issue: { type: 'string' },
46
78
  check: { type: 'boolean' },
@@ -83,15 +115,31 @@ function parse_finding(spec: string): Finding | undefined {
83
115
  return to_finding(spec.slice(0, first), spec.slice(first + 1, second), spec.slice(second + 1))
84
116
  }
85
117
 
86
- function parse_findings(specs: ReadonlyArray<string>): ReadonlyArray<Finding> | undefined {
118
+ interface Positional {
119
+ finding: Finding
120
+ description: string
121
+ }
122
+
123
+ // A positional is `[<disposition> ]<spec>[ — <reason>]`; the disposition rides into the ledger line.
124
+ function parse_positional(positional: string): Positional | undefined {
125
+ const { spec: marked, description } = review_finding_text.split_description(positional)
126
+ const { disposition, spec } = review_finding_ledger.split_disposition(marked)
127
+ const finding = parse_finding(spec)
128
+
129
+ if (finding === undefined) return undefined
130
+
131
+ return { finding: disposition === undefined ? finding : { ...finding, disposition }, description }
132
+ }
133
+
134
+ function parse_findings(positionals: ReadonlyArray<string>): ReadonlyArray<Finding> | undefined {
87
135
  const findings: Array<Finding> = []
88
136
 
89
- for (const spec of specs) {
90
- const finding = parse_finding(spec)
137
+ for (const positional of positionals) {
138
+ const parsed = parse_positional(positional)
91
139
 
92
- if (finding === undefined) return undefined
140
+ if (parsed === undefined) return undefined
93
141
 
94
- findings.push(finding)
142
+ findings.push(parsed.finding)
95
143
  }
96
144
 
97
145
  return findings
@@ -133,6 +181,8 @@ function usage_text(): string {
133
181
  accepted_values('<category>', review_finding_ledger.CATEGORIES),
134
182
  accepted_values('<severity>', review_finding_ledger.SEVERITIES),
135
183
  FILE_HINT,
184
+ DISPOSITION_HINT,
185
+ REASON_HINT,
136
186
  ].join('\n')
137
187
  }
138
188
 
@@ -158,10 +208,25 @@ type CheckStatus = RecordVerdict['status']
158
208
 
159
209
  interface CheckMode {
160
210
  status: (issue: number, root: string) => Promise<CheckStatus>
211
+ recorded: (issue: number) => Promise<string>
161
212
  refusal: (issue: number) => string
162
213
  not_required: string
163
214
  }
164
215
 
216
+ // **A recorded code round also says whether `josh ship` reuses it** (joshuafolkken/kit#4763), from the
217
+ // ship's own predicate, in the ship's three outcomes (joshuafolkken/kit#4878): reused as it stands,
218
+ // reused with the moved files left to round 2, or reviewed again — so the lane runs it itself rather
219
+ // than reading "recorded" as "done".
220
+ async function code_recorded(issue: number): Promise<string> {
221
+ const answer = await review_lane_handover.answer_here(issue)
222
+
223
+ return [RECORDED_LINE, reuse_line(answer)].join('\n')
224
+ }
225
+
226
+ async function interaction_recorded(): Promise<string> {
227
+ return RECORDED_LINE
228
+ }
229
+
165
230
  async function code_status(issue: number, root: string): Promise<CheckStatus> {
166
231
  const verdict = await review_record.check(issue, root)
167
232
 
@@ -172,13 +237,15 @@ async function code_status(issue: number, root: string): Promise<CheckStatus> {
172
237
  const CHECK_MODES: Record<LineKind, CheckMode> = {
173
238
  code: {
174
239
  status: code_status,
240
+ recorded: code_recorded,
175
241
  refusal: review_record.refusal_message,
176
242
  not_required: NOT_REQUIRED_LINE,
177
243
  },
178
244
  interaction: {
179
245
  status: review_interaction.status,
246
+ recorded: interaction_recorded,
180
247
  refusal: review_interaction.refusal_message,
181
- not_required: INTERACTION_NOT_REQUIRED_LINE,
248
+ not_required: review_record_interaction.NOT_REQUIRED_LINE,
182
249
  },
183
250
  }
184
251
 
@@ -195,7 +262,7 @@ async function report_check(issue: number, mode: CheckMode, root: string): Promi
195
262
  return FAILURE_EXIT_CODE
196
263
  }
197
264
 
198
- console.info(status === 'ok' ? RECORDED_LINE : mode.not_required)
265
+ console.info(status === 'ok' ? await mode.recorded(issue) : mode.not_required)
199
266
 
200
267
  return 0
201
268
  }
@@ -212,54 +279,109 @@ async function run_check(parsed: Parsed, root: string): Promise<number> {
212
279
  return await report_check(Number(issue), CHECK_MODES[kind_of(parsed)], root)
213
280
  }
214
281
 
215
- // **A comment that could not be posted fails the record**: it is the round's only copy, so a
216
- // swallowed refusal would read as a recorded round that exists nowhere.
217
- async function post_comment(issue: number, lines: ReadonlyArray<string>): Promise<number> {
218
- try {
219
- const url = await git_gh_issue_write.issue_comment(
220
- String(issue),
221
- review_comment_round.body_of(lines),
222
- )
282
+ // The closed issues' comment rounds ride this round's commit (`review-comment-round.ts`) — **except in a
283
+ // lane child** (joshuafolkken/kit#5326): parallel lanes each wrote the same newly closed issue's file,
284
+ // so their ships waited on each other's overlap and their merges with main conflicted on it.
285
+ // `observations:flush` carries them for the lanes, on the default branch, in one pull request.
286
+ async function carry_comment_rounds(root: string): Promise<void> {
287
+ if (lane_child_marker.is_child_of(root)) {
288
+ console.info(LANE_CARRY_LINE)
223
289
 
224
- console.info(`Recorded ${String(lines.length)} review-finding line(s) in ${url.trim()}.`)
290
+ return
291
+ }
225
292
 
226
- return 0
227
- } catch (error) {
228
- console.error(error instanceof Error ? error.message : String(error))
293
+ await review_comment_carry.carry_reported(root)
294
+ }
229
295
 
230
- return FAILURE_EXIT_CODE
231
- }
296
+ // The round lands in its own issue's file, so two lanes recording at once
297
+ // write two files, and their pull requests never conflict on the ledger.
298
+ interface AppendedRound {
299
+ issue: number
300
+ lines: ReadonlyArray<string>
301
+ root: string
302
+ kind: LineKind
303
+ findings: ReadonlyArray<Finding>
304
+ date: string
232
305
  }
233
306
 
234
- // The closed issues' comment rounds ride this round's commit (`review-comment-round.ts`). **A carry
235
- // that fails never fails the record**: this round is recorded, and the comment rounds wait for the
236
- // next run's.
237
- async function carry_comment_rounds(root: string): Promise<void> {
238
- try {
239
- const count = await review_comment_round.carry(root)
307
+ // A code round opens with its boundary line (`review-finding-ledger.ts`), not counted as a finding line.
308
+ function ledger_lines({ issue, lines, kind, date }: AppendedRound): ReadonlyArray<string> {
309
+ if (kind === 'interaction') return lines
240
310
 
241
- if (count > 0) console.info(`Carried ${String(count)} ${CARRIED_LINE}`)
242
- } catch (error) {
243
- console.warn(`${CARRY_FAILED_LINE} ${error instanceof Error ? error.message : String(error)}`)
244
- }
311
+ return [review_finding_ledger.round_line(date, issue), ...lines]
245
312
  }
246
313
 
247
- // The round lands in its own issue's file, so two lanes recording at once
248
- // write two files, and their pull requests never conflict on the ledger.
249
- async function append_round(
250
- issue: number,
251
- lines: ReadonlyArray<string>,
252
- root: string,
253
- ): Promise<number> {
314
+ // A code round goes on to what its tree means for the ship (`review-record-code-round.ts`).
315
+ async function append_round(round: AppendedRound): Promise<number> {
316
+ const { issue, lines, root, kind, findings } = round
254
317
  const ledger_path = observation_ledger_home.issue_path(issue, root)
255
318
 
256
- await observation_ledger_home.append(ledger_path, lines)
319
+ await observation_ledger_home.append(ledger_path, ledger_lines(round))
257
320
  console.info(confirmation(lines.length, ledger_path))
258
321
  await carry_comment_rounds(root)
259
322
 
323
+ if (kind === 'code') await review_record_code_round.follow(issue, root, findings)
324
+
260
325
  return 0
261
326
  }
262
327
 
328
+ // A code round recorded after the push goes to the issue unasked (`review-record-comment.ts`).
329
+ async function write_round(
330
+ parsed: Parsed,
331
+ request: Request,
332
+ now: Date,
333
+ root: string,
334
+ ): Promise<number> {
335
+ const kind = kind_of(parsed)
336
+ const date = observation_ledger_home.ledger_date(now)
337
+ const lines = build_lines(request, date, kind)
338
+ const { issue, findings } = request
339
+
340
+ if (parsed.comment) return await review_record_comment.post(issue, lines)
341
+
342
+ if (kind === 'code' && (await review_record_comment.is_after_push())) {
343
+ return await review_record_comment.post_after_push({ issue, lines, root, findings })
344
+ }
345
+
346
+ return await append_round({
347
+ issue: request.issue,
348
+ lines,
349
+ root,
350
+ kind,
351
+ findings: request.findings,
352
+ date,
353
+ })
354
+ }
355
+
356
+ // The stop-log finding a positional carries, or `undefined` for one written without a reason.
357
+ function reason_of(positional: string): StopFinding | undefined {
358
+ const parsed = parse_positional(positional)
359
+
360
+ if (parsed === undefined || parsed.description.length === 0) return undefined
361
+
362
+ const { finding, description } = parsed
363
+
364
+ return {
365
+ kind: `${finding.category}:${finding.severity}`,
366
+ location: finding.file,
367
+ sentence: review_finding_text.first_sentence(description),
368
+ }
369
+ }
370
+
371
+ function is_reason(finding: StopFinding | undefined): finding is StopFinding {
372
+ return finding !== undefined
373
+ }
374
+
375
+ // Recorded only once the round itself is, so the stop log never holds a round the ledger refused.
376
+ function record_reasons(issue: number, positionals: ReadonlyArray<string>): void {
377
+ review_stop_log.record({
378
+ issue,
379
+ stage: RECORD_STAGE,
380
+ findings: positionals.map((positional) => reason_of(positional)).filter(is_reason),
381
+ is_fixed: true,
382
+ })
383
+ }
384
+
263
385
  async function run_record(parsed: Parsed, now: Date, root: string): Promise<number> {
264
386
  const request = parsed.comment && parsed.interaction ? undefined : to_request(parsed)
265
387
 
@@ -269,11 +391,11 @@ async function run_record(parsed: Parsed, now: Date, root: string): Promise<numb
269
391
  return FAILURE_EXIT_CODE
270
392
  }
271
393
 
272
- const lines = build_lines(request, observation_ledger_home.ledger_date(now), kind_of(parsed))
394
+ const code = await write_round(parsed, request, now, root)
273
395
 
274
- if (parsed.comment) return await post_comment(request.issue, lines)
396
+ if (code === 0) record_reasons(request.issue, parsed.positionals)
275
397
 
276
- return await append_round(request.issue, lines, root)
398
+ return code
277
399
  }
278
400
 
279
401
  // **The default is the work tree the command runs in, a lane's inside a lane**.
@@ -301,6 +423,7 @@ const review_record_cli = {
301
423
  accepted_values,
302
424
  build_lines,
303
425
  parse_finding,
426
+ parse_positional,
304
427
  run,
305
428
  usage_text,
306
429
  }
@@ -0,0 +1,55 @@
1
+ import { run_ship_detach } from '#scripts/run/ship/run-ship-detach'
2
+ import type { Finding } from './review-finding-ledger'
3
+ import { review_lane_handover } from './review-lane-handover'
4
+ import { review_record_interaction } from './review-record-interaction'
5
+ import { review_record_pinned } from './review-record-pinned'
6
+ import { review_reviewed_tree } from './review-reviewed-tree'
7
+
8
+ // What `josh review:record` does once a code round is on the ledger: it records the tree the verdict
9
+ // stands for, which `josh ship` reuses while the tree holds still (`review-reviewed-tree.ts`), names
10
+ // the ship next for a lane child (`review-lane-handover.ts`), names an interaction review its fixes
11
+ // made due (`review-record-interaction.ts`), reads a `josh run:review --join` the lane skipped, and
12
+ // starts `josh test:pinned` again on a tree its fixes moved (`review-record-pinned.ts`).
13
+
14
+ const HIGH_SEVERITY = 'high'
15
+
16
+ // The files whose finding the round could not have fixed in place — a High never is.
17
+ function unsettled_files(findings: ReadonlyArray<Finding>): ReadonlyArray<string> {
18
+ return findings
19
+ .filter((finding) => finding.severity === HIGH_SEVERITY)
20
+ .map((finding) => finding.file)
21
+ }
22
+
23
+ // A lane child's round the ship reuses names the ship next (joshuafolkken/kit#4850), read after the
24
+ // tree is stamped; the lines that follow name what is done before that ship.
25
+ async function report_handover(issue: number): Promise<boolean> {
26
+ const is_handed_over = await review_lane_handover.is_handed_over(issue)
27
+
28
+ if (is_handed_over) console.info(review_lane_handover.NEXT_STEP_LINE)
29
+
30
+ return is_handed_over
31
+ }
32
+
33
+ // Only a lane child's round the ship will reuse restarts the check: the ship's own rounds run under its
34
+ // supervisor, where nothing reads the answer and the check would hold cores the ship's gate waits on.
35
+ function is_restarted_here(is_handed_over: boolean): boolean {
36
+ return is_handed_over && !run_ship_detach.is_supervised()
37
+ }
38
+
39
+ async function follow(
40
+ issue: number,
41
+ root: string,
42
+ findings: ReadonlyArray<Finding>,
43
+ ): Promise<void> {
44
+ await review_reviewed_tree.record(unsettled_files(findings))
45
+ const is_handed_over = await report_handover(issue)
46
+
47
+ await review_record_interaction.report_due(issue, root)
48
+ if (!is_restarted_here(is_handed_over)) return
49
+ await review_record_pinned.read_skipped_join(root)
50
+ await review_record_pinned.restart_if_moved(root)
51
+ }
52
+
53
+ const review_record_code_round = { follow }
54
+
55
+ export { review_record_code_round }
@@ -0,0 +1,60 @@
1
+ import { git_gh_issue_write } from '#scripts/gh/git-gh-issue-write'
2
+ import { run_ship_probe } from '#scripts/run/ship/run-ship-probe'
3
+ import { review_comment_round } from './review-comment-round'
4
+ import type { Finding } from './review-finding-ledger'
5
+ import { review_record_code_round } from './review-record-code-round'
6
+
7
+ // The issue-comment half of `josh review:record`: a round kept on the issue rather than in the
8
+ // observation ledger (`review-comment-round.ts` carries it there once the issue closes).
9
+
10
+ const FAILURE_EXIT_CODE = 1
11
+ const AFTER_PUSH_LINE =
12
+ 'The branch is pushed and the tree is clean, so this round is recorded on the issue, not in the ledger — a ledger line would need a push of its own and restart CI.'
13
+
14
+ interface CommentRound {
15
+ issue: number
16
+ lines: ReadonlyArray<string>
17
+ root: string
18
+ findings: ReadonlyArray<Finding>
19
+ }
20
+
21
+ // **A comment that could not be posted fails the record**: it is the round's only copy, so a
22
+ // swallowed refusal would read as a recorded round that exists nowhere.
23
+ async function post(issue: number, lines: ReadonlyArray<string>): Promise<number> {
24
+ try {
25
+ const url = await git_gh_issue_write.issue_comment(
26
+ String(issue),
27
+ review_comment_round.body_of(lines),
28
+ )
29
+
30
+ console.info(`Recorded ${String(lines.length)} review-finding line(s) in ${url.trim()}.`)
31
+
32
+ return 0
33
+ } catch (error) {
34
+ console.error(error instanceof Error ? error.message : String(error))
35
+
36
+ return FAILURE_EXIT_CODE
37
+ }
38
+ }
39
+
40
+ // **A code round recorded once the branch is pushed and the tree clean goes to the issue unasked**
41
+ // (joshuafolkken/kit#4907): `josh run:review` pushed at the first green gate, and a ledger line now
42
+ // would ride no commit of the run's but a push of its own, restarting CI. `--check` reads the issue's
43
+ // comment rounds too (`review-record.ts`). The round still stamps its tree, so `josh ship` reuses it
44
+ // as round 1.
45
+ async function is_after_push(): Promise<boolean> {
46
+ return await run_ship_probe.is_pushed_clean()
47
+ }
48
+
49
+ async function post_after_push(round: CommentRound): Promise<number> {
50
+ console.info(AFTER_PUSH_LINE)
51
+ const code = await post(round.issue, round.lines)
52
+
53
+ if (code === 0) await review_record_code_round.follow(round.issue, round.root, round.findings)
54
+
55
+ return code
56
+ }
57
+
58
+ const review_record_comment = { is_after_push, post, post_after_push }
59
+
60
+ export { review_record_comment }
@@ -0,0 +1,35 @@
1
+ import { error_text } from '#scripts/lib/error-message'
2
+ import { review_interaction } from './review-interaction'
3
+
4
+ // What `josh review:record` says about the interaction review (`review-interaction.ts`).
5
+ //
6
+ // **A round-1 fix can make the pass due after its brief opened** (joshuafolkken/kit#4835): the fix
7
+ // reaches the run tooling the original change did not, so round 1 opened with `/code-review`'s brief
8
+ // alone. A recorded code round reads the pass's status over the fixed tree and names its brief, so the
9
+ // lane runs it before `josh ship` instead of the ship's review stage running it alone and stopping on
10
+ // its finding. A status git could not read prints nothing — the merge gate still refuses a missing pass.
11
+
12
+ const NOT_REQUIRED_LINE =
13
+ 'No interaction review is due: the change touches no run tooling, or this checkout keeps no ledger.'
14
+ const DUE_HEAD = 'Interaction review now due'
15
+
16
+ // An interaction reviewer that already ran beside round 1 is only recorded, never run twice.
17
+ function due_line(issue: number): string {
18
+ return `${DUE_HEAD}: this round’s change touches the run tooling and no interaction pass is recorded. Before \`josh ship\`, record it with \`pnpm josh review:record --interaction --issue ${String(issue)} [<finding> ...]\` — if no interaction reviewer ran beside this round, first open its brief with \`pnpm josh review:brief --interaction\` and run that \`reviewer\` — so a finding is fixed in this lane rather than stopping the ship.`
19
+ }
20
+
21
+ async function report_due(issue: number, root: string): Promise<void> {
22
+ try {
23
+ if ((await review_interaction.status(issue, root)) === 'missing') console.info(due_line(issue))
24
+ } catch (error) {
25
+ error_text.trace_swallowed('review_record_interaction.report_due', error)
26
+ }
27
+ }
28
+
29
+ const review_record_interaction = {
30
+ due_line,
31
+ NOT_REQUIRED_LINE,
32
+ report_due,
33
+ }
34
+
35
+ export { review_record_interaction }
@@ -0,0 +1,108 @@
1
+ import { PROJECT_ROOT } from '#scripts/init/init-paths'
2
+ import { lane_child_marker } from '#scripts/lane/lane-child-marker'
3
+ import { error_text } from '#scripts/lib/error-message'
4
+ import { observation_ledger_home } from '#scripts/observations/observation-ledger-home'
5
+ import { run_review_join_read, type JoinVerdict } from '#scripts/run/review/run-review-join-read'
6
+ import { run_review_pinned_join } from '#scripts/run/review/run-review-pinned-join'
7
+ import { run_ship_detach } from '#scripts/run/ship/run-ship-detach'
8
+ import { test_pinned_logic } from '#scripts/test/test-pinned-logic'
9
+ import { review_finding_ledger } from './review-finding-ledger'
10
+
11
+ // What `josh review:record` does about the background `josh test:pinned` (joshuafolkken/kit#4834).
12
+ //
13
+ // **A round-1 fix can add hunks the check never read**: `josh run:review` launched it on the briefed
14
+ // tree, and its join closed before the fix. The ship's pre-detach was then the first to name the fixed
15
+ // tree's unpinned places, and stopped on them. A recorded code round compares the fixed tree with the
16
+ // launch's and, where they differ, starts the check again with the launch's `--unpinned-ok` reason and
17
+ // says who reads its answer. **Nothing waits on it in the foreground** (joshuafolkken/kit#4895): the
18
+ // ship's pre-detach reads that same check's answer on that tree rather than running its own
19
+ // (`run-review-pinned-join.ts`). A foreground read stalled the lane for minutes, and pinning what it
20
+ // named moved the tree again under the next probe.
21
+ //
22
+ // **The same tree starts nothing**, and so does a tree either side could not read, or a checkout with
23
+ // no launch. The fix's first `josh check:related` runs this same restart (joshuafolkken/kit#4948), so a
24
+ // record on the tree it checked takes over the check already running there. `check:related` alone
25
+ // waits on the check it started (joshuafolkken/kit#4987), within a bound that keeps the verdict line
26
+ // under a foreground Bash call's cap (`check-related-pinned.ts`).
27
+
28
+ function started_line(): string {
29
+ return `test:pinned restarted in the background on the tree this round's fixes moved. Where it names unpinned places, the ship's pre-detach stops on them: pin each with a test that turns red without it, or ship with \`--unpinned-ok "<reason>"\`.`
30
+ }
31
+
32
+ // `root` is the checkout `josh run:review` keyed its launch to: the ledger root `review:record` writes
33
+ // under is the same working directory, and a test's temporary root holds no launch. Answers whether a
34
+ // check was started.
35
+ async function restart_if_moved(root: string = PROJECT_ROOT): Promise<boolean> {
36
+ try {
37
+ const is_started = await run_review_pinned_join.restart_if_moved(root)
38
+
39
+ if (is_started) console.info(started_line())
40
+
41
+ return is_started
42
+ } catch (error) {
43
+ error_text.trace_swallowed('review_record_pinned.restart_if_moved', error)
44
+
45
+ return false
46
+ }
47
+ }
48
+
49
+ // **A join the lane skipped is read here** (joshuafolkken/kit#5212): `josh run:review --join` was never
50
+ // run, so the unpinned places would surface only as the ship's pre-detach failure. It reads only an
51
+ // answer already left on this tree, so nothing waits on it either. A read that stops nothing prints
52
+ // nothing, and a join already read changes nothing.
53
+ const CHOICE_LINE =
54
+ 'Unpinned before the ship: pin each place above with a test that turns red without it, or ship with `--unpinned-ok "<reason>"`.\n'
55
+
56
+ function show_stop(joined: JoinVerdict | undefined): void {
57
+ if (joined?.is_stop !== true) return
58
+ console.info(test_pinned_logic.report_text(joined.summary, CHOICE_LINE).trimEnd())
59
+ }
60
+
61
+ async function read_skipped_join(root: string = PROJECT_ROOT): Promise<void> {
62
+ try {
63
+ if (run_review_join_read.is_due(root)) show_stop(await run_review_join_read.read_finished(root))
64
+ } catch (error) {
65
+ error_text.trace_swallowed('review_record_pinned.read_skipped_join', error)
66
+ }
67
+ }
68
+
69
+ // Whether the lane's code round is on the ledger: from then on `review:record` owns the restart, behind
70
+ // its own handover guard.
71
+ async function is_round_recorded(root: string): Promise<boolean> {
72
+ const issue = lane_child_marker.marked_issue()
73
+ if (issue === undefined) return false
74
+ const content = await observation_ledger_home.read(root)
75
+
76
+ return content !== undefined && review_finding_ledger.has_issue_record(content, Number(issue))
77
+ }
78
+
79
+ // `josh check:related`'s restart (joshuafolkken/kit#4948) runs only in a lane child outside a ship's
80
+ // supervisor and before its round 1 is recorded: a launch record outlives its issue in a reused
81
+ // checkout, and a child relaunched after a ship stop may re-detach without `--review`, which reads no
82
+ // answer.
83
+ async function is_restartable_before_record(root: string): Promise<boolean> {
84
+ if (!lane_child_marker.is_child_of(root) || run_ship_detach.is_supervised()) return false
85
+
86
+ return !(await is_round_recorded(root))
87
+ }
88
+
89
+ // Answers whether a check was started, so `check:related` waits on its answer (joshuafolkken/kit#4987).
90
+ async function restart_in_lane(root: string = PROJECT_ROOT): Promise<boolean> {
91
+ try {
92
+ return (await is_restartable_before_record(root)) && (await restart_if_moved(root))
93
+ } catch (error) {
94
+ error_text.trace_swallowed('review_record_pinned.restart_in_lane', error)
95
+
96
+ return false
97
+ }
98
+ }
99
+
100
+ const review_record_pinned = {
101
+ CHOICE_LINE,
102
+ read_skipped_join,
103
+ restart_if_moved,
104
+ restart_in_lane,
105
+ started_line,
106
+ }
107
+
108
+ export { review_record_pinned }
@@ -1,5 +1,6 @@
1
1
  import { session_cite } from '#scripts/issue/session-cite'
2
2
  import { observation_ledger_home } from '#scripts/observations/observation-ledger-home'
3
+ import { review_comment_round } from './review-comment-round'
3
4
  import { review_finding_ledger } from './review-finding-ledger'
4
5
 
5
6
  // The gate that refuses a merge until the `/code-review` round was recorded.
@@ -33,14 +34,37 @@ interface RecordVerdict {
33
34
  // lane. Every file of the directory is read, so the round is found whichever
34
35
  // file holds it; a directory that is not there answers `undefined`, a ledger this checkout does not
35
36
  // keep, which becomes `not-required`.
37
+ //
38
+ // **A round recorded on the issue counts too** (`josh review:record --comment`): a round that ran after
39
+ // the branch was pushed keeps its lines there so CI does not restart (joshuafolkken/kit#4907). Comments
40
+ // that could not be read are no record — the refusal stands.
41
+ type CommentLines = (issue: number) => Promise<ReadonlyArray<string>>
42
+
43
+ async function has_comment_record(issue: number, read: CommentLines): Promise<boolean> {
44
+ try {
45
+ const lines = await read(issue)
46
+
47
+ return review_finding_ledger.has_issue_record(lines.join('\n'), issue)
48
+ } catch {
49
+ return false
50
+ }
51
+ }
52
+
53
+ async function is_recorded(content: string, issue: number, read: CommentLines): Promise<boolean> {
54
+ if (review_finding_ledger.has_issue_record(content, issue)) return true
55
+
56
+ return await has_comment_record(issue, read)
57
+ }
58
+
36
59
  async function check(
37
60
  issue: number,
38
61
  root: string = observation_ledger_home.ledger_root(),
62
+ read_comment_lines: CommentLines = review_comment_round.issue_lines,
39
63
  ): Promise<RecordVerdict> {
40
64
  const content = await observation_ledger_home.read(root)
41
65
 
42
66
  if (content === undefined) return { status: 'not-required' }
43
- if (review_finding_ledger.has_issue_record(content, issue)) return { status: 'ok', issue }
67
+ if (await is_recorded(content, issue, read_comment_lines)) return { status: 'ok', issue }
44
68
 
45
69
  return { status: 'missing', issue }
46
70
  }