@joshuafolkken/kit 1.1784.0 → 1.2114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/.claude/agents/reviewer-verification.md +19 -0
  2. package/.claude/agents/reviewer.md +19 -0
  3. package/.claude/settings.json +5 -6
  4. package/.claude/skills/dependency-update/SKILL.md +9 -10
  5. package/.claude/skills/workflow-commands/SKILL.md +6 -6
  6. package/.claude/skills/workflow-commands/background-commands.md +8 -5
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
  13. package/.claude/skills/workflow-commands/backlogrun.md +1 -1
  14. package/.claude/skills/workflow-commands/chain-rule.md +41 -32
  15. package/.claude/skills/workflow-commands/delegation.md +6 -6
  16. package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
  17. package/.claude/skills/workflow-commands/followup.md +7 -5
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
  19. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  20. package/.claude/skills/workflow-commands/issue-comments.md +9 -4
  21. package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
  22. package/.claude/skills/workflow-commands/kickoff.md +2 -2
  23. package/.claude/skills/workflow-commands/observation-filing.md +1 -1
  24. package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
  25. package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
  26. package/.claude/skills/workflow-commands/prerequisite.md +3 -2
  27. package/.claude/skills/workflow-commands/retrospective.md +2 -2
  28. package/.claude/skills/workflow-commands/split-assessment.md +7 -5
  29. package/.codex/hooks.json +5 -5
  30. package/.github/actions/setup-pnpm/action.yml +9 -16
  31. package/.github/dependabot.yml +16 -0
  32. package/.github/workflows/auto-tag.yml +45 -0
  33. package/.github/workflows/ci.yml +155 -15
  34. package/.github/workflows/dependabot-auto-merge.yml +63 -4
  35. package/.github/workflows/production.yml +8 -0
  36. package/.github/workflows/publish.yml +59 -45
  37. package/.vscode/settings.json +19 -0
  38. package/CLAUDE.md +5 -12
  39. package/SECURITY.md +2 -2
  40. package/dist/CLAUDE.md +5 -12
  41. package/dist/commands/document-read-cli.js +2 -1
  42. package/dist/commands/document-section-main.js +2 -1
  43. package/dist/commands/read-set-cli.js +194 -134
  44. package/dist/commands/run-prep-main.js +9694 -10173
  45. package/dist/commands/run-step-cli.js +22138 -18285
  46. package/dist/hooks/audit-provision.js +23 -5
  47. package/dist/hooks/chunk-3GKE653K.js +6204 -0
  48. package/dist/hooks/chunk-45CJJOO7.js +1243 -0
  49. package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
  50. package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
  51. package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
  52. package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
  53. package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
  54. package/dist/hooks/chunk-VVNYJWEI.js +30 -0
  55. package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
  56. package/dist/hooks/codex-hook-adapter.js +8 -8
  57. package/dist/hooks/format-edited.js +4 -5
  58. package/dist/hooks/inputs.json +415 -389
  59. package/dist/hooks/pretool-guard.js +7 -6
  60. package/dist/hooks/session-lang.js +101 -258
  61. package/dist/hooks/stop-guard.js +1744 -2576
  62. package/dist/josh.js +7133 -6368
  63. package/dist/version/index.js +161 -1
  64. package/eslint/rules/comment-why-only.js +108 -0
  65. package/package.json +15 -8
  66. package/prompts/coding-standards.md +1 -1
  67. package/prompts/collaboration-workflow/file-edits.md +14 -11
  68. package/prompts/collaboration-workflow/issue-citation.md +0 -4
  69. package/prompts/collaboration-workflow/issue-template.md +40 -21
  70. package/prompts/collaboration-workflow/lane-instructions.md +3 -1
  71. package/prompts/collaboration-workflow/measurement.md +8 -1
  72. package/prompts/collaboration-workflow/operating-rules.md +11 -2
  73. package/prompts/collaboration-workflow/output-bounds.md +6 -2
  74. package/prompts/collaboration-workflow/plan-comment.md +1 -1
  75. package/prompts/collaboration-workflow/principles.md +9 -0
  76. package/prompts/collaboration-workflow/residency.md +3 -2
  77. package/prompts/collaboration-workflow/rule-delivery.md +13 -1
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  79. package/prompts/collaboration-workflow/wip-cap.md +3 -1
  80. package/prompts/review-rubric.md +8 -0
  81. package/prompts/review.md +31 -22
  82. package/prompts/testing-guide.md +1 -0
  83. package/scripts/agent/agent-argv.ts +14 -16
  84. package/scripts/agent/agent-provider.ts +138 -0
  85. package/scripts/agent/agent-role-profile.ts +108 -156
  86. package/scripts/agent/agent-safe-text.ts +20 -5
  87. package/scripts/agent/api-usage-limit.ts +65 -0
  88. package/scripts/agent/claude-agent-argv.ts +19 -9
  89. package/scripts/agent/codex-agent-argv.ts +118 -22
  90. package/scripts/agent/usage-limit-reset.ts +179 -0
  91. package/scripts/auth/claude-token-output.ts +2 -2
  92. package/scripts/auto-ok/auto-ok-author.ts +53 -0
  93. package/scripts/auto-ok/auto-ok-cli.ts +20 -9
  94. package/scripts/backlog/backlog-defect-priority.ts +1 -1
  95. package/scripts/backlog/backlog-drive-cli.ts +6 -1
  96. package/scripts/backlog/backlog-drive-hold.ts +3 -3
  97. package/scripts/backlog/backlog-drive-idle.ts +10 -0
  98. package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
  99. package/scripts/backlog/backlog-drive-launch.ts +8 -2
  100. package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
  101. package/scripts/backlog/backlog-drive-named.ts +28 -7
  102. package/scripts/backlog/backlog-drive-paused.ts +5 -4
  103. package/scripts/backlog/backlog-drive-restore.ts +11 -3
  104. package/scripts/backlog/backlog-drive.ts +21 -60
  105. package/scripts/backlog/backlog-gate-scope.ts +61 -0
  106. package/scripts/backlog/backlog-measure-close.ts +112 -0
  107. package/scripts/backlog/backlog-next.ts +39 -49
  108. package/scripts/backlog/backlog-occupied.ts +2 -2
  109. package/scripts/backlog/backlog-overlap.ts +42 -8
  110. package/scripts/backlog/backlog-plan-cli.ts +4 -1
  111. package/scripts/backlog/backlog-plan-comment.ts +81 -0
  112. package/scripts/backlog/backlog-plan-read.ts +19 -6
  113. package/scripts/backlog/backlog-pool.ts +50 -12
  114. package/scripts/backlog/backlog-rank.ts +60 -13
  115. package/scripts/backlog/backlog-stalled-detect.ts +2 -1
  116. package/scripts/backlog/backlog-waves.ts +17 -2
  117. package/scripts/backlog/backlogrun-launch.ts +7 -4
  118. package/scripts/cost-runtime/context-cut-payback.ts +27 -25
  119. package/scripts/cost-runtime/cost-cli.ts +37 -16
  120. package/scripts/cost-runtime/cost-pricing.ts +9 -0
  121. package/scripts/cost-runtime/cost-verdict.ts +4 -1
  122. package/scripts/delegation/delegation-policy.ts +2 -2
  123. package/scripts/delegation/duplicate-read-guard.ts +1 -0
  124. package/scripts/delegation/investigation-guard.ts +14 -2
  125. package/scripts/delegation/investigation-reads.ts +45 -23
  126. package/scripts/dependabot/dependabot-cooldown.ts +3 -2
  127. package/scripts/discovery/repo-party.ts +80 -20
  128. package/scripts/discovery/session-owner-pin.ts +51 -0
  129. package/scripts/document/capped-print.ts +1 -1
  130. package/scripts/document/command-reference-line-budget.ts +42 -0
  131. package/scripts/document/document-byte-budget.ts +17 -7
  132. package/scripts/document/document-checks.ts +20 -0
  133. package/scripts/document/document-ratchet-check.ts +101 -0
  134. package/scripts/document/document-section.ts +1 -0
  135. package/scripts/document/entry-read-budget.ts +7 -3
  136. package/scripts/document/issue-citation-budget.ts +94 -0
  137. package/scripts/epic/epic-cli-argv.ts +2 -2
  138. package/scripts/epic/epic-fetch.ts +4 -2
  139. package/scripts/epic/epic-graph.ts +7 -2
  140. package/scripts/epic/epic-issue.ts +3 -1
  141. package/scripts/epic/epic-rank.ts +5 -0
  142. package/scripts/exports/unused-members-check.ts +62 -0
  143. package/scripts/exports/unused-members-cli.ts +6 -51
  144. package/scripts/followup/followup-ci-path.ts +67 -0
  145. package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
  146. package/scripts/followup/followup-coderabbit-wait.ts +13 -10
  147. package/scripts/followup/followup-failed-tests.ts +160 -0
  148. package/scripts/followup/followup-job-needs.ts +100 -0
  149. package/scripts/followup/followup-job-rerun.ts +303 -0
  150. package/scripts/followup/followup-main-move.ts +113 -0
  151. package/scripts/followup/git-followup-finish.ts +43 -11
  152. package/scripts/followup/git-followup-pending.ts +3 -3
  153. package/scripts/followup/git-followup-stages.ts +41 -11
  154. package/scripts/followup/git-pr-followup-checks.ts +55 -16
  155. package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
  156. package/scripts/followup/git-pr-followup.ts +62 -27
  157. package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
  158. package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
  159. package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
  160. package/scripts/gate/busy-average.ts +34 -2
  161. package/scripts/gate/check-related-pinned.ts +43 -0
  162. package/scripts/gate/check-related-reuse.ts +64 -0
  163. package/scripts/gate/check-related-section.ts +57 -0
  164. package/scripts/gate/check-related-unplanned.ts +34 -0
  165. package/scripts/gate/check-related.ts +265 -0
  166. package/scripts/gate/command-memory.ts +1 -1
  167. package/scripts/gate/core-admission.ts +24 -6
  168. package/scripts/gate/core-budget-timing.ts +20 -6
  169. package/scripts/gate/core-budget.ts +40 -11
  170. package/scripts/gate/core-wait-record.ts +3 -2
  171. package/scripts/gate/core-wait.ts +25 -2
  172. package/scripts/gate/core-weights.ts +15 -7
  173. package/scripts/gate/gate-labels.ts +46 -0
  174. package/scripts/gate/gate-ledger.ts +14 -6
  175. package/scripts/gate/gate-plan.ts +103 -58
  176. package/scripts/gate/gate-report.ts +9 -7
  177. package/scripts/gate/gate-run-steps.ts +26 -3
  178. package/scripts/gate/gate-skip.ts +45 -6
  179. package/scripts/gate/gate-static-group.ts +60 -0
  180. package/scripts/gate/gate-steps.ts +2 -1
  181. package/scripts/gate/gate-tree.ts +4 -2
  182. package/scripts/gate/hook-gate-reuse.ts +19 -2
  183. package/scripts/gate/metrics-totals.ts +59 -0
  184. package/scripts/gate/scoped-green.ts +68 -15
  185. package/scripts/gate/since-green.ts +14 -6
  186. package/scripts/gate/structural-checks.ts +96 -0
  187. package/scripts/gate/verification-gate.ts +51 -16
  188. package/scripts/gate/verification-inputs.ts +21 -6
  189. package/scripts/gate/verification-tail.ts +52 -0
  190. package/scripts/gh/gh-author-association.ts +23 -2
  191. package/scripts/gh/git-ai-review-scan.ts +1 -1
  192. package/scripts/gh/git-gh-api-path.ts +12 -3
  193. package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
  194. package/scripts/gh/git-gh-exec.ts +32 -2
  195. package/scripts/gh/git-gh-issue-read.ts +4 -2
  196. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  197. package/scripts/gh/git-gh-issue-write.ts +8 -2
  198. package/scripts/gh/git-gh-issue.ts +12 -5
  199. package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
  200. package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
  201. package/scripts/gh/git-gh-pr-read.ts +74 -13
  202. package/scripts/gh/git-gh-pr-rest.ts +3 -1
  203. package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
  204. package/scripts/gh/git-gh-pr-too-large.ts +20 -0
  205. package/scripts/gh/git-gh-pr.ts +21 -7
  206. package/scripts/gh/git-gh-retry.ts +141 -0
  207. package/scripts/gh/git-pr-ai-review.ts +15 -6
  208. package/scripts/gh/git-pr-checks-eval.ts +3 -0
  209. package/scripts/gh/git-pr-checks.ts +5 -5
  210. package/scripts/git/base-tree.ts +30 -0
  211. package/scripts/git/change-base.ts +4 -10
  212. package/scripts/git/changed-paths-sync.ts +63 -0
  213. package/scripts/git/changed-paths.ts +16 -1
  214. package/scripts/git/git-common-directory.ts +11 -1
  215. package/scripts/git/git-diff-reads.ts +66 -20
  216. package/scripts/git/git-error.ts +9 -2
  217. package/scripts/git/git-schemas.ts +13 -0
  218. package/scripts/git/git-worktree.ts +13 -0
  219. package/scripts/git/gone-branch.ts +4 -1
  220. package/scripts/git/main-merge-budget-conflict.ts +89 -0
  221. package/scripts/git/main-merge-guard.ts +55 -18
  222. package/scripts/git/main-merge-regenerate.ts +59 -25
  223. package/scripts/git/main-merge.ts +53 -5
  224. package/scripts/git/no-base-checkout.ts +127 -0
  225. package/scripts/git/stash/git-stash.ts +11 -2
  226. package/scripts/git/stash/stash-push-cli.ts +10 -0
  227. package/scripts/hooks/batch-guard.ts +40 -21
  228. package/scripts/hooks/edited-cspell.ts +37 -11
  229. package/scripts/hooks/format-edited-file.ts +22 -2
  230. package/scripts/hooks/lane-plan-guard.ts +50 -0
  231. package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
  232. package/scripts/hooks/pre-commit-lint.ts +14 -1
  233. package/scripts/hooks/pre-push-related-switch.ts +10 -0
  234. package/scripts/hooks/pre-push-unit.ts +76 -10
  235. package/scripts/hooks/pretool-guard.ts +2 -0
  236. package/scripts/hooks/reserved-run.ts +14 -1
  237. package/scripts/hooks/run-hook.sh +23 -8
  238. package/scripts/hooks/step-zero-notice.ts +6 -1
  239. package/scripts/hooks/stop-actions.ts +3 -15
  240. package/scripts/hooks/stop-guard.ts +7 -6
  241. package/scripts/init/distributed-paths.ts +1 -0
  242. package/scripts/init/hook-command-rewrite.ts +5 -1
  243. package/scripts/init/hook-launch.ts +4 -2
  244. package/scripts/issue/aggregation-split.ts +52 -0
  245. package/scripts/issue/defect-origin-line.ts +19 -1
  246. package/scripts/issue/defect-rate-cli.ts +5 -102
  247. package/scripts/issue/defect-report.ts +4 -4
  248. package/scripts/issue/effect-audit-cli.ts +178 -0
  249. package/scripts/issue/effect-audit.ts +185 -0
  250. package/scripts/issue/expected-effect-lint.ts +64 -9
  251. package/scripts/issue/git-next-issues.ts +5 -0
  252. package/scripts/issue/issue-body-or-comment.ts +38 -4
  253. package/scripts/issue/issue-cite-cli.ts +1 -3
  254. package/scripts/issue/issue-classification.ts +1 -0
  255. package/scripts/issue/issue-closing-pr.ts +8 -1
  256. package/scripts/issue/issue-evidence-exit.ts +4 -2
  257. package/scripts/issue/issue-file-cap.ts +58 -0
  258. package/scripts/issue/issue-file-cli.ts +111 -38
  259. package/scripts/issue/issue-file-deferral.ts +52 -0
  260. package/scripts/issue/issue-file-fold.ts +29 -10
  261. package/scripts/issue/issue-file-interrupt.ts +85 -0
  262. package/scripts/issue/issue-file-lane-hint.ts +30 -0
  263. package/scripts/issue/issue-file.ts +43 -6
  264. package/scripts/issue/issue-labels.ts +19 -2
  265. package/scripts/issue/issue-lint-cli.ts +27 -2
  266. package/scripts/issue/issue-measured-cli.ts +13 -35
  267. package/scripts/issue/issue-measured-close.ts +58 -0
  268. package/scripts/issue/issue-not-before-label.ts +2 -2
  269. package/scripts/issue/issue-not-before.ts +4 -1
  270. package/scripts/issue/issue-priority-cli.ts +60 -0
  271. package/scripts/issue/issue-priority-raise.ts +55 -0
  272. package/scripts/issue/issue-priority.ts +174 -43
  273. package/scripts/issue/issue-rank.ts +21 -4
  274. package/scripts/issue/issue-read-cli.ts +32 -6
  275. package/scripts/issue/issue-read.ts +37 -12
  276. package/scripts/issue/issue-sample-gate.ts +95 -74
  277. package/scripts/issue/issue-sample-prime.ts +127 -0
  278. package/scripts/issue/issue-sample-required.ts +57 -0
  279. package/scripts/issue/issue-sample-source.ts +12 -11
  280. package/scripts/issue/issue-search.ts +124 -0
  281. package/scripts/issue/issue-state.ts +13 -1
  282. package/scripts/issue/issue-template-section.ts +43 -0
  283. package/scripts/issue/issue-watch-diff.ts +31 -1
  284. package/scripts/issue/issue-watch-hook.ts +11 -2
  285. package/scripts/issue/issue-watch.ts +55 -12
  286. package/scripts/issue/markdown-section.ts +1 -0
  287. package/scripts/issue/measure-declaration.ts +121 -0
  288. package/scripts/issue/measure-rerun-cli.ts +7 -70
  289. package/scripts/issue/plan-consumers-section.ts +22 -1
  290. package/scripts/issue/reproduction-measure.ts +3 -1
  291. package/scripts/issue/size-estimate.ts +90 -0
  292. package/scripts/issue/trusted-measure.ts +84 -0
  293. package/scripts/josh/command-usage.ts +3 -2
  294. package/scripts/josh/durable-state-migrate.ts +105 -0
  295. package/scripts/josh/durable-state.ts +112 -0
  296. package/scripts/josh/josh-aliases.ts +95 -0
  297. package/scripts/josh/josh-command-map.ts +1 -82
  298. package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
  299. package/scripts/josh/josh-commands-ai.ts +5 -5
  300. package/scripts/josh/josh-commands-development.ts +59 -58
  301. package/scripts/josh/josh-commands-issue-write.ts +23 -4
  302. package/scripts/josh/josh-commands-issue.ts +32 -0
  303. package/scripts/josh/josh-commands-lane.ts +87 -4
  304. package/scripts/josh/josh-commands-lint.ts +16 -3
  305. package/scripts/josh/josh-commands-maintenance.ts +15 -0
  306. package/scripts/josh/josh-commands-review.ts +41 -6
  307. package/scripts/josh/josh-commands-ship.ts +56 -8
  308. package/scripts/josh/josh-commands-test-check.ts +80 -0
  309. package/scripts/josh/josh-commands-workflow.ts +1 -1
  310. package/scripts/josh/josh-environment-file.ts +43 -3
  311. package/scripts/josh/josh-in-process.ts +2 -2
  312. package/scripts/josh/josh-logic.ts +5 -3
  313. package/scripts/josh/josh-run.ts +19 -1
  314. package/scripts/josh/run-record-path.ts +15 -0
  315. package/scripts/josh/stamp-file.ts +11 -2
  316. package/scripts/lane/lane-adopt-cli.ts +98 -0
  317. package/scripts/lane/lane-adopt.ts +208 -0
  318. package/scripts/lane/lane-await.ts +5 -8
  319. package/scripts/lane/lane-baseline.ts +123 -0
  320. package/scripts/lane/lane-breakdown-cli.ts +64 -0
  321. package/scripts/lane/lane-breakdown-implement.ts +170 -0
  322. package/scripts/lane/lane-breakdown-laps.ts +107 -0
  323. package/scripts/lane/lane-breakdown-pinned.ts +76 -0
  324. package/scripts/lane/lane-breakdown-text.ts +145 -0
  325. package/scripts/lane/lane-breakdown.ts +239 -0
  326. package/scripts/lane/lane-check-stats.ts +29 -8
  327. package/scripts/lane/lane-child-invocation.ts +9 -2
  328. package/scripts/lane/lane-child-mark-keys.ts +12 -0
  329. package/scripts/lane/lane-child-marker.ts +20 -1
  330. package/scripts/lane/lane-ci-path-stats.ts +73 -0
  331. package/scripts/lane/lane-claim-stats.ts +84 -0
  332. package/scripts/lane/lane-close.ts +8 -3
  333. package/scripts/lane/lane-dispatch-log.ts +3 -3
  334. package/scripts/lane/lane-dispatch.ts +2 -2
  335. package/scripts/lane/lane-gap-stats.ts +7 -6
  336. package/scripts/lane/lane-guard-policy.ts +7 -1
  337. package/scripts/lane/lane-implement-stats.ts +207 -0
  338. package/scripts/lane/lane-implement-subagents.ts +90 -0
  339. package/scripts/lane/lane-investigation-switch.ts +16 -0
  340. package/scripts/lane/lane-ledger-kind.ts +31 -0
  341. package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
  342. package/scripts/lane/lane-ledger-schema.ts +119 -36
  343. package/scripts/lane/lane-ledger-write.ts +257 -0
  344. package/scripts/lane/lane-ledger.ts +31 -177
  345. package/scripts/lane/lane-load.ts +1 -1
  346. package/scripts/lane/lane-measure-cli.ts +176 -59
  347. package/scripts/lane/lane-net-read.ts +44 -0
  348. package/scripts/lane/lane-net-time.ts +212 -0
  349. package/scripts/lane/lane-open.ts +16 -7
  350. package/scripts/lane/lane-output.ts +2 -4
  351. package/scripts/lane/lane-overrun-prompt.ts +147 -0
  352. package/scripts/lane/lane-overrun.ts +274 -0
  353. package/scripts/lane/lane-paths.ts +24 -1
  354. package/scripts/lane/lane-pause-cli.ts +4 -1
  355. package/scripts/lane/lane-paused-spans.ts +97 -0
  356. package/scripts/lane/lane-plan-check.ts +207 -0
  357. package/scripts/lane/lane-plan-cli.ts +41 -0
  358. package/scripts/lane/lane-plan.ts +144 -0
  359. package/scripts/lane/lane-registry.ts +14 -1
  360. package/scripts/lane/lane-relaunch.ts +1 -1
  361. package/scripts/lane/lane-round-one-stats.ts +51 -0
  362. package/scripts/lane/lane-sampler.ts +23 -4
  363. package/scripts/lane/lane-session-action.ts +93 -18
  364. package/scripts/lane/lane-session-broker.ts +49 -21
  365. package/scripts/lane/lane-session-reread-main.ts +14 -0
  366. package/scripts/lane/lane-session-reread.ts +51 -0
  367. package/scripts/lane/lane-ship-lap-stats.ts +74 -0
  368. package/scripts/lane/lane-sleep.ts +58 -0
  369. package/scripts/lane/lane-spent.ts +1 -1
  370. package/scripts/lane/lane-split-stats.ts +28 -0
  371. package/scripts/lane/lane-stage-stats.ts +13 -1
  372. package/scripts/lane/lane-state.ts +41 -9
  373. package/scripts/lane/lane-stats-tables.ts +58 -0
  374. package/scripts/lane/lane-stats.ts +21 -5
  375. package/scripts/lane/lane-stop-stats.ts +51 -19
  376. package/scripts/lane/lane-tail-stats.ts +32 -0
  377. package/scripts/lane/lane-transcript-calls.ts +67 -10
  378. package/scripts/lane/lane-transcript-stats.ts +44 -12
  379. package/scripts/lane/lane-value-cell.ts +72 -0
  380. package/scripts/lane/lane-value.ts +118 -0
  381. package/scripts/lane/lane-withdraw-closed.ts +124 -0
  382. package/scripts/lane/lane-withdraw.ts +108 -31
  383. package/scripts/lane/lane-yield.ts +85 -0
  384. package/scripts/lane/openai-lane-ship.ts +12 -11
  385. package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
  386. package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
  387. package/scripts/lane/openai-lane-supervisor.ts +5 -4
  388. package/scripts/lib/poll.ts +38 -9
  389. package/scripts/lib/settled-together.ts +10 -0
  390. package/scripts/lib/shell-quote.ts +21 -0
  391. package/scripts/lib/token-shape.ts +111 -0
  392. package/scripts/lint/eslint-daemon-sources.ts +79 -0
  393. package/scripts/lint/eslint-daemon.ts +45 -6
  394. package/scripts/lint/eslint-warm-cli.ts +7 -0
  395. package/scripts/lint/eslint-warm.ts +66 -0
  396. package/scripts/lint/import-graph.ts +141 -11
  397. package/scripts/lint/lint-gate-scope.ts +2 -2
  398. package/scripts/lint/lint-parallel.ts +54 -6
  399. package/scripts/lint/lint-related.ts +154 -33
  400. package/scripts/lint/rename-cli.ts +179 -0
  401. package/scripts/lint/rename-identifier.ts +192 -0
  402. package/scripts/lint/type-only-imports.ts +58 -0
  403. package/scripts/notify/telegram-notify.ts +12 -3
  404. package/scripts/observations/observation-record.ts +42 -16
  405. package/scripts/observations/observations-flush.ts +32 -9
  406. package/scripts/overrides/overrides-check.ts +9 -1
  407. package/scripts/release/release-approval-prune.ts +7 -1
  408. package/scripts/repo/required-checks-logic.ts +4 -1
  409. package/scripts/repo/ruleset-check.ts +4 -3
  410. package/scripts/report/markdown-shape.ts +28 -0
  411. package/scripts/report/report-format-reference.ts +15 -1
  412. package/scripts/report/report-labels.ts +12 -1
  413. package/scripts/report/report-lint-child-summary.ts +94 -0
  414. package/scripts/report/report-lint-cli.ts +26 -7
  415. package/scripts/report/report-lint.ts +2 -20
  416. package/scripts/review/prose-stale-cli.ts +88 -0
  417. package/scripts/review/prose-stale-scan.ts +152 -0
  418. package/scripts/review/review-attest.ts +73 -23
  419. package/scripts/review/review-brief-cli.ts +68 -19
  420. package/scripts/review/review-brief-paths.ts +22 -0
  421. package/scripts/review/review-brief.ts +14 -7
  422. package/scripts/review/review-comment-carry.ts +47 -0
  423. package/scripts/review/review-comment-round.ts +85 -22
  424. package/scripts/review/review-finding-ledger.ts +109 -7
  425. package/scripts/review/review-finding-text.ts +43 -0
  426. package/scripts/review/review-interaction.ts +11 -0
  427. package/scripts/review/review-lane-handover.ts +68 -0
  428. package/scripts/review/review-lint-cli.ts +57 -0
  429. package/scripts/review/review-lint-findings.ts +92 -0
  430. package/scripts/review/review-lint-sections.ts +80 -0
  431. package/scripts/review/review-lint.ts +221 -0
  432. package/scripts/review/review-prior-findings.ts +102 -0
  433. package/scripts/review/review-readers-scan.ts +4 -2
  434. package/scripts/review/review-record-cli.ts +177 -54
  435. package/scripts/review/review-record-code-round.ts +55 -0
  436. package/scripts/review/review-record-comment.ts +60 -0
  437. package/scripts/review/review-record-interaction.ts +35 -0
  438. package/scripts/review/review-record-pinned.ts +108 -0
  439. package/scripts/review/review-record.ts +25 -1
  440. package/scripts/review/review-reviewed-tree.ts +307 -0
  441. package/scripts/review/review-round-one-closure.ts +62 -0
  442. package/scripts/review/review-round-reuse.ts +106 -0
  443. package/scripts/review/review-round2-cli.ts +91 -29
  444. package/scripts/review/review-round2-skip-comment.ts +55 -0
  445. package/scripts/review/review-round2.ts +24 -8
  446. package/scripts/review/review-stamps.ts +7 -3
  447. package/scripts/review/review-stop-log.ts +20 -6
  448. package/scripts/review/review-stops-cli.ts +2 -1
  449. package/scripts/review/review-submit-cli.ts +101 -0
  450. package/scripts/rules/agent-model.ts +1 -1
  451. package/scripts/rules/bash-triggers.ts +3 -3
  452. package/scripts/rules/concise-reply.ts +88 -0
  453. package/scripts/rules/credential-body.ts +77 -0
  454. package/scripts/rules/decision-oracle.ts +1 -1
  455. package/scripts/rules/delivered-rules.ts +36 -17
  456. package/scripts/rules/destructive-command.ts +3 -11
  457. package/scripts/rules/direct-issue-comment.ts +34 -12
  458. package/scripts/rules/direct-issue-read.ts +191 -0
  459. package/scripts/rules/direct-pr-create.ts +4 -24
  460. package/scripts/rules/early-heartbeat.ts +2 -0
  461. package/scripts/rules/edit-tool.ts +27 -0
  462. package/scripts/rules/file-edit-rows.ts +17 -0
  463. package/scripts/rules/file-rewrite.ts +146 -0
  464. package/scripts/rules/firing-point.ts +3 -2
  465. package/scripts/rules/gh-api.ts +128 -7
  466. package/scripts/rules/gh-repo-selector.ts +84 -0
  467. package/scripts/rules/git-force.ts +2 -2
  468. package/scripts/rules/guard-remedy.ts +14 -5
  469. package/scripts/rules/implementation-cut.ts +61 -28
  470. package/scripts/rules/investigator-foreground.ts +231 -0
  471. package/scripts/rules/issue-citation.ts +15 -60
  472. package/scripts/rules/issue-comments.ts +9 -4
  473. package/scripts/rules/josh-git-bare.ts +1 -1
  474. package/scripts/rules/lane-background.ts +41 -13
  475. package/scripts/rules/lane-direct-tool.ts +107 -9
  476. package/scripts/rules/lane-interactive-ask.ts +4 -1
  477. package/scripts/rules/lane-park.ts +4 -2
  478. package/scripts/rules/lane-spilled-read.ts +90 -0
  479. package/scripts/rules/lane-split-park.ts +1 -1
  480. package/scripts/rules/lane-switch-main.ts +4 -4
  481. package/scripts/rules/last-prompt.ts +20 -47
  482. package/scripts/rules/oracle-consulted.ts +1 -1
  483. package/scripts/rules/permission-guards.ts +5 -1
  484. package/scripts/rules/piped-verification-shapes.ts +110 -0
  485. package/scripts/rules/piped-verification.ts +67 -17
  486. package/scripts/rules/poll-loop.ts +72 -9
  487. package/scripts/rules/pr-merge.ts +5 -5
  488. package/scripts/rules/pre-gate-cut.ts +3 -3
  489. package/scripts/rules/protected-files.ts +88 -24
  490. package/scripts/rules/reply-language.ts +3 -17
  491. package/scripts/rules/reply-prose.ts +34 -0
  492. package/scripts/rules/repo-admin.ts +132 -0
  493. package/scripts/rules/reviewer-foreground.ts +88 -0
  494. package/scripts/rules/round-one-check-related.ts +120 -0
  495. package/scripts/rules/rule-body-guard.ts +5 -15
  496. package/scripts/rules/rule-value-cache.ts +53 -5
  497. package/scripts/rules/rule-value-candidates.ts +84 -0
  498. package/scripts/rules/rule-value-cli.ts +59 -11
  499. package/scripts/rules/rule-value.ts +17 -4
  500. package/scripts/rules/run-tail-rule.ts +1 -1
  501. package/scripts/rules/sed-in-place.ts +196 -0
  502. package/scripts/rules/shell-segments.ts +10 -2
  503. package/scripts/rules/stop-rule-rows.ts +1 -13
  504. package/scripts/rules/stop-rules.ts +33 -58
  505. package/scripts/rules/test-declared-commit.ts +1 -1
  506. package/scripts/rules/third-party-write.ts +110 -23
  507. package/scripts/rules/timed-rerun.ts +1 -1
  508. package/scripts/rules/turn-filings.ts +90 -0
  509. package/scripts/rules/worktree-guard.ts +22 -7
  510. package/scripts/run/board/run-board-ending-reason.ts +6 -2
  511. package/scripts/run/board/run-board-fit.ts +24 -1
  512. package/scripts/run/board/run-board-found.ts +134 -0
  513. package/scripts/run/board/run-board-header.ts +8 -0
  514. package/scripts/run/board/run-board-labels.ts +11 -1
  515. package/scripts/run/board/run-board-lane-time.ts +1 -0
  516. package/scripts/run/board/run-board-link.ts +15 -2
  517. package/scripts/run/board/run-board-notes.ts +7 -1
  518. package/scripts/run/board/run-board-operation.ts +4 -2
  519. package/scripts/run/board/run-board-phase.ts +2 -5
  520. package/scripts/run/board/run-board-plan.ts +1 -1
  521. package/scripts/run/board/run-board-read.ts +46 -1
  522. package/scripts/run/board/run-board-reason.ts +20 -8
  523. package/scripts/run/board/run-board-render-checks.ts +3 -2
  524. package/scripts/run/board/run-board-render-drawn.ts +11 -0
  525. package/scripts/run/board/run-board-render-found.ts +157 -0
  526. package/scripts/run/board/run-board-render-lead.ts +9 -0
  527. package/scripts/run/board/run-board-render-legend.ts +19 -0
  528. package/scripts/run/board/run-board-render-tail.ts +1 -1
  529. package/scripts/run/board/run-board-render.ts +82 -18
  530. package/scripts/run/board/run-board-spin.ts +1 -3
  531. package/scripts/run/board/run-board-status.ts +2 -0
  532. package/scripts/run/board/run-board-tick.ts +39 -10
  533. package/scripts/run/carry/run-carry-ended.ts +3 -2
  534. package/scripts/run/carry/run-carry.ts +3 -2
  535. package/scripts/run/cut/run-cut-cli.ts +33 -133
  536. package/scripts/run/cut/run-cut-digest.ts +152 -0
  537. package/scripts/run/cut/run-cut-handoff.ts +52 -8
  538. package/scripts/run/cut/run-cut-report.ts +24 -3
  539. package/scripts/run/cut/run-cut-resume.ts +129 -0
  540. package/scripts/run/cut/run-cut-review.ts +105 -0
  541. package/scripts/run/cut/run-cut.ts +18 -7
  542. package/scripts/run/detached-launch.ts +1 -1
  543. package/scripts/run/entry/run-entry-cli.ts +88 -19
  544. package/scripts/run/entry/run-entry-spill.ts +83 -0
  545. package/scripts/run/entry/run-entry-stop.ts +5 -1
  546. package/scripts/run/entry/run-entry-trust.ts +91 -0
  547. package/scripts/run/event/run-event-baseline.ts +56 -0
  548. package/scripts/run/event/run-event-filed.ts +9 -3
  549. package/scripts/run/event/run-event-overrun.ts +197 -0
  550. package/scripts/run/event/run-event-render.ts +4 -0
  551. package/scripts/run/event/run-event-stream.ts +25 -3
  552. package/scripts/run/hold/run-stop-notify.ts +3 -8
  553. package/scripts/run/merge/run-merge-cap.ts +57 -0
  554. package/scripts/run/merge/run-merge-cli.ts +66 -23
  555. package/scripts/run/merge/run-merge-outcome.ts +2 -0
  556. package/scripts/run/merge/run-merge-ship.ts +13 -3
  557. package/scripts/run/merge/run-merge-signals.ts +40 -23
  558. package/scripts/run/merge/run-merge-steps.ts +56 -36
  559. package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
  560. package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
  561. package/scripts/run/merge/run-merge.ts +41 -14
  562. package/scripts/run/review/run-review-cli.ts +306 -20
  563. package/scripts/run/review/run-review-early-push.ts +121 -0
  564. package/scripts/run/review/run-review-join-read.ts +94 -0
  565. package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
  566. package/scripts/run/review/run-review-pinned-join.ts +216 -0
  567. package/scripts/run/review/run-review-pinned-steps.ts +383 -0
  568. package/scripts/run/review/run-review-pinned-tree.ts +37 -0
  569. package/scripts/run/review/run-review-pinned.ts +53 -0
  570. package/scripts/run/review/run-review-steps.ts +70 -34
  571. package/scripts/run/review/run-review.ts +26 -6
  572. package/scripts/run/run-parent-cut-hook.ts +3 -4
  573. package/scripts/run/run-prep.ts +1 -0
  574. package/scripts/run/run-stage-read.ts +2 -6
  575. package/scripts/run/run-step-cli.ts +17 -5
  576. package/scripts/run/run-step-lane-plan.ts +27 -0
  577. package/scripts/run/run-step-section.ts +26 -7
  578. package/scripts/run/run-step.ts +5 -2
  579. package/scripts/run/ship/run-ship-args.ts +19 -0
  580. package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
  581. package/scripts/run/ship/run-ship-cli.ts +131 -39
  582. package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
  583. package/scripts/run/ship/run-ship-detach.ts +10 -4
  584. package/scripts/run/ship/run-ship-handover.ts +106 -0
  585. package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
  586. package/scripts/run/ship/run-ship-lap.ts +63 -0
  587. package/scripts/run/ship/run-ship-next.ts +27 -26
  588. package/scripts/run/ship/run-ship-overlap.ts +8 -3
  589. package/scripts/run/ship/run-ship-place.ts +9 -2
  590. package/scripts/run/ship/run-ship-planned.ts +92 -0
  591. package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
  592. package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
  593. package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
  594. package/scripts/run/ship/run-ship-preflight.ts +16 -4
  595. package/scripts/run/ship/run-ship-probe.ts +23 -9
  596. package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
  597. package/scripts/run/ship/run-ship-relaunch.ts +51 -0
  598. package/scripts/run/ship/run-ship-return.ts +103 -29
  599. package/scripts/run/ship/run-ship-review-reason.ts +24 -0
  600. package/scripts/run/ship/run-ship-review-steps.ts +230 -59
  601. package/scripts/run/ship/run-ship-review.ts +171 -51
  602. package/scripts/run/ship/run-ship-reviewer.ts +138 -42
  603. package/scripts/run/ship/run-ship-scoped.ts +39 -10
  604. package/scripts/run/ship/run-ship-stage.ts +49 -13
  605. package/scripts/run/ship/run-ship-steps.ts +24 -4
  606. package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
  607. package/scripts/run/ship/run-ship-stop-context.ts +50 -13
  608. package/scripts/run/ship/run-ship-sync.ts +171 -30
  609. package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
  610. package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
  611. package/scripts/run/ship/run-ship-waiter.ts +114 -0
  612. package/scripts/run/ship/run-ship.ts +16 -2
  613. package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
  614. package/scripts/run/wake/run-wake-cli.ts +6 -113
  615. package/scripts/run/wake/run-wake-code.ts +53 -11
  616. package/scripts/run/wake/run-wake-driver.ts +5 -3
  617. package/scripts/run/wake/run-wake-finish.ts +137 -0
  618. package/scripts/run/wake/run-wake-loop.ts +5 -3
  619. package/scripts/run/wake/run-wake-ports.ts +11 -3
  620. package/scripts/run/wake/run-wake-session.ts +2 -0
  621. package/scripts/run/wake/run-wake.ts +3 -2
  622. package/scripts/safe-chain/ci-installer-pin.ts +49 -8
  623. package/scripts/safe-chain/project-config.ts +3 -2
  624. package/scripts/security/secretlint-scan.ts +42 -9
  625. package/scripts/security/security-audit-provision-main.ts +9 -1
  626. package/scripts/security/security-audit-provision.ts +1 -1
  627. package/scripts/security/security-audit.ts +21 -1
  628. package/scripts/security/sonar-file.ts +10 -5
  629. package/scripts/split/split-assess.ts +12 -3
  630. package/scripts/split/split-early-notice.ts +116 -0
  631. package/scripts/split/split-measure.ts +20 -2
  632. package/scripts/split/split-resolution.ts +107 -0
  633. package/scripts/test/direct-importers.ts +185 -0
  634. package/scripts/test/pure-files-entries.ts +83 -0
  635. package/scripts/test/related-heavy-tests.ts +81 -0
  636. package/scripts/test/test-no-base.ts +88 -0
  637. package/scripts/test/test-pinned-cache-logic.ts +363 -0
  638. package/scripts/test/test-pinned-cache.ts +337 -0
  639. package/scripts/test/test-pinned-emit.ts +49 -0
  640. package/scripts/test/test-pinned-functions.ts +116 -0
  641. package/scripts/test/test-pinned-ledger.ts +80 -0
  642. package/scripts/test/test-pinned-logic.ts +208 -20
  643. package/scripts/test/test-pinned-main.ts +84 -18
  644. package/scripts/test/test-pinned-pool.ts +73 -0
  645. package/scripts/test/test-pinned-probe.ts +254 -0
  646. package/scripts/test/test-pinned-prune-logic.ts +118 -0
  647. package/scripts/test/test-pinned-reach.ts +194 -0
  648. package/scripts/test/test-pinned-record.ts +196 -0
  649. package/scripts/test/test-pinned-rewire.ts +148 -0
  650. package/scripts/test/test-pinned-spawn.ts +81 -0
  651. package/scripts/test/test-pinned-stage.ts +70 -0
  652. package/scripts/test/test-pinned.ts +258 -47
  653. package/scripts/test/test-reach-cli.ts +61 -0
  654. package/scripts/test/test-read-map.ts +35 -11
  655. package/scripts/test/test-read-recording.ts +17 -5
  656. package/scripts/test/test-read-trace.ts +26 -8
  657. package/scripts/test/test-red-logic.ts +46 -7
  658. package/scripts/test/test-red.ts +34 -14
  659. package/scripts/test/test-related-claim.ts +37 -0
  660. package/scripts/test/test-related-main.ts +4 -1
  661. package/scripts/test/test-related-moved.ts +91 -0
  662. package/scripts/test/test-related-record.ts +43 -23
  663. package/scripts/test/test-related-scope.ts +99 -34
  664. package/scripts/test/test-related-synced.ts +135 -0
  665. package/scripts/test/test-related-touched.ts +84 -0
  666. package/scripts/test/test-related.ts +167 -83
  667. package/scripts/test/test-unit-guard.ts +28 -5
  668. package/scripts/test/unit-durations.ts +41 -0
  669. package/scripts/test/unit-worker-share.ts +5 -4
  670. package/scripts/test/vitest-cache-directory.ts +19 -0
  671. package/scripts/test/vitest-cli-excludes.ts +14 -0
  672. package/scripts/test/vitest-failure-summary.ts +111 -0
  673. package/scripts/test/whole-suite-files.ts +12 -1
  674. package/scripts/time-runtime/time-batch-guard.ts +42 -4
  675. package/scripts/time-runtime/time-bundle-call.ts +1 -1
  676. package/scripts/time-runtime/time-bundles.ts +36 -5
  677. package/scripts/time-runtime/time-markers.ts +2 -2
  678. package/scripts/time-runtime/time-search-call.ts +38 -0
  679. package/scripts/time-runtime/time-shell.ts +1 -1
  680. package/scripts/time-runtime/time-transcript-line.ts +17 -5
  681. package/scripts/version/development-engines-verdict.ts +124 -0
  682. package/scripts/version/latest-corepack.ts +2 -0
  683. package/templates/gitignore +2 -0
  684. package/templates/workflows/ci.yml +41 -0
  685. package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
  686. package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
  687. package/dist/hooks/chunk-TUIFS5E7.js +0 -72
  688. package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
  689. package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
  690. package/scripts/rules/filing-cap.ts +0 -139
