@joshuafolkken/kit 1.1455.0 → 1.1471.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 (211) hide show
  1. package/.claude/skills/dependency-update/SKILL.md +26 -55
  2. package/.claude/skills/epic-commands/SKILL.md +87 -148
  3. package/.claude/skills/epic-commands/epic-bundle.md +45 -77
  4. package/.claude/skills/epic-commands/execution-waves.md +44 -81
  5. package/.claude/skills/verify-ui/SKILL.md +25 -50
  6. package/.claude/skills/workflow-commands/background-commands.md +36 -47
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +72 -85
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +91 -121
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +73 -117
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +7 -9
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +11 -20
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +43 -52
  13. package/.claude/skills/workflow-commands/chain-rule.md +24 -34
  14. package/.claude/skills/workflow-commands/followup.md +57 -76
  15. package/.claude/skills/workflow-commands/issue-comments.md +43 -60
  16. package/.claude/skills/workflow-commands/kickoff.md +65 -74
  17. package/.claude/skills/workflow-commands/observation-filing.md +62 -107
  18. package/.claude/skills/workflow-commands/observation-ledger.md +56 -111
  19. package/.claude/skills/workflow-commands/pre-gate-cut.md +89 -138
  20. package/.claude/skills/workflow-commands/prerequisite.md +10 -15
  21. package/.claude/skills/workflow-commands/progress-watcher.md +21 -26
  22. package/.claude/skills/workflow-commands/retrospective.md +31 -50
  23. package/.claude/skills/workflow-commands/split-assessment.md +34 -58
  24. package/.claude/skills/workflow-commands/working-tree-hold.md +54 -71
  25. package/CLAUDE.md +6 -5
  26. package/dist/CLAUDE.md +6 -5
  27. package/dist/hooks/batch-guard.js +6 -6
  28. package/dist/hooks/{chunk-7WQBPLUN.js → chunk-43ZHT22P.js} +31 -15
  29. package/dist/hooks/{chunk-LIAFCXL7.js → chunk-AS74OU3D.js} +23 -7
  30. package/dist/hooks/{chunk-3C4XRYG6.js → chunk-E7OIKX5Z.js} +17 -12
  31. package/dist/hooks/{chunk-Z4XI7CZS.js → chunk-EUMACUK2.js} +18 -12
  32. package/dist/hooks/{chunk-WNLVGT7E.js → chunk-H5HVWYXK.js} +4 -4
  33. package/dist/hooks/{chunk-HHI6FO3R.js → chunk-IIGFYXKC.js} +345 -240
  34. package/dist/hooks/{chunk-GPLGZ6IC.js → chunk-J47HU5H5.js} +14 -3
  35. package/dist/hooks/{chunk-OLMO72ON.js → chunk-K4EOONYM.js} +1 -1
  36. package/dist/hooks/{chunk-D5QBTOCZ.js → chunk-K4LMBQC2.js} +4 -4
  37. package/dist/hooks/{chunk-TBJFTSUY.js → chunk-KC5AK2GF.js} +8 -6
  38. package/dist/hooks/chunk-SHGPANFB.js +56 -0
  39. package/dist/hooks/{chunk-5H4SSDSD.js → chunk-YHBZAJSV.js} +3 -3
  40. package/dist/hooks/{chunk-HFGWYGUV.js → chunk-YYPI7SJZ.js} +5 -5
  41. package/dist/hooks/codex-hook-adapter.js +13 -13
  42. package/dist/hooks/duplicate-read-guard.js +7 -7
  43. package/dist/hooks/format-edited.js +3 -3
  44. package/dist/hooks/inputs.json +216 -214
  45. package/dist/hooks/investigation-guard.js +7 -7
  46. package/dist/hooks/pretool-guard.js +12 -12
  47. package/dist/hooks/session-lang.js +6 -5
  48. package/dist/hooks/stop-guard.js +18 -14
  49. package/dist/josh.js +5 -6
  50. package/dist/managed-marker/index.js +1 -2
  51. package/dist/version/index.js +15 -12
  52. package/eslint/base.js +2 -1
  53. package/eslint/rules/unicorn.js +16 -0
  54. package/package.json +3 -3
  55. package/prompts/coding-standards.md +12 -22
  56. package/prompts/collaboration-workflow/file-edits.md +26 -44
  57. package/prompts/collaboration-workflow/gh-rest.md +20 -36
  58. package/prompts/collaboration-workflow/glossary.md +5 -7
  59. package/prompts/collaboration-workflow/issue-citation.md +7 -13
  60. package/prompts/collaboration-workflow/issue-template.md +29 -29
  61. package/prompts/collaboration-workflow/operating-rules.md +35 -44
  62. package/prompts/collaboration-workflow/output-bounds.md +15 -15
  63. package/prompts/collaboration-workflow/overview.md +14 -19
  64. package/prompts/collaboration-workflow/plan-comment.md +13 -13
  65. package/prompts/collaboration-workflow/principles.md +50 -53
  66. package/prompts/collaboration-workflow/proposal-request.md +1 -9
  67. package/prompts/collaboration-workflow/report-format.md +32 -49
  68. package/prompts/collaboration-workflow/residency.md +10 -10
  69. package/prompts/collaboration-workflow/rule-delivery.md +9 -9
  70. package/prompts/collaboration-workflow/shell-body.md +10 -20
  71. package/prompts/collaboration-workflow/turn-batching.md +8 -14
  72. package/prompts/collaboration-workflow/upstream-interrupt.md +26 -34
  73. package/prompts/collaboration-workflow/wip-cap.md +24 -30
  74. package/prompts/collaboration-workflow.md +24 -25
  75. package/prompts/refactoring.md +33 -43
  76. package/prompts/review-rubric.md +84 -129
  77. package/prompts/review.md +111 -141
  78. package/prompts/sonar-hotspot-handling.md +22 -50
  79. package/prompts/testing-guide.md +48 -99
  80. package/scripts/adopt/adopt-toolkits.ts +2 -4
  81. package/scripts/agent/agent-exit-record.ts +23 -1
  82. package/scripts/agent/codex-agent-argv.ts +7 -2
  83. package/scripts/backlog/backlog-budget-cli.ts +1 -2
  84. package/scripts/backlog/backlog-drive-carried.ts +26 -0
  85. package/scripts/backlog/backlog-drive-cli.ts +10 -5
  86. package/scripts/backlog/backlog-drive-named.ts +2 -4
  87. package/scripts/backlog/backlog-drive-restore.ts +19 -1
  88. package/scripts/backlog/backlog-drive-seats.ts +27 -0
  89. package/scripts/backlog/backlog-drive.ts +11 -6
  90. package/scripts/backlog/backlog-ready.ts +13 -6
  91. package/scripts/behavior/behavior-rules.ts +3 -2
  92. package/scripts/cost-runtime/codex-usage.ts +4 -2
  93. package/scripts/cost-runtime/cost-cli.ts +1 -2
  94. package/scripts/delegation/investigation-guard.ts +1 -1
  95. package/scripts/delegation/investigation-reads.ts +1 -1
  96. package/scripts/discovery/repo-discovery.ts +4 -2
  97. package/scripts/discovery/repo-origin.ts +2 -4
  98. package/scripts/doctor/doctor-logic.ts +6 -3
  99. package/scripts/document/document-byte-budget.ts +27 -27
  100. package/scripts/document/document-byte-check.ts +1 -2
  101. package/scripts/document/entry-read-budget.ts +2 -2
  102. package/scripts/epic/epic-audit-rationale.ts +8 -2
  103. package/scripts/epic/epic-bundle-cli.ts +1 -2
  104. package/scripts/epic/epic-chains.ts +6 -2
  105. package/scripts/epic/epic-close-comment.ts +1 -2
  106. package/scripts/gate/verification-gate.ts +7 -2
  107. package/scripts/gh/git-pr.ts +6 -2
  108. package/scripts/git/git-common-directory.ts +3 -3
  109. package/scripts/git/git-diff-reads.ts +16 -9
  110. package/scripts/git/git-execa-error.ts +1 -2
  111. package/scripts/hooks/format-edited-file.ts +10 -4
  112. package/scripts/hooks/pre-push-unit.ts +15 -4
  113. package/scripts/hooks/pretool-guard.ts +23 -29
  114. package/scripts/hooks/step-zero-notice.ts +3 -2
  115. package/scripts/init/hook-command-rewrite.ts +6 -2
  116. package/scripts/init/init-logic-deploy-vps.ts +4 -2
  117. package/scripts/issue/behavior-change-lint.ts +12 -6
  118. package/scripts/issue/issue-scout-cli.ts +3 -2
  119. package/scripts/josh/file-map-stamp.ts +1 -3
  120. package/scripts/josh/hook-decision.ts +17 -2
  121. package/scripts/lane/lane-await.ts +3 -2
  122. package/scripts/lane/lane-child-invocation.ts +14 -1
  123. package/scripts/lane/lane-guard-policy.ts +4 -4
  124. package/scripts/lane/lane-ledger.ts +9 -0
  125. package/scripts/lane/lane-load.ts +9 -2
  126. package/scripts/lane/lane-measure-cli.ts +2 -0
  127. package/scripts/lane/lane-parked.ts +18 -0
  128. package/scripts/lane/lane-process-load.ts +125 -0
  129. package/scripts/lane/lane-process-stats.ts +93 -0
  130. package/scripts/lane/lane-registry.ts +8 -3
  131. package/scripts/lane/lane-session-broker.ts +29 -5
  132. package/scripts/lane/lane-spent.ts +14 -3
  133. package/scripts/lane/lane-stats.ts +1 -0
  134. package/scripts/managed-marker/managed-marker-logic.ts +1 -2
  135. package/scripts/overrides/lockfile-overrides.ts +1 -3
  136. package/scripts/propagate/propagate.ts +1 -2
  137. package/scripts/release/release-progress.ts +3 -2
  138. package/scripts/report/report-lint.ts +7 -4
  139. package/scripts/review/review-record-cli.ts +6 -2
  140. package/scripts/rules/destructive-command.ts +6 -9
  141. package/scripts/rules/direct-filing.ts +3 -7
  142. package/scripts/rules/early-heartbeat.ts +7 -18
  143. package/scripts/rules/file-body.ts +6 -13
  144. package/scripts/rules/filing-cap.ts +3 -6
  145. package/scripts/rules/git-force.ts +5 -9
  146. package/scripts/rules/implementation-cut.ts +37 -35
  147. package/scripts/rules/index-guard.ts +4 -7
  148. package/scripts/rules/issue-comments.ts +5 -15
  149. package/scripts/rules/josh-git-bare.ts +3 -6
  150. package/scripts/rules/lane-background.ts +10 -21
  151. package/scripts/rules/lane-carry-conflict.ts +7 -17
  152. package/scripts/rules/lane-interactive-ask.ts +6 -11
  153. package/scripts/rules/lane-park.ts +5 -13
  154. package/scripts/rules/lane-split-park.ts +2 -7
  155. package/scripts/rules/lane-switch-main.ts +9 -12
  156. package/scripts/rules/oracle-consulted.ts +4 -5
  157. package/scripts/rules/piped-verification.ts +81 -31
  158. package/scripts/rules/poll-loop.ts +7 -17
  159. package/scripts/rules/pre-gate-cut.ts +7 -21
  160. package/scripts/rules/prior-comment-read.ts +7 -5
  161. package/scripts/rules/protected-files.ts +5 -9
  162. package/scripts/rules/raw-field-body.ts +3 -7
  163. package/scripts/rules/rule-body-guard.ts +4 -11
  164. package/scripts/rules/run-tail-rule.ts +6 -22
  165. package/scripts/rules/shell-body-trigger.ts +4 -6
  166. package/scripts/rules/shell-segments.ts +7 -0
  167. package/scripts/rules/stop-rules.ts +16 -29
  168. package/scripts/rules/test-declared-commit.ts +4 -10
  169. package/scripts/rules/third-party-write.ts +5 -10
  170. package/scripts/rules/worktree-guard.ts +5 -12
  171. package/scripts/run/board/run-board-github.ts +11 -3
  172. package/scripts/run/board/run-board-idle.ts +31 -0
  173. package/scripts/run/board/run-board-read.ts +9 -12
  174. package/scripts/run/board/run-board-reason.ts +7 -3
  175. package/scripts/run/board/run-board-state.ts +4 -0
  176. package/scripts/run/board/run-board-status.ts +18 -3
  177. package/scripts/run/board/run-board-thanks.ts +7 -2
  178. package/scripts/run/board/run-board-tick.ts +32 -7
  179. package/scripts/run/carry/run-carry-args.ts +1 -3
  180. package/scripts/run/carry/run-carry-conversation.ts +7 -2
  181. package/scripts/run/cut/run-cut-cli.ts +15 -20
  182. package/scripts/run/cut/run-cut-decline.ts +72 -0
  183. package/scripts/run/cut/run-cut-ready.ts +74 -0
  184. package/scripts/run/cut/run-cut-report.ts +13 -0
  185. package/scripts/run/cut/run-cut.ts +10 -1
  186. package/scripts/run/hold/run-hold-cli.ts +14 -3
  187. package/scripts/run/hold/run-hold.ts +6 -3
  188. package/scripts/run/merge/run-merge-cli.ts +30 -7
  189. package/scripts/run/merge/run-merge-ship.ts +59 -1
  190. package/scripts/run/merge/run-merge.ts +3 -2
  191. package/scripts/run/run-ending.ts +31 -3
  192. package/scripts/run/run-parent-cut-hook.ts +5 -10
  193. package/scripts/run/run-preflight.ts +1 -2
  194. package/scripts/run/run-stop-notify.ts +1 -2
  195. package/scripts/run/run-watcher-guard.ts +6 -3
  196. package/scripts/run/ship/run-ship-review-steps.ts +13 -4
  197. package/scripts/run/ship/run-ship-review.ts +15 -2
  198. package/scripts/run/tidy/run-tidy-cli.ts +3 -3
  199. package/scripts/run/tidy/run-tidy-lanes.ts +3 -2
  200. package/scripts/safe-chain/project-config.ts +7 -2
  201. package/scripts/sync/sync-hook-safety.ts +8 -2
  202. package/scripts/test/unit-worker-share.ts +3 -2
  203. package/scripts/time-runtime/time-batch-guard.ts +3 -3
  204. package/scripts/time-runtime/time-hook-transcript.ts +3 -2
  205. package/scripts/time-runtime/time-shell.ts +10 -0
  206. package/scripts/version/effective-upstream.ts +3 -4
  207. package/scripts/version/kit-version-config.ts +8 -2
  208. package/scripts/version/latest-corepack.ts +1 -2
  209. package/scripts/version/release-hold.ts +11 -4
  210. package/scripts/version/version-commands.ts +12 -4
  211. package/dist/hooks/chunk-UT7YC3N2.js +0 -56
