@erclx/canon 5.40.0 → 5.42.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 (187) hide show
  1. package/README.md +34 -17
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/references/adopted.md +34 -14
  4. package/claude/skills/auto-ship/REQUIREMENT.md +2 -0
  5. package/claude/skills/auto-ship/SKILL.md +28 -2
  6. package/claude/skills/auto-ship/references/draft-mark.md +32 -6
  7. package/claude/skills/auto-ship/references/failure-recovery.md +15 -13
  8. package/claude/skills/auto-ship/references/fan-in.md +59 -0
  9. package/claude/skills/auto-ship/references/tier-failures.md +31 -10
  10. package/claude/skills/auto-ship/references/ui-checklist.md +9 -4
  11. package/claude/skills/auto-ship/references/worktree-name.md +9 -3
  12. package/claude/skills/build-in-slices/references/adopted.md +35 -21
  13. package/claude/skills/canvas-board/references/canvas.md +17 -6
  14. package/claude/skills/canvas-board/references/design.md +26 -7
  15. package/claude/skills/code-craft/references/adopted.md +58 -20
  16. package/claude/skills/codebase-layout/references/adopted.md +49 -16
  17. package/claude/skills/codebase-layout/references/frontend.md +11 -4
  18. package/claude/skills/codebase-layout/references/tests.md +4 -2
  19. package/claude/skills/context-fold/references/classify.md +10 -15
  20. package/claude/skills/context-fold/references/completion-report.md +11 -9
  21. package/claude/skills/context-fold/references/context-refresh.md +26 -9
  22. package/claude/skills/context-fold/references/unusable-baseline.md +5 -3
  23. package/claude/skills/create-rule/REQUIREMENT.md +5 -0
  24. package/claude/skills/create-rule/SKILL.md +9 -1
  25. package/claude/skills/create-rule/references/checklist.md +26 -0
  26. package/claude/skills/create-rule/references/rule.md +98 -20
  27. package/claude/skills/create-skill/SKILL.md +1 -0
  28. package/claude/skills/create-skill/references/skill-disclosure.md +10 -2
  29. package/claude/skills/create-skill/references/skill-frontmatter.md +43 -0
  30. package/claude/skills/create-skill/references/skill-paths.md +7 -4
  31. package/claude/skills/create-skill/references/skill-practice.md +6 -3
  32. package/claude/skills/create-skill/references/skill-requirement.md +4 -2
  33. package/claude/skills/create-skill/references/skill.md +67 -44
  34. package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
  35. package/claude/skills/decision-escalate/SKILL.md +1 -2
  36. package/claude/skills/deploy-app/references/vercel.md +2 -1
  37. package/claude/skills/deprecation-migration/references/adopted.md +44 -25
  38. package/claude/skills/design-taste/references/adopted.md +9 -1
  39. package/claude/skills/design-taste/references/craft.md +3 -1
  40. package/claude/skills/design-taste/references/kinds.md +8 -7
  41. package/claude/skills/design-taste/references/preflight.md +12 -0
  42. package/claude/skills/design-taste/references/systems.md +7 -6
  43. package/claude/skills/design-taste/references/tells.md +24 -25
  44. package/claude/skills/design-taste/references/vocabulary.md +7 -5
  45. package/claude/skills/document-health/references/axes.md +54 -30
  46. package/claude/skills/draft-and-pick/references/live-arms.md +2 -2
  47. package/claude/skills/draft-doc/references/context.md +4 -3
  48. package/claude/skills/draft-doc/references/docs.md +6 -3
  49. package/claude/skills/draft-doc/references/readme/agent-facing.md +6 -0
  50. package/claude/skills/draft-doc/references/readme/application.md +8 -2
  51. package/claude/skills/draft-doc/references/readme/cli.md +5 -1
  52. package/claude/skills/draft-doc/references/readme/library.md +4 -0
  53. package/claude/skills/draft-doc/references/readme/plugin.md +9 -1
  54. package/claude/skills/draft-doc/references/readme.md +30 -13
  55. package/claude/skills/draft-doc/references/requirements.md +17 -4
  56. package/claude/skills/draft-doc/references/wiki-kind.md +20 -10
  57. package/claude/skills/draft-figure/references/architecture-set.md +7 -3
  58. package/claude/skills/draft-figure/references/figures.md +8 -6
  59. package/claude/skills/draft-figure/references/hand-drawn.md +3 -1
  60. package/claude/skills/draft-figure/references/mermaid-path.md +19 -9
  61. package/claude/skills/draft-figure/references/mermaid.md +10 -5
  62. package/claude/skills/draft-ready/references/ready.md +22 -15
  63. package/claude/skills/git-branch/REQUIREMENT.md +17 -6
  64. package/claude/skills/git-branch/SKILL.md +63 -7
  65. package/claude/skills/git-branch/references/branch.md +11 -1
  66. package/claude/skills/git-branch/references/slug.md +17 -5
  67. package/claude/skills/git-commit/references/commit.md +8 -0
  68. package/claude/skills/git-commit/references/versioning.md +23 -17
  69. package/claude/skills/git-followup/REQUIREMENT.md +1 -1
  70. package/claude/skills/git-followup/SKILL.md +5 -6
  71. package/claude/skills/git-issue/references/issue.md +29 -16
  72. package/claude/skills/git-pr/REQUIREMENT.md +1 -5
  73. package/claude/skills/git-pr/SKILL.md +11 -22
  74. package/claude/skills/git-pr/references/final-command.md +21 -8
  75. package/claude/skills/git-pr/references/labels.md +45 -28
  76. package/claude/skills/git-pr/references/pr.md +28 -9
  77. package/claude/skills/git-pr/references/publish.md +42 -28
  78. package/claude/skills/git-pr/references/task-number.md +20 -8
  79. package/claude/skills/git-ship/SKILL.md +1 -1
  80. package/claude/skills/plan-feature/references/batches.md +48 -1
  81. package/claude/skills/plan-feature/references/plan-lifecycle.md +10 -3
  82. package/claude/skills/plan-feature/references/plan.md +59 -20
  83. package/claude/skills/plan-groundwork/references/groundwork-spikes.md +4 -1
  84. package/claude/skills/plan-groundwork/references/groundwork.md +14 -16
  85. package/claude/skills/plan-intake/references/intake.md +29 -24
  86. package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
  87. package/claude/skills/plan-intake-answer/SKILL.md +1 -2
  88. package/claude/skills/pr-evidence/REQUIREMENT.md +40 -0
  89. package/claude/skills/pr-evidence/SKILL.md +53 -0
  90. package/claude/skills/pr-evidence/references/evidence.md +150 -0
  91. package/claude/skills/review-address/references/post-review-findings.md +10 -3
  92. package/claude/skills/review-address/references/rebase-conflicts.md +22 -7
  93. package/claude/skills/review-address/references/rest-reads.md +3 -1
  94. package/claude/skills/review-craft/references/adopted.md +35 -18
  95. package/claude/skills/review-craft/references/security.md +42 -7
  96. package/claude/skills/review-craft/references/ui.md +23 -8
  97. package/claude/skills/review-pr/SKILL.md +6 -6
  98. package/claude/skills/review-pr/references/body-variants.md +29 -9
  99. package/claude/skills/review-pr/references/close-out.md +20 -5
  100. package/claude/skills/review-pr/references/key-changes.md +27 -3
  101. package/claude/skills/review-pr/references/post.md +83 -31
  102. package/claude/skills/review-pr/references/scope.md +54 -19
  103. package/claude/skills/review-ui/SKILL.md +2 -0
  104. package/claude/skills/review-ui/references/close-out.md +49 -0
  105. package/claude/skills/review-ui/references/driving.md +24 -4
  106. package/claude/skills/review-ui/references/post.md +43 -13
  107. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +67 -17
  108. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +81 -40
  109. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +52 -15
  110. package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +48 -26
  111. package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +12 -13
  112. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +72 -36
  113. package/claude/skills/role-orchestrator/references/orchestrator-output.md +12 -4
  114. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +64 -24
  115. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +80 -26
  116. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +41 -18
  117. package/claude/skills/role-orchestrator/references/orchestrator-resume.md +19 -7
  118. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +22 -12
  119. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +15 -6
  120. package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +25 -7
  121. package/claude/skills/role-orchestrator/references/orchestrator-watch.md +34 -8
  122. package/claude/skills/role-orchestrator/scripts/poll.ts +16 -24
  123. package/claude/skills/role-worker/REQUIREMENT.md +2 -0
  124. package/claude/skills/role-worker/SKILL.md +17 -0
  125. package/claude/skills/search-craft/references/adopted.md +18 -6
  126. package/claude/skills/session-map/references/session.md +26 -7
  127. package/claude/skills/session-worktree/references/main-root-writes.md +25 -8
  128. package/claude/skills/systematic-debugging/references/adopted.md +30 -16
  129. package/claude/skills/target-check/references/domains.md +39 -11
  130. package/claude/skills/target-setup/references/detect.md +80 -65
  131. package/claude/skills/target-setup/references/indexes.md +8 -6
  132. package/claude/skills/task-board/references/board.md +86 -30
  133. package/claude/skills/task-board/references/decline.md +29 -13
  134. package/claude/skills/task-board/references/tasks-decline.md +12 -5
  135. package/claude/skills/task-board/references/tasks.md +65 -33
  136. package/claude/skills/task-complete/references/archive.md +41 -17
  137. package/claude/skills/task-complete/references/receipt-sweep.md +23 -9
  138. package/claude/skills/task-complete/references/unusable-baseline.md +10 -3
  139. package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
  140. package/claude/skills/teach-workspace/SKILL.md +1 -2
  141. package/claude/skills/teach-workspace/references/glossary.md +6 -2
  142. package/claude/skills/teach-workspace/references/lesson-build.md +44 -16
  143. package/claude/skills/teach-workspace/references/lesson-craft.md +12 -7
  144. package/claude/skills/teach-workspace/references/pedagogy.md +6 -3
  145. package/claude/skills/teach-workspace/references/promotion-fold.md +17 -11
  146. package/claude/skills/teach-workspace/references/promotion.md +31 -8
  147. package/claude/skills/teach-workspace/references/revisit.md +8 -2
  148. package/claude/skills/teach-workspace/references/teach.md +17 -9
  149. package/claude/skills/test-craft/references/adopted.md +48 -14
  150. package/claude/skills/test-craft/references/component.md +7 -4
  151. package/claude/skills/test-craft/references/e2e.md +25 -7
  152. package/claude/skills/test-craft/references/unit.md +3 -1
  153. package/claude/skills/test-first/references/adopted.md +12 -4
  154. package/claude/skills/ui-checklist/REQUIREMENT.md +1 -1
  155. package/claude/skills/ui-checklist/SKILL.md +1 -1
  156. package/claude/skills/video-craft/references/adopted.md +62 -18
  157. package/claude/skills/write-human/references/adopted.md +21 -8
  158. package/docs/workflow/parallel-features.md +2 -1
  159. package/docs/workflow/skill-map.md +2 -1
  160. package/package.json +1 -1
  161. package/src/claude/cases/git.ts +4 -0
  162. package/src/claude/cases/workflow.ts +5 -0
  163. package/src/commands/pr.ts +174 -37
  164. package/src/commands/records.ts +11 -3
  165. package/src/context/shape-gated.ts +1 -0
  166. package/src/markdown/scope.ts +150 -2
  167. package/src/pr/frames.ts +53 -9
  168. package/src/pr/lift.ts +6 -3
  169. package/src/pr/review-state.ts +182 -0
  170. package/src/records/validate.ts +1 -0
  171. package/src/tasks/answers.ts +79 -2
  172. package/src/tasks/fan-in.ts +176 -0
  173. package/src/tasks/stack.ts +1 -1
  174. package/tooling/astro/reference.md +80 -39
  175. package/tooling/base/reference.md +63 -32
  176. package/tooling/base/seeds/canon/context/ci.md +7 -15
  177. package/tooling/base/seeds/canon/context/development.md +14 -14
  178. package/tooling/claude/reference.md +40 -22
  179. package/tooling/cloudflare/reference.md +31 -12
  180. package/tooling/go/reference.md +47 -23
  181. package/tooling/nextjs/reference.md +52 -19
  182. package/tooling/php/reference.md +35 -16
  183. package/tooling/python/reference.md +47 -30
  184. package/tooling/shell/reference.md +6 -5
  185. package/tooling/vite-react/reference.md +49 -21
  186. package/tooling/web/reference.md +130 -70
  187. package/claude/skills/git-pr/references/evidence.md +0 -124