@@ -1,4 +1,7 @@
1
+ import { gh_author_association, type AuthorFields } from '#scripts/gh/gh-author-association'
1
2
  import { git_gh_command } from '#scripts/gh/git-gh-command'
3
+ import { parse_json_object_or_undefined } from '#scripts/git/parse-json-array'
4
+ import { z } from 'zod'
2
5
 
3
6
  // One text written to an issue: **into the body when the body is blank, as a comment otherwise.**
4
7
  // Two writers make this decision — `followup`'s completion notice and `issue:plan`'s plan — and a copy
@@ -6,6 +9,11 @@ import { git_gh_command } from '#scripts/gh/git-gh-command'
6
9
  //
7
10
  // A body that could not be read is not blank: overwriting a body nobody saw could erase a person's
8
11
  // text, so an unreadable body falls to a comment, which loses nothing.
12
+ //
13
+ // **A blank body filed by an author without write access is not written into either**
14
+ // (joshuafolkken/kit#4663). Readers judge a body by the issue's author, not by who last edited it, so
15
+ // a trusted `kickoff` plan written there would read as untrusted text, and `run:entry` — which waits
16
+ // for a trusted comment on such an issue — would never see the plan it waits for.
9
17
 
10
18
  type Destination = 'body' | 'comment'
11
19
 
