@joshuafolkken/kit 1.1784.0 → 1.2114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +59 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +415 -389
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +15 -8
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -0,0 +1,49 @@
1
+ import type { TypeScriptApi } from '#scripts/review/comment-ranges'
2
+ import { test_pinned_functions } from './test-pinned-functions'
3
+ import { test_pinned_logic, type Hunk } from './test-pinned-logic'
4
+ import { test_pinned_rewire } from './test-pinned-rewire'
5
+
6
+ // Which hunks `josh test:pinned` can probe at all (joshuafolkken/kit#4647). A hunk whose revert leaves
7
+ // the emitted JavaScript as it was — a comment, a type, a blank line — changes nothing a test runs, so
8
+ // no test can pin it, and listing it `unpinned` would stop every `josh run:review` that edited one.
9
+ // Only a script file is compared: a Svelte component's markup is not TypeScript.
10
+
11
+ function emitted(api: TypeScriptApi, file: string, content: string): string {
12
+ const compiler_options = { removeComments: true, target: api.ScriptTarget.ESNext }
13
+
14
+ return api.transpileModule(content, { compilerOptions: compiler_options, fileName: file })
15
+ .outputText
16
+ }
17
+
18
+ function changes_runtime(api: TypeScriptApi, content: string, hunk: Hunk): boolean {
19
+ if (!test_pinned_functions.is_script(hunk.file)) return true
20
+ const reverted = test_pinned_logic.revert(content, hunk)
21
+
22
+ return emitted(api, hunk.file, reverted) !== emitted(api, hunk.file, content)
23
+ }
24
+
25
+ interface RuntimeRead {
26
+ hunks: Array<Hunk>
27
+ rewired: number
28
+ }
29
+
30
+ // The hunks to probe, each beside its file's content: the ones whose revert changes the emitted code,
31
+ // less the rewires (`test-pinned-rewire.ts`), which are counted.
32
+ function probed_of(
33
+ api: TypeScriptApi,
34
+ hunks: ReadonlyArray<Hunk>,
35
+ contents: ReadonlyArray<string>,
36
+ ): RuntimeRead {
37
+ const runtime = hunks
38
+ .map((hunk, index) => ({ hunk, content: contents[index] ?? '' }))
39
+ .filter((read) => changes_runtime(api, read.content, read.hunk))
40
+ const probed = runtime.filter(
41
+ (read) => !test_pinned_rewire.is_rewire(api, read.content, read.hunk),
42
+ )
43
+
44
+ return { hunks: probed.map((read) => read.hunk), rewired: runtime.length - probed.length }
45
+ }
46
+
47
+ const test_pinned_emit = { changes_runtime, probed_of }
48
+
49
+ export { test_pinned_emit }
@@ -0,0 +1,116 @@
1
+ import type { TypeScriptApi } from '#scripts/review/comment-ranges'
2
+ import type ts from 'typescript'
3
+ import type { Hunk } from './test-pinned-logic'
4
+
5
+ // The added-file half of `josh test:pinned` (joshuafolkken/kit#4647). Reverting an added file is a
6
+ // missing module every importer fails on, so its functions are probed instead: each top-level function
7
+ // — a `function` declaration, a `const` bound to a function, or a function member of a top-level object
8
+ // literal (a namespace object) — becomes one hunk whose lines carry that function with its body
9
+ // replaced by a throw. `test_pinned_logic.revert` puts those lines in, so a probe runs as a hunk does.
10
+ //
11
+ // Only a script file is parsed: a Svelte component's markup is not TypeScript, and its script block
12
+ // holds no module-level function an importer calls by name.
13
+
14
+ const STUB_BODY = "{ throw new Error('josh test:pinned') }"
15
+ const SCRIPT_FILE = /\.[cm]?[jt]sx?$/u
16
+ const LINE_BREAK = '\n'
17
+ const DEFAULT_NAME = 'default'
18
+
19
+ type FunctionValue = ts.ArrowFunction | ts.FunctionExpression
20
+
21
+ interface FunctionSite {
22
+ name: string
23
+ extent: ts.Node
24
+ body: ts.Node
25
+ }
26
+
27
+ function is_script(file: string): boolean {
28
+ return SCRIPT_FILE.test(file)
29
+ }
30
+
31
+ function is_function_value(api: TypeScriptApi, node: ts.Node | undefined): node is FunctionValue {
32
+ if (node === undefined) return false
33
+
34
+ return api.isArrowFunction(node) || api.isFunctionExpression(node)
35
+ }
36
+
37
+ function member_site(
38
+ api: TypeScriptApi,
39
+ owner: string,
40
+ member: ts.ObjectLiteralElementLike,
41
+ ): Array<FunctionSite> {
42
+ if (api.isMethodDeclaration(member) && member.body !== undefined) {
43
+ return [{ name: `${owner}.${member.name.getText()}`, extent: member, body: member.body }]
44
+ }
45
+
46
+ if (!api.isPropertyAssignment(member) || !is_function_value(api, member.initializer)) return []
47
+
48
+ return [
49
+ { name: `${owner}.${member.name.getText()}`, extent: member, body: member.initializer.body },
50
+ ]
51
+ }
52
+
53
+ function declaration_sites(
54
+ api: TypeScriptApi,
55
+ declaration: ts.VariableDeclaration,
56
+ ): Array<FunctionSite> {
57
+ const { initializer } = declaration
58
+ const name = declaration.name.getText()
59
+
60
+ if (is_function_value(api, initializer)) {
61
+ return [{ name, extent: declaration, body: initializer.body }]
62
+ }
63
+
64
+ if (initializer === undefined || !api.isObjectLiteralExpression(initializer)) return []
65
+
66
+ return initializer.properties.flatMap((member) => member_site(api, name, member))
67
+ }
68
+
69
+ // An overload signature has no body to replace.
70
+ function function_site(statement: ts.FunctionDeclaration): Array<FunctionSite> {
71
+ if (statement.body === undefined) return []
72
+
73
+ return [{ name: statement.name?.text ?? DEFAULT_NAME, extent: statement, body: statement.body }]
74
+ }
75
+
76
+ function statement_sites(api: TypeScriptApi, statement: ts.Statement): Array<FunctionSite> {
77
+ if (api.isFunctionDeclaration(statement)) return function_site(statement)
78
+ if (!api.isVariableStatement(statement)) return []
79
+
80
+ return statement.declarationList.declarations.flatMap((declaration) =>
81
+ declaration_sites(api, declaration),
82
+ )
83
+ }
84
+
85
+ // The whole lines the function spans, with its body swapped for the throw: the hunk replaces lines,
86
+ // so a signature sharing a line with other code keeps that code.
87
+ function stub_hunk(file: string, source: ts.SourceFile, site: FunctionSite): Hunk {
88
+ const start = site.extent.getStart(source)
89
+ const first = source.getLineAndCharacterOfPosition(start).line
90
+ const last = source.getLineAndCharacterOfPosition(site.extent.getEnd()).line
91
+ const offset = start - source.getLineAndCharacterOfPosition(start).character
92
+ const lines = source.text.slice(offset, source.getLineEndOfPosition(site.extent.getEnd()))
93
+ const before = lines.slice(0, site.body.getStart(source) - offset)
94
+ const stubbed = `${before}${STUB_BODY}${lines.slice(site.body.getEnd() - offset)}`
95
+
96
+ return {
97
+ file,
98
+ new_start: first + 1,
99
+ new_count: last - first + 1,
100
+ old_lines: stubbed.split(LINE_BREAK),
101
+ new_lines: lines.split(LINE_BREAK),
102
+ function_name: site.name,
103
+ }
104
+ }
105
+
106
+ function stub_hunks(api: TypeScriptApi, file: string, content: string): Array<Hunk> {
107
+ const source = api.createSourceFile(file, content, api.ScriptTarget.Latest, true)
108
+
109
+ return source.statements
110
+ .flatMap((statement) => statement_sites(api, statement))
111
+ .map((site) => stub_hunk(file, source, site))
112
+ }
113
+
114
+ const test_pinned_functions = { STUB_BODY, is_script, stub_hunks }
115
+
116
+ export { test_pinned_functions }
@@ -0,0 +1,80 @@
1
+ import type { TestPinnedRecord } from '#scripts/lane/lane-ledger'
2
+ import { lane_ledger_schema } from '#scripts/lane/lane-ledger-schema'
3
+ import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
4
+ import { lane_paths } from '#scripts/lane/lane-paths'
5
+ import type { Hunk } from './test-pinned-logic'
6
+ import type { RedProbe } from './test-red-logic'
7
+
8
+ // One `test-pinned` ledger row per `josh test:pinned` run that probed (joshuafolkken/kit#5078): how
9
+ // many hunks the verdict cache answered, and each probed hunk's test files and wall time, so
10
+ // `josh lane:breakdown` can say what a long ship pre-detach spent its probe on.
11
+
12
+ interface ProbeTime {
13
+ file: string
14
+ tests?: number | undefined
15
+ elapsed_ms: number
16
+ }
17
+
18
+ function time_of(hunk: Hunk, verdict: RedProbe, elapsed_ms: number): ProbeTime {
19
+ return { file: hunk.file, tests: verdict.ran, elapsed_ms }
20
+ }
21
+
22
+ // What started a run (joshuafolkken/kit#5262): `run:review`'s background check, the ship's pre-detach,
23
+ // or a `josh test:pinned` typed by hand.
24
+ type PinnedOrigin = NonNullable<TestPinnedRecord['origin']>
25
+
26
+ const MANUAL_ORIGIN: PinnedOrigin = 'manual'
27
+ const BACKGROUND_ORIGIN: PinnedOrigin = 'run-review'
28
+
29
+ // A `--origin` value: none is `manual`, one not named above `undefined`.
30
+ function origin_of(raw: string | undefined): PinnedOrigin | undefined {
31
+ if (raw === undefined) return MANUAL_ORIGIN
32
+ const parsed = lane_ledger_schema.pinned_origin_schema.safeParse(raw)
33
+
34
+ return parsed.success ? parsed.data : undefined
35
+ }
36
+
37
+ // The hunks a run did not probe: `held` the cache answered, `rewired` left out as a rewire; and what
38
+ // started it, `manual` when unnamed.
39
+ interface Skipped {
40
+ held: number
41
+ rewired: number
42
+ origin?: PinnedOrigin | undefined
43
+ }
44
+
45
+ async function record(
46
+ skipped: Skipped,
47
+ probes: ReadonlyArray<ProbeTime>,
48
+ elapsed_ms: number,
49
+ ): Promise<void> {
50
+ await lane_ledger_write.record_test_pinned({
51
+ issue: lane_paths.issue_here(),
52
+ held: skipped.held,
53
+ rewired: skipped.rewired,
54
+ probes: [...probes],
55
+ elapsed_ms,
56
+ origin: skipped.origin ?? MANUAL_ORIGIN,
57
+ })
58
+ }
59
+
60
+ // A background check stopped before its answer writes no row of its own, so its stop writes this one:
61
+ // the wall time it ran, and nothing it probed. `origin` is its launcher: `run:review`'s check, or the
62
+ // pre-detach's probe of the hunks past its stop (joshuafolkken/kit#5327).
63
+ async function record_discarded(
64
+ elapsed_ms: number,
65
+ origin: PinnedOrigin = BACKGROUND_ORIGIN,
66
+ ): Promise<void> {
67
+ await lane_ledger_write.record_test_pinned({
68
+ issue: lane_paths.issue_here(),
69
+ held: 0,
70
+ probes: [],
71
+ elapsed_ms,
72
+ origin,
73
+ discarded: true,
74
+ })
75
+ }
76
+
77
+ const test_pinned_ledger = { BACKGROUND_ORIGIN, origin_of, record, record_discarded, time_of }
78
+
79
+ export type { PinnedOrigin, ProbeTime }
80
+ export { test_pinned_ledger }
@@ -1,9 +1,12 @@
1
+ import { verification_tail, type KeptLog } from '#scripts/gate/verification-tail'
1
2
  import { test_declared_logic } from './test-declared-logic'