@@ -7,45 +7,59 @@ description: Retirement act the wind-down owes the fleet it dispatched, the talk
7
7
 
8
8
  Settle this act before writing the map. A session retired afterwards is one the map already listed as running, and the map is what the next session reads the fleet off.
9
9
 
10
- The act reaches every session this one dispatched that no verb can decide. `canon worktrees reclaim` refuses a directory on any of seven conditions and reclaims one that trips none, and three of the seven are what this act turns on: a merged pull request, a clean tree, and no live session holding the directory. A running session trips the third whatever its branch did, and retiring it is what clears that one, which is why the retirement runs ahead of the reclaim rather than after it.
10
+ The act reaches every session this one dispatched that no verb can decide. `canon worktrees reclaim` refuses a directory on any of seven conditions, and three are what this act turns on, being a merged pull request, a clean tree, and no live session holding the directory.
11
11
 
12
- Two cases stay undecided even once the session is gone. A worker whose branch has not merged is refused on `no-merged-pull-request`, and a planner is refused as `main-worktree` and handed a null removal route, since it never enters a worktree and registers against the tree it was launched from.
13
-
14
- Name the planner as the case always in this set, and scope the act no narrower. A rule covering planners alone leaves the unmerged worker unreached while reading as complete.
12
+ - A running session trips the third whatever its branch did, and retiring it clears that one, so the retirement runs ahead of the reclaim
13
+ - A worker whose branch has not merged stays undecided once gone, refused on `no-merged-pull-request`
14
+ - A planner stays undecided too, refused as `main-worktree` with a null removal route, since it registers against the tree it was launched from
15
+ - Name the planner as the case always in this set, and scope the act no narrower, since a rule for planners alone leaves the unmerged worker unreached
15
16
 
16
17
  ### Which sessions this session may retire unasked
17
18
 
18
- Retire what this session dispatched. Report a hand-launched session and leave the act to the operator, since the knowledge making the act safe is a delivery this session received and it received nothing from a session it never launched. The `worker-` and `planner-` name prefixes separate the two populations, per `orchestrator-launch.md`.
19
+ Retire what this session dispatched. Report a hand-launched session and leave the act to the operator, since what makes the act safe is a delivery this session received, and it received nothing from a session it never launched.
19
20
 
20
- A talk session is the exception inside the dispatched population. Retire it only on the operator's word, given here or carried in the session's own close message, and never on its delivery, at wind-down or at any other point. Its plan landing or its pull request opening tells this session nothing about whether the conversation is over. Until the word arrives, report it as held open next to the hand-launched read. A talk session is found by the `sessionId` the prior map records or this session's own launch output carries, since the client can rename it and drop the `-talk` suffix `orchestrator-launch.md` gives it.
21
+ - The `worker-` and `planner-` name prefixes separate the two populations, per `orchestrator-launch.md`
22
+ - A capability gap sits beside that knowledge gap. A hand-launched session is often interactive, and `claude rm <id>` has no id to take for one.
21
23
 
22
- A capability gap sits beside the knowledge gap, and it holds even where delivery is somehow known. A hand-launched session is as often interactive as background, and `claude rm <id>` has no id to take for an interactive one at all, so the command cannot reach it whatever this session learned about its delivery.
24
+ ### Talk sessions
23
25
 
24
- ### Telling a delivered session from a blocked one
26
+ A talk session is the exception inside the dispatched population. Retire it only on the operator's word, given here or carried in the session's own close message, and never on its delivery, at wind-down or any other point.
25
27
 
26
- No status field carries the difference. `status` reads `busy` or `waiting` straight off the client record, and both describe the last turn rather than the work, so `waiting` is the ordinary answer for a session that reported and stopped, which is what a correct delivery looks like. The `statusDwellMs` beside it separates a long idle from a short one and separates nothing else.
28
+ - Its plan landing or its pull request opening tells this session nothing about whether the conversation is over
29
+ - Until the word arrives, report it as held open next to the hand-launched read
30
+ - Find it by the `sessionId` the prior map records or this session's launch output carries, since the client can rename it and drop the `-talk` suffix
27
31
 
