@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,7 +7,10 @@ description: The cloud build and review shapes, being the launch prompt that car
7
7
 
8
8
  Run this once `orchestrator-dispatch.md` has cleared a row and picked cloud for it. The worker runs on a Claude Code cloud VM that clones the repository from GitHub, loads no plugin, and cannot see this machine's `.canon/`.
9
9
 
10
- The shape needs a `SessionStart` hook in the repository that, on the VM alone, copies the plugin skills into `.claude/skills/` and puts `canon` on the path. A repository without one cannot take this shape, so fall back to a local worker there. Where the hook exists, the launch prompt calls `/auto-ship` with no `canon:` prefix, since the copied skills list as project skills.
10
+ The shape needs a `SessionStart` hook in the repository that, on the VM alone, copies the plugin skills into `.claude/skills/` and puts `canon` on the path.
11
+
12
+ - A repository without one cannot take this shape, so fall back to a local worker there
13
+ - Where the hook exists, the prompt calls `/auto-ship` with no `canon:` prefix, since the copied skills list as project skills
11
14
 
12
15
  ## Contents
13
16
 
@@ -19,7 +22,9 @@ The shape needs a `SessionStart` hook in the repository that, on the VM alone, c
19
22
 
20
23
  ## Check the row is unclaimed
21
24
 
22
- A cloud worker never appears in `canon sessions list` and never pushes the derived branch, since the cloud assigns it a `claude/` branch of its own. So the roster and the refs read clear on a row a cloud worker is already building. Run the local check in `orchestrator-dispatch.md` anyway, since a local worker on the same row still collides, then read the two places a cloud worker does show:
25
+ A cloud worker never appears in `canon sessions list` and never pushes the derived branch, since the cloud assigns it a `claude/` branch of its own, so the roster and the refs read clear on a row it is building.
26
+
27
+ Run the local check in `orchestrator-dispatch.md` anyway, since a local worker on the same row still collides, then read the two places a cloud worker does show:
23
28
 
24
29
  ```bash
25
30
  prs=$(gh api 'repos/{owner}/{repo}/pulls?state=open&per_page=100' --jq '.[] | select(.head.ref | startswith("claude/")) | .number') || { echo 'unreadable: the open pull request list'; exit 1; }
@@ -37,7 +42,8 @@ Branch on the line it prints rather than on the exit, which a shell function wra
37
42
 
38
43
  - `claimed: #<n>`: a cloud worker's pull request names the plan slug. Treat the row as claimed and report each number.
39
44
  - `clear`, and this pass's launched record holds no cloud session for the row: the row is clear of cloud workers.
40
- - `unreadable: <what>`: the list or a comment read failed, so nothing was checked. Treat the candidate as unverified and fall back to the human-launch line, the same as a refused local check in `orchestrator-dispatch.md`. Never read it as clear, since an empty answer from a failed read is the collision this check exists to catch.
45
+ - `unreadable: <what>`: nothing was checked, so treat the candidate as unverified and fall back to the human-launch line, as for a refused local check
46
+ - Never read `unreadable` as clear, since an empty answer from a failed read is the collision this check exists to catch
41
47
 
42
48
  The launched record covers the minutes before the pull request opens, when nothing on GitHub names the row yet. It is this session's alone, so a second dispatcher sees only the pull request list, which is the window `orchestrator-dispatch.md` already states for local workers under `## Hold what this pass already launched`.
43
49
 