3
+ import { test_pinned_stage, type Staged } from './test-pinned-stage'
4
+ import type { RedProbe, RedVerdict } from './test-red-logic'
2
5
  import { related_scope } from './test-related-scope'
3
6
 
4
7
  // The pure half of `josh test:pinned` (joshuafolkken/kit#4516): read a `git diff -U0` into hunks, put
5
8
  // one hunk's old lines back into the changed file, and split the hunks at the run's cap. The run itself
6
- // is `test-pinned.ts`.
9
+ // is `test-pinned.ts`; an added file's hunks are its functions (`test-pinned-functions.ts`).
7
10
 
8
11
  const DEFAULT_MAX_HUNKS = 20
9
12
  const HEADER = /^@@ -\d+(?:,\d+)? \+(?<start>\d+)(?:,(?<count>\d+))? @@/u
@@ -11,9 +14,20 @@ const FILE_HEADER = '+++ b/'
11
14
  const SECTION_HEADER = 'diff --git '
12
15
  const OLD_LINE = '-'
13
16
  const OLD_FILE_HEADER = '--- '
17
+ const NEW_LINE = '+'
18
+ const FILE_HEADER_MARK = '+++ '
19
+ const OLD_FILE_PATH = '--- a/'
14
20
  const LINE_BREAK = '\n'