28
- The read is the report this session is holding. Retire a session whose delivery arrived here, and leave every other one. A plan sitting at `.canon/plans/feature-<slug>.md` corroborates that report and never stands in for it, because a planner writes the file and can then stop on a follow-up question with the file already landed. Retiring a blocked session destroys the context it held and nothing on disk records what it had read, so the act runs in the keeping direction the reclaim reading already takes: retire what is recorded as delivered, and leave the rest for the operator.
32
+ ### Telling a delivered session from a blocked one
29
33
 
30
- ### The act, and the order it runs in
34
+ No status field carries the difference. `status` reads `busy` or `waiting` off the client record, both describing the last turn rather than the work, so `waiting` is the ordinary answer for a session that reported and stopped. `statusDwellMs` separates a long idle from a short one and nothing else.
31
35
 
32
- `claude rm <id>` is meant to remove a background session and its worktree together, though its own report is not reliable, so `canon worktrees list` is the reading to trust afterward. It takes one target per call, so a wave costs one call per session. The argument is the id rather than the name, which `claude agents --json` carries beside the name on every row, so a session read off a roster by name is matched to its id there before the call. The name form answers `No job matching`.
36
+ The read is the report this session is holding. Retire a session whose delivery arrived here, and leave every other one for the operator.
33
37
 
34
- The command belongs to the client rather than to this toolkit, so a target running another client performs whatever removal that client offers.
38
+ - A plan at `.canon/plans/feature-<slug>.md` corroborates that report and never stands in for it, since a planner can stop on a question after writing it
39
+ - Retiring a blocked session destroys its context and nothing on disk records what it had read, so the act keeps, as the reclaim reading does
35
40
 
36
- Run `canon worktrees reclaim` after the retirements rather than before them. `held-by-session` is one of the conditions that reading refuses on, so a reclaim taken first refuses the directories the retirement is about to free and reports a board with nothing left to do.
41
+ ### The act, and the order it runs in
42
+
43
+ `claude rm <id>` is meant to remove a background session and its worktree together, though its own report is not reliable, so trust `canon worktrees list` afterward. It takes one target per call, so a wave costs one call per session.
37
44
 
38
- Report the retired sessions as a list, the hand-launched ones under it as a read rather than an act, and what the reclaim removed below both.
45
+ - The argument is the id, which `claude agents --json` carries beside the name on every row, and the name form answers `No job matching`
46
+ - The command belongs to the client, so a target running another client performs whatever removal that client offers
47
+ - Run `canon worktrees reclaim` after the retirements, since it refuses on `held-by-session` and a reclaim taken first finds nothing left to do
48
+ - Report the retired sessions as a list, the hand-launched ones under it as a read rather than an act, and what the reclaim removed below both
39
49
 
40
50
  ## Write the map
41
51
 
42
- Write the pre-compaction handoff as orchestrator. Invoke `canon:session-map` for the generic half, which is the filename, the three core sections, the write procedure, the drift step and the ref it reads, and the citation rule. Everything in this section is the extension this role adds over that core, and none of it belongs to a session holding no delegated authority.
52
+ Write the pre-compaction handoff as orchestrator. Invoke `canon:session-map` for the generic half, being the filename, the three core sections, the write procedure, the drift step and the ref it reads, and the citation rule. Everything in this section is the extension this role adds.
43
53
 
44
- Settle all three steps below before the door writes, so one write carries the core and the extension together. The door reports the map as written and knows nothing of this role, so its success line ends the generic half rather than this runbook, and a session that stops there ships a map missing everything this section adds to it.
54
+ Settle all three steps below before the door writes, so one write carries the core and the extension together. The door's success line ends the generic half rather than this runbook, so a session stopping there ships a map missing everything this section adds.
45
55
 
46
- 1. Add `## Decisions taken under delegated authority` directly after `## State`, holding each decision and why it went that way, so nobody re-proposes it. It sits there rather than after the core because a decision is read against the state it was taken in.
47
- 2. Add `## Talk sessions held open` directly after that section, with one line per open talk session giving its name, its `sessionId`, and its row, or `None.` when there are none. The next session reads it to know which sessions it must not retire on a delivery.
48
- 3. Close the file with the block below, resolving `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md` and `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` to absolute paths as you write it and pasting each in place of `<RESUME_RUNBOOK>` and `<POLL_RUNBOOK>`:
56
+ 1. Add `## Decisions taken under delegated authority` directly after `## State`, holding each decision and why it went that way, so nobody re-proposes it.
57
+ - It sits there because a decision is read against the state it was taken in
58
+ 2. Add `## Talk sessions held open` directly after that, one line per open talk session giving its name, its `sessionId`, and its row, or `None.`.
59
+ - The next session reads it to know which sessions it must not retire on a delivery
60
+ 3. Close the file with the block below, resolving each runbook path to an absolute one as you write it.
61
+ - Paste `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md` resolved in place of `<RESUME_RUNBOOK>`
62
+ - Paste `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` resolved in place of `<POLL_RUNBOOK>`
49
63
 
50
64
  ```markdown
51
65
  Resume by loading the orchestrator skill and asking it to resume after a compaction. This repository spells that `/canon:role-orchestrator` followed by the request. Following <RESUME_RUNBOOK> reaches the same place with no skill loaded at all.
@@ -53,14 +67,22 @@ Resume by loading the orchestrator skill and asking it to resume after a compact
53
67
  That resume reads the board and stops. It restarts nothing, so the review poll is a second thing owed here, and <POLL_RUNBOOK> holds the prompt and the condition. Do not reach for `session-resume`, which reads tracked work and reports the newest map without restarting this loop.
54
68
  ```
55
69
 
56
- The delegated-authority section is the orchestrator's alone because a worker holds no delegation to have exercised, and a section a session cannot fill teaches its reader to skip the file. The closing block is the orchestrator's for the same reason from the other direction: it restarts a review poll no other role runs.
70
+ ### Why these sections are the orchestrator's
71
+
72
+ The delegated-authority section is the orchestrator's alone because a worker holds no delegation to have exercised, and a section a session cannot fill teaches its reader to skip the file. The closing block is the orchestrator's because it restarts a review poll no other role runs.
73
+
74
+ - The substitution sits in step 3 because that step ends the write
75
+ - The variable expands while this runbook renders, never when the handoff is read back
76
+ - A path left unresolved reaches a session holding no skill as a string matching nothing. `orchestrator-poll.md` resolves its script at the same point.
57
77
 
58
- The substitution belongs in step 3 because that step ends the write. A reader who treats the list as finished elsewhere ships the literal placeholders, and the variable expands while this runbook renders rather than in the turn that reads the handoff back, so a path left unresolved reaches a session holding no skill as a string matching nothing. `orchestrator-poll.md` resolves its script at the same point and for the same reason.
78
+ ### Why the block appears twice
59
79
 
60
- That block sits in this runbook and again in the file this runbook writes, which is the fix rather than a copy for a later pass to collapse. A session has to already be holding this runbook to read it, and a compaction that took the skill body took the routing to it too, so the session that most needs the resume is the one that can no longer find it. The map survives that, so it carries the invocation itself. Each of the two reaches a reader the other cannot.
80
+ That block sits here and again in the file this runbook writes, which is the fix rather than a copy to collapse. A compaction that took the skill body took the routing to this runbook too, so the map carries the invocation itself, and each copy reaches a reader the other cannot.
61
81
 
62
- The requirement is a resume request to the orchestrator skill with that skill loaded first. The command the block carries is this repository's spelling rather than the only one, since the skill ships to every target holding the plugin and each runs whatever client it runs. The poll restart is named beside it because the resume performs none.
82
+ - The requirement is a resume request to the orchestrator skill with it loaded first, and the command shown is this repository's spelling, not the only one
83
+ - The poll restart is named beside it because the resume performs none
84
+ - This runbook varies the door rather than replacing it, stating only what differs, so the two cannot disagree
63
85
 
64
- This runbook varies the door rather than replacing it, which is why the door is invoked first and this runbook states only what differs. The generic half moved out whole, the drift step and its ref recovery with it, so nothing here restates a step the door already carries and the two cannot disagree.
86
+ ## Where a lesson goes
65
87
 