@@ -1,14 +1,21 @@
1
1
  # `backlogrun` — lanes and concurrency
2
2
 
3
- Point-of-use, read one section at a time from `backlogrun.md` → "The route table".
3
+ Point-of-use, read one section at a time from `backlogrun.md` → "The route table". Reasons:
4
+
5
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Why the lane ceiling is shaped the way it is"
6
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Why CI concurrency is capped by the lane limit"
7
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Why a lane's review needs a brief and an attestation"
8
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Why the lane branch is `<N>-lane` and never switched"
9
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Why lanes cost as well as buy throughput"
10
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Why `lane:launch` folds the lane steps into one"
11
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Why a committed child's lane is kept"
12
+ - `docs/maintainers/backlogrun-lanes-rationale.md` → "Where each rule came from"
4
13
 
5
14
  ## Concurrency: as many children per repository as it has free lanes
6
15
 
7
- **One session per repository**, each running only its own repository's children; the per-repository
8
- lane ceiling (`JOSH_LANE_LIMIT`, counted from the `in-progress` listing by `epic:next`) is
9
- `.claude/skills/epic-commands/SKILL.md` → "An `in-progress` issue occupies a lane", and a dependency that crosses a
10
- repository is `.claude/skills/epic-commands/SKILL.md` → "Epics that span repositories". Rationale:
11
- `docs/maintainers/backlogrun-lanes-rationale.md` → "Why the lane ceiling is shaped the way it is".
16
+ **One session per repository**, each running only its own repository's children. The lane ceiling is
17
+ `.claude/skills/epic-commands/SKILL.md` → "An `in-progress` issue occupies a lane"; a dependency that
18
+ crosses a repository is `.claude/skills/epic-commands/SKILL.md` → "Epics that span repositories".
12
19
 