@@ -14,15 +22,41 @@ interface PostOutcome {
14
22
  url: string
15
23
  }
16
24
 
17
- function is_blank_body(body: string | undefined): boolean {
25
+ const BODY_FIELDS = `body,${gh_author_association.AUTHOR_FIELDS}`
26
+
27
+ const body_schema = z.looseObject({
28
+ body: z.string().nullish(),
29
+ ...gh_author_association.author_fields_schema,
30
+ })
31
+
32
+ function is_blank_body(body: string | null | undefined): boolean {
18
33
  return body?.trim().length === 0
19
34
  }
20
35
 
36
+ // The write-access lookup asks *this* repository's collaborators, which says nothing about access to
37
+ // another one — so an issue elsewhere is asked with no login, which `trust_of` answers for `OWNER`
38
+ // alone (the rule `auto-ok-author.ts` applies to an epic child in another repository).
39
+ async function is_author_trusted(row: AuthorFields, repo?: string): Promise<boolean> {
40
+ const author = gh_author_association.author_of(row)
41
+
42
+ return await gh_author_association.is_trusted(
43
+ repo === undefined ? author : { ...author, login: undefined },
44
+ )
45
+ }
46
+
47
+ // Whether the body is blank *and* its author has write access — a failed read is neither.
48
+ async function is_writable_body(issue_number: string, repo?: string): Promise<boolean> {
49
+ const json = await git_gh_command.issue_view_json(issue_number, BODY_FIELDS, repo)
50
+ const parsed = json === undefined ? undefined : parse_json_object_or_undefined(json, body_schema)
51
+
52
+ if (parsed === undefined || !is_blank_body(parsed.body ?? '')) return false
53
+
54
+ return await is_author_trusted(parsed, repo)
55
+ }
56
+
21
57
  // `repo` (`owner/name`) addresses an issue in another repository; left out, the checkout's own.
22
58
  async function post(issue_number: string, text: string, repo?: string): Promise<PostOutcome> {
23
- const current_body = await git_gh_command.issue_get_body(issue_number, repo)
24
-
25
- if (is_blank_body(current_body)) {
59
+ if (await is_writable_body(issue_number, repo)) {
26
60
  const url = await git_gh_command.issue_edit_body(issue_number, text, repo)
27
61
 
28
62
  return { destination: 'body', url }
@@ -129,8 +129,7 @@ function read_targets(args: ReadonlyArray<string>): ReadonlyArray<CiteTarget> |
129
129
  return parse_targets(parsed.positionals, parsed.values.repo)
130
130
  }
131
131
 
132
- // The lines `issue:cite` prints for `args`, without printing them — the `Stop` hook shows them itself
133
- // (`stop-actions.ts`). `undefined` for a line nobody can read.
132
+ // The lines `issue:cite` prints for `args`, or `undefined` for a line nobody can read.
134
133
  async function cite(args: ReadonlyArray<string>): Promise<CiteReport | undefined> {
135
134
  const targets = read_targets(args)
136
135
  if (targets === undefined) return undefined
@@ -159,7 +158,6 @@ async function run(args: ReadonlyArray<string>): Promise<number> {
159
158
 
160
159
  const issue_cite_cli = {
161
160
  USAGE,
162
- cite,
163
161
  parse_targets,
164
162
  run,
165
163
  }
@@ -56,6 +56,7 @@ function problems(body: string): ReadonlyArray<string> {
56
56
  bug_classification_problem(body),
57
57
  label_conflict(body),
58
58
  defect_origin_line.problem(body),
59
+ defect_origin_line.reproduction_problem(body),
59
60
  ]
60
61
 
61
62
  return found.filter((problem) => problem !== undefined)
@@ -88,6 +88,13 @@ async function read_closing_pr(issue: string): Promise<string | undefined> {
88
88
  }
89
89
  }
90
90
 
91
- const issue_closing_pr = { read_closing_pr }
91
+ // The closing pull request's number, read off the URL `read_closing_pr` answers.
92
+ async function read_closing_number(issue: number): Promise<number | undefined> {
93
+ const url = await read_closing_pr(String(issue))
94
+
95
+ return url === undefined ? undefined : Number(url.slice(url.lastIndexOf('/') + 1))
96
+ }
97
+
98
+ const issue_closing_pr = { read_closing_number, read_closing_pr }
92
99
 
93
100
  export { issue_closing_pr }
@@ -94,7 +94,9 @@ async function run(argv: ReadonlyArray<string>, exit: EvidenceExit): Promise<num
94
94
  : FAILURE_EXIT_CODE
95
95
  }
96
96
 
97
- const issue_evidence_exit = { run }
97
+ // The writes alone, for evidence composed in process — `backlog:drive`'s measured close
98
+ // (`backlog-measure-close.ts`), which holds no tree of the issue's, so there is nothing to release.
99
+ const issue_evidence_exit = { run, write: write_exit }
98
100
 
99
- export type { EvidenceExit }
101
+ export type { EvidenceExit, EvidenceRequest }
100
102
  export { issue_evidence_exit }
@@ -0,0 +1,58 @@
1
+ import { run_hold_member } from '#scripts/run/hold/run-hold-member'
2
+ import { issue_file_fold } from './issue-file-fold'
3
+ import { session_cite } from './session-cite'
4
+
5
+ // The automatic-filing cap, asked by `josh issue:file` itself as the fold and the WIP cap are.
6
+ //
7
+ // **Ten filings per originating work item, refused at the eleventh** (joshuafolkken/kit#4750). The
8
+ // origin is the fold's finder — the `--found-during` the filing names, else the lane child's mark, else
9
+ // the Issue the checkout's branch names — so a lane's filings, a long lane the parent investigated and
10
+ // the Issue a prerequisite came out of are each their own count. The count is the origin's `filed`
11
+ // events on the repository's event stream, read whole, so it outlives a session cut; a transcript tail
12
+ // counted every origin a long session touched against one ceiling and forgot each filing once it
13
+ // scrolled out (joshuafolkken/kit#2119).
14
+ //
15
+ // **Only a run's filings are automatic**: the cap holds in a run's session — a lane child or the
16
+ // hold's owner — and counts the filings marked as a run's, so a person filing from their own session
17
+ // is the further Issue the refusal leaves to them. **A filing with no origin counts against the
18
+ // invocation running** — the carry record's scope the fold reads for it too — so a retrospective's or a
19
+ // parent's own filings share one count per run. **A failed filing never counts**: `issue:file` appends
20
+ // its `filed` event only once the Issue exists.
21
+
22
+ const FILING_CAP = 10
23
+
24
+ // How many Issues the origin has already filed from a run.
25
+ async function prior_count(origin: string | undefined): Promise<number> {
26
+ const events = await issue_file_fold.events_of(origin)
27
+
28
+ return issue_file_fold.finder_filings(events, origin).filter((filed) => filed.is_run === true)
29
+ .length
30
+ }
31
+
32
+ function owner_of(origin: string | undefined): string {
33
+ return origin === undefined ? 'this run (no originating Issue)' : session_cite.issue(origin)
34
+ }
35
+
36
+ function reason_of(origin: string | undefined): string {
37
+ return (
38
+ `✖ filing cap: ${owner_of(origin)} has already filed ${String(FILING_CAP)} Issues, the ceiling ` +
39
+ "per originating work item. Stop filing and report; a further Issue is a person's to file from " +
40
+ 'their own session (`.claude/skills/workflow-commands/prerequisite.md`).'
41
+ )
42
+ }
43
+
44
+ // Whether the filing may go on: `false`, with the reason printed, once a run's filing finds its
45
+ // origin's count at the cap — this filing would be the eleventh.
46
+ async function is_cap_clear(named: string | undefined): Promise<boolean> {
47
+ if (!(await run_hold_member.is_run_member())) return true
48
+ const origin = await issue_file_fold.finder(named)
49
+
50
+ if ((await prior_count(origin)) < FILING_CAP) return true
51
+ console.error(reason_of(origin))
52
+
53
+ return false
54
+ }
55
+
56
+ const issue_file_cap = { FILING_CAP, is_cap_clear, reason_of }
57
+
58
+ export { issue_file_cap }
@@ -8,6 +8,7 @@ import { git_gh_exec } from '#scripts/gh/git-gh-exec'
8
8
  import { git_gh_issue_list, MAX_SCANNED } from '#scripts/gh/git-gh-issue-list'
9
9
  import { git_gh_issue_write } from '#scripts/gh/git-gh-issue-write'
10
10
  import { github_issue_url } from '#scripts/gh/github-issue-url'
11
+ import { lane_child_marker } from '#scripts/lane/lane-child-marker'
11
12
  import { error_text } from '#scripts/lib/error-message'
12
13
  import type { PollOptions } from '#scripts/lib/poll'
13
14
  import { repository_labels } from '#scripts/repo/repository-labels'
@@ -15,37 +16,48 @@ import { run_event_filed } from '#scripts/run/event/run-event-filed'
15
16
  import { run_event_stream } from '#scripts/run/event/run-event-stream'
16
17
  import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
17
18
  import { run_hold_member } from '#scripts/run/hold/run-hold-member'
19
+ import { split_resolution } from '#scripts/split/split-resolution'
18
20
  import { issue_auto_ok } from './issue-auto-ok'
19
21
  import { issue_cite } from './issue-cite'
20
22
  import { issue_file, type FileArguments } from './issue-file'
23
+ import { issue_file_cap } from './issue-file-cap'
24
+ import { issue_file_deferral } from './issue-file-deferral'
21
25
  import { issue_file_fold } from './issue-file-fold'
26
+ import { issue_file_interrupt } from './issue-file-interrupt'
27
+ import { issue_file_lane_hint } from './issue-file-lane-hint'
22
28
  import { issue_lint_cli } from './issue-lint-cli'
23
29
  import { issue_priority } from './issue-priority'
24
30
  import { issue_release_cli } from './issue-release-cli'
31
+ import { issue_sample_required } from './issue-sample-required'
25
32
  import { issue_sample_source } from './issue-sample-source'
26
33
  import { issue_scout_cli } from './issue-scout-cli'
27
34
  import { issue_wip } from './issue-wip'
35
+ import { size_estimate } from './size-estimate'
28
36
 
29
37
  // `josh issue:file "<title>" --body-file <path> [--route <route>] [--label <name>]…
30
- // [--repo <owner/repo>] [--distinct <N,…>] [--over-cap] [--no-auto-ok] [--release]` — file an Issue
31
- // with every filing step run in order: the third-party refusal, the body
32
- // lint, the `## Origin` check for another repository, the `auto-ok` decision
33
- // with the run label it owes, the start condition read as a pull request, the fold question against
34
- // the run's earlier
35
- // filings, the WIP cap count, the
36
- // duplicate scout, the missing workflow labels created, the create call
37
- // carrying every label, the release link on `--release`, and `epic:bundle`.
38
+ // [--repo <owner/repo>] [--distinct <N,…>] [--found-during <N>] [--over-cap] [--no-auto-ok]
39
+ // [--release] [--blocks-finder]` — file an Issue with every filing step run: the third-party refusal,
40
+ // the filing cap per origin and the fold question against the run's earlier filings, each ending the
41
+ // filing on its own; then, each tier printing every refusal of its own at once, the local checks —
42
+ // the body lint, the size estimate against the split guide, the start condition a measurement
43
+ // follow-up owes, the `## Origin` check for another repository, the `auto-ok` decision with the run
44
+ // label it owes; once those pass, the start condition read as a pull request and the WIP cap count;
45
+ // once those pass, the duplicate scout; then the missing workflow labels created, the create call
46
+ // carrying every label, a blocking interrupt's finder recorded as blocked by it, the release link on
47
+ // `--release`, and `epic:bundle`.
38
48
  // A direct `gh api …/issues` filing is refused by the `direct-filing` delivered rule and pointed here.
39
49
 
40
50
  const SUCCESS_EXIT_CODE = 0
41
51
  const FAILURE_EXIT_CODE = 1
42
52
  const ARGV_OFFSET = 2
43
53
  const USAGE =
44
- 'Usage: josh issue:file "<title>" --body-file <path> [--route <tier-a|split|interrupt|review-cap>] [--label <name>]… [--repo <owner/repo>] [--distinct <N,…>] [--over-cap] [--no-auto-ok] [--release]'
54
+ 'Usage: josh issue:file "<title>" --body-file <path> [--route <tier-a|split|interrupt|review-cap>] [--label <name>]… [--repo <owner/repo>] [--distinct <N,…>] [--found-during <N>] [--over-cap] [--no-auto-ok] [--release] [--blocks-finder]'
45
55
  const UNKNOWN_REPO_MESSAGE =
46
56
  'Could not read this repository from `git remote`, so the filing has no repository to compare against — check `gh auth status`.'
47
57
  const THIRD_PARTY_MESSAGE =
48
58
  '✖ third-party target: a tracker we do not own is Tier C — draft the Issue for a person to post instead (`CLAUDE.md` → "Third-party repositories are Tier C").'
59
+ const UNKNOWN_PARTY_MESSAGE =
60
+ '✖ unknown party: the owner of this session or of the target could not be read (`git remote` / `--repo`), so the target is not known to be ours — check `pnpm josh repo:party`.'
49
61
  // `GH_REPO` is the variable `gh` reads `{owner}/{repo}` from, so setting it points every listing the
50
62
  // scout and `epic:bundle` make at the target repository rather than at this checkout.
51
63
  const GH_REPO_VARIABLE = 'GH_REPO'
@@ -68,18 +80,22 @@ async function read_body(path: string): Promise<string | undefined> {
68
80
  }
69
81
  }
70
82
 
71
- function is_third_party(target: string): boolean {
83
+ // An owner that cannot be read is refused like a third party — stricter than the `third-party-write`
84
+ // hook, which stays silent on `unknown`: a filing is admitted only when the target is known to be ours.
85
+ function party_refusal(target: string): string | undefined {
72
86
  const party = repo_party.classify(repo_party.current_owner(), repo_party.target_owner(target))
73
87
 
74
- return party === repo_party.THIRD_PARTY
88
+ if (party === repo_party.FIRST_PARTY) return undefined
89
+
90
+ return party === repo_party.THIRD_PARTY ? THIRD_PARTY_MESSAGE : UNKNOWN_PARTY_MESSAGE
75
91
  }
76
92
 
77
- // Every refusal the filing can meet before a request is sent, in the order the steps run — `[]` when
78
- // the filing may go on to the scout.
93
+ // Every refusal the body and the arguments carry, read locally — `[]` when the body is admitted.
79
94
  function refusals_of(filing: Filing): ReadonlyArray<string> {
80
- if (is_third_party(filing.target)) return [THIRD_PARTY_MESSAGE]
81
95
  const problems = [
82
96
  ...issue_lint_cli.problems(filing.body),
97
+ size_estimate.guide_problem(filing.body, filing.args.route),
98
+ issue_sample_required.problem(filing.body),
83
99
  issue_auto_ok.declaration_problem(filing.body),
84
100
  issue_priority.problem(filing.body, filing.args.labels),
85
101
  issue_file.origin_problem(filing.body, filing.target, filing.current),
@@ -143,7 +159,8 @@ async function is_scout_clear(filing: Filing): Promise<boolean> {
143
159
 
144
160
  if (outcome === undefined) return false
145
161
  console.info(outcome.report)
146
- const open = issue_file.unacknowledged(outcome.candidates, filing.args.distinct)
162
+ const answered = issue_file.acknowledged(filing.args, filing.target, filing.current)
163
+ const open = issue_file.unacknowledged(outcome.candidates, answered)
147
164
 
148
165
  if (open.length > 0) console.error(unacknowledged_message(open))
149
166
 
@@ -151,8 +168,8 @@ async function is_scout_clear(filing: Filing): Promise<boolean> {
151
168
  }
152
169
 
153
170
  // Every label the create call carries, or `undefined` when an `auto-ok` filing names neither run label.
154
- // Decided before the WIP count and the scout, so a refusal costs no listing. The decision reads the
155
- // labels the body's declarations add, so a declared breaking change is excluded like its label.
171
+ // The decision reads the labels the body's declarations add, so a declared breaking change is excluded
172
+ // like its label.
156
173
  function labels_of(filing: Filing): ReadonlyArray<string> | undefined {
157
174
  const auto_ok = issue_auto_ok.decide({
158
175
  is_opted_out: filing.args.is_auto_ok_opted_out,
@@ -229,33 +246,60 @@ async function place(url: string, target: string): Promise<void> {
229
246
 
230
247
  // Every filing lands on the run's event stream: this is the one filing path, so
231
248
  // one append here reaches `run:board` from every route. A filing outside a run lands too, unmarked as
232
- // the run's (`run_hold_member`), and the board counts only the marked ones; the append is best-effort,
233
- // as every emit is.
249
+ // the run's (`run_hold_member`), and the board counts only the marked ones; a lane's overrun
250
+ // investigation marks its own, which the board draws after 🔍; the append is best-effort, as every emit is.
251
+ async function emit_filed(
252
+ reference: string,
253
+ filing: Filing,
254
+ labels: ReadonlyArray<string>,
255
+ found_during: string | undefined,
256
+ ): Promise<void> {
257
+ const kind = run_event_filed.kind_of(labels)
258
+ const is_run = await run_hold_member.is_run_member()
259
+ const is_overrun = lane_child_marker.is_overrun()
260
+ const { title } = filing.args
261
+ const text = run_event_filed.text_of({ reference, kind, title, found_during, is_run, is_overrun })
262
+
263
+ await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.FILED, text)
264
+ }
265
+
234
266
  async function record(url: string, filing: Filing, labels: ReadonlyArray<string>): Promise<void> {
235
267
  const number = String(issue_number_of(url))
236
268
  const reference = issue_cite.plain(
237
269
  number,
238
270
  issue_file_fold.reference_prefix(filing.target, filing.current),
239
271
  )
240
- const found_during = await issue_file_fold.finder()
241
- const kind = run_event_filed.kind_of(labels)
242
- const is_run = await run_hold_member.is_run_member()
243
- const { title } = filing.args
244
- const text = run_event_filed.text_of({ reference, kind, title, found_during, is_run })
272
+ const found_during = await issue_file_fold.finder(filing.args.found_during)
245
273
 
246
- await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.FILED, text)
274
+ await emit_filed(reference, filing, labels, found_during)
275
+ await issue_file_deferral.note_finder({
276
+ found_during: filing.args.found_during,
277
+ reference,
278
+ title: filing.args.title,
279
+ current: filing.current,
280
+ })
281
+ await split_resolution.record_child({ route: filing.args.route, found_during, child: reference })
282
+ await issue_file_interrupt.block_finder({
283
+ route: filing.args.route,
284
+ is_blocking_finder: filing.args.is_blocking_finder,
285
+ found_during,
286
+ blocker: issue_number_of(url),
287
+ is_here: issue_file.is_same_repository(filing.target, filing.current),
288
+ })
247
289
  }
248
290
 
249
- function is_admitted(filing: Filing): boolean {
291
+ async function is_admitted(filing: Filing): Promise<boolean> {
250
292
  const refusals = refusals_of(filing)
251
293
 
252
294
  if (refusals.length === 0) return true
253
- console.error(refusals.join('\n'))
295
+ const hint = await issue_file_lane_hint.lines_of(filing.args.found_during, filing.body)
296
+
297
+ console.error([...refusals, ...hint].join('\n'))
254
298
 
255
299
  return false
256
300
  }
257
301
 
258
- // The start condition's citation read against GitHub — after the local refusals, before any listing.
302
+ // The start condition's citation read against GitHub.
259
303
  async function is_source_clear(filing: Filing): Promise<boolean> {
260
304
  const is_here = issue_file.is_same_repository(filing.target, filing.current)
261
305
  const problem = await issue_sample_source.problem(
@@ -281,23 +325,46 @@ async function send(filing: Filing, labels: ReadonlyArray<string>): Promise<numb
281
325
  return SUCCESS_EXIT_CODE
282
326
  }
283
327
 
284
- // The holds that read the run and the backlog, in the order they cost: the fold reads the local event
285
- // stream and diff, the WIP count one listing, the scout a search.
286
- async function is_clear(filing: Filing): Promise<boolean> {
328
+ // The holds that end the filing whatever the body says, read first: the filing cap reads the local
329
+ // event stream, the fold the stream and diff.
330
+ async function is_run_clear(filing: Filing): Promise<boolean> {
287
331
  const prefix = issue_file_fold.reference_prefix(filing.target, filing.current)
288
332
 
289
- if (!(await issue_file_fold.is_fold_clear(prefix, filing.args))) return false
333
+ return (
334
+ (await issue_file_cap.is_cap_clear(filing.args.found_during)) &&
335
+ (await issue_file_fold.is_fold_clear(prefix, filing.args))
336
+ )
337
+ }
338
+
339
+ // Every step the caller answers from the body and the arguments, cheapest first, each tier's refusals
340
+ // printed at once and fixed in one reissue: the local checks (the body's own refusals and the run
341
+ // label) before anything asks GitHub, then the start condition's citation and the WIP count, then the
342
+ // duplicate scout's search, run only once nothing else refuses. The labels, or `undefined` when any refused.
343
+ async function labels_in_one_pass(filing: Filing): Promise<ReadonlyArray<string> | undefined> {
344
+ const is_body_clear = await is_admitted(filing)
345
+ const labels = labels_of(filing)
346
+
347
+ if (!is_body_clear || labels === undefined) return undefined
348
+ const verdicts = [await is_source_clear(filing), await is_wip_clear(filing)]
290
349
 
291
- return (await is_wip_clear(filing)) && (await is_scout_clear(filing))
350
+ if (!verdicts.every(Boolean)) return undefined
351
+
352
+ return (await is_scout_clear(filing)) ? labels : undefined
292
353
  }
293
354
 
294
355
  async function file(filing: Filing): Promise<number> {
295
- if (!is_admitted(filing) || !(await is_source_clear(filing))) return FAILURE_EXIT_CODE
296
- const labels = labels_of(filing)
356
+ const party_problem = party_refusal(filing.target)
297
357
 
298
- if (labels === undefined || !(await is_clear(filing))) return FAILURE_EXIT_CODE
358
+ if (party_problem !== undefined) {
359
+ console.error(party_problem)
299
360
 
300
- return await send(filing, labels)
361
+ return FAILURE_EXIT_CODE
362
+ }
363
+
364
+ if (!(await is_run_clear(filing))) return FAILURE_EXIT_CODE
365
+ const labels = await labels_in_one_pass(filing)
366
+
367
+ return labels === undefined ? FAILURE_EXIT_CODE : await send(filing, labels)
301
368
  }
302
369
 
303
370
  async function filing_of(args: FileArguments): Promise<Filing | string> {
@@ -336,7 +403,13 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
336
403
  process.exitCode = await run(argv)
337
404
  }
338
405
 
339
- const issue_file_cli = { FRESH_ISSUE_POLL, THIRD_PARTY_MESSAGE, record, run }
406
+ const issue_file_cli = {
407
+ FRESH_ISSUE_POLL,
408
+ THIRD_PARTY_MESSAGE,
409
+ UNKNOWN_PARTY_MESSAGE,
410
+ record,
411
+ run,
412
+ }
340
413
 
341
414
  if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
342
415
 
@@ -0,0 +1,52 @@
1
+ import { git_gh_issue_write } from '#scripts/gh/git-gh-issue-write'
2
+ import { shell_quote } from '#scripts/lib/shell-quote'
3
+ import { session_cite } from './session-cite'
4
+
5
+ // What `josh issue:file --found-during <N>` leaves on #N: one comment, `NOTE_PREFIX <filed> <title>`, so
6
+ // the deferral is read wherever #N is read. The run event alone reached neither `issue:read <N>` nor the
7
+ // ship reviewer's brief, so the reviewer raised the deferred gap again as a Medium and the ship
8
+ // stopped on scope the lane had already filed away (joshuafolkken/kit#4821). `review-rubric.md` →
9
+ // "Stop conditions" is the rule that reads the note.
10
+ //
11
+ // Only a finder the filing names is noted — a finder inferred from the lane mark or the branch is the
12
+ // run's, not a declared deferral. The finder is an Issue in this repository, so the comment is posted
13
+ // to `current` even when `GH_REPO` points the filing's listings at another target. The Issue already
14
+ // exists, so a failed comment is reported rather than failed, for the reason `issue-file-cli.ts` →
15
+ // `place` gives.
16
+
17
+ const NOTE_PREFIX = '先送り:'
18
+
19
+ interface Deferral {
20
+ found_during: string | undefined
21
+ reference: string
22
+ title: string
23
+ current: string
24
+ }
25
+
26
+ function note_of(deferral: Deferral): string {
27
+ return `${NOTE_PREFIX} ${deferral.reference} ${deferral.title}`
28
+ }
29
+
30
+ function failure_line(finder: number, note: string): string {
31
+ const rerun = `pnpm josh issue:comment ${String(finder)} --body ${shell_quote.single_quoted(note)}`
32
+
33
+ return `⚠ the deferral note did not reach ${session_cite.issue(finder)} — run \`${rerun}\`.`
34
+ }
35
+
36
+ async function note_finder(deferral: Deferral): Promise<void> {
37
+ const finder = Number(deferral.found_during)
38
+
39
+ if (!Number.isSafeInteger(finder) || finder <= 0) return
40
+ const note = note_of(deferral)
41
+ const is_noted = await git_gh_issue_write.issue_try_comment(
42
+ String(finder),
43
+ note,
44
+ deferral.current,
45
+ )
46
+
47
+ if (!is_noted) console.error(failure_line(finder, note))
48
+ }
49
+
50
+ const issue_file_deferral = { NOTE_PREFIX, note_finder }
51
+
52
+ export { issue_file_deferral }
@@ -28,6 +28,7 @@ const CLOSED_STATE = 'CLOSED'
28
28
  interface FoldArguments {
29
29
  route: string | undefined
30
30
  distinct: ReadonlyArray<number>
31
+ found_during: string | undefined
31
32
  }
32
33
 
33
34
  function number_of(reference: string): number {
@@ -55,10 +56,12 @@ async function branch_issue(): Promise<number | undefined> {
55
56
  }
56
57
  }
57
58
 
58
- // Whose work turned the finding up: the lane child's mark, else the Issue the checkout's branch names,
59
- // so a person's `fullrun` on `3423-x` is one finder across its filings just as a lane child is. A
60
- // checkout on no Issue's branch — a `backlogrun` parent on `main` — has none.
61
- async function finder(): Promise<string | undefined> {
59
+ // Whose work turned the finding up: the `--found-during` the filing named, else the lane child's mark,
60
+ // else the Issue the checkout's branch names, so a person's `fullrun` on `3423-x` is one finder across
61
+ // its filings just as a lane child is. A checkout on no Issue's branch — a `backlogrun` parent on
62
+ // `main` — has none unless the filing names one.
63
+ async function finder(named?: string): Promise<string | undefined> {
64
+ if (named !== undefined) return named
62
65
  const marked = lane_child_marker.marked_issue()
63
66
 
64
67
  if (marked !== undefined) return marked
@@ -76,6 +79,17 @@ async function events_of(found_during: string | undefined): Promise<ReadonlyArra
76
79
  return await run_event_stream_emit.all_events()
77
80
  }
78
81
 
82
+ // The finder's filings on the events, in every repository.
83
+ function finder_filings(
84
+ events: ReadonlyArray<RunEvent>,
85
+ found_during: string | undefined,
86
+ ): ReadonlyArray<Filed> {
87
+ return events
88
+ .filter((event) => event.kind === run_event_stream.EVENT_KIND.FILED)
89
+ .flatMap((event) => run_event_filed.parse(event.text) ?? [])
90
+ .filter((filed) => filed.found_during === found_during)
91
+ }
92
+
79
93
  // This run's earlier filings by the same finder — so a parallel lane's filing is never what this one
80
94
  // folds into — in the repository this filing targets. One the caller named in `--distinct` has been
81
95
  // declared a separate deliverable and is left out, the same declaration the scout's candidates take.
@@ -85,10 +99,8 @@ function prior_filings(
85
99
  prefix: string,
86
100
  distinct: ReadonlyArray<number>,
87
101
  ): ReadonlyArray<Filed> {
88
- return events
89
- .filter((event) => event.kind === run_event_stream.EVENT_KIND.FILED)
90
- .flatMap((event) => run_event_filed.parse(event.text) ?? [])
91
- .filter((filed) => filed.found_during === found_during && prefix_of(filed.reference) === prefix)
102
+ return finder_filings(events, found_during)
103
+ .filter((filed) => prefix_of(filed.reference) === prefix)
92
104
  .filter((filed) => !distinct.includes(number_of(filed.reference)))
93
105
  }
94
106
 
@@ -136,7 +148,7 @@ function held_message(priors: ReadonlyArray<Filed>): string {
136
148
  // exempt, as it is from the WIP cap: the split assessment already decided it is a separate deliverable.
137
149
  async function is_fold_clear(prefix: string, args: FoldArguments): Promise<boolean> {
138
150
  if (args.route === SPLIT_ROUTE_LABEL) return true
139
- const found_during = await finder()
151
+ const found_during = await finder(args.found_during)
140
152
  const filings = prior_filings(await events_of(found_during), found_during, prefix, args.distinct)
141
153
  const priors = await open_filings(filings, prefix)
142
154
 
@@ -150,6 +162,13 @@ async function is_fold_clear(prefix: string, args: FoldArguments): Promise<boole
150
162
  return verdict !== issue_fold.FOLD
151
163
  }
152
164
 
153
- const issue_file_fold = { finder, is_fold_clear, prior_filings, reference_prefix }
165
+ const issue_file_fold = {
166
+ events_of,
167
+ finder,
168
+ finder_filings,
169
+ is_fold_clear,
170
+ prior_filings,
171
+ reference_prefix,
172
+ }
154
173
 
155
174
  export { issue_file_fold }
@@ -0,0 +1,85 @@
1
+ import { epic_relations } from '#scripts/epic/epic-relations'
2
+ import { git_gh_api_path } from '#scripts/gh/git-gh-api-path'
3
+ import { INTERRUPT_ROUTE_LABEL } from './issue-labels'
4
+ import { session_cite } from './session-cite'
5
+
6
+ // What `josh issue:file` just filed on `--route interrupt --blocks-finder`: the Issue whose work turned
7
+ // the defect up is recorded as blocked by it, in the same command as the filing — so a session that
8
+ // dies after the filing still leaves the dispatch a relation that keeps the finder back until the
9
+ // interrupt lands (`upstream-interrupt.md` → the run-machinery case). An interrupt that blocks nobody
10
+ // (`wip-cap.md` → the three conditions) omits the flag, since a relation there is a false dependency.
11
+ // Written through the relation path epic creation and `epic --add` use, and only for a filing in this
12
+ // repository: the relation write resolves both numbers here.
13
+ //
14
+ // The Issue already exists, so a failed write is reported rather than failed, for the reason
15
+ // `issue-file-cli.ts` → `place` gives.
16
+
17
+ interface InterruptFiling {
18
+ route: string | undefined
19
+ is_blocking_finder: boolean
20
+ found_during: string | undefined
21
+ blocker: number
22
+ is_here: boolean
23
+ }
24
+
25
+ function is_issue_number(value: number): boolean {
26
+ return Number.isSafeInteger(value) && value > 0
27
+ }
28
+
29
+ function finder_of(filing: InterruptFiling): number | undefined {
30
+ if (filing.route !== INTERRUPT_ROUTE_LABEL || !filing.is_here) return undefined
31
+ const finder = Number(filing.found_during)
32
+
33
+ return is_issue_number(finder) ? finder : undefined
34
+ }
35
+
36
+ // An explicit `--blocks-finder` that records nothing is said, so the caller does not read the
37
+ // silence as a recorded relation and leave the finder dispatchable.
38
+ function ignored_line(filing: InterruptFiling): string {
39
+ const reason =
40
+ filing.route === INTERRUPT_ROUTE_LABEL
41
+ ? 'no finder and filed Issue pair in this repository was read'
42
+ : 'it applies to `--route interrupt` only'
43
+
44
+ return `⚠ --blocks-finder recorded nothing: ${reason}.`
45
+ }
46
+
47
+ // The re-run writes the one relation and nothing else — no epic placement and no chain splice, which
48
+ // would record dependencies the interrupt does not have.
49
+ function failure_line(blocked: number, blocker: number): string {
50
+ const path = git_gh_api_path.blocked_by_api_path(String(blocked))
51
+ const id = `$(gh api ${git_gh_api_path.issue_api_path(String(blocker))} --jq .id)`
52
+ const cited = `${session_cite.issue(blocked)} could not be recorded as blocked by ${session_cite.issue(blocker)}`
53
+
54
+ return `⚠ ${cited} — run \`gh api ${path} -F issue_id=${id}\`.`
55
+ }
56
+
57
+ async function record(blocked: number, blocker: number): Promise<void> {
58
+ const links = [{ blocked, blocker }]
59
+ const failures = await epic_relations.apply_relations(links, 'record')
60
+
61
+ if (failures === 0) {
62
+ console.info(epic_relations.format_relation_report({ links, failures, action: 'record' }))
63
+
64
+ return
65
+ }
66
+
67
+ console.error(failure_line(blocked, blocker))
68
+ }
69
+
70
+ async function block_finder(filing: InterruptFiling): Promise<void> {
71
+ if (!filing.is_blocking_finder) return
72
+ const blocked = finder_of(filing)
73
+
74
+ if (blocked === undefined || !is_issue_number(filing.blocker)) {
75
+ console.warn(ignored_line(filing))
76
+
77
+ return
78
+ }
79
+
80
+ await record(blocked, filing.blocker)
81
+ }
82
+
83
+ const issue_file_interrupt = { block_finder }
84
+
85
+ export { issue_file_interrupt }