66
- This session commits nothing, and the orchestrator's boundaries forbid writing a context entry from it. A domain fact belongs to the task that owns the surface and goes in that task's Findings, and so does a lesson about how to work, since nothing reads a lesson left only in the map once the session after it is past it.
88
+ This session commits nothing, and the orchestrator's boundaries forbid writing a context entry from it. A domain fact goes in the Findings of the task owning the surface, and so does a lesson about how to work, since nothing reads a lesson left only in the map once the next session is past it.
@@ -7,17 +7,16 @@ description: What each message from another session costs the orchestrator's con
7
7
 
8
8
  Part of `role-orchestrator`'s `## Parallelism`. The session reads this file before widening a wave, since review attention is what binds the track count and this is what it costs.
9
9
 
10
- Inbound turns are the third input to that judgment. Claude Code delivers a
11
- message from another session as a new turn whenever this one sits idle, and the
12
- turn carries the whole accumulated context rather than the few lines the worker
13
- sent, so one handback from a wide wave costs more than the same handback from a
14
- narrow one. A recurring review poll bills that window again on every interval it
15
- fires. Weigh the spend before widening, since it lands on this session's context
16
- and never on the worker's.
10
+ Inbound turns are the third input to that judgment. Claude Code delivers a message from another session as a new turn whenever this one sits idle, and the turn carries the whole accumulated context rather than the few lines the worker sent.
17
11
 
18
- `crossSessionInbound` is the control, on an `accept`, `hold`, `refuse` ladder,
19
- and it is recorded here as deliberately not pulled. `hold` and `refuse` are the
20
- two values that bound the cost, and both break the handback this loop runs on,
21
- since a held message reaches nobody until a later `accept` applies and a refused
22
- one is dropped outright. `accept` bounds nothing. Read the ladder before turning
23
- concurrency up rather than after, and leave it unset.
12
+ - One handback from a wide wave therefore costs more than the same handback from a narrow one
13
+ - A recurring review poll bills that window again on every interval it fires
14
+ - Weigh the spend before widening, since it lands on this session's context and never on the worker's
15
+
16
+ ## The control left unset
17
+
18
+ `crossSessionInbound` is the control, on an `accept`, `hold`, `refuse` ladder, and it is deliberately not pulled. Read the ladder before turning concurrency up rather than after, and leave it unset.
19
+
20
+ - `hold` and `refuse` are the two values that bound the cost, and both break the handback this loop runs on
21
+ - A held message reaches nobody until a later `accept` applies, and a refused one is dropped outright
22
+ - `accept` bounds nothing
@@ -21,42 +21,62 @@ claude --bg --model <model> -n "worker-<project>-<slug>" "/canon:auto-ship <plan
21
21
  Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message it when the pull request opens, carrying the number, the branch, the head sha, the CI state, and every point you departed from the plan on, and message it again if you stop on a question."
22
22
  ```
23
23
 
24
- `--bg, --background` starts the session as a background agent and returns immediately, `-n, --name` sets the display name that tells a self-dispatched worker from an operator's own launch in `canon sessions list`, and `--model` overrides the inheritance `## Pick the model` states. Pass `-n` on every dispatch rather than letting the client derive one. A launch that omits it leaves the session named for a fragment of its own identifier, which is both its address on the send channel and the whole of what the operator sees for it in agent view.
24
+ `--bg, --background` starts the session as a background agent and returns immediately, and `--model` overrides the inheritance `## Pick the model` states. `-n, --name` sets the display name that tells a self-dispatched worker from an operator's own launch in `canon sessions list`.
25
25
 
26
- The prefix reads `worker-` because that is the role it marks. A prefix naming a role the session does not hold sends a worker filtering the roster for that string to a sibling or itself on every row. Nothing matches the prefix programmatically, which keeps a rename down to three strings.
26
+ - Pass `-n` on every dispatch, since a launch omitting it names the session for a fragment of its identifier, its send address and all the operator sees
27
+ - The prefix reads `worker-` because that is the role it marks, since a prefix naming another role sends a worker filtering the roster to a sibling or itself
28
+ - Nothing matches the prefix programmatically, which keeps a rename down to three strings
27
29
 
28
- `<project>` is the basename of the main worktree root, not of wherever the dispatcher happens to be running. Resolve the main root first, the way `session-worktree` Step 1 does, since a bare `git rev-parse --show-toplevel` inside a linked worktree returns the worktree path rather than the project's. `claude agents` lists every session on the machine with no path column and no per-project filter, so `<project>` in the name is the only thing left telling two fleets apart.
30
+ ### The project and the controller id
29
31
 
30
- Read `<dispatcher-id>` with `canon sessions list --self --json` and interpolate the `sessionId` that row carries. Carry the id rather than the name. A name is derived from whatever the session turned out to be doing and can be renamed minutes after launch, inside the window a worker announces its pull request in, so a name written into the prompt is aimed at a send that happens after it goes stale.
32
+ `<project>` is the basename of the main worktree root, resolved the way `session-worktree` Step 1 does, since `git rev-parse --show-toplevel` inside a linked worktree returns the worktree path. `claude agents` lists every session on the machine with no path column, so `<project>` is all that tells two fleets apart.
31
33
 
32
- Where the installed CLI answers `--self` with an unknown option, that flag is newer than the release the target holds. Read the `sessionId` from the record the client writes for this session under its configuration directory, and say which route answered so the reader knows whether the id was read or inferred.
34
+ Read `<dispatcher-id>` with `canon sessions list --self --json` and interpolate the row's `sessionId`. Carry the id rather than the name, since a name can be renamed minutes after launch, inside the window a worker announces its pull request in.
33
35
 
34
- The worker resolves that id back to a name through `canon sessions list --json`, which carries `sessionId` per row, rather than through the agent listing, which prints a name and a short ref and no id at all. A worker reaching for the listing first therefore finds no lookup and can conclude there is none. That failure is silent in both directions: the session has nothing useful to do with the message it owes and goes idle holding it, and nothing on this side reports the quiet, so the loss surfaces as a missing worktree or a pull request that never opens rather than as anything watching for it.
36
+ - Where the installed CLI answers `--self` with an unknown option, read the `sessionId` from the record the client writes under its configuration directory
37
+ - Say which route answered, so the reader knows whether the id was read or inferred
35
38
 
36
- The template carries no worktree call. `auto-ship` Step 0 invokes `canon:role-worker` and then `canon:session-worktree` itself, and neither carries the flag, so both are reachable through the `Skill` tool regardless of where a call to them would sit in a prompt. The autoship call carries `<plan>`, the same file `orchestrator-dispatch.md` read to derive the branch, so its Step 1 takes it as the caller-supplied plan rather than re-deriving one from the slug the worker's branch happens to carry.
39
+ ### How the worker resolves the id
37
40
 
38
- The template names no branch, and it does not need to. `auto-ship` Step 0 runs `canon tasks plan-branch <plan>` on the same file the candidate was derived from, and hands the `<type>/<slug>` it reports to `session-worktree` as its tier 0 argument, so the two sides agree by calling one derivation rather than by a string copied between them. What still travels on judgment is the fallback: a worker whose installed binary carries no `plan-branch` derives by prose.
41
+ The worker resolves that id back to a name through `canon sessions list --json`, which carries `sessionId` per row. The agent listing prints a name and a short ref and no id, so a worker reaching for it first finds no lookup and can conclude there is none.
42
+
43
+ That failure is silent in both directions. The worker goes idle holding the message it owes, and nothing on this side reports the quiet, so the loss surfaces as a missing worktree or a pull request that never opens.
44
+
45
+ ### No worktree call and no branch
46
+
47
+ The template carries no worktree call. `auto-ship` Step 0 invokes `canon:role-worker` and then `canon:session-worktree` itself, and neither carries the flag, so both are reachable through the `Skill` tool wherever a call sits in a prompt.
48
+
49
+ - The autoship call carries `<plan>`, the file `orchestrator-dispatch.md` read to derive the branch, so Step 1 takes it as the caller-supplied plan
50
+ - Step 0 runs `canon tasks plan-branch <plan>` on that file and hands the `<type>/<slug>` to `session-worktree` as its tier 0 argument
51
+ - The two sides agree by calling one derivation rather than copying a string, and only a binary lacking `plan-branch` derives by prose
39
52
 
40
53
  ### Position zero
41
54
 