13
20
  ## A solo run
14
21
 
@@ -19,65 +26,50 @@ it a defect (not an improvement, refactor, removal or feature)? Is it in kit's o
19
26
  (lint / type check / spell check / unit tests), the code review, the pre-push hook, or the merge
20
27
  checks — not a consumer repository's CI or template? Does it, on `main` now, make unrelated PRs
21
28
  answer wrongly (a false green or a false red)? All three, and the issue carries `run:solo`; any one
22
- missing, and it carries `run:lane`. `backlog:next` and `epic:next --lanes` answer `triage` for an issue
23
- with neither, so an issue a run files carries one of the two from its
24
- filing. **It stops the other lanes for one reason only: a batch run on broken verification leaves
25
- nobody's result trustworthy.** This section is the rule's single source; rationale:
26
- `docs/maintainers/wip-cap-rationale.md` → "Why a solo run"; provenance:
27
- `docs/maintainers/backlogrun-lanes-rationale.md` → "Where each rule came from".
29
+ missing, and it carries `run:lane`. `backlog:next` and `epic:next --lanes` answer `triage` for an
30
+ issue with neither, so a filed issue carries one of the two from its filing. **It stops the other
31
+ lanes for one reason only: a batch run on broken verification leaves nobody's result trustworthy.**
32
+ This section is the rule's single source; why: `docs/maintainers/wip-cap-rationale.md` → "Why a solo run".
28
33
 
29
34
  ## Lanes — running more than one child at a time
30
35
 