15
21
  const GREEN_REASON = 'reverting it left every related test green'
16
22
  const NO_TEST_REASON = 'no related test ran with it reverted'
23
+ const STUB_GREEN_REASON = 'replacing its body with a throw left every related test green'
24
+ const STUB_NO_TEST_REASON = 'no related test ran with its body replaced by a throw'
25
+ const UNPARSED_REASON = 'an added file, and typescript is not installed to read its functions'
26
+ const NO_RUNNER_REASON = 'vitest is not installed to run its related tests'
27
+ const STOPPED_REASON = 'vitest stopped before any test ran with it reverted'
28
+ const CUT_REASON = 'not probed: the run stopped at the first unpinned hunk'
29
+ const STOPPED_VERDICT: RedVerdict = 'stopped'
30
+ const SETTLED_VERDICTS: ReadonlySet<RedVerdict> = new Set<RedVerdict>(['red', STOPPED_VERDICT])
17
31
 
18
32
  interface Hunk {
19
33
  file: string
@@ -21,6 +35,13 @@ interface Hunk {
21
35
  new_start: number
22
36
  new_count: number
23
37
  old_lines: Array<string>
38
+ // The working file's lines the hunk spans (`+` lines; an added file's probe, the function's): a revert
39
+ // never reads them, but an unpinned place's key does (`test-pinned-record.ts`), since two changes of one
40
+ // length share the rest.
41
+ new_lines?: Array<string>
42
+ // Set on an added file's probe (`test-pinned-functions.ts`): the function the old lines put back
43
+ // with its body replaced by a throw.
44
+ function_name?: string
24
45
  }
25
46
 
26
47
  interface HunkSplit {
@@ -28,16 +49,48 @@ interface HunkSplit {
28
49
  unchecked: ReadonlyArray<Hunk>
29
50
  }
30
51
 
31
- // A reverted hunk nothing went red on: `is_green` when its related tests ran and passed, otherwise none
32
- // ran at all — no related test, or a vitest that stopped before running one.
52
+ // A reverted hunk nothing went red on: `is_green` when its related tests ran and passed, otherwise
53
+ // vitest passed with no related test to run.
33
54
  interface UnpinnedHunk extends Hunk {
34
55
  is_green: boolean
35
56
  }
36
57
 
37
- interface PinnedReport {
58
+ interface HunkOutcome {
38
59
  unpinned: ReadonlyArray<UnpinnedHunk>
60
+ // Hunks whose revert stopped vitest before any test ran (joshuafolkken/kit#5043) — a config that
61
+ // imports the file could not load. No test was asked, so it is neither pinned nor unpinned.
62
+ stopped: ReadonlyArray<Hunk>
63
+ // Hunks a `--first-unpinned` run did not probe once one was unpinned (joshuafolkken/kit#5153): the
64
+ // run fails already, so the rest wait for the next run.
65
+ cut?: ReadonlyArray<Hunk>
66
+ // Whether every checked hunk had a verdict — false when a cache-only read found one the cache no
67
+ // longer holds (joshuafolkken/kit#5078).
68
+ is_held?: boolean
69
+ // How many fresh probes the direct importers decided or escalated (joshuafolkken/kit#5292).
70
+ staged?: Staged
71
+ }
72
+
73
+ interface PinnedReport extends HunkOutcome {
39
74
  unchecked: ReadonlyArray<Hunk>
75
+ // Added files whose functions could not be read, so none of them was probed.
76
+ unparsed: ReadonlyArray<string>
40
77
  max_hunks: number
78
+ // False when no Vitest is installed to run a probe, so every hunk is `unchecked` rather than run and
79
+ // read as a `no-test` unpinned one.
80
+ has_runner: boolean
81
+ }
82
+
83
+ interface UncheckedPlace {
84
+ place: string
85
+ why: string
86
+ }
87
+
88
+ // A report as printed (joshuafolkken/kit#5188): `text` is its lines above the counts line, each ending in
89
+ // a newline; `counts` is absent for a check that could not run, and `log` where no full list was kept.
90
+ interface ReportParts {
91
+ text: string
92
+ counts?: string | undefined
93
+ log?: KeptLog | undefined
41
94
  }
42
95
 
43
96
  interface DiffWalk {
@@ -65,6 +118,7 @@ function hunk_from(file: string, line: string): Hunk | undefined {
65
118
  new_start: Number(groups['start']),
66
119
  new_count: count_of(groups['count']),
67
120
  old_lines: [],
121
+ new_lines: [],
68
122
  }
69
123
  }
70
124
 
@@ -72,10 +126,22 @@ function is_old_line(line: string): boolean {
72
126
  return line.startsWith(OLD_LINE) && !line.startsWith(OLD_FILE_HEADER)
73
127
  }
74
128
 
129
+ function is_new_line(line: string): boolean {
130
+ return line.startsWith(NEW_LINE) && !line.startsWith(FILE_HEADER_MARK)
131
+ }
132
+
133
+ function record_line(hunk: Hunk | undefined, line: string): void {
134
+ if (hunk === undefined) return
135
+ if (is_old_line(line)) hunk.old_lines.push(line.slice(OLD_LINE.length))
136
+ else if (is_new_line(line)) hunk.new_lines?.push(line.slice(NEW_LINE.length))
137
+ }
138
+
75
139
  // Each file section starts unnamed, so a `+++` line this does not read (a quoted path with a space)
76
- // leaves its hunks on no file rather than on the previous one.
140
+ // leaves its hunks on no file rather than on the previous one. A deleted file (`+++ /dev/null`) keeps
141
+ // the name its `--- a/` line gave it.
77
142
  function file_after(file: string, line: string): string {
78
143
  if (line.startsWith(FILE_HEADER)) return line.slice(FILE_HEADER.length)
144
+ if (line.startsWith(OLD_FILE_PATH)) return line.slice(OLD_FILE_PATH.length)
79
145
 
80
146
  return line.startsWith(SECTION_HEADER) ? '' : file
81
147
  }
@@ -84,18 +150,24 @@ function step(walk: DiffWalk, line: string): void {
84
150
  walk.file = file_after(walk.file, line)
85
151
  const hunk = hunk_from(walk.file, line)
86
152
 
87
- if (hunk !== undefined) walk.hunks.push(hunk)
88
- else if (is_old_line(line)) walk.hunks.at(-1)?.old_lines.push(line.slice(OLD_LINE.length))
153
+ if (hunk === undefined) record_line(walk.hunks.at(-1), line)
154
+ else walk.hunks.push(hunk)
89
155
  }
90
156
 
91
- // One `-U0` diff into its hunks, in diff order. The `+` lines are not kept: the working file already
92
- // holds them, at `new_start` for `new_count` lines.
93
- function parse_hunks(diff: string): Array<Hunk> {
157
+ // One `-U0` diff (`a/` and `b/` prefixes) into every file's hunks, in diff order — also read by
158
+ // `prose-stale-cli.ts` for the lines a diff removed and added.
159
+ function all_hunks(diff: string): Array<Hunk> {
94
160
  const walk: DiffWalk = { file: '', hunks: [] }
95
161
 
96
162
  for (const line of diff.split(LINE_BREAK)) step(walk, line)
97
163
 
98
- return walk.hunks.filter((hunk) => is_target(hunk.file))
164
+ return walk.hunks
165
+ }
166
+
167
+ // The hunks a revert probes. A revert puts the old lines back over the working file's `new_count` lines
168
+ // at `new_start`.
169
+ function parse_hunks(diff: string): Array<Hunk> {
170
+ return all_hunks(diff).filter((hunk) => is_target(hunk.file))
99
171
  }
100
172
 
101
173
  // A pure deletion's `new_start` names the line before the gap, so the old lines go in after it.
@@ -116,30 +188,146 @@ function split(hunks: ReadonlyArray<Hunk>, max_hunks: number): HunkSplit {
116
188
  return { checked: hunks.slice(0, max_hunks), unchecked: hunks.slice(max_hunks) }
117
189
  }
118
190
 
191
+ // The probes, the ones whose file reaches the fewest tests first (joshuafolkken/kit#5153), so a run
192
+ // that stops at its first unpinned hunk reaches it soonest; a file `reach` lacks counts as 0, and
193
+ // equal counts keep their order.
194
+ function by_reach<T extends { hunk: Hunk }>(
195
+ probes: ReadonlyArray<T>,
196
+ reach: ReadonlyMap<string, number>,
197
+ ): Array<T> {
198
+ function count(probe: T): number {
199
+ return reach.get(probe.hunk.file) ?? 0
200
+ }
201
+
202
+ return probes.toSorted((first, second) => count(first) - count(second))
203
+ }
204
+
205
+ // `green` and `no-test` leave a hunk unpinned: either way nothing went red when it was reverted.
206
+ function is_unpinned(probe: RedProbe): boolean {
207
+ return !SETTLED_VERDICTS.has(probe.verdict)
208
+ }
209
+
210
+ // A hunk with no verdict yet is neither pinned nor unpinned.
211
+ function unpinned_of(hunk: Hunk, probe: RedProbe | undefined): Array<UnpinnedHunk> {
212
+ if (probe === undefined || !is_unpinned(probe)) return []
213
+
214
+ return [{ ...hunk, is_green: probe.verdict === 'green' }]
215
+ }
216
+
217
+ function stopped_of(hunk: Hunk, probe: RedProbe | undefined): Array<Hunk> {
218
+ return probe?.verdict === STOPPED_VERDICT ? [hunk] : []
219
+ }
220
+
221
+ // Each checked hunk by its verdict, in the hunks' order: `red` pins it, `stopped` sets it aside, and
222
+ // any other leaves it unpinned.
223
+ function outcome(
224
+ hunks: ReadonlyArray<Hunk>,
225
+ verdicts: ReadonlyArray<RedProbe | undefined>,
226
+ ): HunkOutcome {
227
+ return {
228
+ unpinned: hunks.flatMap((hunk, index) => unpinned_of(hunk, verdicts[index])),
229
+ stopped: hunks.flatMap((hunk, index) => stopped_of(hunk, verdicts[index])),
230
+ }
231
+ }
232
+
119
233
  function location(hunk: Hunk): string {
120
- return `${hunk.file}:${String(Math.max(hunk.new_start, 1))}`
234
+ const line = `${hunk.file}:${String(Math.max(hunk.new_start, 1))}`
235
+
236
+ return hunk.function_name === undefined ? line : `${line} ${hunk.function_name}`
237
+ }
238
+
239
+ function reason(hunk: UnpinnedHunk): string {
240
+ if (hunk.function_name === undefined) return hunk.is_green ? GREEN_REASON : NO_TEST_REASON
241
+
242
+ return hunk.is_green ? STUB_GREEN_REASON : STUB_NO_TEST_REASON
243
+ }
244
+
245
+ function unchecked_reason(report: PinnedReport): string {
246
+ return report.has_runner ? `over the ${String(report.max_hunks)}-hunk cap` : NO_RUNNER_REASON
247
+ }
248
+
249
+ function unpinned_lines(report: PinnedReport): Array<string> {
250
+ return report.unpinned.map((hunk) => `unpinned ${location(hunk)} — ${reason(hunk)}`)
251
+ }
252
+
253
+ function place_of(hunk: Hunk, why: string): UncheckedPlace {
254
+ return { place: location(hunk), why }
255
+ }
256
+
257
+ // Every unchecked place with its reason, in the full list's order.
258
+ function unchecked_places(report: PinnedReport): Array<UncheckedPlace> {
259
+ return [
260
+ ...report.unchecked.map((hunk) => place_of(hunk, unchecked_reason(report))),
261
+ ...report.stopped.map((hunk) => place_of(hunk, STOPPED_REASON)),
262
+ ...(report.cut ?? []).map((hunk) => place_of(hunk, CUT_REASON)),
263
+ ...report.unparsed.map((file) => ({ place: file, why: UNPARSED_REASON })),
264
+ ]
265
+ }
266
+
267
+ // Whether the printed report folds any place, so the full list is worth keeping.
268
+ function has_unchecked(report: PinnedReport): boolean {
269
+ return unchecked_places(report).length > 0
121
270
  }
122
271
 
272
+ // One line per unpinned or unchecked place — the full list `josh test:pinned` keeps in its log.
123
273
  function format(report: PinnedReport): string {
124
- const unpinned = report.unpinned.map(
125
- (hunk) => `unpinned ${location(hunk)} — ${hunk.is_green ? GREEN_REASON : NO_TEST_REASON}`,
126
- )
127
- const unchecked = report.unchecked.map(
128
- (hunk) => `unchecked ${location(hunk)} — over the ${String(report.max_hunks)}-hunk cap`,
129
- )
274
+ const unchecked = unchecked_places(report).map((item) => `unchecked ${item.place} — ${item.why}`)
275
+
276
+ return [...unpinned_lines(report), ...unchecked].join(LINE_BREAK)
277
+ }
278
+
279
+ // The unchecked places folded to one line per reason (joshuafolkken/kit#5188): a cap's overflow listed
280
+ // one line each pushed the unpinned places, and what to do about them, out of a `tail` window.
281
+ function folded_unchecked(report: PinnedReport): Array<string> {
282
+ const counts = new Map<string, number>()
283
+
284
+ for (const { why } of unchecked_places(report)) counts.set(why, (counts.get(why) ?? 0) + 1)
285
+
286
+ return [...counts].map(([why, count]) => `unchecked ${String(count)} — ${why}`)
287
+ }
288
+
289
+ function counts_line(report: PinnedReport): string {
290
+ const unchecked = String(unchecked_places(report).length)
291
+
292
+ const staged = test_pinned_stage.counts_suffix(report.staged)
293
+
294
+ return `unpinned ${String(report.unpinned.length)} · unchecked ${unchecked}${staged}`
295
+ }
296
+
297
+ // The report's parts: each unpinned place and the folded unchecked lines, and the counts line.
298
+ function report_parts(report: PinnedReport): ReportParts {
299
+ const lines = [...unpinned_lines(report), ...folded_unchecked(report)]
300
+
301
+ return { text: lines.map((line) => `${line}${LINE_BREAK}`).join(''), counts: counts_line(report) }
302
+ }
303
+
304
+ // What `josh test:pinned`, `josh run:review` and the ship's pre-detach print, in the verification-tail
305
+ // shape (`verification-tail.ts`): the places, then `note` (what to do about them, each line ending in a
306
+ // newline), then where the full list went, and the counts line last. Without a counts line — a check
307
+ // that could not run — the text and the note alone.
308
+ function report_text(parts: ReportParts, note = ''): string {
309
+ const failures = `${parts.text}${note}`
310
+ if (parts.counts === undefined) return failures
130
311
 
131
- return [...unpinned, ...unchecked].join(LINE_BREAK)
312
+ return verification_tail.format_tail({ failures, log: parts.log, verdict: parts.counts })
132
313
  }
133
314
 
134
315
  const test_pinned_logic = {
316
+ all_hunks,
135
317
  DEFAULT_MAX_HUNKS,
318
+ by_reach,
136
319
  format,
320
+ has_unchecked,
137
321
  is_target,
322
+ is_unpinned,
138
323
  location,
324
+ outcome,
139
325
  parse_hunks,
326
+ report_parts,
327
+ report_text,
140
328
  revert,
141
329
  split,
142
330
  }
143
331
 
144
- export type { Hunk, PinnedReport, UnpinnedHunk }
332
+ export type { Hunk, HunkOutcome, PinnedReport, ReportParts, UnpinnedHunk }
145
333
  export { test_pinned_logic }