42
- Put a command whose skill carries `disable-model-invocation: true` at position zero of the launch prompt, followed by a space and its argument, with nothing before it. The client expands a slash command there as a user invocation, which is the route the flag permits. Anything reaching the session as prose falls to the model, which invokes it through the `Skill` tool, and that route answers a flagged skill inconsistently. `auto-ship` carries the flag. A comma or other punctuation glued to the command name at position zero has failed to expand, so treat the space as part of the rule until a dispatch shows otherwise.
55
+ Put a command whose skill carries `disable-model-invocation: true` at position zero of the launch prompt, followed by a space and its argument, with nothing before it. The client expands a slash command there as a user invocation, which is the route the flag permits.
43
56
 
44
- Never depend on the `Skill` tool route for a flagged skill. A refusal there tells the session not to replicate the workflow by other means, so a refused worker stops with a clean worktree, which is the correct outcome. The refusal is sticky inside a session, so recovery belongs to whoever writes the next prompt: re-dispatch onto the same branch with the build template above.
57
+ - Anything reaching the session as prose falls to the model, which invokes it through the `Skill` tool, a route that answers a flagged skill inconsistently
58
+ - `auto-ship` carries the flag
59
+ - A comma or other punctuation glued to the command name at position zero has failed to expand, so treat the space as part of the rule
45
60
 
46
- The review-address and planning shapes below, and the reviewer shapes in `orchestrator-reviewer-launch.md`, depend on no expansion at all. None of `role-worker`, `review-address`, `role-planner`, `plan-feature`, `role-reviewer`, or `review-pr` carries the flag, so all three correctly keep their leading word regardless of the delimiter or the position it sits at.
61
+ Never depend on the `Skill` tool route for a flagged skill. A refusal there tells the session not to replicate the workflow by other means, so a refused worker stops with a clean worktree, the correct outcome. The refusal is sticky inside a session, so recover by re-dispatching onto the same branch with the build template above.
47
62
 
48
- The same rule reaches a human relay. Hand an operator one message carrying one command at position zero, since two chained blocks pasted as separate messages can land as one, where everything after the first command's name reads as that command's argument and the second never fires.
63
+ ### Shapes needing no expansion
64
+
65
+ The review-address and planning shapes below, and the reviewer shapes in `orchestrator-reviewer-launch.md`, depend on no expansion. None of `role-worker`, `review-address`, `role-planner`, `plan-feature`, `role-reviewer`, or `review-pr` carries the flag, so each keeps its leading word whatever the delimiter or position.
66
+
67
+ The same rule reaches a human relay. Hand an operator one message carrying one command at position zero, since two blocks pasted as separate messages can land as one, where the second never fires.
49
68
 
50
69
  ### What the brief may carry
51
70
 
52
71
  The prompt carries pointers and standing context, and stops there. The branch and the plan stay arguments, because a skill resolves an argument through a documented ladder and reads no prose at all. What the prose reaches is the worker's judgment, so it holds only what a session has to weigh:
53
72
 
54
73
  - Name the addressee and what it is owed, which the two message clauses above already do.
55
- - Carry standing context this session holds that a cold one cannot derive, such as a constraint settled in conversation that never reached the plan.
56
- - Leave out anything scope-shaped. A file list, a naming convention, or a check to run belongs in the plan, where the review reads it back against the diff. Scope that arrives as prose is scope nothing verifies afterward.
57
- - On a reviewer launch, carry the sibling pull requests in flight, the files each shares with this one, the merge order, and a constraint settled in conversation, all as facts. Leave out this session's own read of the change, the author's argument for it, and any list of what to look for, since the first two cost the independence the dispatch pays for and the third is `review-craft`'s.
74
+ - Carry standing context a cold session cannot derive, such as a constraint settled in conversation that never reached the plan
75
+ - Leave out anything scope-shaped, such as a file list, a naming convention, or a check, which belongs in the plan the review reads back against the diff
76
+ - On a reviewer launch, carry the sibling pull requests in flight, the files each shares with this one, the merge order, and a settled constraint, all as facts
77
+ - Leave out this session's read of the change and the author's argument, which cost the dispatch its independence, and any list of what to look for, which is `review-craft`'s
58
78
 
59
- Report the dispatch as loudly as the human-launch line it replaces: name the branch, the model, the task, and the session name, so a person reading the transcript can follow what fired without watching it happen.
79
+ Report the dispatch as loudly as the human-launch line it replaces, naming the branch, the model, the task, and the session name, so a person reading the transcript can follow what fired without watching it happen.
60
80
 
61
81
  ## Dispatch to a cloud worker
62
82
 
@@ -64,45 +84,59 @@ Read `${CLAUDE_SKILL_DIR}/references/orchestrator-cloud-launch.md` when `orchest
64
84
 
65
85
  ## Dispatch to address a review
66
86
 
67
- `review-address` is a single pass, not a chain, so a launch naming it alone reaches no `role-worker` and takes no role, which owes no message either. Reach the role directly on this launch instead of wrapping a second chain around one skill that has none of its own.
87
+ `review-address` is a single pass, not a chain, so a launch naming it alone reaches no `role-worker` and owes no message. Reach the role directly on this launch instead of wrapping a second chain around one skill.
68
88
 
69
- The branch already exists here, opened by whatever built it, so this shape skips the plan-derived name the build shape resolves above. Take `<branch>` off the pull request's own head ref. Enter the worktree the original build left on disk, `.claude/worktrees/<slug>/`, with `EnterWorktree`'s `path` form when it is still there, or `git worktree add .claude/worktrees/<slug>/ <branch>` when it was cleaned up, so `<slug>` is that directory name either way.
89
+ The branch already exists, so this shape skips the plan-derived name and takes `<branch>` off the pull request's own head ref. `<slug>` is the directory name of the original build's worktree, `.claude/worktrees/<slug>/`.
70
90
 
71
- `EnterWorktree` refuses that path in the ordinary case, because the original build session stays registered against its own worktree after going idle and holds a harness-level lock the roster does not report. Work in the folder directly with `Bash`, `Read`, and `Edit` instead of retrying the tool.
91
+ - Enter it with `EnterWorktree`'s `path` form when it is still there, or `git worktree add .claude/worktrees/<slug>/ <branch>` when it was cleaned up
92
+ - `EnterWorktree` refuses that path in the ordinary case, since the idle build session holds a harness-level lock the roster does not report
93
+ - Work in the folder directly with `Bash`, `Read`, and `Edit` instead of retrying the tool
72
94
 
73
95
  ```bash
74
96
  claude --bg --model <model> -n "worker-<project>-<slug>" "Enter the worktree for <branch> at .claude/worktrees/<slug>/, creating it from that branch if the folder is gone. Run /canon:role-worker, then /canon:review-address. Your controller is the session whose sessionId is <dispatcher-id>, and your reviewer is the session whose sessionId is <reviewer-id>. Resolve each current name from its id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message the reviewer when the address pass finishes, asking it to re-review and carrying what was addressed and the PR's CI state, and send that to the controller instead when the reviewer's id resolves to no live session. Message the controller if you stop on a question."