@@ -67,15 +73,26 @@ session=$(grep -A 2 'Created cloud session:' "$dir/create.typescript" | grep -o
67
73
  printf 'session=%s\n' "$session"
68
74
  ```
69
75
 
70
- Run it from the main worktree root, since the session targets whichever repository that checkout's `origin` names. That folder is already trusted, so the create screen shows no trust prompt. From a checkout this machine has not trusted, such as a fresh clone of another repository, the screen asks first, and piped keys answer it: replace `<(sleep 30)` with `<(sleep 4; printf '\033[B'; sleep 1; printf '\r'; sleep 30)`. Either way stdin stays open for the create, which is the shape the wrapper was measured in, since an early end of input can reach the terminal before the create screen settles.
76
+ Run it from the main worktree root, since the session targets whichever repository that checkout's `origin` names. That folder is already trusted, so the create screen shows no trust prompt.
77
+
78
+ - From an untrusted checkout, such as a fresh clone of another repository, the screen asks first, and piped keys answer it
79
+ - Replace `<(sleep 30)` with `<(sleep 4; printf '\033[B'; sleep 1; printf '\r'; sleep 30)` there
80
+ - Either way stdin stays open for the create, the measured shape, since an early end of input can reach the terminal before the screen settles
81
+
82
+ ### The readout
71
83
 
72
- The readout is the text `Created cloud session: <title>`, unanchored since a terminal capture can open a line with escape codes, followed by a `View:` address carrying the `session_...` id. Anything else is a failed create, including a run that exits zero. Report the typescript's last lines and fall back to the human-launch line in `orchestrator-dispatch.md` rather than recording a session that does not exist. The wrapper is a stopgap: any change to the interactive create screen breaks it, which is why the readout fails loudly instead of guessing.
84
+ The readout is the text `Created cloud session: <title>`, unanchored since a terminal capture can open a line with escape codes, followed by a `View:` address carrying the `session_...` id. Anything else is a failed create, including a run that exits zero.
73
85
 
74
- Record `session` beside the row's branch in this pass's launched record. A cloud worker never registers in `canon sessions list`, so that record and the pull request list are the only two readings that know it exists. Report the dispatch the way the local shape does, naming the row, the plan, the repository, and the session id in place of a session name.
86
+ - On a failed create, report the typescript's last lines and fall back to the human-launch line in `orchestrator-dispatch.md`
87
+ - The wrapper is a stopgap any change to the interactive create screen breaks, which is why the readout fails loudly instead of guessing
88
+ - Record `session` beside the row's branch in this pass's launched record, since that and the pull request list are the only readings that know it exists
89
+ - Report the dispatch as the local shape does, naming the row, the plan, the repository, and the session id in place of a session name
75
90
 
76
91
  ## Recognize the pull request
77
92
 
78
- A cloud worker cannot message this session and never appears in the roster `watch.ts` reads, so its pull request and its `ANNOUNCE:` comment are the announcement. Start the poll in `orchestrator-poll.md` when the cloud dispatch goes out, rather than at that runbook's thirty-minute fallback. A pull request on a `claude/` head is this row's when one of its commits carries a `Claude-Session:` trailer naming the session id the create recorded:
93
+ A cloud worker cannot message this session and never appears in the roster `watch.ts` reads, so its pull request and its `ANNOUNCE:` comment are the announcement. Start the poll in `orchestrator-poll.md` when the cloud dispatch goes out, rather than at its thirty-minute fallback.
94
+
95
+ A pull request on a `claude/` head is this row's when one of its commits carries a `Claude-Session:` trailer naming the session id the create recorded:
79
96
 
80
97
  ```bash
81
98
  gh api 'repos/{owner}/{repo}/pulls/<number>/commits' --jq '.[].commit.message' | grep -c 'Claude-Session:.*<session>'
@@ -85,15 +102,31 @@ A count above zero matches the row. A count of zero is someone else's pull reque
85
102
 
86
103
  ## Dispatch a review to a cloud reviewer
87
104
 
88
- Run this once `orchestrator-review-dispatch.md` has sent a code review to a dispatched reviewer and the operator picked cloud for it. The reviewer needs the same `SessionStart` hook as the build shape, and a `canon` on the VM whose `pr` reads run on REST, since the proxy refuses GraphQL. A UI review never takes this shape, because it drives a browser the VM does not have.
105
+ Run this once `orchestrator-review-dispatch.md` has sent a code review to a dispatched reviewer and the operator picked cloud for it. A UI review never takes this shape, because it drives a browser the VM does not have.
106
+
107
+ - The reviewer needs the same `SessionStart` hook as the build shape
108
+ - It needs a `canon` on the VM whose `pr` reads run on REST, since the proxy refuses GraphQL
109
+
110
+ ### Confirm the REST reads
89
111
 
90
- Confirm the VM's `canon` reads over REST before dispatching. In this repository the setup hook links the checkout's own CLI, so a pushed branch carries the reads. Any other repository's VM installs `canon` from npm, so its `pr` reads run on REST only once a release carrying them is published, and its copied skills carry the REST lookups only once that repository's skills are re-scaffolded from that release.
112
+ Confirm the VM's `canon` reads over REST before dispatching. In this repository the setup hook links the checkout's own CLI, so a pushed branch carries the reads.
91
113
 
92
- Read `npm view @erclx/canon version` against the first release whose changelog names the REST reads, and check the target's copied `review-pr` the same way, by running `grep -rnE 'gh pr (list|view|review|diff|comment)'` over it and expecting no output. A version short of that release, or a hit, dispatches a reviewer that fails on its first GraphQL call, so take the local shape instead.
114
+ - Any other repository's VM installs `canon` from npm, so its `pr` reads run on REST only once a release carrying them is published
115
+ - Its copied skills carry the REST lookups only once that repository's skills are re-scaffolded from that release
116
+ - Read `npm view @erclx/canon version` against the first release whose changelog names the REST reads
117
+ - Run `grep -rnE 'gh pr (list|view|review|diff|comment)'` over the target's copied `review-pr` and expect no output
118
+ - A version short of that release, or a hit, dispatches a reviewer that fails on its first GraphQL call, so take the local shape instead
93
119
 
94
- Check this pass's launched record for a cloud reviewer already holding the number, and run `canon pr review-state <number> --json` for a pass already posted. A cloud reviewer never appears in `canon sessions list`, so the live-session check the local shape runs reads clear on a pull request one already holds.
120
+ ### Before the create
95
121
 
96
- The create targets whichever repository the checkout it runs from names as `origin`. For a pull request in this repository, write the prompt to `.canon/tmp/cloud-review-<number>/prompt.md` at the main worktree root and run the create there. For a pull request in another repository, run the create from a checkout of that repository and write the prompt under that checkout's own `.canon/tmp/cloud-review-<number>/`, which its `.gitignore` has to cover before the create runs. A fresh clone made for this is untrusted, so the create takes the trust-prompt key variant under `## The create`:
122
+ Check this pass's launched record for a cloud reviewer already holding the number, and run `canon pr review-state <number> --json` for a pass already posted. A cloud reviewer never appears in `canon sessions list`, so the local shape's live-session check reads clear on one.
123
+
124
+ The create targets whichever repository the checkout it runs from names as `origin`.
125
+
126
+ - For a pull request in this repository, write the prompt to `.canon/tmp/cloud-review-<number>/prompt.md` at the main worktree root and create there
127
+ - For another repository, run the create from its checkout and write the prompt under that checkout's own `.canon/tmp/cloud-review-<number>/`
128
+ - That checkout's `.gitignore` has to cover the folder before the create runs
129
+ - A fresh clone made for this is untrusted, so the create takes the trust-prompt key variant under `## The create`:
97
130
 
98
131
  ```plaintext
99
132
  /role-reviewer
@@ -104,12 +137,29 @@ Your controller cannot receive a message from this session. The review you post
104
137
 
105
138
  The cross-branch facts are the ones `### What the brief may carry` in `orchestrator-launch.md` allows a reviewer brief, and nothing of this session's own read. Neither skill carries the invocation flag, so no position-zero expansion is at stake and the bare names reach the copied project skills.
106
139
 
107
- Create the session with the wrapper under `## The create`, setting `dir` to that prompt's folder, and keep its readout rule: no `session_` id means nothing was dispatched. Record the session id beside the number in this pass's launched record, and name the number, the repository, and the session id in the dispatch report.
140
+ ### Create and record
141
+
142
+ Create the session with the wrapper under `## The create`, setting `dir` to that prompt's folder, and keep its readout rule, so no `session_` id means nothing was dispatched.
143
+
144
+ - Record the session id beside the number in this pass's launched record, and name the number, the repository, and the session id in the report
145
+ - `poll.ts` reads every open pull request's review state from this machine, so the posted `## Review` reaches the next poll like a local reviewer's
146
+ - Start the poll when the dispatch goes out rather than at its fallback
147
+ - A `QUESTION: review <number>` comment reaches the same poll as an unclassified reply, so answer it on the pull request
148
+
149
+ ### Checking the transcript
150
+
151
+ The pull request is the record to act on, and the transcript is read back only to check for a refused call. Search the capture for `HTTP 403` and `graphql`, and report a hit as a finding naming a call still on GraphQL rather than reading the review as clean.
108
152
 
109
- `poll.ts` lists every open pull request from this machine and reads each one's review state, so the posted `## Review` reaches the next poll like a local reviewer's. Start the poll when the dispatch goes out rather than at its fallback. A `QUESTION: review <number>` comment reaches the same poll as an unclassified reply, so answer it on the pull request.
153
+ - Run `claude --teleport <session>` under `script` from a throwaway clone of the target outside this repository
154
+ - Answer its trust prompt with the same piped keys
155
+ - Set the terminal to 500 rows first, since only the screen tail is captured otherwise
110
156
 
111
- The pull request is the record to act on, and the transcript is read back only to check for a refused call. Run `claude --teleport <session>` under `script` from a throwaway clone of the target outside this repository, answer its trust prompt with the same piped keys, and set the terminal to 500 rows first, since only the screen tail is captured otherwise. Search the capture for `HTTP 403` and `graphql`. A hit names a call still on GraphQL, so report it as a finding rather than reading the posted review as clean.
157
+ ### What a cloud reviewer cannot do
112
158
 
113
- A cloud reviewer cannot be messaged after it posts, and it cannot message the worker either. `poll.ts` reports nothing when a code review posts on an unchanged head, so the poll's cloud-reviewer rule reads `canon pr review-state <number> --json` on every run for each pull request one holds, and sends the `review-address` dispatch from this session when that read shows an open pass. A re-review after the worker's address pass is a fresh dispatch, local or cloud by the same pick, rather than the message a worker sends a live local reviewer.
159
+ A cloud reviewer cannot be messaged after it posts, and it cannot message the worker either. `poll.ts` reports nothing when a code review posts on an unchanged head, so the poll's cloud-reviewer rule reads `canon pr review-state <number> --json` on every run for each pull request one holds.
114
160
 
115
- A cloud reviewer cannot lift the draft mark, since `canon pr lift` makes its one write through the GraphQL mutation the proxy refuses. Leave the lift out of its prompt. The same per-run read runs the verb from this session once the review reads closed at the head on a pull request still a draft. A local reviewer whose run refused reports that refusal in its close message, which reaches loop step 6 rather than the poll.
161
+ - That read sends the `review-address` dispatch from this session when it shows an open pass
162
+ - A re-review after the worker's address pass is a fresh dispatch, local or cloud by the same pick
163
+ - It cannot lift the draft mark, since `canon pr lift` writes through the GraphQL mutation the proxy refuses, so leave the lift out of its prompt
164
+ - The same per-run read runs the verb from this session once the review reads closed at the head on a pull request still a draft
165
+ - A local reviewer whose run refused reports that in its close message, which reaches loop step 6 rather than the poll
@@ -20,54 +20,65 @@ Run this at loop step 4, for a `## Run now` row whose plan is verified, in place
20
20
 
21
21
  ## Derive the candidate
22
22
 
23
- Run `canon tasks plan-branch <plan> --json` against the row's plan file and read `branch`, `type`, `slug`, and `conforms` off the record.
23
+ Run `canon tasks plan-branch <plan> --json` against the row's plan file and read `branch`, `type`, `slug`, and `conforms` off the record. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero.
24
24
 
25
25
  - `conforms: true`: take `branch` as the candidate, and take `type` and `slug` from the same record for the check below.
26
- - `conforms: false`: the plan's own filename breaks a cap in `${CLAUDE_SKILL_DIR}/../git-branch/references/branch.md`. Report which, and hand the row to the human-launch line below rather than shortening the slug here. A rename parts the branch from the plan filename that `session-worktree` tier 1 and `git-pr`'s plan lookup both read back.
27
- - `reason: archived`, `no-plan`, or `bad-input`: the row does not cite a live plan. Repoint the row or fix the citation rather than dispatching, since `auto-ship` Step 1 refuses the same file and the worker would meet that refusal after the launch spent.
28
- - Anything else, including a record carrying no `branch` key and an installed binary carrying no `plan-branch` subcommand: treat the candidate as unverified rather than clear, name which reading could not be taken, and fall back to the human-launch line below. Re-deriving by prose here rebuilds the defect the verb closes, and does it quietly.
26
+ - `conforms: false`: the plan's filename breaks a cap in `${CLAUDE_SKILL_DIR}/../git-branch/references/branch.md`. Report which, and hand the row to the human-launch line below.
27
+ - `reason: archived`, `no-plan`, or `bad-input`: the row cites no live plan, so repoint the row or fix the citation, since `auto-ship` Step 1 refuses the same file
28
+ - Anything else, including no `branch` key or a binary lacking `plan-branch`: treat the candidate as unverified, name the missing reading, and fall back to the human
29
29
 
30
- Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero.
30
+ ### Why the verb decides
31
31
 
32
- The worker calls the same verb on the same plan at `auto-ship` Step 0, so the branch this gate checks and the branch that session takes are one string by construction rather than two readings of one paragraph. Two readings of one plan part on the slug and on the type alike, and a check against a branch nobody uses verifies nothing.
32
+ Never shorten a non-conforming slug here, since a rename parts the branch from the plan filename that `session-worktree` tier 1 and `git-pr`'s plan lookup read back. Re-deriving by prose rebuilds the defect the verb closes, quietly.
33
33
 
34
- The type the verb reports is fixed at `feat`, which is safe because a branch type is cosmetic: `git-stage` and `git-pr` read their types off the diff, and nothing a release reads passes through the branch name. The cost is a worktree listing where every dispatched branch reads `feat/`.
34
+ - The worker calls the same verb on the same plan at `auto-ship` Step 0, so the checked branch and the taken branch are one string by construction
35
+ - Two readings of one plan part on the slug and the type alike, and a check against a branch nobody uses verifies nothing
36
+ - The type is fixed at `feat`, which is safe because `git-stage` and `git-pr` read types off the diff and no release reads the branch name
37
+ - The cost is a worktree listing where every dispatched branch reads `feat/`
35
38
 
36
39
  ## Check the plan waits on nobody
37
40
 
38
- Run `canon tasks plan-answers <plan> --json` and read `launchable` off the record.
41
+ Run `canon tasks plan-answers <plan> --json` and read `launchable` off the record. Branch on `launchable` rather than on the exit code, which a wrapping shell function can flatten to zero and so read a held row as clear.
39
42
 
40
43
  - `launchable: true`: the plan answers itself, so proceed to the branch check.
41
- - `launchable: false`: the row is not dispatchable. Report every entry in `open`, each carrying the question label and the reason its suggestion gave for needing a person, and hand the row to the human-launch line below. Never fill the slot on the operator's behalf, the one move the plan standard forbids outright.
42
- - `reason: archived`: the row's plan sits in `.canon/plans/archive/` and describes work that already shipped. Repoint the row at a live plan rather than dispatching, since `auto-ship` Step 1 refuses the same file and the worker would meet that refusal after the launch spent.
44
+ - `launchable: false`: report every entry in `open`, each with its question label and stated reason, and hand the row to the human-launch line below
45
+ - Never fill the slot on the operator's behalf, the one move the plan standard forbids outright
46
+ - `reason: archived`: the plan sits in `.canon/plans/archive/` and describes shipped work, so repoint the row, since `auto-ship` Step 1 refuses the same file
43
47
 
44
48
  ### Refusals and staging
45
49
 
46
- - The command refuses for any other reason, or the record carries no `launchable` key: treat the row as unverified rather than clear, name what could not be read, and fall back to the human. A gate that reads nothing and proceeds is the gate not running.
47
- - The same read also refuses a plan still staging its batches in one file with `**Batch N**` sub-headings. That reports as an entry in `open` labeled `Batch staging`, so a staged plan reads as `launchable: false` the same way an unanswered operator call does, and the row waits on a split rather than on the operator.
48
- - An entry labeled `Stacked sibling` means the plan stacks on a live sibling it mostly shares files with, so the row waits on a fold into that sibling or on a `Judged apart from` constraint line, and not on the operator.
50
+ A refusal or a staged plan holds the row as surely as an open question.
49
51
 
50
- Branch on `launchable` rather than on the exit code, which a shell function wrapping `canon` can flatten to zero and so read a held row as a clear one.
52
+ - Any other refusal, or no `launchable` key: treat the row as unverified, name what could not be read, and fall back, since a gate reading nothing is not running
53
+ - A plan still staging batches in one file with `**Batch N**` sub-headings reports an `open` entry labeled `Batch staging`, so the row waits on a split
54
+ - A `Fan-in` entry holds a fan-in set, per `batches.md` in `plan-feature`
55
+ - A `Stacked sibling` entry means the plan stacks on a live sibling it mostly shares files with, so the row waits on a fold or a `Judged apart from` line
51
56
 
52
- This gate runs first because it is the cheapest reading, needing no roster and no ref, and the only one asking about the row itself. It reads the plan rather than a cell describing one, since the conflict check reads sets a dispatcher wrote, and a cell omitting a renamed path clears a check the tree would fail.
57
+ ### What the gate reads
53
58
 
54
- A blank `- Answer:` is not an unanswered question. `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md` fixes an empty slot as accepting the `- Suggested:` line above it, which is what makes a plan decision-ready in one pass. The narrow case this reads is `- Suggested: needs your call, <why>` and its two demonstrated paraphrases, `needs operator's call` and `needs the operator's call`, over an empty slot, the form that same standard writes where the answer turns on preference rather than on a technical default. A gate reading every blank slot as open would refuse every plan in the folder.
59
+ This gate runs first because it is the cheapest reading, needing no roster and no ref, and the only one asking about the row itself. It reads the plan rather than a cell describing one, since a cell omitting a renamed path clears a check the tree would fail.
55
60
 
56
- What it prevents is a halt nobody is watching for. `role-worker` instructs a session to stop on a question written as needing the operator's call, correctly and by its own body, so a dispatch that never reads the plan lands a worker in a wait for a person who does not know it is waiting. The worker's halt is not the defect, and the dispatch that made it necessary is.
61
+ A blank `- Answer:` is not an unanswered question, since `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md` fixes an empty slot as accepting the suggestion. A gate reading every blank slot as open would refuse every plan in the folder.
62
+
63
+ - The narrow case is `- Suggested: needs your call, <why>` over an empty slot, the form the standard writes where the answer turns on preference
64
+ - Two demonstrated paraphrases read the same, `needs operator's call` and `needs the operator's call`
65
+
66
+ The gate prevents a halt nobody is watching for. `role-worker` correctly stops a session on a question written as needing the operator's call, so a dispatch that never reads the plan lands a worker waiting for a person who does not know it. The dispatch is the defect, not the halt.
57
67
 
58
68
  ## Check the branch is unclaimed
59
69
 
60
- Run `canon sessions list --branch <type>/<slug> --json` and read `claimed` off the record.
70
+ Run `canon sessions list --branch <type>/<slug> --json` and read `claimed` off the record. The field is already the composed answer across the worktree listing, the live roster, and the refs naming the branch, so nothing here re-derives the OR.
61
71
 
62
- - `claimed: true`: the row is not free. Report what holds it, `worktree` when it names a path, `sessions` when it carries a row, and `refs` when the branch already exists. Move to the next candidate rather than colliding.
72
+ - `claimed: true`: report what holds it, `worktree` naming a path, `sessions` carrying a row, or `refs` when the branch exists, and move to the next candidate
63
73
  - `claimed: false`, `sessionsReadable: true`, and `refsReadable: true`: proceed to the conflict check.
64
- - `claimed: false` with either flag false, or the command refuses, or the record carries no `claimed` key (`reason` reads `no-registry` or `no-repository`): treat the candidate as unverified rather than clear. Report which reading could not be taken and fall back to the human-launch line below. Dispatching on a check that could not be read reproduces the exact collision this exists to prevent.
74
+ - `claimed: false` with either flag false, a refusal, or no `claimed` key, such as `no-registry` or `no-repository`: treat it as unverified and fall back to the human
75
+ - Dispatching on a check that could not be read reproduces the exact collision this exists to prevent
65
76
 
66
- Reading `claimed` off the record is what keeps this a check rather than a rule a session can talk itself out of. The field is already the composed answer across the worktree listing, the live session roster, and the refs that name the branch, so nothing here re-derives the OR.
77
+ ### The refs reading
67
78
 
68
- `refs` is the reading that catches a shipped row. A branch behind a merged pull request has no worktree and no session, so the check answered clear on one until a worker refused the instruction and named the consequences: a second pull request against a head GitHub shows merged, a row whose pull-request line points at two numbers, and the `ambiguous` refusal `canon tasks archive` documents.
79
+ `refs` catches a shipped row, since a branch behind a merged pull request has no worktree and no session. Without it the check answered clear until a worker refused and named the cost: a second pull request against a merged head, a row citing two numbers, and `canon tasks archive`'s `ambiguous` refusal.
69
80
 
70
- What the ref read cannot see is a branch pushed from another machine since the last fetch. A `git ls-remote` per dispatch costs 0.438s against 0.001s, so the gap is recorded rather than closed.
81
+ The ref read cannot see a branch pushed from another machine since the last fetch. A `git ls-remote` per dispatch costs 0.438s against 0.001s, so the gap is recorded rather than closed.
71
82
 
72
83
  ### A cloud worker's claim
73
84
 
@@ -77,32 +88,55 @@ A cloud worker never appears in the roster and never pushes the derived branch,
77
88
 
78
89
  A worker registers with `branch: main` and the main worktree as its `cwd` until `auto-ship` Step 0 moves it, which took several seconds on both measured runs. Neither the roster nor the refs name the candidate during that window, so a second check inside it reads clear.
79
90
 
80
- Keep the branch of every row this pass has launched and treat a candidate matching one as claimed, without re-running the check. That closes the window for this dispatcher and only for it. A second dispatcher in another session reads git and the roster alone, sees none of this record, and can still take the same row. Say so when reporting, rather than implying the window is shut.
91
+ Keep the branch of every row this pass has launched and treat a candidate matching one as claimed, without re-running the check. That closes the window for this dispatcher alone, since a second dispatcher reads only git and the roster, so say so when reporting.
81
92
 
82
93
  ## Check for a conflict with the tracks in flight
83
94
 
84
95
  No count binds this, and a shared file does not either. Hold a candidate behind a track in flight when any of these five holds, naming the hold and the track, and dispatch it otherwise:
85
96
 
86
- 1. Dependency. The row or plan cites the track as something it waits on or builds over, including a stacked slice based on the other's branch.
87
- 2. Contract. One plan changes a contract the other consumes, such as an exported signature, a CLI verb's flags or JSON record, a skill step another skill cites, or a config or frontmatter key, read off the changing plan's `**Risks:**`.
88
- 3. Relocation. One plan moves, renames, splits, or deletes a path the other writes or reads, which a rebase cannot settle mechanically. Both sides of a rename sit before the colon of a `**Files to touch:**` entry, per `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`.
89
- 4. Sweep. One plan rewrites a file or folder wholesale, such as a terminology pass or a `canon/context/` reflow, and the other writes inside it.
90
- 5. A stated reason, written on the hold: a singleton resource, or tracks interacting where no file reading shows, as a row creating a skill does with one counting that catalog. Nothing verifies the reason, so this hold stands only while the dispatcher applies it.
97
+ - **Dependency.** The row or plan cites the track as something it waits on or builds over, including a stacked slice on the other's branch.
98
+ - **Contract.** One plan changes a contract the other consumes, such as an exported signature, a verb's flags or record, a cited skill step, or a config key.
99
+ - **Relocation.** One plan moves, renames, splits, or deletes a path the other writes or reads, which a rebase cannot settle mechanically.
100
+ - **Sweep.** One plan rewrites a file or folder wholesale, such as a terminology pass or a `canon/context/` reflow, and the other writes inside it.
101
+ - **A stated reason.** A singleton resource, or tracks interacting where no file reading shows, as a row creating a skill does with one counting that catalog.
102
+
103
+ Read a contract off the changing plan's `**Risks:**`, and both sides of a rename before the colon of a `**Files to touch:**` entry, per `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`. Nothing verifies a stated reason, so it stands only while the dispatcher applies it.
104
+
105
+ ### A shared file is not a hold
106
+
107
+ Dispatch both and name the shared paths, so the merge order and the second branch's rebase are planned rather than discovered. The branch merging second resolves after the first merges, never against a sibling still building.
108
+
109
+ - It resolves by running `review-address` in the session that built it, whose Step 5 rebases the branch once it no longer merges
110
+ - A hunk needing a decision the tree does not carry goes to the controller
111
+ - A branch no live session holds gets the review-address shape in `orchestrator-launch.md`
91
112
 
92
- A shared file with none of the five is not a hold. Dispatch both and name the shared paths, so the merge order and the second branch's rebase are planned rather than discovered. The branch merging second resolves after the first merges, never against a sibling still building, by running `review-address` in the session that built it, whose Step 5 rebases the branch once it no longer merges. A hunk needing a decision the tree does not carry goes to the controller, and a branch no live session holds gets the review-address shape in `orchestrator-launch.md`.
113
+ ### The evidence
93
114
 
94
- No practitioner source serializes on a shared file. Each builds in parallel and tests at integration, where the merge surfaces a textual conflict and the suite run over the merged result surfaces a semantic one. Fowler's [branching patterns](https://martinfowler.com/articles/branching-patterns.html) have whoever integrates second pull mainline in and check health "even if it's a clean merge", his [Semantic Conflict](https://martinfowler.com/bliki/SemanticConflict.html) names self-testing code as the first defense, [DORA](https://dora.dev/capabilities/trunk-based-development/) keeps branches to a few hours, and GitHub's [merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) tests each pull request against everything queued ahead of it. A candidate has no commits to trial-merge, so `git merge-tree` runs at integration and this check reads what a plan declares.
115
+ No practitioner source serializes on a shared file. Each builds in parallel and tests at integration, where the merge surfaces a textual conflict and the suite over the merged result a semantic one.
95
116
 
96
- Read `canon sessions list --json` for the branches in flight as well as the board, since a track a person launched by hand carries no row, and read the plan of any branch no row names. `canon tasks validate` and `canon tasks plan-reach` report the paths two rows share, which is a candidate list for the five holds and the paths the dispatch names. A shared folder means a Touches cell claimed it bare, so narrow that cell rather than reading the folder as a sweep.
117
+ - Fowler's [branching patterns](https://martinfowler.com/articles/branching-patterns.html) have the second integrator pull mainline in and check health "even if it's a clean merge"
118
+ - His [Semantic Conflict](https://martinfowler.com/bliki/SemanticConflict.html) names self-testing code as the first defense, and [DORA](https://dora.dev/capabilities/trunk-based-development/) keeps branches to a few hours
119
+ - GitHub's [merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) tests each pull request against everything queued ahead of it
120
+ - A candidate has no commits to trial-merge, so `git merge-tree` runs at integration and this check reads what a plan declares
97
121
 
98
- A declared set predicts what a branch writes rather than bounding it, since `canon:context-fold`, `canon:docs-sync`, and the regenerated drift stages write past every plan. Such a crossing changes what the second branch rebases over rather than whether a row holds, and `canon tasks plan-reach` at `canon:git-ship` step 5 names it before the pull request opens. What binds past the five holds is review attention, which `## Parallelism` in the skill body states. The one number this skill carries is the review dispatch's count of three in `orchestrator-review-dispatch.md`, which moves a review rather than binding a track, and this runbook carries none.
122
+ ### Reading the tracks
123
+
124
+ Read `canon sessions list --json` for the branches in flight as well as the board, since a hand-launched track carries no row, and read the plan of any branch no row names.
125
+
126
+ - `canon tasks validate` and `canon tasks plan-reach` report the paths two rows share, a candidate list for the five holds and the paths a dispatch names
127
+ - A shared folder means a Touches cell claimed it bare, so narrow that cell rather than reading the folder as a sweep
128
+ - A declared set predicts rather than bounds, since `canon:context-fold`, `canon:docs-sync`, and the drift stages write past every plan
129
+ - Such a crossing changes what the second branch rebases over, not whether a row holds, and `canon tasks plan-reach` at `canon:git-ship` step 5 names it
130
+
131
+ What binds past the five holds is review attention, which `## Parallelism` in the skill body states.
99
132
 
100
133
  ## Pick the model
101
134
 
102
135
  This section binds every launch shape that names `<model>`, the planner and both reviewers as well as the step 4 build, none of which pass through that step.
103
136
 
104
- A `claude --bg` session inherits the launching session's model, so an orchestrator on the larger model spends it on every session it launches. Name `<model>` on each launch with one test: `opus` where a wrong result is costly and nothing automatic would catch it, `sonnet` otherwise, never `haiku`. Read the role's worst failure and whether a test, gate, or later review stops it, and never the folder or the plan's length.
137
+ A `claude --bg` session inherits the launching session's model, so an orchestrator on the larger model spends it on every launch. Name `<model>` on each with one test: `opus` where a wrong result is costly and nothing automatic would catch it, `sonnet` otherwise, never `haiku`.
105
138
 
139
+ - Read the role's worst failure and whether a test, gate, or review stops it, never the folder or the plan's length
106
140
  - Planner: `opus` for a row that changes a contract others consume, spans modules, or needs slicing. `sonnet` for a narrow row, even one inside a hook or governance folder.
107
141
  - Worker, and the review-address pass against the findings in hand: `opus` where the plan leaves a cross-module call tests will not settle. `sonnet` where it pins the fix, however long.
108
142
  - Code reviewer: `opus` where a miss would ship unseen, a change to behavior no test or gate exercises that other surfaces read. `sonnet` otherwise, a one-line hook edit included.
@@ -116,18 +150,25 @@ A row qualifies for that pick when its plan carries no open question and touches
116
150
 
117
151
  ## Dispatch
118
152
 
119
- Read `${CLAUDE_SKILL_DIR}/references/orchestrator-launch.md` once every check above clears, and launch from its build template. That runbook also holds the review-address and planning shapes, which skip the checks above. A row the operator picked for cloud launches from `${CLAUDE_SKILL_DIR}/references/orchestrator-cloud-launch.md` instead, since the cloud VM shares neither the plugin nor the board with this machine.
153
+ Read `${CLAUDE_SKILL_DIR}/references/orchestrator-launch.md` once every check above clears, and launch from its build template, which sits beside the review-address and planning shapes that skip these checks. A cloud row launches from `${CLAUDE_SKILL_DIR}/references/orchestrator-cloud-launch.md`, since the VM shares no plugin or board.
120
154
 
121
155
  ## Fall back to the human
122
156
 
123
- Hand the row to the human-launch line in step 4 instead of dispatching when any of these hold, and name which one: the plan still waits on the operator, the plan-answer read could not be taken, the collision check refused, or the row holds behind a track already out under the conflict check, on a dependency, a contract, a relocation, a sweep, or a stated reason. A shared file alone is not listed.
157
+ Hand the row to the human-launch line in step 4 instead of dispatching when any of these hold, and name which one. A shared file alone is not listed.
158
+
159
+ - The plan still waits on the operator
160
+ - The plan-answer read could not be taken, or the collision check refused
161
+ - The row holds behind a track already out on a dependency, a contract, a relocation, a sweep, or a stated reason
162
+
163
+ The first is the one that reaches a person rather than the board. A row held on its branch or under the conflict check waits on the wave clearing, and one held on its plan waits on an answer only the operator can give, so hand it over with the question label and its stated reason attached.
124
164
 
125
- The first of those four is the one that reaches a person rather than the board. A row held on its branch or under the conflict check waits on the wave clearing, where a row held on its plan waits on an answer only the operator can give, so hand that one over with the question label and its stated reason attached rather than as a name and a refusal.
165
+ ### The command to hand over
126
166
 
127
- Hand the person one command: `/canon:auto-ship <plan>`, naming the row, the plan path, and the branch together, with no worktree call ahead of it. A leading worktree call adds nothing beyond what `auto-ship` Step 0 already reaches for itself. A second command also risks a client folding two commands into one message, which reads everything after the first command's name as its own argument and drops the second, per `### Position zero` in `orchestrator-launch.md`.
167
+ Hand the person one command, `/canon:auto-ship <plan>`, naming the row, the plan path, and the branch together, with no worktree call ahead of it. `auto-ship` Step 0 already enters the worktree.
128
168
 
129
- Suggest, as one line to the operator, that they rename their own session to the row's id, so a process listing shows what the session is for without a cross-reference to the board.
169
+ - A second command risks a client folding two into one message, dropping the second, per `### Position zero` in `orchestrator-launch.md`
170
+ - Suggest in one line that the operator rename their own session to the row's id, so a process listing shows what the session is for
130
171
 
131
172
  ## Stop the loop
132
173
 
133
- Wrapped in `/loop`, re-run the check against `## Run now` on each wake. Stop rather than firing again once the group is empty or every row in it reads `claimed: true`. Report that once, on the wake that finds it, and let the loop end rather than continuing to poll a board nobody is clearing. `orchestrator-poll.md` already carries this reasoning for the review trigger, and it binds a dispatcher the same way.
174
+ Wrapped in `/loop`, re-run the check against `## Run now` on each wake, and stop once the group is empty or every row reads `claimed: true`. Report that once, on the wake that finds it, rather than polling a board nobody is clearing, the reasoning `orchestrator-poll.md` carries for the review trigger.
@@ -7,34 +7,71 @@ Read this at loop step 6, once the poll reports a branch stale or conflicted, or
7
7
 
8
8
  ## Sending the handback
9
9
 
10
- - Read the threshold off `review-pr`, which states it once and governs the heading with it, so an open heading and an owed dispatch answer the same question and either one is enough to send
11
- - Resolve the target at the moment of sending with `canon sessions list --branch`, never from a mapping written down earlier, since names rotate as sessions end and one recorded earlier in a session has failed inside the hour. `orchestrator-poll.md` routes on the count and the confidence it answers with
12
- - Open the message with the worktree and branch the sender believes the reader holds, asking to be corrected, whenever that mapping is inferred rather than confirmed
10
+ Read the threshold off `review-pr`, which states it once and governs the heading with it, so an open heading and an owed dispatch answer the same question and either one is enough to send.
11
+
12
+ - Resolve the target at sending with `canon sessions list --branch`, never from an earlier mapping, since names rotate as sessions end
13
+ - A mapping recorded earlier in a session has failed inside the hour. `orchestrator-poll.md` routes on the count and the confidence the verb answers with.
14
+ - Open the message with the worktree and branch the sender believes the reader holds, asking to be corrected, whenever that mapping is inferred
13
15
  - Name the skill for the reader to run rather than writing an invocation, which arrives as text
14
- - Read the pull request's own draft flag rather than the state a worker reports, and report what the read returned and when rather than the state alone. `canon pr head --help` states why a reported field can lag and say nothing about it. The flag settles the question only once the worker's chain has run its undo, and nothing marks that moment, so a read taken between the pull request opening and that call sees a genuinely ready pull request about to become a draft and has told an operator the opposite of what the worker had said.
16
+
17
+ ### Reading the draft flag
18
+
19
+ Read the pull request's own draft flag rather than the state a worker reports, and report what the read returned and when rather than the state alone. `canon pr head --help` states why a reported field can lag and say nothing about it.
20
+
21
+ The flag settles the question only once the worker's chain has run its undo, and nothing marks that moment. A read taken between the pull request opening and that call sees a ready pull request about to become a draft, and once told an operator the opposite of what the worker had said.
15
22
 
16
23
  ## The rebase handback
17
24
 
18
- A `STALE` or `CONFLICT` from the poll goes to the branch's own session the same way, with `review-address` as the skill to run, since its staleness test rebases a branch `main` moved under even when the merge is clean. Name what merged under the branch, being the pull request that landed and the files the poll listed, so the worker reads those hunks first rather than re-deriving them from `git log`.
25
+ A `STALE` or `CONFLICT` from the poll goes to the branch's own session the same way, with `review-address` as the skill to run, since its staleness test rebases a branch `main` moved under even when the merge is clean.
19
26
 
20
- Say that a check failing after a clean rebase is a semantic conflict to fix on the branch, and that a hunk needing a decision the tree does not carry comes back as a message rather than as a guess. A pull request carrying review findings as well earns one message naming both, since one `review-address` run answers them together.
27
+ - Name what merged under the branch, being the pull request that landed and the files the poll listed, so the worker reads those hunks first
28
+ - Say that a check failing after a clean rebase is a semantic conflict to fix on the branch
29
+ - Say that a hunk needing a decision the tree does not carry comes back as a message rather than as a guess
30
+ - A pull request carrying review findings as well earns one message naming both, since one `review-address` run answers them together
21
31
 
22
32
  The worker that built the branch rebases it, not this session. It holds the plan behind each hunk, and a rebase made here would also write a branch this session does not own.
23
33
 
24
34
  ## Re-review and reachability
25
35
 
26
- A dispatched reviewer sends the `review-address` dispatch to the worker itself, carrying its own sessionId, and the worker sends the re-review request straight back to it. Neither leg passes through this session, which sends either one only as the fallback:
36
+ A dispatched reviewer sends the `review-address` dispatch to the worker itself, carrying its own sessionId, and the worker sends the re-review request straight back to it. Neither leg passes through this session, which sends either one only as a fallback.
37
+
38
+ ### A cloud reviewer's pass
39
+
40
+ A cloud session can send no message, and the script reports no code review posting on an unchanged head. The poll's cloud-reviewer rule reads `canon pr review-state` for each pull request a cloud reviewer holds and routes the dispatch here.
41
+
42
+ ### No worker resolved
43
+
44
+ A reviewer reports that `canon sessions list --branch` returned no session or an unconfirmed match. Route it the way the poll's dispatch rule routes the count.
45
+
46
+ - On zero, launch the review-address shape in `orchestrator-launch.md`, carrying the reviewer's sessionId so the new worker answers the reviewer directly
47
+ - On an unconfirmed match, pick from a session listing and ask to be corrected, since a session may well hold the branch
48
+
49
+ ### No reviewer resolved
50
+
51
+ A worker reports that the reviewer's sessionId resolved to no live session, or sends a re-review request with no reviewer named in its dispatch. Launch a fresh reviewer through the reviewer shape in `orchestrator-reviewer-launch.md`, never a pass in place, rather than messaging a name that no longer answers.
52
+
53
+ A re-review this session sends goes to the reviewer that took the first pass. Find a live `reviewer-<project>-<number>` through `canon sessions list --json` by name and message it to re-run `review-pr`, launching a fresh one only when none is live.
54
+
55
+ ### When no session is live
56
+
57
+ A session is reachable when it appears in a live listing, which reads what each session registered on disk rather than probing it. A message carries plain text and no authority.
58
+
59
+ - When no live session holds the branch, launch the review-address shape in `orchestrator-launch.md`, which enters the branch's own worktree
60
+ - Only where that launch cannot run, report the invocation for the human, naming the branch, the pull request, and the skill, then stop
61
+ - Retrying or waiting leaves the loop believing it is open while nothing acts on it
27
62
 
28
- - A pass a cloud reviewer posted, since a cloud session can send no message. The script reports no code review posting on an unchanged head, so the poll's cloud-reviewer rule reads `canon pr review-state` for each pull request a cloud reviewer holds and routes the dispatch here.
29
- - A reviewer reporting that `canon sessions list --branch` returned no session or an unconfirmed match. Route it the way the poll's dispatch rule routes the count: on zero, launch the review-address shape in `orchestrator-launch.md`, carrying the reviewer's sessionId so the worker it launches answers the reviewer directly, and on an unconfirmed match, pick from a session listing and ask to be corrected, since a session may well hold the branch.
30
- - A worker reporting that the reviewer's sessionId resolved to no live session, or a re-review request from a worker whose dispatch named no reviewer. Launch a fresh reviewer through the reviewer shape in `orchestrator-reviewer-launch.md`, never a pass in place, rather than messaging a name that no longer answers.
63
+ ## The return leg
31
64
 
32
- A re-review this session sends goes to the reviewer that took the first pass. Find a live `reviewer-<project>-<number>` for that pull request through `canon sessions list --json` by name and message it to re-run `review-pr`, and launch a fresh one only when none is live.
65
+ The channel runs both ways, and the return leg carries what the pull request cannot. A worker answering a finding by naming the plan question that already declined it changes the outcome in the moment, where a thread comment waits on its next reader.
33
66
 
34
- A session is reachable when it appears in a live listing, which reads what each session registered on disk rather than probing it, and a message carries plain text and no authority. When no live session holds the branch, launch the review-address shape in `orchestrator-launch.md`, which enters the branch's own worktree. Report the invocation for the human only where that launch cannot run, naming the branch, the pull request, and the skill to run, then stop. Retrying or waiting leaves the loop believing it is open while nothing acts on it.
67
+ - Read what a worker volunteers as part of the review rather than as an aside, and read a refusal the same way
68
+ - The corrections that landed on this session's model of the world arrived as a worker arguing back rather than complying
69
+ - What the worker owes on its own side is stated in `role-worker`, being the announcement, the block message, and the board ban. Do not restate it here.
35
70
 
36
- The channel runs both ways and the return leg carries what the pull request cannot. A worker answering a posted finding by naming the plan question that had already declined it changes the outcome in the moment, where a thread comment waits on whoever reads it next. Read what a worker volunteers as part of the review rather than as an aside, and read a refusal the same way, since the corrections that landed on this session's model of the world arrived as a worker arguing back rather than complying.
71
+ ### Placing a reply
37
72
 
38
- What the worker owes on its own side is stated in the `role-worker` skill that session loads, being the pull-request announcement, the message a block goes out as before it becomes a prompt, and the ban on writing the board. Do not restate any of it here.
73
+ What arrives does not become a record by being read, so place it by what it changes. Writing a tracked file to hold it is forbidden, which leaves the pull request and the board as the two surfaces this session writes.
39
74
 
40
- What arrives there does not become a record by being read, so place it by what it changes. An answer that settles a finding goes onto the pull request through the next pass, which withdraws or regrades that finding and names the fact behind it, per `review-pr`. An answer that changes what this session believes about the world instead, which is a mapping correction or a constraint on what a worker can do, settles no finding and reaches no thread, so route it the way `## Boundaries` in the skill body routes a change found while orchestrating, which lands it on the task owning the surface it describes. Writing a tracked file to hold either is forbidden here, which leaves the pull request and the board as the two surfaces this session writes.
75
+ - An answer settling a finding goes onto the pull request through the next pass, which withdraws or regrades it and names the fact behind it, per `review-pr`
76
+ - An answer changing what this session believes, such as a mapping correction or a constraint on a worker, settles no finding and reaches no thread
77
+ - Route that second kind the way `## Boundaries` in the skill body routes a change found while orchestrating, onto the task owning the surface it describes