31
- `pnpm josh epic:next <E> --repo <owner/repo> --lanes` answers with **one issue number per line**, up to
32
- the number of free lanes, and each of those children runs in a **lane** of its own: a linked git work
33
- tree with its own branch, its own `.env` and its own dev and preview ports (`docs/josh-commands-run.md` →
34
- "`josh lane:open` / `josh lane:close` / `josh lane:list` / `josh lane:prune`"). **Implementation, the
35
- verification gate and the review run in parallel; the merges stay serial** — each one lands on the
36
- `main` the next is then measured against.
37
-
38
- **A lane child may cut its own turn before the gate.** Implementation done, it ends its process and a
39
- fresh one resumes the same lane from the gate onward — the boundary, the two commands and the resume
40
- verification are `pre-gate-cut.md`, the single source. **The child is told apart from a person, and its
41
- resume stage is handed to it, by a mark the dispatch sets** — `JOSH_LANE_CHILD`, the lane's issue
42
- number (`pre-gate-cut.md` → "The dispatch mark" and "The stage is passed to the resumed child").
43
-
44
- **A lane's review does not inherit the lane, and `pnpm josh review:brief` is what closes that.**
45
- `pnpm josh review:brief` prints the lane's absolute root, branch and HEAD, hands over targets written
46
- `git -C <root> …`, and prints a nonce the review attests with `pnpm josh review:attest <nonce>` from
47
- the checkout it actually read. **The child asks `pnpm josh review:attest --check` before it counts a
48
- round**, and `pnpm josh followup` asks again before it merges; `missing` and `mismatch` are both
49
- refusals. A clean round is the case to check hardest, not the case to skip the check on. Rationale:
50
- `docs/maintainers/backlogrun-lanes-rationale.md` → "Why a lane's review needs a brief and an
51
- attestation".
52
-
53
- **A lane's branch is `<N>-lane`, and the issue number leads it so that the commit path accepts it.**
54
- **Never switch the lane to another branch** — a switched lane loses its seat, its listing and its
55
- isolation. So `epic:next` is asked **with** `--lanes`, and everything below runs as written. Rationale:
56
- `docs/maintainers/backlogrun-lanes-rationale.md` → "Why the lane branch is `<N>-lane` and never
57
- switched".
58
-
59
- **Report the throughput gain only with its merge-race cost** — every overlap that becomes a conflict
60
- costs a resolution, a re-run gate and a review (`backlogrun-recovery.md` → "Conflicts are not predicted"). Rationale:
61
- `docs/maintainers/backlogrun-lanes-rationale.md` → "Why lanes cost as well as buy throughput".
36
+ `pnpm josh epic:next <E> --repo <owner/repo> --lanes` answers **one issue number per line**, up to the
37
+ free lanes. Each child runs in a **lane**: a linked work tree with its own branch, `.env` and ports
38
+ (`docs/josh-commands-run.md` → "`josh lane:open` / `josh lane:close` / `josh lane:list` / `josh
39
+ lane:prune`"). **Implementation, the verification gate and the review run in parallel; the merges
40
+ stay serial.**
41
+
42
+ **A lane child may cut its own turn before the gate** — `pre-gate-cut.md`, the single source. The
43
+ child is told apart from a person, and handed its resume stage, by `JOSH_LANE_CHILD`
44
+ (`pre-gate-cut.md` → "The dispatch mark" and "The stage is passed to the resumed child").
45
+
46
+ **A lane's review does not inherit the lane, and `pnpm josh review:brief` is what closes that**: it
47
+ prints the lane's root, branch and HEAD, targets written `git -C <root> …`, and a nonce the review
48
+ attests with `pnpm josh review:attest <nonce>`. **The child asks `pnpm josh review:attest --check`
49
+ before it counts a round**, and `pnpm josh followup` asks again before merging; `missing` and
50
+ `mismatch` are refusals. A clean round is checked hardest.
51
+
52
+ **A lane's branch is `<N>-lane`. Never switch the lane to another branch** — it loses its seat,
53
+ listing and isolation. So `epic:next` is asked **with** `--lanes`.
54
+
55
+ **Report the throughput gain only with its merge-race cost** (`backlogrun-recovery.md` → "Conflicts
56
+ are not predicted").
62
57
 
63
58
  ### Once per repository, before the first lane opens
64
59
 
65
- In the **primary checkout**, in this order, never again per lane: `pnpm josh ms`; `pnpm josh
66
- latest:scope` and the update on `required` (`backlogrun-child.md` → "`josh latest` runs once per
67
- session, not once per child"); `pnpm josh lane:prune`; `pnpm josh run:tidy`.
60
+ In the **primary checkout**, in order, never per lane: `pnpm josh ms`; `pnpm josh latest:scope` and the
61
+ update on `required` (`backlogrun-child.md` → "`josh latest` runs once per session, not once per
62
+ child"); `pnpm josh lane:prune`; `pnpm josh run:tidy`.
68
63
 
69
- **The rewritten lock file reaches a pull request through the first lane.** In the primary checkout,
70
- only if the update rewrote anything, `git stash push -u -m "backlogrun: josh latest before lanes"`, and
71
- record it on that first child's Issue. **The first lane's `pnpm josh lane:launch "$n" --stash
72
- "backlogrun: josh latest before lanes"` pops it by message** — never a positional `stash pop` on the
73
- shared stack. **Under `backlog:drive` the driver passes `--stash`, never you**; the push stays the
74
- parent's, before the driver starts.
64
+ **The rewritten lock file reaches a pull request through the first lane.** Only if the update rewrote
65
+ anything: `git stash push -u -m "backlogrun: josh latest before lanes"` in the primary checkout, and
66
+ record it on the first child's Issue. **The first lane's `pnpm josh lane:launch "$n" --stash
67
+ "backlogrun: josh latest before lanes"` pops it by message** — never a positional `stash pop`. **Under
68
+ `backlog:drive` the driver passes `--stash`, never you**; the push stays the parent's.
75
69
 
76
70
  ### Opening one lane and dispatching its child
77
71
 
78
- **One command opens the lane, prepares it, and dispatches the child — `pnpm josh lane:launch`** (over
79
- `lane:open`, `stash:pop` and `lane:dispatch`, each guard unchanged; rationale:
80
- `docs/maintainers/backlogrun-lanes-rationale.md` → "Why `lane:launch` folds the lane steps into one"):
72
+ **One command opens the lane, prepares it, and dispatches the child — `pnpm josh lane:launch`**:
81
73
 
82
74
  ```bash
83
75
  pid=$(pnpm josh lane:launch "$n") || exit 1 # the child's pid on stdout, nothing else
@@ -90,93 +82,71 @@ pid=$(pnpm josh lane:launch "$n") || exit 1 # the child's pid on stdout, nothi
90
82
  | empty, non-zero, `already-open` or a failed install | **Park that child and name `pnpm josh lane:close <N>`** — a lock the lane cannot build is a person's to fix |
91
83
  | `lane:open` reports a reused `<N>-lane` on stderr | The way back to a child parked after it pushed — **a reused branch is not a fresh lane** |
92
84
 
93
- **Nothing switches the lane's branch.** In a lane `lane:open`'s answer replaces `pnpm josh run:hold`'s
94
- preflight, and the child claims `run:hold` inside the lane, keyed on its own git directory.
85
+ **Nothing switches the lane's branch.** In a lane, `lane:open`'s answer replaces `pnpm josh
86
+ run:hold`'s preflight; the child claims `run:hold` inside the lane.
95
87
 
96
88
  ### Handing the child over
97
89
 
98
- The child runs as `fullrun #<N>` in that lane, and neither `josh latest` nor a progress watcher is
99
- started there. Everything else — the plan, the gate, `/code-review`, `pnpm josh git`,
100
- `pnpm josh followup` — is unchanged, and `pnpm josh followup` releases that lane's hold at the merge.
101
-
102
- **The child is started as a process of its own, not as a subagent of this session** — `lane:launch`'s
103
- final step, the `lane:dispatch` it runs after the lane is opened and prepared, whose pid it returns.
104
- The bullets below describe that dispatch:
105
-
106
- - **It records where the child writes as it starts it** — the dispatch's own
107
- `<temp>/josh-lane-dispatch-<N>.log`.
108
- - **A refusal is an empty capture beside a non-zero exit**, and every refusal also sends a `warning`
109
- Telegram — no lane open, a path that could not be recorded, a launch that failed. **Park that child
110
- and name the log the message carries**; do not re-dispatch into the same lane without reading it.
111
- - **A child that started with nowhere to write exits zero and warns.** The launcher starts the session
112
- even when it could not open the log, so the child really is running. **Poll that lane on the process
113
- trace alone**, because its log will never grow.
114
- - **The child is started as `fullrun #<N>` with the lane as its working directory.** The batch a
115
- person approved by typing `backlogrun` covers the child.
116
- - **It passes `--permission-mode bypassPermissions`, never `--dangerously-skip-permissions`.** A
117
- current Claude Code ignores the mode `.claude/settings.json` declares, and a new lane worktree is
118
- never a trusted workspace; that file's `deny` list still refuses what it names, so the run reports
119
- what stopped rather than loosening it.
90
+ The child runs as `fullrun #<N>` in that lane, with neither `josh latest` nor a progress watcher.
91
+ Everything else is unchanged; `pnpm josh followup` releases the lane's hold at the merge.
92
+
93
+ **The child is started as a process of its own, not as a subagent of this session** (`lane:dispatch`,
94
+ `lane:launch`'s final step):
95
+
96
+ - **It records where the child writes** — `<temp>/josh-lane-dispatch-<N>.log`.
97
+ - **A refusal is an empty capture beside a non-zero exit**, with a `warning` Telegram. **Park that
98
+ child and name the log the message carries**; never re-dispatch into the same lane without reading it.
99
+ - **A child that started with nowhere to write exits zero and warns** — **poll that lane on the
100
+ process trace alone**.
101
+ - **The child is started as `fullrun #<N>` with the lane as its working directory**; the typed
102
+ `backlogrun` covers it.
103
+ - **It passes `--permission-mode bypassPermissions`, never `--dangerously-skip-permissions`.**
104
+ `.claude/settings.json`'s `deny` list still refuses what it names; report what stopped, never loosen it.
120
105
 
121
106
  **Start each child without blocking on it, and poll them all** — a silent one is
122
- `backlogrun-recovery.md` → "A delegated unit that stopped without reporting", read in that child's
123
- lane.
107
+ `backlogrun-recovery.md` → "A delegated unit that stopped without reporting", read in that child's lane.
124
108
 
125
- **`pnpm josh ms` is the parent's now, not the child's.** No lane can switch to the
126
- default branch, so the refresh moves to the primary checkout **before each `lane:open`** — the ref the
127
- lane is cut from.
109
+ **`pnpm josh ms` is the parent's now, not the child's** — run it in the primary checkout **before
110
+ each `lane:open`**.
128
111
 
129
112
  ### Conflicts are not predicted
130
113
 
131
114
  **A child whose pull request conflicts with `main` resolves it in its own lane rather than stopping** —
132
- read `backlogrun-recovery.md` → "Conflicts are not predicted" when `pnpm josh followup` reports the
133
- conflict.
115
+ read `backlogrun-recovery.md` → "Conflicts are not predicted" when `pnpm josh followup` reports it.
134
116
 
135
117
  ### What happens to a lane
136
118
 
137
119
  | When | The lane | Why |
138
120
  | --- | --- | --- |
139
- | The child **merged** | `pnpm josh lane:close <N>` | `followup` released the hold and the branch is on `main`; nothing in that tree is wanted |
140
- | The child was **parked before its commit** | **Left open**, its uncommitted work in place, its directory and held seat recorded on the Issue | The stash stack is shared by every work tree, so a parallel lane can pop another's entry — the tree itself is the safe place for the work. `lane:close` is a **forced** removal that would take it. `pnpm josh lane:launch <N>` dispatches the released child into the kept lane rather than refusing it as `already-open` — only a lane a child was already dispatched into; a failed-install lane is still refused |
141
- | The child was **parked after its commit and push** | **Left open**, its directory and held seat recorded on the Issue | The tree is clean because committed. What `lane:close` would take is the **local branch**, which is the resume path |
142
- | The child hit a **merge conflict** | **Left open** — the resolution happens in it | The child resolves in place (`backlogrun-recovery.md` → "Conflicts are not predicted"). A park under that section's four conditions takes the row above |
143
- | The child stopped on **`needs-human-review`** | **Left open and untouched** | The uncommitted work *is* the artifact a person has to look at. Name the lane directory in the stop report and in the Telegram |
144
- | The child **failed** | Whichever of the two parked rows applies, plus the consecutive-failure count | Same reasoning; only the counter differs. **A merge conflict is not this row** — it takes the row above, and it is not counted |
145
- | **`lane:open` failed on the install** | `pnpm josh lane:close <N>`, then park the child | A lane exists that no `pnpm josh …` runs in and the next `lane:open` answers `already-open`. Closing frees the seat; parking is right because the cause is one a person fixes. Carry pnpm's reason into the park note |
146
- | The lane is **spent** — no child working in it, its Issue closed, not one this run launched and has not collected with `run:merge`, a clean tree, no commit that is on no remote | Nothing to do — `pnpm josh lane:prune` closes it | Nothing in it is wanted, so no one has to type the close. Any other lane is kept and `lane:prune` says why on standard error |
147
- | The run was **interrupted** | Nothing to do — the work tree survives on disk | The next session's `pnpm josh lane:prune` closes what git no longer has a tree for. **Park that child**, naming the lane and `pnpm josh lane:close <N>` as the way out |
148
-
149
- **A lane closed after a push is reopened by `pnpm josh lane:open <N>`**, which attaches to a local
150
- `<N>-lane` or creates one from `origin/<N>-lane`, saying on standard error which it reused. **The branch
151
- still has to have reached the remote for that to hold** — a child parked before its commit has nothing
152
- on `origin`, which is why that row keeps its lane open rather than closing it. Rationale:
153
- `docs/maintainers/backlogrun-lanes-rationale.md` → "Why a committed child's lane is kept".
121
+ | The child **merged** | `pnpm josh lane:close <N>` | Nothing in that tree is wanted |
122
+ | The child was **parked before its commit** | **Left open**, its uncommitted work in place, its directory and held seat recorded on the Issue | The shared stash stack is unsafe; `lane:close` is a **forced** removal. `pnpm josh lane:launch <N>` re-dispatches into the kept lane (a failed-install lane is still refused) |
123
+ | The child was **parked after its commit and push** | **Left open**, its directory and held seat recorded on the Issue | `lane:close` would take the **local branch**, the resume path |
124
+ | The child hit a **merge conflict** | **Left open** — the resolution happens in it | `backlogrun-recovery.md` → "Conflicts are not predicted"; a park there takes the row above |
125
+ | The child stopped on **`needs-human-review`** | **Left open and untouched** | The uncommitted work is what a person looks at. Name the lane directory in the stop report and Telegram |
126
+ | The child **failed** | Whichever of the two parked rows applies, plus the consecutive-failure count | **A merge conflict is not this row**, and is not counted |
127
+ | **`lane:open` failed on the install** | `pnpm josh lane:close <N>`, then park the child | Frees the seat; a person fixes the cause. Carry pnpm's reason into the park note |
128
+ | The lane is **spent** — no child working in it, its Issue closed, not one this run launched and has not collected with `run:merge`, a clean tree, no commit that is on no remote | Nothing to do — `pnpm josh lane:prune` closes it | Any other lane is kept, with the reason on standard error |
129
+ | The run was **interrupted** | Nothing to do — the work tree survives on disk | **Park that child**, naming the lane and `pnpm josh lane:close <N>` |
130
+
131
+ **A lane closed after a push is reopened by `pnpm josh lane:open <N>`** (a local `<N>-lane`, or one
132
+ from `origin/<N>-lane`). A child parked before its commit has nothing on `origin`, so its lane stays open.
154
133
 
155
134
  **Which row a child takes is decided by what `followup` printed, not by reading the situation.** **What
156
- it prints is `PR checks failed (merge conflict)`** — that string is what reaches you;
157
- `mergeStateStatus: DIRTY` is the internal spelling `git-pr-checks-eval.ts` compares against, never an
158
- output line to search for. That string sends the child to resolve the conflict in the lane it is
159
- standing in. Do not grep the output for `mergeable_state`: that is the REST field name, normalized away
160
- before anything prints it.
135
+ it prints is `PR checks failed (merge conflict)`** — resolve in the lane. Never search for
136
+ `mergeStateStatus: DIRTY` or `mergeable_state`; neither is printed.
161
137
 
162
138
  **A kept lane holds its seat. Say it in the park comment**: the lane directory, that its seat is held,
163
- and `pnpm josh lane:close <N>` as the way to give it back.
139
+ and `pnpm josh lane:close <N>` to give it back.
164
140
 
165
- **Release the hold on either parked arm, and leave the lane before closing it.** `pnpm josh followup`
166
- releases the working-tree hold at the **merge**, so a parked child's is still held: run
167
- `pnpm josh run:release <N>` in the lane — **a release names the run it belongs to**, and the child's own
168
- number is what that record carries. **A `needs-human-review` stop is not a park and keeps its hold.**
169
- `lane:close` does not release the hold for you — the record is keyed to the work tree's git directory,
170
- so removing the tree strands it. And `cd` out of the lane **before** `pnpm josh lane:close <N>`: the
171
- close removes the directory the shell is sitting in.
141
+ **Release the hold on either parked arm, and leave the lane before closing it**: `pnpm josh
142
+ run:release <N>` in the lane (**a release names the run it belongs to**); `lane:close` does not
143
+ release it. `cd` out of the lane **before** `pnpm josh lane:close <N>`. **A `needs-human-review` stop is
144
+ not a park and keeps its hold.**
172
145
 
173
- **A `needs-human-review` stop ends the run, and the lanes already in flight are allowed to finish.** No
174
- new lane is opened, and no unit is killed mid-gate. When the others have merged or parked, report and
175
- stop.
146
+ **A `needs-human-review` stop ends the run, and the lanes already in flight are allowed to finish** —
147
+ no new lane opens, no unit is killed mid-gate; then report and stop.
176
148
 
177
149
  ### CI concurrency
178
150
 
179
- **`JOSH_LANE_LIMIT` lowers the ceiling with no code** when CI jobs start to queue. Whether queueing
180
- bites is read from the multi-day backlog timing report — a `checks-wait` that grows with the lane count
181
- is the queueing. Rationale: `docs/maintainers/backlogrun-lanes-rationale.md` → "Why CI concurrency is
182
- capped by the lane limit".
151
+ **`JOSH_LANE_LIMIT` lowers the ceiling with no code** when CI jobs queue — a `checks-wait` growing
152
+ with the lane count in the backlog timing report.
@@ -1,99 +1,79 @@
1
1
  # `backlogrun` — a child that cannot finish
2
2
 
3
3
  **Read this file in full when a child cannot finish** — before parking it, before a
4
- `needs-human-review` stop, or before recording a mid-run prerequisite or split. It is a point-of-use
5
- document, never an entry read: the entry procedure is `backlogrun.md`, which points here at that
6
- moment. This file is the single source of park-and-continue, the
7
- `needs-human-review` stop, a stale `in-progress`, a prerequisite discovered mid-run, and a mid-run
8
- split. Provenance of each rule: `docs/maintainers/backlogrun-park-rationale.md` → "Where each rule came from".
4
+ `needs-human-review` stop, or before recording a mid-run prerequisite or split. Point-of-use, never an
5
+ entry read (`backlogrun.md` points here). Single source of park-and-continue, the `needs-human-review`
6
+ stop, a stale `in-progress`, a mid-run prerequisite and a mid-run split. Provenance:
7
+ `docs/maintainers/backlogrun-park-rationale.md` → "Where each rule came from".
9
8
 
10
9
  ## What happens to a child that cannot finish
11
10
 
12
- Nothing here is new, and nothing here is restated — a `backlogrun` child is a `fullrun` under a batch
13
- authorization, whether it came from a named epic or from the opted-in pool:
14
-
15
- - **A stop that would end the run parks one issue and the run continues** — → "park
16
- and continue", which is that rule's single source, including what happens to the issue's lane.
17
- - **A prerequisite discovered mid-run is recorded as a dependency rather than parked** —
18
- → "A prerequisite discovered mid-run", and `prerequisite.md` for the three-way
19
- distinction between a prerequisite, a split and an upstream defect. With no epic there is no
20
- `pnpm josh epic --add` to record the ordering into, so the `blocked-by` relation is written on the
21
- issue itself (step 3 below) — still a dependency, never a `needs-decision` park.
22
- - **A split found mid-run** files the children and the epic and does not stop the batch, because the
23
- keyword already authorized a batch — `split-assessment.md` for the assessment, → "Splitting a child
24
- mid-run" for the branch. The split child is not parked or counted as a failure; its new children
25
- remain available to the normal `backlog:next` / `epic:next` offer.
26
- - **`in-progress` left behind by an interrupted run** is → "`in-progress` is removed by
27
- whoever finds it stale".
11
+ A `backlogrun` child is a `fullrun` under a batch authorization:
12
+
13
+ - **A stop that would end the run parks one issue and the run continues** — → "park and continue".
14
+ - **A prerequisite discovered mid-run is recorded as a dependency rather than parked** — → "A
15
+ prerequisite discovered mid-run"; `prerequisite.md` separates prerequisite, split and upstream
16
+ defect. With no epic, the `blocked-by` is written on the issue itself.
17
+ - **A split found mid-run** files the children and the epic and does not stop the batch —
18
+ `split-assessment.md`, → "Splitting a child mid-run". Not a park, not a failure.
19
+ - **`in-progress` left behind by an interrupted run** — → "`in-progress` is removed by whoever finds
20
+ it stale".
28
21
  - **A child released from `needs-decision` is re-dispatched to a lane, never implemented by the
29
- parent.** The parent is an orchestrator: `backlogrun.md` → "Claim nothing at the entry — this
30
- parent orchestrates and never implements" is the single source, and "Removing the label
31
- is Tier A" below carries the re-dispatch itself. A released child takes a lane exactly as any batch child
32
- does.
22
+ parent** — `backlogrun.md` → "Claim nothing at the entry — this parent orchestrates and never
23
+ implements".
33
24
 
34
25
  ## The parent does not investigate a lane failure itself
35
26
 
36
27
  **A lane failure whose reason is not on its Issue is read by a unit** — `pnpm josh delegate
37
- lane-failure-investigation`; the parent checks the cited lines and
38
- `pnpm josh issue:state` before it parks, re-dispatches or files.
28
+ lane-failure-investigation`; the parent checks the cited lines and `pnpm josh issue:state` before it
29
+ parks, re-dispatches or files.
39
30
 
40
31
  ## `needs-human-review` — the one stop that is not a park
41
32
 
42
- A child carrying **`needs-human-review`** is degraded to a `halfrun`-shaped stop and **the whole run ends
43
- there** — implementation and the verification gate run, nothing is committed, the working tree is left
44
- dirty and unstashed, a `confirmation` Telegram carrying the resume command goes out, and the remaining
45
- children are not started.
46
-
47
- **This is the exception to park-and-continue below** — rationale:
48
- `docs/maintainers/backlogrun-park-rationale.md` → "Why `needs-human-review` ends the run instead of parking".
33
+ A child carrying **`needs-human-review`** stops `halfrun`-shaped and **the whole run ends there**:
34
+ implementation and the gate run, nothing is committed, the tree is left dirty and unstashed, a
35
+ `confirmation` Telegram carries the resume command, and the remaining children are not started.
36
+ Rationale: `docs/maintainers/backlogrun-park-rationale.md` → "Why `needs-human-review` ends the run
37
+ instead of parking".
49
38
 
50
- **The child goes on holding its repository.** `needs-decision` outranks `in-progress` in the
51
- per-repository exclusion so a parked child releases the checkout; this label deliberately does not,
52
- because releasing it would start the next child on top of uncommitted work. **Its lane is left open and
53
- untouched**, for the same reason. **Name the lane directory in the stop report and in the Telegram.** The lanes
54
- already in flight finish; no new lane is opened.
39
+ **The child goes on holding its repository**, and **its lane is left open and untouched**. **Name the
40
+ lane directory in the stop report and in the Telegram.** Lanes in flight finish; no new lane opens.
55
41
 
56
- **Never apply or remove the label** — a person's alone. Full definition and the
57
- `needs-decision` comparison: `needs-human-review.md`, which is the single source.
42
+ **Never apply or remove the label** — a person's alone (`needs-human-review.md`, the single source).
58
43
 
59
44
  ## park and continue
60
45
 
61
- When a child hits something only a person can decide — → "Only a person's judgement carries
62
- `needs-decision`" below — **park the child and keep going.**
46
+ When a child hits something only a person can decide (→ "Only a person's judgement carries
47
+ `needs-decision`"), **park the child and keep going**:
63
48
 
64
49
  ```bash
65
50
  gh api repos/{owner}/{repo}/issues/<N>/labels -f 'labels[]=needs-decision'
66
51
  pnpm josh issue:comment <N> --body-file <path> # what needs deciding, and the options
67
52
  ```
68
53
 
69
- `in-progress` is left as it is, and the parked child does **not** hold the repository — `epic:next` gives
70
- `needs-decision` precedence over `in-progress`, so the next child is offered normally. Then return to
71
- step 1; the other children are unaffected unless they depend on this one.
54
+ `in-progress` stays; the parked child does **not** hold the repository (`needs-decision` takes
55
+ precedence in `epic:next`). Return to step 1.
72
56
 
73
57
  **A parked child's lane is kept, whether or not it had committed**, and every parked ending owes
74
- `pnpm josh run:release <N>` — `backlogrun-lanes.md` → "What happens to a lane", the single source. A
75
- lost merge race resolves in its lane instead (`backlogrun-recovery.md` → "Conflicts are not predicted").
58
+ `pnpm josh run:release <N>` — `backlogrun-lanes.md` → "What happens to a lane". A lost merge race
59
+ resolves in its lane instead (`backlogrun-recovery.md` → "Conflicts are not predicted").
76
60
 
77
61
  **Parking replaces stopping the session, not the rule that produced the stop** — an upstream defect is
78
62
  still filed at once, and a workaround is still forbidden. `epic:bundle`'s `ask` is Tier A, not a park:
79
- add the epic you recommend with `pnpm josh epic --add <E> <N> --after <M>` and record it on both
80
- Issues' `## Decisions`.
63
+ `pnpm josh epic --add <E> <N> --after <M>` and record it on both Issues' `## Decisions`.
81
64
 
82
- **Removing the label is Tier A — do it without asking**, once the decision is recorded; without it the
83
- parked child never runs again:
65
+ **Removing the label is Tier A — do it without asking**, once the decision is recorded:
84
66
 
85
67
  ```bash
86
68
  gh api -X DELETE repos/{owner}/{repo}/issues/<N>/labels/needs-decision 2>/dev/null || true
87
69
  ```
88
70
 
89
71
  **The released child goes back to a lane, never into the parent's own context** — `pnpm josh
90
- lane:launch <N>` (`backlogrun.md` → "Claim nothing at the entry — this parent orchestrates and never
91
- implements").
72
+ lane:launch <N>`.
92
73
 
93
74
  ## Only a person's judgement carries `needs-decision`
94
75
 
95
- **`needs-decision` means "a person has to choose", and nothing else.** This is the single source of
96
- when a run may apply it, by hand or through a park. It carries only:
76
+ **`needs-decision` means "a person has to choose", and nothing else.** It carries only:
97
77
 
98
78
  - a design choice nobody has made;
99
79
  - a Tier B toss-up, or a Tier C action (`CLAUDE.md` → "Decision autonomy");
@@ -108,34 +88,25 @@ It never carries:
108
88
  - a defect in the running repository's own run tooling — the run fixes it and resumes
109
89
  (`prompts/collaboration-workflow/upstream-interrupt.md` → "実行中のリポジトリ自身のラン機構の不具合").
110
90
 
111
- **When in doubt, it is Tier A**: decide, comment the decision, and continue. **A label a mechanical step applied** — a
112
- failed or abandoned child, a lost merge race's four conditions — is read against this list once its
113
- reason is known, and removed (Tier A, above) when the reason is not on it. Rationale:
91
+ **When in doubt, it is Tier A**: decide, comment the decision, and continue. **A label a mechanical step
92
+ applied** (a failed or abandoned child, a lost merge race) is read against this list once its reason is
93
+ known, and removed when the reason is not on it. Rationale:
114
94
  `docs/maintainers/backlogrun-park-rationale.md` → "Why a run spends no attention on a non-finding".
115
95
 
116
96
  ## `in-progress` is removed by whoever finds it stale
117
97
 
118
- A run's own ending removes `in-progress` — `pnpm josh followup` on a merge, `pnpm josh run:release <N>`
119
- on a stop. An interrupted run reaches neither and leaves it behind, and a child that carries it is
120
- excluded from every future `epic:next` — permanently. The removal below is the one hand-written call
121
- left, for a label no live run owns: another tree's record is not this tree's to release.
122
- **A session that detects a stale child removes the label itself** (Tier A) and reports it, before
123
- continuing the loop.
124
-
125
- **It costs more than that one child now.** An open issue carrying `in-progress` occupies one of the
126
- repository's lanes — whichever epic it belongs to — so a stale label narrows every epic that touches
127
- that checkout. **The rule therefore applies to any open issue in the repository, not only to this epic's
128
- children**, and `epic:next` names the holders on standard error. **Age alone is not the test.** Check the
129
- 90-minute window below *and* look at what is holding it, because three states hold the label legitimately
130
- for longer: a `halfrun` stopped for manual verification, any run paused mid-child, and a child stopped by
131
- `needs-human-review` (which waits on a person reading an artifact, and carries its own label alongside
132
- `in-progress`). **All three leave uncommitted work in the checkout**, so `git status` there is the
133
- decisive read: a dirty tree means the hold is real — leave the label alone and report, never strip it and
134
- start a second child on top of that work.
135
-
136
- **A closed issue's labels are neither a finding nor something to clean up.** A closed issue holds no lane
137
- (`epic-busy.ts` counts holders from the open listing alone) and `epic:next` never offers it, so
138
- `in-progress` left behind on one changes nothing. **Do not report it, and do not strip it.**
98
+ An interrupted run leaves `in-progress` behind, which excludes the child from `epic:next` permanently
99
+ and occupies a lane. **A session that detects a stale child removes the label itself** (Tier A) and
100
+ reports it, before continuing. **The rule therefore applies to any open issue in the repository, not
101
+ only to this epic's children** (`epic:next` names the holders on standard error).
102
+
103
+ **Age alone is not the test.** Past the 90-minute window, check what holds it: a `halfrun` stopped for
104
+ manual verification, a run paused mid-child, and a `needs-human-review` child hold it legitimately.
105
+ **All three leave uncommitted work in the checkout**, so `git status` there decides: a dirty tree means
106
+ the hold is real — leave the label and report.
107
+
108
+ **A closed issue's labels are neither a finding nor something to clean up** (no lane, never offered).
109
+ **Do not report it, and do not strip it.**
139
110
 
140
111
  ```bash
141
112
  gh api -X DELETE repos/{owner}/{repo}/issues/<N>/labels/in-progress 2>/dev/null || true
@@ -143,50 +114,35 @@ gh api -X DELETE repos/{owner}/{repo}/issues/<N>/labels/in-progress 2>/dev/null
143
114
 
144
115
  ## A prerequisite discovered mid-run
145
116
 
146
- Finding that something else in **this** repository has to land first is not a split, and not an upstream
147
- defect. The child in hand is still one deliverable; it just needs another one before it. The three-way
148
- distinction, the `route:tier-a` filing command and the filing ceiling are `prerequisite.md`, the single
149
- source; what follows is this entry's branch.
150
-
151
- `<M>` below is the child being implemented when the prerequisite turned up; `<N>` is the new Issue.
117
+ Something else in **this** repository has to land first: not a split, not an upstream defect.
118
+ `prerequisite.md` is the single source of the distinction, the `route:tier-a` filing and the ceiling.
119
+ `<M>` is the child in hand; `<N>` the new Issue.
152
120
 
153
- 1. File the prerequisite Issue `<N>` with the `route:tier-a` label — Tier A for a first-party
154
- repository, no confirmation. It is filed **first** because the next step names it.
155
- 2. **Stash the work in progress.** A child is implemented on the default branch with an uncommitted tree,
156
- so `<M>`'s half-finished edits are sitting there, and the next child's `pnpm josh ms`
157
- would refuse or carry them into the prerequisite's branch and PR.
121
+ 1. File the prerequisite `<N>` with `route:tier-a` (Tier A, first-party, no confirmation) — **first**,
122
+ because the next step names it.
123
+ 2. **Stash the work in progress**:
158
124
 
159
125
  ```bash
160
126
  git stash push -u -m "backlogrun: paused #<M> for prerequisite #<N>"
161
127
  pnpm josh issue:comment <M> --body-file <path> # what was stashed, and that #<N> must land first
162
128
  ```
163
129
 
164
- **`-u` is not optional** (a new `*.test.ts` is untracked). The comment makes the paused state
165
- auditable and tells the session that resumes `<M>` a stash is waiting. **Pop it by message, never by
166
- position** — `pnpm josh stash:pop "backlogrun: paused #<M> for prerequisite #<N>"` — when `epic:next`
167
- offers `<M>` again, after its `pnpm josh ms`. The stash is a repository-wide stack
168
- every lane shares, so a bare `git stash pop` would take whichever lane last pushed; the message
169
- targets this one. The prerequisite has merged by then, so expect to resolve conflicts.
170
-
171
- 3. `pnpm josh epic --add <E> <N> --before <M>` — one command writes the task-list row, the declaration
172
- and the `blocked-by` relation together. Never edit the body by hand: the declaration and the relations
173
- then disagree, `epic:next` returns `error`, and the unattended run stops.
174
- **With no epic** (a pool child), record the relation alone, `<M>` blocked by `<N>`, with the
175
- `gh api …/dependencies/blocked_by` call in `prompts/collaboration-workflow/issue-template.md` →
176
- "複数 Issue に分割するときの epic Issue", step 4.
177
- 4. **Remove `in-progress` from `<M>`** — `pnpm josh run:release <M>`, which removes the label with the hold.
178
- This is what lets `<M>` run again: `epic:next` classifies a child carrying `in-progress` as waiting on
179
- time **before** it looks at any blocker, so a child left labelled is never offered again.
180
- 5. **Do not park.** Go back to step 1 of the loop. `epic:next` classifies the original child as resolving
181
- on its own and hands back the prerequisite first, so the order is kept with no human input.
182
-
183
- **A stop a dependency can express is never parked**, and a defect in this repository's own gate or run
184
- tooling is such a stop — `prerequisite.md` holds that rule and what the driver does with it.
130
+ **`-u` is not optional** (new test files are untracked). **Pop it by message, never by position** —
131
+ `pnpm josh stash:pop "backlogrun: paused #<M> for prerequisite #<N>"` — when `epic:next` offers `<M>`
132
+ again, after its `pnpm josh ms`; expect conflicts.
133
+ 3. `pnpm josh epic --add <E> <N> --before <M>` — row, declaration and `blocked-by` in one command;
134
+ never a hand edit. **With no epic**, record `<M>` blocked by `<N>` alone with the `gh api
135
+ …/dependencies/blocked_by` call in
136
+ `prompts/collaboration-workflow/issue-template.md` → "複数 Issue に分割するときの epic Issue", step 4.
137
+ 4. **Remove `in-progress` from `<M>`** — `pnpm josh run:release <M>`; a labelled child is never offered again.
138
+ 5. **Do not park.** Back to step 1 of the loop; `epic:next` hands back the prerequisite first.
139
+
140
+ **A stop a dependency can express is never parked**, including a defect in this repository's own gate
141
+ or run tooling — `prerequisite.md`.
185
142
 
186
143
  ## Splitting a child mid-run
187
144
 
188
- Discovering that a child is really several is not a reason to stop. File the new children with the
189
- `route:split` label (Tier A for a first-party repository — no confirmation), then add them with
190
- `pnpm josh epic --add <E> <N...> [--before <M> | --after <M>]` rather than editing the epic body by hand.
191
- Use the same split criteria as `kickoff`. If what remains of the original child needs a person, park
192
- **that** child and move on. Splitting alone never adds `needs-decision` to the promoted epic.
145
+ Not a reason to stop. File the new children with `route:split` (Tier A, first-party), then
146
+ `pnpm josh epic --add <E> <N...> [--before <M> | --after <M>]` — never a hand edit. Same criteria as
147
+ `kickoff`. If what remains needs a person, park **that** child and move on. Splitting alone never adds
148
+ `needs-decision` to the promoted epic.
@@ -41,10 +41,9 @@ provenance of each rule: `docs/maintainers/backlogrun-progress-rationale.md` →
41
41
  ## After a named epic completes
42
42
 
43
43
  **When a named epic's children are all processed — merged or parked — the run advances to the next
44
- named item, and then drains the opted-in backlog** (unless `--only`, which stops after the named
45
- list). A completed epic is one step of the invocation, never its end. A named item that is a bare,
46
- non-epic Issue reaches the same point when it merges. The epic's own completion summary is sent by the
47
- session standing in the repository that owns it ("Who sends the summary, and who propagates" below).
44
+ named item, and then drains the opted-in backlog** (unless `--only`). A completed epic — or a merged
45
+ bare named Issue — is one step of the invocation, never its end. Its summary is sent per "Who sends the
46
+ summary, and who propagates" below.
48
47
 
49
48
  ## The hand-off — one session does not have to run the whole batch
50
49
 
@@ -88,13 +87,12 @@ park** — nothing is labelled, stashed or filed.
88
87
 
89
88
  ### Picking the lanes up in the fresh session
90
89
 
91
- **Start no child again and open no lane already open.** In one turn: `pnpm josh lane:list` (every line
90
+ **Start no child again and open no lane already open.** In one turn: `pnpm josh lane:list` (a line
92
91
  with a path is a handed-over child, polled per `backlogrun-recovery.md` → "A delegated unit that stopped
93
92
  without reporting"), `pnpm josh run:progress --wait --output <handed-over paths>` in the background
94
- (the `run:watcher:guard` enforces it), `pnpm josh run:liveness`, and
95
- `epic:next --lanes` with a lane for each child it offers. **A carried-over child finishes in its own
96
- unit — never run its `followup` yourself**; one that did not survive the cut is re-dispatched with
97
- `pnpm josh lane:open <N>` then `pnpm josh lane:dispatch <N>`, never adopted.
93
+ (`run:watcher:guard`), `pnpm josh run:liveness`, and `epic:next --lanes`, a lane per child it offers.
94
+ **A carried-over child finishes in its own unit — never run its `followup` yourself**; one lost in the
95
+ cut is re-dispatched with `pnpm josh lane:open <N>` then `pnpm josh lane:dispatch <N>`.
98
96
 
99
97
  ### What carries over
100
98