75
97
  ```
76
98
 
77
- `<dispatcher-id>`, `<model>`, and `<project>` resolve the same way the build shape resolves them above. `<reviewer-id>` is the sessionId the reviewer's own message carried, so a worker launched fresh answers the reviewer directly. Where no local reviewer is live, which a cloud reviewer always leaves, drop the reviewer clause and send the finished message to the controller, which launches the re-review itself.
78
-
79
- Take this shape wherever a review needs answering and no live session already holds the branch. Where one does, message it to run `review-address` instead, per the loop's own step 6, since a session already there needs no second one dispatched onto the same branch.
99
+ `<dispatcher-id>`, `<model>`, and `<project>` resolve the same way the build shape resolves them above. `<reviewer-id>` is the sessionId the reviewer's own message carried, so a worker launched fresh answers the reviewer directly.
80
100
 
81
- That check is blind to a session working through the direct-path fallback above, since a session that never runs `EnterWorktree` never moves its registered branch off `main`, so `canon sessions list --branch` reports nothing holding it. A dispatch landing on a branch worked that way collides with nothing the check can see.
101
+ - Where no local reviewer is live, as a cloud reviewer always leaves, drop the reviewer clause and send the finished message to the controller
102
+ - Take this shape wherever a review needs answering and no live session holds the branch. Where one does, message it per the loop's step 6.
103
+ - That check is blind to a session working through the direct-path fallback, since it never moves its registered branch off `main`
104
+ - `canon sessions list --branch` then reports nothing holding the branch, so a dispatch landing there collides with nothing the check can see
82
105
 
83
106
  ## Dispatch to plan a row
84
107
 
85
- `plan-feature` is a procedure rather than a role, so a launch naming it alone reaches no `role-planner` and takes no role, which owes no message either. Reach the role directly on this launch, the way the build shape above reaches `role-worker`, rather than retyping the role's obligations as prose into each launch.
108
+ `plan-feature` is a procedure rather than a role, so a launch naming it alone reaches no `role-planner` and owes no message. Reach the role directly, the way the build shape reaches `role-worker`, rather than retyping its obligations as prose.
86
109
 
87
- No branch and no worktree exist here and none is created. A planner writes one gitignored file at the main worktree root, so this shape names the row's task file rather than a branch and opens with the role instead of a worktree call. That write meets the isolation guard the same way a linked worktree's main-root write does, with no worktree here to redirect it to, so `role-planner` sends it as a `Bash` heredoc rather than through `Write`.
110
+ No branch and no worktree exist here and none is created. A planner writes one gitignored file at the main worktree root, so this shape names the row's task file and opens with the role.
111
+
112
+ - That write meets the isolation guard as a linked worktree's main-root write does, with no worktree to redirect it to
113
+ - `role-planner` therefore sends it as a `Bash` heredoc rather than through `Write`
88
114
 
89
115
  ```bash
90
116
  claude --bg --model <model> -n "planner-<project>-<slug>" "Run /canon:role-planner, then /canon:plan-feature <task>. Your controller is the session whose sessionId is <dispatcher-id>. Resolve its current name from that id through canon sessions list --json, which carries sessionId per row, at the moment you send, and never resolve an addressee by name prefix. Message it when the plan lands, carrying the path and what the task file got wrong, and message it again if you stop on a question."
91
117
  ```
92
118
 
93
- `<task>` is the row's task file path and `<slug>` the slug its plan will take, resolved off the row the way the build shape resolves one off a plan. `<dispatcher-id>`, `<model>`, and `<project>` resolve the same way they do above. The prefix reads `planner-` for the reason the worker's reads `worker-`, which is that it marks the role of the session it names rather than the one that launched it.
119
+ `<task>` is the row's task file path and `<slug>` the slug its plan will take, resolved off the row. `<dispatcher-id>`, `<model>`, and `<project>` resolve as above, and the prefix reads `planner-` because it marks the role of the session it names.
94
120
 
95
- None of the three checks in `orchestrator-dispatch.md` binds this shape. The branch check has no candidate to read, and the conflict check has nothing to compare, since a planner writes one file no track in flight can hold. The plan-answer gate reaches no plan at all, because the planner is dispatched to write the file a build would later read, so running it here would refuse every planning dispatch over a plan nobody has written yet.
121
+ ### Which checks bind
96
122
 
97
- What a planning dispatch owes instead is the reverse reading, because the plan it produces carries a constraint per track in flight and a row planned during a wave is planned against a tree that wave is changing. `role-planner` composes the session roster with the pull request list for that read rather than reading pull requests alone, which is why the brief carries no branch list for it: the planner takes this reading itself either way.
123
+ None of the three checks in `orchestrator-dispatch.md` binds this shape.
98
124
 
99
- One row per dispatch. A session reused across a batch pays the context load once and ages its picture of the tree while it works, which is what puts the in-flight read on the task rather than on the batch, and one that compacts mid-batch loses the reasoning behind its earlier plans with nothing reporting it. Cap a reused session where the saving is worth it and say what the cap was.
125
+ - The branch check has no candidate to read
126
+ - The conflict check has nothing to compare, since a planner writes one file no track in flight can hold
127
+ - The plan-answer gate reaches no plan, since the planner writes the file a build later reads, so running it would refuse every planning dispatch
100
128
 
101
- ## Dispatch a talk session
129
+ What a planning dispatch owes instead is the reverse reading, since a row planned during a wave is planned against a tree that wave is changing. `role-planner` composes the session roster with the pull request list itself, which is why the brief carries no branch list.
130
+
131
+ ### One row per dispatch
102
132
 
103
- A planner or worker the operator will talk with takes the same launch as its cold shape above, with two changes. It carries a `-talk` suffix on its name, and its brief gains one sentence. A cold session works alone and reports back, and a talk session stays open after its plan or pull request lands so the operator can keep shaping the row with it.
133
+ A session reused across a batch pays the context load once and ages its picture of the tree while it works, which is why the in-flight read sits on the task rather than the batch. One that compacts mid-batch loses the reasoning behind its earlier plans with nothing reporting it.
134
+
135
+ Cap a reused session where the saving is worth it and say what the cap was.
136
+
137
+ ## Dispatch a talk session
104
138
 
105
- Take the planning shape or the build shape and change those two things:
139
+ A planner or worker the operator will talk with takes the same launch as its cold shape above, with a `-talk` suffix on its name and one sentence added to its brief. A cold session works alone and reports back, and a talk session stays open after its plan or pull request lands so the operator can keep shaping the row.
106
140
 
107
141
  ```bash
108
142
  claude --bg --model <model> -n "planner-<project>-<slug>-talk" "Run /canon:role-planner, then /canon:plan-feature <task>. This is a talk session: the operator will talk with you here, so run your role's talk clause, and message your controller when the operator ends the conversation. Your controller is the session whose sessionId is <dispatcher-id>. ..."
@@ -112,13 +146,15 @@ This is a talk session: the operator will talk with you here, so run your role's
112
146
 
113
147
  The ellipsis stands for the rest of the cold template's message clauses, unchanged. The build variant keeps `/canon:auto-ship <plan>` at position zero with nothing before it, per the rule above.
114
148
 
115
- Keep the role prefix and add the suffix rather than inventing a prefix. `orchestrator-handoff.md` separates dispatched sessions from hand-launched ones by `worker-` and `planner-`, so a new prefix would read as a hand launch and fall outside the retirement act.
149
+ - Keep the role prefix and add the suffix, since `orchestrator-handoff.md` separates dispatched sessions by `worker-` and `planner-` and a new prefix reads as a hand launch
150
+ - A talk session is retired only on the operator's word, stated once in `orchestrator-handoff.md`, so do not restate it in a launch report
151
+ - Reviewers get no talk shape, since a reviewer's pass holds no operator dialogue
116
152
 
117
- Read the session's `sessionId` off the launch output and carry it in this session's own context, then write it into the map's `## Talk sessions held open` section at the next handoff. The map exists only once the handoff writes it, so the launches this session made, read from its own context with the prior map, are the source the first wind-down reads talk sessions from. The client can rename a session after launch and drop the suffix, so the id is the durable marker and the suffix is only for display.
153
+ ### Recording the talk session
118
154
 
119
- A talk session is retired only on the operator's word, which `orchestrator-handoff.md` states under the retirement act. That runbook is the one place the rule lives, so do not restate it in a launch report.
155
+ Read the session's `sessionId` off the launch output, carry it in this session's own context, and write it into the map's `## Talk sessions held open` at the next handoff. The client can rename a session and drop the suffix, so the id is the durable marker and the suffix is only for display.
120
156
 
121
- Reviewers get no talk shape, since a reviewer's pass holds no operator dialogue.
157
+ The map exists only once the handoff writes it, so this session's own launches, read with the prior map, are what the first wind-down reads talk sessions from.
122
158
 
123
159
  ## Dispatch a reviewer
124
160
 
@@ -37,11 +37,16 @@ Next: <the single most useful action>
37
37
 
38
38
  Omit any section with nothing in it. Recommend a handoff only for a plan the conflict check in `orchestrator-dispatch.md` holds behind no track already in flight, and name any paths it shares with one.
39
39
 
40
- `In flight` covers the state between the other two, which lasts ten to thirty minutes and is most of what an operator sees once this session dispatches its own workers. Read the progress figures off each worker's worktree rather than from the worker, since a busy status says a session is alive and nothing about whether it is moving, and name the model because a dispatcher now picks one per row.
40
+ - The block opens on the board rather than a version, since no committed file states one and a version line would restate the rows, dated by nothing
41
+ - Leave a plan out of `Ready to build` once a row in flight names it, since its file stays in `.canon/plans/` for the whole build
42
+ - Listing it would recommend handing off work underway, and the conflict check withdraws that only for a reader who knows what is running
41
43
 
42
- Leave a plan out of `Ready to build` once a row in flight names it. The plan file stays in `.canon/plans/` for the whole build, so listing it there recommends handing off work already underway, and the conflict check withdraws the recommendation only for a reader who already knows what is running.
44
+ ### In flight
43
45
 
44
- The block opens on the board rather than on a version, because no committed file states one, and a version line would restate what a reader can already see on the rows, dated by nothing.
46
+ `In flight` covers the state between the other two, which lasts ten to thirty minutes and is most of what an operator sees once this session dispatches its own workers.
47
+
48
+ - Read the progress figures off each worker's worktree, since a busy status says a session is alive and nothing about whether it is moving
49
+ - Name the model, because a dispatcher now picks one per row
45
50
 
46
51
  ## Every later turn
47
52
 
@@ -56,6 +61,9 @@ Decisions:
56
61
  Next: <the single most useful action>
57
62
  ```
58
63
 
59
- Keep the detail below the block and keep it skippable. A decision reached at the bottom of three paragraphs has been buried, which is the failure this shape exists to prevent. Reuse the vocabulary above rather than inventing a second one, and keep a file set on the row claiming it so the reader can check a hold or a shared-path claim instead of taking it.
64
+ Keep the detail below the block and keep it skippable. A decision reached at the bottom of three paragraphs has been buried, which is the failure this shape exists to prevent.
65
+
66
+ - Reuse the vocabulary above rather than inventing a second one
67
+ - Keep a file set on the row claiming it, so the reader can check a hold or a shared-path claim instead of taking it
60
68
 
61
69
  Write no shape for a correction. A correction is a sentence, and a format for admitting error invites ceremony where plainness is the whole value.
@@ -5,69 +5,109 @@ description: Re-testing every parked blocker against the current tree, the two t
5
5
 
6
6
  Re-test every parked row as orchestrator. A blocker cell is a measurement taken the day the row was parked and nothing re-takes it, so a row can wait on a condition that stopped holding weeks earlier with no surface reporting the gap.
7
7
 
8
- Two triggers start this pass. `orchestrator-sweep.md` ends by sending the rows `canon tasks validate` listed as untested here, because a merge changes the tree under every parked row at once rather than under the rows naming it. The other is an idle session: nothing merged, workers are building, no pull request is waiting on a first pass, and the board is not moving.
8
+ ## Triggers
9
9
 
10
- The two differ in scope rather than in procedure. A merge sends the untested rows, since the validator already re-took the two kinds it can settle. An idle session walks every parked row, because no event narrowed which of them to look at, and it alone also walks `backlog.md`: a merge names no backlog row as untested, since `canon tasks validate` re-tests blocker cells and a backlog row carries none.
10
+ Two triggers start this pass, and they differ in scope rather than in procedure.
11
11
 
12
- Neither trigger is a scheduler. `orchestrator-poll.md` owns the one recurring trigger this skill has, and a second loop firing into a static board is the always-on failure that file already warns about.
12
+ | Trigger | Scope |
13
+ | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
14
+ | `orchestrator-sweep.md` sends the rows `canon tasks validate` listed untested | Those rows alone, since a merge changes the tree under every parked row and the validator already re-took the two kinds it settles |
15
+ | An idle session, with nothing merged, workers building, and no pull request awaiting a first pass | Every parked row, since no event narrowed them, plus every `backlog.md` row, which carries no blocker cell for the validator to name |
13
16
 
14
- The sweep's own question stays distinct from this one. It asks which parked row to promote next, taking the blocker cell as read, and this pass asks whether that cell is still true. A session collapsing them runs whichever it remembers and re-tests nothing.
17
+ - Neither trigger is a scheduler. `orchestrator-poll.md` owns the one recurring trigger, and a second loop firing into a static board is the always-on failure it warns about.
18
+ - The sweep asks which parked row to promote next, taking the blocker cell as read, and this pass asks whether the cell is still true
19
+ - A session collapsing the two runs whichever it remembers and re-tests nothing
15
20
 
16
21
  ## Scope
17
22
 
18
- Every row under `## Up next` and `## Needs a plan` in `.canon/tasks/priority.md`. A `## Run now` row carries no blocker by definition, so the pass skips it. On the idle trigger, also every row in `.canon/tasks/backlog.md` when the file exists, per the trigger split above. Resolve the board, the backlog, and each task file at the main worktree root, the way `session-worktree` does.
23
+ Every row under `## Up next` and `## Needs a plan` in `.canon/tasks/priority.md`, plus every row in `.canon/tasks/backlog.md` on the idle trigger when the file exists. A `## Run now` row carries no blocker, so the pass skips it. Resolve the board, the backlog, and each task file at the main worktree root, the way `session-worktree` does.
19
24
 
20
- Take the board rows in board order and finish one before opening the next. Clearing a row changes what the next row holds behind, so a pass that measures every row first and writes afterwards writes against a board it has already invalidated. On the idle trigger, walk the backlog after the board, in the file's own filename order, since `${CLAUDE_SKILL_DIR}/../task-board/references/board.md` fixes that file as unordered and nothing about a row's position there means anything to preserve mid-pass.
25
+ - Take the board rows in board order and finish one before opening the next, since clearing a row changes what the next row holds behind
26
+ - A pass that measures every row first and writes afterwards writes against a board it has already invalidated
27
+ - On the idle trigger, walk the backlog after the board in filename order, since `${CLAUDE_SKILL_DIR}/../task-board/references/board.md` fixes it as unordered
21
28
 
22
29
  ## Re-testing a row
23
30
 
24
31
  The blocker cell states what the row waits on, and each kind is tested differently. `canon tasks validate` already re-takes the first two and reports the rest as untested, so run it first and re-take by hand only what it names.
25
32
 
26
- - A hold behind a track in flight: the validator tests the file the cell cites against the Touches column of every `## Run now` row. A track that merged since the row was parked is no longer in flight, whatever the sets still share. Re-test the cell under the conflict check in `orchestrator-dispatch.md` too, since a row parked on a shared file alone holds on nothing and moves up. A cell naming the file in prose rather than in backticks cites nothing, so write the hold the way the board format spells it and the check picks the row up on the next run.
27
- - A dependency on another task: the validator opens the task a link in the cell names. One whose outcomes are all `[x]`, one already archived, or one already declined, holds nothing. A cell naming the task in prose resolves to no file, so open it by hand and rewrite the cell as a link.
33
+ ### A hold behind a track in flight
34
+
35
+ The validator tests the file the cell cites against the Touches column of every `## Run now` row. A track that merged since the row was parked is no longer in flight, whatever the sets still share.
36
+
37
+ - Re-test the cell under the conflict check in `orchestrator-dispatch.md` too, since a row parked on a shared file alone holds on nothing and moves up
38
+ - A cell naming the file in prose rather than backticks cites nothing, so rewrite the hold in the board's spelling and the next run picks it up
39
+
40
+ ### A dependency on another task
41
+
42
+ The validator opens the task a link in the cell names. One whose outcomes are all `[x]`, one already archived, or one already declined holds nothing. A cell naming the task in prose resolves to no file, so open it by hand and rewrite the cell as a link.
43
+
44
+ ### The other three kinds
45
+
46
+ These the validator reports untested, and each takes its own handling.
47
+
28
48
  - A condition about the tree, such as a count of some shape or the presence of a construct: measure it again, per Two ways a re-test goes wrong below.
29
49
  - Waiting on a plan: nothing external holds the row, so the pass writes the plan rather than testing anything. See The plan half below.
30
- - Waiting on an operator action, such as a run that happens from a shell: record it as untestable this pass and name what the operator has to do. A session cannot clear it, and re-measuring it every pass is waste.
50
+ - Waiting on an operator action, such as a run from a shell: record it as untestable this pass and name what the operator has to do, since re-measuring it is waste
31
51
 
32
- Every measurement this pass takes is a blocker re-test on a row already filed, and it decides whether that row can start rather than how big it is. Sizing a row is the filing boundary `role-orchestrator` states under `## Boundaries`, which leaves the extent and the cause to whoever plans the row.
52
+ ### Writing the result
33
53
 
34
- Write the result into the row. A re-test reported in chat is lost at the next compaction and the next pass measures the same thing again. Rewrite a blocker cell whose test no longer holds, move the row to the group its new state puts it in, and record the measurement in that task's `## Findings` as a line labeled with this session and the date it was taken, per `${CLAUDE_SKILL_DIR}/../task-board/references/tasks.md`. `### Writing the board` in `role-orchestrator` owns the method, and `canon tasks validate` runs once the board is rewritten and before the report.
54
+ Every measurement this pass takes decides whether a row can start rather than how big it is. Sizing a row is the filing boundary `role-orchestrator` states under `## Boundaries`, which leaves the extent and the cause to whoever plans it.
55
+
56
+ Write the result into the row, since a re-test reported in chat is lost at the next compaction and measured again.
57
+
58
+ - Rewrite a blocker cell whose test no longer holds, and move the row to the group its new state puts it in
59
+ - Record the measurement in the task's `## Findings` as a line labeled with this session and the date, per `${CLAUDE_SKILL_DIR}/../task-board/references/tasks.md`
60
+ - `### Writing the board` in `role-orchestrator` owns the method, and `canon tasks validate` runs once the board is rewritten and before the report
35
61
 
36
62
  ## Re-testing a backlog row
37
63
 
38
- A backlog row carries no blocker cell, since `${CLAUDE_SKILL_DIR}/../task-board/references/board.md` fixes `backlog.md` as a flat list of links with no state of its own. The five kinds above test what a blocker names, and a backlog row names none, so this pass asks the board-or-backlog question the standard already states instead: has the work in front of the row landed, or has the world changed under it. Read the answer from the task file's own `## Findings` and its origin line (`Plan:`, `Groundwork:`, `Intake:`, or `Issue:`), which name what the row was filed against and whether the fact behind it still holds.
64
+ A backlog row carries no blocker cell, since `${CLAUDE_SKILL_DIR}/../task-board/references/board.md` fixes `backlog.md` as a flat list of links with no state of its own. This pass asks the standard's board-or-backlog question instead, whether the work in front of the row landed or the world changed under it.
65
+
66
+ - Read the answer from the task file's `## Findings` and its origin line, `Plan:`, `Groundwork:`, `Intake:`, or `Issue:`
67
+ - Clearing a row answers yes, never a count of how long it waited, since age is refused as evidence here on the same ground as for a board row
68
+ - This pass only clears a row upward. Declining or archiving a backlog row is `backlog-triage`.
39
69
 
40
- Clearing a row answers yes to that question. It is not a count of how long the row has waited: `## Two results that are not a re-test` below refuses age as evidence for a board row, and it refuses it here on the same ground, since a row untouched for weeks is not more clearable than one added yesterday.
70
+ ### Moving a cleared row
41
71
 
42
- A row this test clears moves out of `backlog.md` and onto the bottom of `## Needs a plan`, carrying a `Waiting on` cell that states what changed and ends with the word `last`. `canon tasks validate`'s ordering check reads `last` as the ordinal bottom placement already claims, and a cell stating only what changed matches neither that check's ordinal reading nor its rank reading, which raises the finding this pass would then have written against its own row. The next refill sweep's promotion step still orders the row against the rest of that heading the way it orders every other row there, per step 5 under `## Refilling the ready queue` in `role-orchestrator`.
72
+ A cleared row moves out of `backlog.md` onto the bottom of `## Needs a plan`, with a `Waiting on` cell stating what changed and ending with the word `last`.
43
73
 
44
- This pass only clears a row upward. Declining or archiving a backlog row is `backlog-triage`, which files a verdict for every row and applies the ones the operator approved.
74
+ - `canon tasks validate`'s ordering check reads `last` as the ordinal the bottom placement claims
75
+ - A cell stating only what changed matches neither the ordinal nor the rank reading, raising a finding against the pass's own row
76
+ - The next refill sweep's promotion step still orders the row against the rest of that heading, per step 5 under `## Refilling the ready queue` in `role-orchestrator`
45
77
 
46
78
  ## Two ways a re-test goes wrong
47
79
 
48
80
  Both return a confident wrong answer rather than an error, which is why each gets a step of its own.
49
81
 
50
- The first is reading the condition looser than the code defines it. A row parked on a count of some shape names a shape its consumer defines precisely, and a count taken by eye or by a pattern that approximates it lands somewhere else. The row that motivated this runbook counted 19 instances of a shape whose real count under the consumer's definition was zero.
82
+ ### Reading the condition looser than the code
83
+
84
+ A row parked on a count of some shape names a shape its consumer defines precisely, and a count by eye or by an approximate pattern lands elsewhere. The row that motivated this runbook counted 19 instances of a shape whose real count under the consumer's definition was zero.
51
85
 
52
86
  Find the code that consumes the shape, read the definition off it, and measure with that. A count taken any other way is not evidence about the blocker.
53
87
 
54
- The second is measuring against the wrong tree. A command that ships to targets is at risk in corpora this repository never formats, so a condition measured here reads as unreachable while it stays live where the command runs. Ask which tree the condition is about before asking what the count is. A local formatter removing the shape on contact says nothing about a target running no such formatter.
88
+ ### Measuring against the wrong tree
55
89
 
56
- ## The plan half
90
+ A command that ships to targets is at risk in corpora this repository never formats, so a condition measured here reads as unreachable while it stays live where the command runs. Ask which tree the condition is about before asking what the count is.
57
91
 
58
- Plan what the pass clears, and plan any `## Needs a plan` row whose only blocker is the missing plan. The window is the argument: this pass runs while workers build and the session is otherwise idle, which is when planning costs the critical path nothing, and a row cleared with no plan is a row the next pass looks at again.
92
+ A local formatter removing the shape on contact says nothing about a target running no such formatter.
59
93
 
60
- Run `plan-feature` for each, carrying the constraint per in-flight track that `## The loop` in `role-orchestrator` requires. Verify each plan against the tree the way that step does, since a plan written now is written against a tree several branches are already changing.
94
+ ## The plan half
61
95
 
62
- Stop where `## Parallelism` stops rather than planning every row the pass cleared. A plan the conflict check holds behind every track in flight is one nobody can dispatch.
96
+ Plan what the pass clears, and any `## Needs a plan` row whose only blocker is the missing plan. This pass runs while workers build and the session is idle, when planning costs the critical path nothing, and a row cleared with no plan is looked at again next pass.
63
97
 
64
- Do not restate the refill procedure. `orchestrator-refill.md` owns it and `orchestrator-sweep.md` wraps it for a batch of merges, so this pass promotes through that method rather than a second one.
98
+ - Run `plan-feature` for each, carrying the constraint per in-flight track that `## The loop` in `role-orchestrator` requires
99
+ - Verify each plan against the tree the way that step does, since several branches are already changing it
100
+ - Stop where `## Parallelism` stops, since a plan the conflict check holds behind every track in flight is one nobody can dispatch
101
+ - Do not restate the refill procedure. `orchestrator-refill.md` owns it, so this pass promotes through that method.
65
102
 
66
103
  ## Two results that are not a re-test
67
104
 
68
- Age is not evidence. A row untouched for weeks invites promotion, and the waiting is not an argument for it. `role-orchestrator` refuses to promote a task to fill the queue and this pass inherits that refusal, so a row whose blocker still holds stays where it is. Reporting it as still parked, against a measurement taken this pass, is a result.
105
+ Neither result below justifies moving a row.
69
106
 
70
- A scoping defect can wear a blocker. A task conflicting with every other by construction, through a contract everything consumes or a sweep over everything, is oversized rather than blocked, and planning it again produces the same plan nobody can dispatch. Split it so each piece holds behind fewer tracks, and the board stops carrying a row that re-measures the same way every pass. A task that merely shares files with everything is not this case.
107
+ - Age is not evidence. `role-orchestrator` refuses to promote a task to fill the queue, so a row whose blocker still holds stays, reported as still parked against this pass's measurement.
108
+ - A scoping defect can wear a blocker. A task conflicting with every other through a contract everything consumes or a sweep over everything is oversized, not blocked.
109
+ - Split such a task so each piece holds behind fewer tracks, since planning it again produces the same undispatchable plan
110
+ - A task that merely shares files with everything is not this case
71
111
 
72
112
  ## Output
73
113