@erclx/canon 5.41.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 (154) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/api-design/references/adopted.md +34 -14
  3. package/claude/skills/auto-ship/REQUIREMENT.md +1 -0
  4. package/claude/skills/auto-ship/SKILL.md +22 -2
  5. package/claude/skills/auto-ship/references/draft-mark.md +32 -6
  6. package/claude/skills/auto-ship/references/failure-recovery.md +15 -13
  7. package/claude/skills/auto-ship/references/tier-failures.md +31 -10
  8. package/claude/skills/auto-ship/references/ui-checklist.md +9 -4
  9. package/claude/skills/auto-ship/references/worktree-name.md +9 -3
  10. package/claude/skills/build-in-slices/references/adopted.md +35 -21
  11. package/claude/skills/canvas-board/references/canvas.md +17 -6
  12. package/claude/skills/canvas-board/references/design.md +26 -7
  13. package/claude/skills/code-craft/references/adopted.md +58 -20
  14. package/claude/skills/codebase-layout/references/adopted.md +49 -16
  15. package/claude/skills/codebase-layout/references/frontend.md +11 -4
  16. package/claude/skills/codebase-layout/references/tests.md +4 -2
  17. package/claude/skills/context-fold/references/classify.md +10 -15
  18. package/claude/skills/context-fold/references/completion-report.md +11 -9
  19. package/claude/skills/context-fold/references/context-refresh.md +26 -9
  20. package/claude/skills/context-fold/references/unusable-baseline.md +5 -3
  21. package/claude/skills/create-rule/REQUIREMENT.md +5 -0
  22. package/claude/skills/create-rule/SKILL.md +9 -1
  23. package/claude/skills/create-rule/references/checklist.md +26 -0
  24. package/claude/skills/create-rule/references/rule.md +98 -20
  25. package/claude/skills/create-skill/SKILL.md +1 -0
  26. package/claude/skills/create-skill/references/skill-disclosure.md +10 -2
  27. package/claude/skills/create-skill/references/skill-frontmatter.md +43 -0
  28. package/claude/skills/create-skill/references/skill-paths.md +7 -4
  29. package/claude/skills/create-skill/references/skill-practice.md +6 -3
  30. package/claude/skills/create-skill/references/skill-requirement.md +4 -2
  31. package/claude/skills/create-skill/references/skill.md +67 -44
  32. package/claude/skills/deploy-app/references/vercel.md +2 -1
  33. package/claude/skills/deprecation-migration/references/adopted.md +44 -25
  34. package/claude/skills/design-taste/references/adopted.md +9 -1
  35. package/claude/skills/design-taste/references/craft.md +3 -1
  36. package/claude/skills/design-taste/references/kinds.md +8 -7
  37. package/claude/skills/design-taste/references/preflight.md +12 -0
  38. package/claude/skills/design-taste/references/systems.md +7 -6
  39. package/claude/skills/design-taste/references/tells.md +24 -25
  40. package/claude/skills/design-taste/references/vocabulary.md +7 -5
  41. package/claude/skills/document-health/references/axes.md +54 -30
  42. package/claude/skills/draft-and-pick/references/live-arms.md +2 -2
  43. package/claude/skills/draft-doc/references/context.md +4 -3
  44. package/claude/skills/draft-doc/references/docs.md +6 -3
  45. package/claude/skills/draft-doc/references/readme/agent-facing.md +6 -0
  46. package/claude/skills/draft-doc/references/readme/application.md +8 -2
  47. package/claude/skills/draft-doc/references/readme/cli.md +5 -1
  48. package/claude/skills/draft-doc/references/readme/library.md +4 -0
  49. package/claude/skills/draft-doc/references/readme/plugin.md +9 -1
  50. package/claude/skills/draft-doc/references/readme.md +30 -13
  51. package/claude/skills/draft-doc/references/requirements.md +17 -4
  52. package/claude/skills/draft-doc/references/wiki-kind.md +20 -10
  53. package/claude/skills/draft-figure/references/architecture-set.md +7 -3
  54. package/claude/skills/draft-figure/references/figures.md +8 -6
  55. package/claude/skills/draft-figure/references/hand-drawn.md +3 -1
  56. package/claude/skills/draft-figure/references/mermaid-path.md +19 -9
  57. package/claude/skills/draft-figure/references/mermaid.md +10 -5
  58. package/claude/skills/draft-ready/references/ready.md +22 -15
  59. package/claude/skills/git-branch/references/branch.md +11 -1
  60. package/claude/skills/git-branch/references/slug.md +17 -5
  61. package/claude/skills/git-commit/references/commit.md +8 -0
  62. package/claude/skills/git-commit/references/versioning.md +23 -17
  63. package/claude/skills/git-followup/REQUIREMENT.md +1 -1
  64. package/claude/skills/git-followup/SKILL.md +5 -6
  65. package/claude/skills/git-issue/references/issue.md +29 -16
  66. package/claude/skills/git-pr/REQUIREMENT.md +1 -5
  67. package/claude/skills/git-pr/SKILL.md +11 -22
  68. package/claude/skills/git-pr/references/final-command.md +21 -8
  69. package/claude/skills/git-pr/references/labels.md +45 -28
  70. package/claude/skills/git-pr/references/pr.md +28 -9
  71. package/claude/skills/git-pr/references/publish.md +42 -28
  72. package/claude/skills/git-pr/references/task-number.md +20 -8
  73. package/claude/skills/git-ship/SKILL.md +1 -1
  74. package/claude/skills/plan-feature/references/plan-lifecycle.md +10 -3
  75. package/claude/skills/plan-feature/references/plan.md +57 -20
  76. package/claude/skills/plan-groundwork/references/groundwork-spikes.md +4 -1
  77. package/claude/skills/plan-groundwork/references/groundwork.md +14 -16
  78. package/claude/skills/plan-intake/references/intake.md +29 -24
  79. package/claude/skills/pr-evidence/REQUIREMENT.md +40 -0
  80. package/claude/skills/pr-evidence/SKILL.md +53 -0
  81. package/claude/skills/pr-evidence/references/evidence.md +150 -0
  82. package/claude/skills/review-address/references/post-review-findings.md +10 -3
  83. package/claude/skills/review-address/references/rebase-conflicts.md +15 -7
  84. package/claude/skills/review-address/references/rest-reads.md +3 -1
  85. package/claude/skills/review-craft/references/adopted.md +35 -18
  86. package/claude/skills/review-craft/references/security.md +42 -7
  87. package/claude/skills/review-craft/references/ui.md +23 -8
  88. package/claude/skills/review-pr/SKILL.md +6 -6
  89. package/claude/skills/review-pr/references/body-variants.md +29 -9
  90. package/claude/skills/review-pr/references/close-out.md +20 -5
  91. package/claude/skills/review-pr/references/key-changes.md +27 -3
  92. package/claude/skills/review-pr/references/post.md +83 -31
  93. package/claude/skills/review-pr/references/scope.md +54 -19
  94. package/claude/skills/review-ui/references/close-out.md +7 -5
  95. package/claude/skills/review-ui/references/driving.md +24 -4
  96. package/claude/skills/review-ui/references/post.md +43 -15
  97. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +67 -17
  98. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +80 -40
  99. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +52 -15
  100. package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +48 -26
  101. package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +12 -13
  102. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +72 -36
  103. package/claude/skills/role-orchestrator/references/orchestrator-output.md +12 -4
  104. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +64 -24
  105. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +80 -26
  106. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +41 -18
  107. package/claude/skills/role-orchestrator/references/orchestrator-resume.md +19 -7
  108. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +22 -12
  109. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +15 -6
  110. package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +25 -7
  111. package/claude/skills/role-orchestrator/references/orchestrator-watch.md +34 -8
  112. package/claude/skills/role-orchestrator/scripts/poll.ts +16 -24
  113. package/claude/skills/role-worker/REQUIREMENT.md +1 -0
  114. package/claude/skills/role-worker/SKILL.md +8 -0
  115. package/claude/skills/search-craft/references/adopted.md +18 -6
  116. package/claude/skills/session-map/references/session.md +26 -7
  117. package/claude/skills/session-worktree/references/main-root-writes.md +25 -8
  118. package/claude/skills/systematic-debugging/references/adopted.md +30 -16
  119. package/claude/skills/target-check/references/domains.md +39 -11
  120. package/claude/skills/target-setup/references/detect.md +80 -65
  121. package/claude/skills/target-setup/references/indexes.md +8 -6
  122. package/claude/skills/task-board/references/board.md +86 -30
  123. package/claude/skills/task-board/references/decline.md +29 -13
  124. package/claude/skills/task-board/references/tasks-decline.md +12 -5
  125. package/claude/skills/task-board/references/tasks.md +65 -33
  126. package/claude/skills/task-complete/references/archive.md +41 -17
  127. package/claude/skills/task-complete/references/receipt-sweep.md +23 -9
  128. package/claude/skills/task-complete/references/unusable-baseline.md +10 -3
  129. package/claude/skills/teach-workspace/references/glossary.md +6 -2
  130. package/claude/skills/teach-workspace/references/lesson-build.md +44 -16
  131. package/claude/skills/teach-workspace/references/lesson-craft.md +12 -7
  132. package/claude/skills/teach-workspace/references/pedagogy.md +6 -3
  133. package/claude/skills/teach-workspace/references/promotion-fold.md +17 -11
  134. package/claude/skills/teach-workspace/references/promotion.md +31 -8
  135. package/claude/skills/teach-workspace/references/revisit.md +8 -2
  136. package/claude/skills/teach-workspace/references/teach.md +17 -9
  137. package/claude/skills/test-craft/references/adopted.md +48 -14
  138. package/claude/skills/test-craft/references/component.md +7 -4
  139. package/claude/skills/test-craft/references/e2e.md +25 -7
  140. package/claude/skills/test-craft/references/unit.md +3 -1
  141. package/claude/skills/test-first/references/adopted.md +12 -4
  142. package/claude/skills/ui-checklist/REQUIREMENT.md +1 -1
  143. package/claude/skills/ui-checklist/SKILL.md +1 -1
  144. package/claude/skills/video-craft/references/adopted.md +62 -18
  145. package/claude/skills/write-human/references/adopted.md +21 -8
  146. package/docs/workflow/parallel-features.md +1 -1
  147. package/docs/workflow/skill-map.md +1 -0
  148. package/package.json +1 -1
  149. package/src/claude/cases/workflow.ts +5 -0
  150. package/src/commands/pr.ts +142 -28
  151. package/src/markdown/scope.ts +144 -0
  152. package/src/pr/lift.ts +6 -3
  153. package/src/pr/review-state.ts +182 -0
  154. package/claude/skills/git-pr/references/evidence.md +0 -124
@@ -9,27 +9,39 @@ Run the orchestrator's review trigger. The poll reports pull request movement an
9
9
 
10
10
  ## When to run it
11
11
 
12
- Start the poll on an open pull request and stop it when the last one merges with nothing else out. That is the whole condition and it resolves from the open list without asking the operator. A release pull request alone does not qualify, since its sweep carries no findings.
12
+ Start the poll on an open pull request and stop it when the last one merges with nothing else out. That is the whole condition, and it resolves from the open list without asking the operator. A release pull request alone does not qualify, since its sweep carries no findings.
13
13
 
14
- A dispatch no longer starts it. The script reads pull requests and a building worker has none, so every interval between the launch and the push is a fixed cost returning nothing, measured as five consecutive runs reporting no movement across roughly fifteen minutes while one worker built. What replaces it is the worker announcing its own pull request the moment it opens one, per the `role-worker` skill that session loads, which covers exactly the transition the poll cannot observe.
14
+ ### A dispatch no longer starts it
15
15
 
16
- The dispatched-worker condition survives as a fallback rather than as a trigger. Start the poll against any dispatch still out after thirty minutes with no announcement, which is past the upper end of the ten to thirty minutes a row here takes. The announcement is newer than the narrowing it justifies, so a silent failure would otherwise leave a finished worker unnoticed the way one already sat idle for eighteen minutes, and the fallback keeps the cover a straight narrowing would have removed. `${CLAUDE_SKILL_DIR}/scripts/watch.ts` covers the same window at a lower cost, since it reads the roster alongside the pull request list and reports a worker that vanished as well as one that finished. Read `${CLAUDE_SKILL_DIR}/references/orchestrator-watch.md` before starting it, since it carries the stall alarm and the notification each alarm line owes the operator.
16
+ The script reads pull requests and a building worker has none, so every interval between the launch and the push returns nothing. That cost measured as five consecutive runs reporting no movement across roughly fifteen minutes while one worker built.
17
17
 
18
- A session holding a recurring-prompt scheduler starts the loop itself on that condition and cancels it on the same test, without waiting for the operator. Both halves belong to whoever holds the loop, since a session that can start one can stop one, and a runbook stating only the start leaves the always-on failure unaddressed on the side that causes it.
18
+ - The worker announces its own pull request the moment it opens one, per `role-worker`, which covers the transition the poll cannot observe
19
+ - Start the poll against any dispatch still out after thirty minutes with no announcement, past the upper end of the ten to thirty a row takes
20
+ - That fallback keeps the cover against a silent failure, since a finished worker once sat idle for eighteen minutes unnoticed
19
21
 
20
- Nothing enforces this. No hook starts the poll and no check stops it, so the condition holds only while whoever holds the loop applies it. Left always-on it fires into an empty board through every gap between a dispatch and its push.
22
+ `${CLAUDE_SKILL_DIR}/scripts/watch.ts` covers the same window at a lower cost, since it reads the roster beside the pull request list and reports a vanished worker as well as a finished one. Read `${CLAUDE_SKILL_DIR}/references/orchestrator-watch.md` before starting it, for the stall alarm and the notification each alarm line owes the operator.
21
23
 
22
- The poll is session-scoped and dies with the session that started it. Restart it after a compaction, and take the prompt from this file rather than from a transcript, since a running loop holds whatever wording it was started with and a correction here does not reach it.
24
+ ### Who starts and stops it
23
25
 
24
- The reverse direction is the one that goes unnoticed. A scheduled prompt cannot be edited, so every routing fix is a cancel and a re-create, and three made inside one session each reached the running loop and none reached this file. Edit the block here first and re-create the loop from what this file then says. Rewriting the block from memory drops what the shipped one covered, which is how a `SEEN` report once fell through to no rule at all.
26
+ A session holding a recurring-prompt scheduler starts the loop on that condition and cancels it on the same test, without waiting for the operator. A runbook stating only the start leaves the always-on failure unaddressed on the side that causes it.
25
27
 
26
- ## The prompt
28
+ - Nothing enforces this. No hook starts the poll and no check stops it, so the condition holds only while the loop's holder applies it.
29
+ - Left always-on, it fires into an empty board through every gap between a dispatch and its push
30
+ - The poll is session-scoped and dies with its session, so restart it after a compaction, taking the prompt from this file rather than a transcript
31
+
32
+ ### Editing the prompt
33
+
34
+ A running loop holds whatever wording it was started with, and a scheduled prompt cannot be edited, so every routing fix is a cancel and a re-create. Three fixes made inside one session once reached the running loop and none reached this file.
27
35
 
28
- The requirement is a recurring prompt at roughly three minutes carrying the block below. `/loop 3m <the block>` is the mechanism this repository uses and one example among the schedulers a client may hold, so a client without that command reaches the same requirement through whatever recurring prompt it can schedule. Naming one vendor's command as the only path dates a file that ships to every target holding the plugin.
36
+ Edit the block here first and re-create the loop from what this file then says. Rewriting the block from memory drops what the shipped one covered, which is how a `SEEN` report once fell through to no rule at all.
37
+
38
+ ## The prompt
29
39
 
30
- The interval belongs to the schedule rather than to the script. One run is a single snapshot returning in about six seconds, so a session that reads `3m` as the script's runtime and relaunches on completion fires every few seconds and never settles, which happened once for 35 minutes.
40
+ The requirement is a recurring prompt at roughly three minutes carrying the block below. `/loop 3m <the block>` is this repository's mechanism and one example among the schedulers a client may hold, so a client without it schedules whatever recurring prompt it can.
31
41
 
32
- Resolve `${CLAUDE_SKILL_DIR}/scripts/poll.ts` to an absolute path and paste that in place of `<POLL_SCRIPT>` below. The variable expands while this runbook renders and not in a standalone loop turn, so a block carrying the variable reaches the session as a literal string and the run improvises a substitute.
42
+ - The interval belongs to the schedule, since one run is a six-second snapshot, and relaunching on completion once fired every few seconds for 35 minutes
43
+ - Paste the absolute path of `${CLAUDE_SKILL_DIR}/scripts/poll.ts` in place of `<POLL_SCRIPT>` below
44
+ - The variable expands while this runbook renders and not in a standalone loop turn, so a block carrying it reaches the session as a literal and the run improvises
33
45
 
34
46
  ```plaintext
35
47
  Poll GitHub for pull request movement by running `bun <POLL_SCRIPT>`, then act on what it reports.
@@ -55,36 +67,78 @@ After a pass that posts a finding, at any severity, and that no live local revie
55
67
 
56
68
  ## Reading the output
57
69
 
58
- Every classification line names a pull request and a state. A line starting `poll:` is not a classification. It means a query failed and the script declined to guess, so that pull request keeps its last known state and is neither reported as moved nor swept as merged. Treat it as unread and let the next run classify it.
70
+ Every classification line names a pull request and a state. A line starting `poll:` is a failed query rather than a classification, so that pull request keeps its last known state and is neither reported as moved nor swept as merged.
59
71
 
60
- The script exits non-zero and classifies nothing when the open pull request list itself fails to load. That case would otherwise report every tracked pull request as merged, so the baseline is left untouched and the run says so.
72
+ - The script exits non-zero and classifies nothing when the open list itself fails to load, leaving the baseline untouched, since it would report every pull request merged
73
+ - The baseline lives at `.canon/tmp/pr/poll/baseline.txt` under the main worktree root and is per-machine
74
+ - A first run against a board already in flight reports each open pull request once before it settles
61
75
 
62
- The baseline lives at `.canon/tmp/pr/poll/baseline.txt` under the main worktree root and is per-machine. A first run against a board already in flight reports each open pull request once before it settles.
76
+ ### Headings the script knows
63
77
 
64
- The eight headings the script knows are written by `review-pr`, `review-address`, `canon pr evidence`, and `review-ui`, and the whole set is stated once in the first. The reply family and the UI family are matched by filters in `poll.ts`, so a project posting either under different headings edits those to match. The review family is matched inside `canon pr review-state` instead, which the script and `review-pr` both read through, so a project renaming either review heading changes the verb rather than the script. Either way, a heading nothing matches reads as a pull request nobody has reviewed. The `UI-` states report the newest UI pass on its transition, and `UI-STALE` fires beside the `MOVED` of a push that left its marker behind. A first sighting reports none, which costs the mark nothing, since `canon pr lift` reads the UI review itself and holds the mark wherever `canon pr evidence <number> --json` carries a `checklist` until a UI close names the head.
78
+ The eight headings the script knows are written by `review-pr`, `review-address`, `canon pr evidence`, and `review-ui`, and the whole set is stated once in the first. A heading nothing matches reads as a pull request nobody has reviewed.
65
79
 
66
- `UNMATCHED` is what a comment reaches under a heading outside the six the comment filters know, a UI heading posted as a comment included, carried the same way `RESPONSE` is: a rising count against the baseline is what is new to this script, and the message names the heading so a person can tell whether to answer it by hand or add it to the set. It fires on a tracked pull request only, since a first sighting reports `SEEN` or `OPENED` and takes whatever count already sits on the thread as its starting baseline rather than flagging history the poll never watched.
80
+ - The reply family matches by a filter in `poll.ts`, so a project posting it under different headings edits that
81
+ - The review and UI families match inside `canon pr review-state`, which the script and `review-pr` both read, so renaming one changes the verb
82
+ - The `UI-` states report the newest UI pass on its transition, and `UI-STALE` fires beside the `MOVED` of a push that left its marker behind
83
+ - A first sighting reports no `UI-` state at no cost to the mark, since `canon pr lift` reads the UI review itself and holds the mark on a `canon pr evidence` checklist until a UI close names the head
67
84
 
68
- `RESPONSE` is qualified by recency as well as by count, so it means a reply the last pass has not already answered rather than one this script has not seen before. A worker answers a finding and the reviewing session posts its close-out seconds later, which is the ordinary handback rather than a race, so a count on its own reported the answered thread on the next run and the re-review it routed to stopped at its own guard. The state now fires when the newest reply is stamped later than the last pass, and on a pull request carrying no pass at all, which is a worker talking to nobody and worth the turn. A reply landing inside the same second as the pass is dropped, matching the comparison `review-pr` makes on the same two fields.
85
+ ### UNMATCHED and RESPONSE
69
86
 
70
- `STALLED` is the one state the script derives from a heading rather than from a commit or a count, since `review-pr` posts the open heading exactly when a dispatch is owed, per the threshold that skill states. The heading alone cannot carry it, because an open pass means a dispatch was owed and made, so the ordinary healthy thread is a worker still working. The age of that pass is the third test: the state fires when the open pass covers the head, nothing has followed it, and it is older than the `STALE_AFTER` seconds set at the top of the script. It reports once per entry and fires again after any commit or reply resets the thread. A project whose workers run longer than the default two hours raises that number.
87
+ `UNMATCHED` is a comment under a heading outside the six the comment filters know, a UI heading posted as a comment included. It fires on a rising count against the baseline, and the message names the heading so a person can answer by hand or add it to the set.
71
88
 
72
- The state reaches every stalled dispatch, since one threshold governs the heading and the dispatch alike and a pass carrying anything posts the open heading. A minors-only pass therefore reports here on the same terms as a blocking one, which widens the state from what it caught while the two were split. It stays a heading test rather than a count test, so nothing here pins the summary line, which is a second string this script does not own.
89
+ - It fires on a tracked pull request only, since a first sighting takes the thread's count as its baseline rather than flagging history
90
+ - `RESPONSE` means a reply the last pass has not answered, qualified by recency as well as count, since a close-out seconds after a worker's answer is the ordinary handback
91
+ - It fires when the newest reply is stamped later than the last pass, or on a pull request with no pass, which is a worker talking to nobody
92
+ - A reply landing in the same second as the pass is dropped, matching the comparison `review-pr` makes on the same two fields
93
+
94
+ ### STALLED
95
+
96
+ `STALLED` is the one state derived from a heading rather than a commit or a count, since `review-pr` posts the open heading exactly when a dispatch is owed. An open pass alone is the ordinary healthy thread, a worker still working, so the age of the pass is the third test.
97
+
98
+ - It fires when the open pass covers the head, nothing has followed it, and it is older than the `STALE_AFTER` seconds set at the top of the script
99
+ - It reports once per entry and fires again after any commit or reply resets the thread. A project whose workers run past two hours raises the number.
100
+ - One threshold governs the heading and the dispatch, so a minors-only pass reports here on the same terms as a blocking one
101
+ - It stays a heading test, so nothing pins the summary line, a second string this script does not own
73
102
 
74
103
  ### Base movement
75
104
 
76
- A pull request's run tests the merge with the base as of its last push, so once a sibling merges, that green describes a merge nobody will make. `STALE` closes that gap by hand where a ruleset requiring branches to be current, or a merge queue, would close it on the host. It fires when the base changed a file the pull request writes since the commit it branched from, and names the files. A base that moved only on files the branch does not write reads as nothing, since re-testing after every merge is a merge queue's cost without its batching.
105
+ A pull request's run tests the merge with the base as of its last push, so once a sibling merges, that green describes a merge nobody will make. `STALE` closes that gap by hand where a ruleset requiring current branches, or a merge queue, would close it on the host.
106
+
107
+ - It fires when the base changed a file the pull request writes since the commit it branched from, and names the files
108
+ - A base moving only on files the branch does not write reads as nothing, since re-testing after every merge is a merge queue's cost without its batching
109
+ - `STALE` and `CONFLICT` report on their transition and on every push leaving the reading standing, then live only in the baseline
77
110
 
78
- `STALE` and `CONFLICT` each report on their transition and again on every push that leaves the reading standing, then live only in the baseline, which is as old as the last run. Read a standing one with `--check <number>`, which fetches the base and reads the head at call time, so a sibling merging after the last run still shows, and prints `CONFLICT`, `STALE`, `CLEAR`, or `UNKNOWN`, writing nothing. It takes the standing `canon pr lift <number> --check --json` reads, so the lift and this check answer from one read, and falls back to its own merge-tree read where the record carries no standing gate, which a binary older than that verb leaves. A pull request whose written set could not be read, being a fork or a deleted head, reads as `UNKNOWN` rather than clear, so its lift waits on a person.
111
+ ### Reading a standing state
79
112
 
80
- `OVERLAP` names two open pull requests that conflict with each other, read by merging their heads locally. Only pairs sharing a written path are tried, which keeps a wave of ten to a handful of merges. It reports once per pair, carried in the tenth baseline field, so the merge order is settled before the second branch has to rebase rather than after.
113
+ Read a standing one with `--check <number>`, which fetches the base and reads the head at call time, so a sibling merging after the last run still shows. It prints `CONFLICT`, `STALE`, `CLEAR`, or `UNKNOWN` and writes nothing.
114
+
115
+ - It takes the standing `canon pr lift <number> --check --json` reads, so the lift and this check answer from one read
116
+ - It falls back to its own merge-tree read where the record carries no standing gate, as a binary older than that verb leaves
117
+ - A pull request whose written set could not be read, being a fork or a deleted head, reads `UNKNOWN`, so its lift waits on a person
118
+
119
+ ### OVERLAP
120
+
121
+ `OVERLAP` names two open pull requests that conflict with each other, read by merging their heads locally. Only pairs sharing a written path are tried, which keeps a wave of ten to a handful of merges. It reports once per pair, carried in the tenth baseline field, so the merge order is settled before the second branch has to rebase.
81
122
 
82
123
  ### What a SEEN rests on
83
124
 
84
- `SEEN` used to fire early, on a head nobody had read. A review's `commit.oid` is stamped with the head at submission rather than with the commit the reviewer read, so an author pushing between the diff read and the post left the pass recorded against a commit it never saw, and `SEEN` then fired on a head still awaiting its first look at that delta.
125
+ A review's `commit.oid` is stamped with the head at submission rather than the commit the reviewer read. An author pushing between the diff read and the post would leave the pass recorded against a commit it never saw, and `SEEN` would fire on an unread delta.
126
+
127
+ The pass carries its own record instead. `review-pr` writes the commit it read and the instant it read it as a marker on the last line of every body, and both this script and that skill resolve the covered state through `canon pr review-state`, the one place the marker is parsed.
128
+
129
+ - A commit pushed inside a pass's compose window falls outside the marked range, so it reads as `MOVED` rather than `SEEN`
130
+ - A `SEEN` is a claim about what a session read rather than what GitHub stamped, so it wants no second read to be believed
131
+
132
+ ### The source behind a SEEN
133
+
134
+ Read `source` on the record before trusting a `SEEN` on a thread whose newest pass is old.
135
+
136
+ - `marker`: the read-time record
137
+ - `fallback`: a pass posted before the marker shipped, or a target whose CLI predates the verb, carrying the defect above, so read the reviews once before believing it
138
+ - `none`: a thread carrying no pass at all
85
139
 
86
- The pass now carries its own record instead. `review-pr` writes the commit it read and the instant it read it as a marker on the last line of every body it posts, and both this script and that skill resolve the covered state through `canon pr review-state`, which is the one place the marker is parsed. A commit pushed inside a pass's compose window falls outside the marked range, so it reads as `MOVED` rather than as `SEEN`. A `SEEN` is a claim about what a session read rather than about what GitHub stamped, so it wants no second read to be believed.
140
+ ### The head side of the comparison
87
141
 
88
- Read `source` on the record before trusting a `SEEN` on a thread whose newest pass is old. `marker` is the read-time record. `fallback` is a pass posted before the mechanism shipped, or a target whose CLI predates the verb, and it carries the defect above unchanged, so a `SEEN` under it is worth one read of the pull's reviews before it is believed. `none` is a thread carrying no pass at all.
142
+ The pull read's `head.sha` answers from the pull request object, which trails the branch ref by up to a minute after a push and reports nothing about the trail. A stamp ahead of the commit read, compared against a head behind the real one, made the two errors compound.
89
143
 
90
- The other side of that comparison used to lag as well, which made the two errors compound rather than cancel. The pull read's `head.sha` answers from the pull request object and that object trails the branch ref by up to a minute after a push, reporting nothing about the trail, so a pass stamped ahead of the commit it read was compared against a head stamped behind the commit that exists. The head now comes from `canon pr head`, which resolves the tip through `git ls-remote` and reports which commit each source names, and the object's head stays behind it as the fallback for a target whose CLI predates the verb. Both halves of the comparison now answer about a commit somebody named rather than one GitHub stamped, which is what lets a `SEEN` be read as covered.
144
+ The head now comes from `canon pr head`, which resolves the tip through `git ls-remote` and reports which commit each source names. The object's head stays behind it as the fallback for a target whose CLI predates the verb, so both halves answer about a commit somebody named.
@@ -5,22 +5,36 @@ description: The queue-refill procedure run after a merge, on a thin ready list,
5
5
 
6
6
  Run this when `## Refilling the ready queue` in the skill body names one of its three triggers. `orchestrator-sweep.md` wraps it for a batch of merges and adds the plan re-verification that a merge invalidates.
7
7
 
8
- The third trigger reaches a window the first two cannot. A session with three workers mid-build has merged nothing and has watched its ready list sit still, so both reactive triggers stay silent across the one stretch where planning costs the session nothing, and the wave finishes into an empty `## Run now`. Nothing starts this pass, in the way nothing starts the review poll, so it holds only while the session applies it.
8
+ ## The mid-wave trigger
9
9
 
10
- It counts unclaimed plans against workers rather than reading the reserve in step 4, which is sized for one worker finishing and falls short of a wave landing together. A plan a worker has already taken serves nobody who finishes next, so counting it is what lets the queue read full while it is about to empty. How many to write forward past that floor is the parallelism call rather than a count of free slots, and `## Parallelism` in the skill body states what binds it.
10
+ The third trigger reaches a window the first two cannot. A session with three workers mid-build has merged nothing and watched its ready list sit still, so both reactive triggers stay silent across the one stretch where planning costs nothing, and the wave finishes into an empty `## Run now`.
11
+
12
+ - Nothing starts this pass, as nothing starts the review poll, so it holds only while the session applies it
13
+ - It counts unclaimed plans against workers rather than reading step 4's reserve, which is sized for one worker finishing and falls short of a wave landing together
14
+ - A plan a worker already took serves nobody who finishes next, so counting it lets the queue read full while it is about to empty
15
+ - How many to write past that floor is the parallelism call rather than a count of free slots, and `## Parallelism` in the skill body states what binds it
11
16
 
12
17
  ## Running the refill
13
18
 
14
19
  1. Run `gh pr list --state open` and `git log --oneline -8`. Report any pull request whose review has not been posted and stop for that one first.
15
- 2. For each pull request merged since the last sweep, place every finding it produced. Route a finding that changes a rule to the standard or rule that states it, one that changes another task to that task's Findings, and one that overturns a groundwork lean to that folder marked answered. Never leave a finding in a pull request thread alone.
20
+ 2. For each pull request merged since the last sweep, place every finding it produced, and never leave one in a pull request thread alone.
21
+ - A finding that changes a rule goes to the standard or rule that states it
22
+ - One that changes another task goes to that task's Findings, and one that overturns a groundwork lean to that folder marked answered
16
23
  3. Archive what closed.
17
- - A task whose outcomes are all `[x]` and whose pull request merged is archived by the `post-merge` hook through `canon tasks archive`, which carries its plans with it. Run `task-complete` to archive one the hook left in place
18
- - A task whose outcomes describe standing policy rather than a deliverable never closes on its own, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason recorded and archive once that branch merges. Encoding it from this session would write a tracked file, which `## Boundaries` in the skill body forbids.
24
+ - A task whose outcomes are all `[x]` and whose pull request merged is archived by the `post-merge` hook through `canon tasks archive`, plans included
25
+ - Run `task-complete` to archive one the hook left in place
26
+ - A task whose outcomes are standing policy never closes, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason and archive once that branch merges
27
+ - Encoding it from this session would write a tracked file, which `## Boundaries` in the skill body forbids
19
28
  4. Read `.canon/tasks/priority.md` and count entries under its `## Run now` heading that carry a written plan. Keep one in reserve beyond what is running.
20
- 5. Promote from the top of `## Needs a plan`, which is where the last sweep recorded what to plan next. Depart from that order when something has changed under it and say what changed, since a position nobody honors is the ordering going stale on the surface built to hold it. What sets the order in the first place is whether a task establishes functionality rather than how old it is, so prefer a task that adds or proves a mechanism over one that trims, tidies, or audits an existing surface.
21
- - Re-take the demotion half of the board-or-backlog call while the file is open. A row that has stopped being near-term moves to `backlog.md`, one line removed from `priority.md` and written there, per the standard's test. The promotion half is `orchestrator-parked.md`'s to run as a full walk over every backlog row, so this step does not repeat it. A row that pass clears already sits at the bottom of `## Needs a plan` before this sweep reads the heading.
22
- 6. Before promoting a candidate, test it against every task already running under the conflict check in `orchestrator-dispatch.md`. Serialize it behind a task only on one of that check's holds, and name the hold. A path the two merely share is promoted beside it, named so the merge order plans the rebase.
23
- - A candidate held by something outside the tree stays where it is whatever the check shows. A conflict is one of the reasons a task cannot start, so clearing the check clears that reason alone and leaves an external condition standing.
29
+ 5. Promote from the top of `## Needs a plan`, where the last sweep recorded what to plan next.
30
+ - Depart from that order when something changed under it and say what, since a position nobody honors is the ordering going stale
31
+ - The order is set by whether a task establishes functionality, so prefer one that adds or proves a mechanism over one that trims, tidies, or audits
32
+ - Re-take the demotion half of the board-or-backlog call while the file is open, moving a row no longer near-term to `backlog.md` per the standard's test
33
+ - The promotion half is `orchestrator-parked.md`'s full walk over every backlog row, and a row it clears already sits at the bottom of `## Needs a plan`
34
+ 6. Before promoting a candidate, test it against every running task under the conflict check in `orchestrator-dispatch.md`.
35
+ - Serialize it behind a task only on one of that check's holds, and name the hold
36
+ - A path the two merely share is promoted beside it, named so the merge order plans the rebase
37
+ - A candidate held by something outside the tree stays put whatever the check shows, since clearing a conflict leaves an external condition standing
24
38
  7. Write a plan for each newly promoted task with `plan-feature`, carrying the in-flight constraint that `## The loop` in the skill body states, then report:
25
39
 
26
40
  ```plaintext
@@ -34,23 +48,32 @@ Ready now: <tasks with plans, and what each waits on>
34
48
 
35
49
  That block is the detail. Lead the reply with the three slots under `## Every later turn` in `orchestrator-output.md`, so the human reads what they own before the evidence for it.
36
50
 
37
- A task that edits `canon/context/` entries wholesale is a sweep under the conflict check, and holds every other task, because the root instruction file requires each task to update its own domain entry as it lands.
38
-
39
- Do not promote a task to fill the queue when nothing qualifies. A thin queue is a real answer and it beats a plan nobody needed.
51
+ - A task editing `canon/context/` entries wholesale is a sweep under the conflict check and holds every other task, since the root instruction file requires each task to update its own domain entry
52
+ - Do not promote a task to fill the queue when nothing qualifies. A thin queue is a real answer and it beats a plan nobody needed.
40
53
 
41
54
  ## Writing the board
42
55
 
43
56
  Promoting, demoting, and archiving a row all write `.canon/tasks/priority.md`, and this session is the only writer apart from `canon tasks archive`. Moving a task between the board and `.canon/tasks/backlog.md` writes both files, and this session is that file's only writer.
44
57
 
45
- - Edit the file with the file-editing tool. A shell stream editor and an inline string replace both exit clean on a non-match, so a promotion that matched nothing leaves the board wrong with nothing reporting it, and the file-editing tool errors instead.
46
- - Write both halves of a move before reporting it. A row removed from one surface and not written to the other leaves a task file nothing names, and the folder is gitignored with no history to recover the row from. `canon tasks validate` reports that state, so run it after any move.
47
- - Put the reason a row sits where it does in its Waiting on cell. Position is the ordering and the cell is where the ordering's rationale lives, so a row promoted with the cell left alone carries an order the next sweep cannot check.
58
+ - Edit with the file-editing tool, which errors on a non-match, where a shell stream editor or an inline replace exits clean and leaves the board wrong
59
+ - Write both halves of a move before reporting it, since a row on neither surface leaves a task file nothing names in a gitignored folder with no history
60
+ - `canon tasks validate` reports that state, so run it after any move
61
+ - Put the reason a row sits where it does in its Waiting on cell, since a row promoted with the cell left alone carries an order the next sweep cannot check
48
62
 
49
63
  ### Columns and read-back
50
64
 
51
- - Put a pointer in the Plan column, never prose. `## Run now` claims a written plan covers every open outcome, and `auto-ship` refuses at its guard when it follows the column and finds no plan, which spends a worker dispatch to learn what the row should have said.
52
- - Name the file set in the Touches column. It feeds the merge order and the shared paths a dispatch names, and the hold call in step 6 is only checkable later when the sets are written down rather than reasoned once and discarded.
65
+ Each column carries a fact a later reader checks rather than reasons again.
66
+
67
+ - Put a pointer in the Plan column, never prose, since `auto-ship` refuses at its guard when the column leads to no plan, spending a dispatch
68
+ - `## Run now` claims a written plan covers every open outcome, which is what the pointer backs
69
+ - Name the file set in the Touches column, which feeds the merge order and the shared paths a dispatch names, so step 6's hold call stays checkable later
53
70
  - Re-resolve every Plan pointer after anything archives a plan
54
71
  - Read the file back after writing it, since the row that lands is the row a worker acts on
55
72
 
56
- A Plan pointer goes stale from a merge this board never sees. The `post-merge` hook moves a plan to `.canon/plans/archive/` through `canon tasks archive` and rewrites the citation in the archived task file alone, so a row for a task still on the board keeps pointing into `.canon/plans/` at a file that has moved. `task-complete` marks outcomes on each worker's branch and moves nothing, so the move lands at the merge, and the board reads as correct until a pointer is followed.
73
+ ### Stale plan pointers
74
+
75
+ A Plan pointer goes stale from a merge this board never sees. The `post-merge` hook moves a plan to `.canon/plans/archive/` through `canon tasks archive` and rewrites the citation in the archived task file alone.
76
+
77
+ - A row for a task still on the board keeps pointing into `.canon/plans/` at a file that has moved
78
+ - `task-complete` marks outcomes on each worker's branch and moves nothing, so the move lands at the merge
79
+ - The board then reads as correct until a pointer is followed
@@ -6,9 +6,13 @@ description: What to read back after a compaction, and how to treat a groundwork
6
6
  Resume as orchestrator after a compaction. Read the board and the groundwork behind the live work before answering anything, because a compaction summary keeps conclusions and drops the reasoning that produced them.
7
7
 
8
8
  1. Resolve the main worktree root with `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. Every path below resolves against it.
9
- 2. Read `.canon/tasks/priority.md` for the ordering and what each task waits on. Read the newest `.canon/tasks/session-*.md` when one exists, per `${CLAUDE_SKILL_DIR}/../session-map/references/session.md`, and treat it as the previous session's scratch rather than a source.
9
+ 2. Read `.canon/tasks/priority.md` for the ordering and what each task waits on.
10
+ - Read the newest `.canon/tasks/session-*.md` when one exists, per `${CLAUDE_SKILL_DIR}/../session-map/references/session.md`
11
+ - Treat it as the previous session's scratch rather than a source
10
12
  3. Read the task file for every entry under `## Run now`, plus any entry a live pull request names.
11
- 4. Read the groundwork folder each of those tasks cites. Read `README.md` for the file map, then `06-decision.md` when the track is closed, or `07-next-session.md` and the numbered topic files when it is open. A task's Findings section is a lossy summary of its track, so planning against the summary re-derives what the folder already settled.
13
+ 4. Read the groundwork folder each of those tasks cites.
14
+ - `README.md` for the file map, then `06-decision.md` when the track is closed, or `07-next-session.md` and the topic files when open
15
+ - A task's Findings section is a lossy summary, so planning against it re-derives what the folder already settled
12
16
  5. Run `gh pr list --state open` and `git log --oneline -5` to see what shipped since the folder was written.
13
17
  6. Report in this shape and stop:
14
18
 
@@ -22,12 +26,20 @@ Held open: <talk sessions from the map's `## Talk sessions held open`, or none>
22
26
 
23
27
  Read `Held open:` off the newest session map's `## Talk sessions held open`, so a resumed session does not mistake a conversation for a finished delivery. `orchestrator-handoff.md` states what ends one.
24
28
 
25
- Treat a groundwork folder as three kinds of content with different shelf lives. Trust the reasoning and the method, which stay correct. Re-measure every count, size, and cost, because they were true when written. Check every `Leaning:` against what has shipped, because work spawned by a track routinely overturns the lean that spawned it and nothing writes back.
29
+ ## Groundwork shelf lives
26
30
 
27
- A plan a live task cites goes stale the same way, and `role-orchestrator` states the check that catches it.
31
+ Treat a groundwork folder as three kinds of content with different shelf lives. A plan a live task cites goes stale the same way, and `role-orchestrator` states the check that catches it.
28
32
 
29
- After each merge, place every finding the work produced before starting anything else. A finding that changes a standard goes to the standard, one that changes another task goes to that task's Findings, and one that overturns a groundwork lean gets marked answered in that folder. Findings recorded in a pull request thread and nowhere else are lost at merge.
33
+ - Trust the reasoning and the method, which stay correct
34
+ - Re-measure every count, size, and cost, because they were true when written
35
+ - Check every `Leaning:` against what has shipped, since a track's spawned work routinely overturns its lean and nothing writes back
36
+ - Cite a file and line for any claim taken from a groundwork folder, so a later reader can tell a read from a recall
37
+ - Read only the folders the live tasks cite, since a speculative sweep of the whole folder is the cost this rule exists to bound
30
38
 
31
- Cite a file and line for any claim taken from a groundwork folder, so a later reader can tell a read from a recall.
39
+ ## After each merge
32
40
 
33
- Do not read every groundwork folder. Read the ones the live tasks cite. A speculative sweep of the whole folder is the cost this rule exists to bound.
41
+ Place every finding the work produced before starting anything else, since a finding recorded in a pull request thread and nowhere else is lost at merge.
42
+
43
+ - A finding that changes a standard goes to the standard
44
+ - One that changes another task goes to that task's Findings
45
+ - One that overturns a groundwork lean gets marked answered in that folder
@@ -9,30 +9,40 @@ Run this on every first pass, from `### The review dispatch` in the skill body.
9
9
 
10
10
  Dispatch every pull request's review to a reviewer under `role-reviewer`, first pass included, whatever its size or its paths. A release pull request is the one exception, since its sweep carries no findings and owes no pass.
11
11
 
12
- This session reviews nothing in place. A warm pass reads the whole diff into the one context the wave shares, so every pull request reviewed here thins the attention each later one gets, and a cold session pays for its own context instead.
13
-
14
- Nothing checks that a first pass was dispatched rather than run here. This is prose this session applies to itself, on the same standing as the poll's own start condition, so a pull request reviewed in place is a rule that went unread rather than a check that failed.
15
-
16
- Pick the reviewer's model by `## Pick the model` in `orchestrator-dispatch.md`, which states the test for every role this session launches. Stating the pick here as well would leave two sources for one call.
12
+ - This session reviews nothing in place, since a warm pass reads the whole diff into the wave's one context and thins every later pull request's attention
13
+ - A cold session pays for its own context instead
14
+ - Nothing checks that a first pass was dispatched, so a pull request reviewed in place is a rule that went unread rather than a check that failed
15
+ - Pick the reviewer's model by `## Pick the model` in `orchestrator-dispatch.md`, the one source for every role this session launches
17
16
 
18
17
  ## The UI reviewer
19
18
 
20
- A pull request whose evidence record carries a checklist takes a second reviewer, a UI reviewer under `review-ui`, dispatched beside the code reviewer so the two passes run at once. Read the record with `canon pr evidence <number> --json` and branch on its `checklist` field rather than on the exit code. A record carrying none dispatches no UI reviewer, since the pass would stop on arrival.
19
+ A pull request whose evidence record carries a checklist takes a second reviewer, a UI reviewer under `review-ui`, dispatched beside the code reviewer so the two passes run at once. Read the record with `canon pr evidence <number> --json` and branch on its `checklist` field rather than on the exit code.
21
20
 
22
- The UI reviewer reads no diff and never hears the code reviewer's verdict, so neither brief carries the other's result. Each posts its own family and runs `canon pr lift` on posting its close, and the verb lifts the draft mark only once both read closed at the head, per the draft-lift boundary in the skill body.
21
+ - A record carrying no checklist dispatches no UI reviewer, since the pass would stop on arrival
22
+ - The UI reviewer reads no diff and never hears the code verdict, so neither brief carries the other's result
23
+ - Each posts its own family and runs `canon pr lift` on its close, and the verb lifts the draft mark only once both read closed at the head
23
24
 
24
25
  ## The cross-branch pass
25
26
 
26
- This session keeps one pass per wave beside the dispatched reviews. It reads the file sets of every open pull request against each other, the board, and the merge order, and never the diffs themselves. What it looks for is what no single pull request shows: two branches regenerating one asset, several writing one context entry, a figure true only after another branch lands.
27
+ This session keeps one pass per wave beside the dispatched reviews. It reads the file sets of every open pull request against each other, the board, and the merge order, and never the diffs themselves.
27
28
 
28
- Hand what it finds to each reviewer as facts in the brief, per `### What the brief may carry` in `orchestrator-launch.md`, rather than posting a comment of its own, so each pull request keeps one live verdict. A fact surfacing after a reviewer posted goes to that reviewer as a re-review request.
29
+ - It looks for what no single pull request shows, such as two branches regenerating one asset, several writing one context entry, or a figure true only after another lands
30
+ - Hand what it finds to each reviewer as facts in the brief, per `### What the brief may carry` in `orchestrator-launch.md`, so each pull request keeps one live verdict
31
+ - A fact surfacing after a reviewer posted goes to that reviewer as a re-review request
29
32
 
30
33
  ## Launching the reviewer
31
34
 
32
- Take the reviewer shape in `orchestrator-reviewer-launch.md`, or its UI reviewer shape for a pull request carrying a checklist. Check `canon sessions list --json` for a live `reviewer-<project>-<number>`, or `reviewer-ui-<project>-<number>`, first and message it instead of launching a second, since two reviewers on one pull request post two verdicts. The re-review after a worker's address pass reaches that reviewer from the worker directly, and this session sends it only as the fallback `orchestrator-handback.md` states.
35
+ Take the reviewer shape in `orchestrator-reviewer-launch.md`, or its UI reviewer shape for a pull request carrying a checklist.
36
+
37
+ - Check `canon sessions list --json` first for a live `reviewer-<project>-<number>` or `reviewer-ui-<project>-<number>`, and message it instead of launching
38
+ - Two reviewers on one pull request post two verdicts
39
+ - The re-review after a worker's address pass reaches the reviewer from the worker, and this session sends it only as the fallback `orchestrator-handback.md` states
33
40
 
34
41
  ## Local or cloud
35
42
 
36
- A code review goes to a cloud reviewer rather than `claude --bg` only on the operator's explicit pick for that dispatch, the same standing the build shape's pick holds in `orchestrator-dispatch.md`. The cloud session costs no local context and no machine slot, which matters on a wide wave. It also reads nothing this machine holds, so a review that needs the board, a local preview, or a sandbox stays local.
43
+ A code review goes to a cloud reviewer rather than `claude --bg` only on the operator's explicit pick for that dispatch, the same standing the build shape's pick holds in `orchestrator-dispatch.md`. A UI review always stays local.
37
44
 
38
- This session hears a cloud reviewer through `poll.ts` alone, which already lists every open pull request from this machine, so the posted review is the announcement and no message arrives. `orchestrator-cloud-launch.md` carries the shape under `## Dispatch a review to a cloud reviewer`. A UI review always stays local.
45
+ - The cloud session costs no local context and no machine slot, which matters on a wide wave
46
+ - It reads nothing this machine holds, so a review needing the board, a local preview, or a sandbox stays local
47
+ - This session hears a cloud reviewer through `poll.ts` alone, so the posted review is the announcement and no message arrives
48
+ - `orchestrator-cloud-launch.md` carries the shape under `## Dispatch a review to a cloud reviewer`
@@ -15,11 +15,15 @@ No branch and no worktree are entered here. The reviewer reads the pull request
15
15
  claude --bg --model <model> -n "reviewer-<project>-<number>" "Run /canon:role-reviewer, then /canon:review-pr <number>. 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. When the pass posts under ## Review, message the worker holding the branch to run review-address, carrying your own sessionId, and send it to the controller instead when no worker resolves. When it posts ## Review closed, run canon pr lift <number> --json and message the controller with the heading, the count line, and the reason the verb returned, unless that reason names the UI review as still open or missing. Message the controller again if you stop on a question."
16
16
  ```
17
17
 
18
- `<number>` is the pull request's number, and the brief pins no head, since `review-pr` resolves the head itself and stamps the range it covered in its marker. `<model>` comes from `## Pick the model` in `orchestrator-dispatch.md`, which states the test for a reviewer as for every other role. `<dispatcher-id>` and `<project>` resolve the same way they do in `orchestrator-launch.md`.
18
+ - `<number>` is the pull request's number, and the brief pins no head, since `review-pr` resolves it and stamps the covered range in its marker
19
+ - `<model>` comes from `## Pick the model` in `orchestrator-dispatch.md`, which states the test for a reviewer as for every other role
20
+ - `<dispatcher-id>` and `<project>` resolve the same way they do in `orchestrator-launch.md`
21
+ - Append the cross-branch facts after the controller clause, per `### What the brief may carry` in `orchestrator-launch.md`
22
+ - Check `canon sessions list --json` for a live `reviewer-<project>-<number>` before launching, and message it instead when one holds the pull request
19
23
 
20
- The channel clauses restate what `role-reviewer` holds, so a reviewer whose plugin cache predates that body still sends the dispatch itself rather than leaving it to this session. The worker reads the reviewer's sessionId off that message and sends its re-review request back to it, since a reviewer holds the trunk branch and no branch lookup finds it. Append the cross-branch facts after the controller clause, per `### What the brief may carry` in `orchestrator-launch.md`.
24
+ ### The channel clauses
21
25
 
22
- Check `canon sessions list --json` for a live `reviewer-<project>-<number>` before launching, and message that session instead when one holds the pull request.
26
+ The channel clauses restate what `role-reviewer` holds, so a reviewer whose plugin cache predates that body still sends the dispatch itself. The worker reads the reviewer's sessionId off that message and sends its re-review request back to it, since a reviewer holds the trunk branch and no branch lookup finds it.
23
27
 
24
28
  ## Dispatch a review to a cloud reviewer
25
29
 
@@ -33,8 +37,13 @@ Read `${CLAUDE_SKILL_DIR}/references/orchestrator-cloud-launch.md` when the oper
33
37
  claude --bg --model sonnet -n "reviewer-ui-<project>-<number>" "Run /canon:role-reviewer, then /canon:review-ui <number>. 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. When the pass posts under ## UI review, message the worker holding the branch to run review-address, carrying your own sessionId, and send it to the controller instead when no worker resolves. When it posts ## UI review closed, run canon pr lift <number> --json and message the controller with the heading, the count line, and the reason the verb returned, unless that reason names the code review as still open or missing. Message the controller again if you stop on a question."
34
38
  ```
35
39
 
36
- The model is `sonnet`, always, as the UI reviewer line in `## Pick the model` in `orchestrator-dispatch.md` states with its measured reason.
40
+ The model is `sonnet`, always, as the UI reviewer line in `## Pick the model` in `orchestrator-dispatch.md` states with its measured reason. `<number>`, `<dispatcher-id>`, and `<project>` resolve the same way they do in `orchestrator-launch.md`.
37
41
 
38
- Name an address in the brief only when the evidence record carries no `preview` and no `local` field, as `Drive <url>.` after the controller clause. An address the record already holds is the one the pass reads first, and a second in the brief is a second source for one fact. Name a CLI config path the same way when the operator keeps a GPU recipe for this machine, since the pass renders in software otherwise. Carry nothing else: the UI reviewer reads no diff and no code verdict, so the cross-branch facts the code brief carries stay out of this one.
42
+ - The prefix reads `reviewer-ui-` so a roster read for `reviewer-<project>-<number>` never matches it, and the two passes stay two sessions
43
+ - Carry no cross-branch facts, since the UI reviewer reads no diff and no code verdict
39
44
 
40
- `<number>`, `<dispatcher-id>`, and `<project>` resolve the same way they do in `orchestrator-launch.md`. The prefix reads `reviewer-ui-` so a roster read for `reviewer-<project>-<number>` never matches the UI reviewer, and the two passes on one pull request stay two sessions.
45
+ ### What the UI brief may carry
46
+
47
+ Name an address only when the evidence record carries no `preview` and no `local` field, as `Drive <url>.` after the controller clause. An address the record holds is the one the pass reads first, and a second in the brief is a second source for one fact.
48
+
49
+ Name a CLI config path the same way when the operator keeps a GPU recipe for this machine, since the pass renders in software otherwise.
@@ -5,17 +5,35 @@ description: The once-per-batch board sweep, plan re-verification, and where eac
5
5
 
6
6
  Sweep the board as orchestrator after merging. Run this once per batch of merges, before answering what to do next, because the surfaces that record what shipped are the ones nothing updates on its own.
7
7
 
8
- 1. Pull into the main worktree rather than fetching. A fetch leaves the local branch behind, so `git log` reports a state that has not arrived. A repository that adds a post-merge hook to name archive candidates gets it on a pull and never on a fetch.
8
+ 1. Pull into the main worktree rather than fetching, since a fetch leaves the local branch behind and `git log` reports a state that has not arrived.
9
+ - A repository that adds a post-merge hook to name archive candidates gets it on a pull and never on a fetch
9
10
  2. Follow `orchestrator-refill.md`, every step in order. It owns the procedure. Do not restate it here and do not run it from memory.
10
- 3. Re-verify every plan already written, not only the ones this sweep writes. A queued plan goes stale from whatever merged while it waited, and the loop's verify step fires at handoff rather than after a merge, so nothing else catches it. Grep each construct the plan names and count the sites against its claim, then open each file rather than trusting its account.
11
- 4. Re-check any precondition a plan states about live state outside the repository. A remote branch, an open issue, or an installed version was true when the plan was written and is not a fact about the tree.
11
+ 3. Re-verify every plan already written, not only the ones this sweep writes.
12
+ - A queued plan goes stale from whatever merged while it waited, and the loop's verify step fires at handoff, so nothing else catches it
13
+ - Grep each construct the plan names and count the sites against its claim, then open each file rather than trusting its account
14
+ 4. Re-check any precondition a plan states about live state outside the repository, such as a remote branch, an open issue, or an installed version.
15
+ - Each was true when the plan was written and is not a fact about the tree
12
16
 
13
- Run `canon worktrees list` after the pull, which is the first point at which the merges this sweep followed are readable. It owns the reclaim rule and it removes nothing, so read its rows and act on the ones you mean to. Never substitute a git ancestry check for it.
17
+ ## Worktrees and the validator
14
18
 
15
- Run `canon tasks validate` once the board is rewritten and before reporting it. It resolves every plan pointer, accounts every task file against the board and the backlog both, reports the paths `## Run now` rows share as a candidate list for the conflict check, and re-takes the two blocker kinds a command can settle. It reports and never writes, so fix each row it names and run it again. A finding it reports is a board defect rather than a task finding, so it goes nowhere but the board.
19
+ Run `canon worktrees list` after the pull, the first point at which the merges this sweep followed are readable. It owns the reclaim rule and removes nothing, so read its rows and act on the ones you mean to. Never substitute a git ancestry check for it.
16
20
 
17
- Then run `orchestrator-parked.md` over the rows the validator listed as untested. Those carry the three blocker kinds no command settles, and the merge this sweep followed changed the tree under every one of them at once while the refill above re-read none. Take the untested rows alone rather than the whole board, since the validator already answered the rest.
21
+ Run `canon tasks validate` once the board is rewritten and before reporting it. It reports and never writes, so fix each row it names and run it again.
18
22
 
19
- Place every finding the merged work produced before promoting anything. A finding that changes a rule goes to the standard or the rule that states it, one that changes another task goes to that task's Findings, and one that overturns a groundwork lean gets marked answered in that folder. A pull request body counts as nowhere, since the thread stops being read the moment it merges.
23
+ - It resolves every plan pointer and accounts every task file against the board and the backlog both
24
+ - It reports the paths `## Run now` rows share as a candidate list for the conflict check, and re-takes the two blocker kinds a command can settle
25
+ - A finding it reports is a board defect rather than a task finding, so it goes nowhere but the board
26
+
27
+ ### Untested rows
28
+
29
+ Then run `orchestrator-parked.md` over the rows the validator listed as untested. Those carry the three blocker kinds no command settles, and the merge changed the tree under every one at once while the refill re-read none. Take the untested rows alone, since the validator already answered the rest.
30
+
31
+ ## Place the findings
32
+
33
+ Place every finding the merged work produced before promoting anything. A pull request body counts as nowhere, since the thread stops being read the moment it merges.
34
+
35
+ - A finding that changes a rule goes to the standard or the rule that states it
36
+ - One that changes another task goes to that task's Findings
37
+ - One that overturns a groundwork lean gets marked answered in that folder
20
38
 
21
39
  Report what closed, what moved, and what is ready to hand a worker. Name the file set each ready task touches and the hold or shared paths it carries, so the reader can check the conflict call rather than take it.
@@ -7,20 +7,46 @@ Run the watch beside the poll when the dispatch fallback in `orchestrator-poll.m
7
7
 
8
8
  ## The watch beside it
9
9
 
10
- `${CLAUDE_SKILL_DIR}/scripts/watch.ts` is a long-running loop rather than a scheduled prompt, started as `bun <path>`. It reads the open pull request list and the session roster together every sixty seconds and prints one line per new pull request, per worker whose name, branch, or status changed, and per worker that dropped out of the roster. Start it in the background and read what it emits. It writes nothing.
10
+ `${CLAUDE_SKILL_DIR}/scripts/watch.ts` is a long-running loop rather than a scheduled prompt, started as `bun <path>` in the background. It writes nothing. Every sixty seconds it reads the open pull request list and the session roster together and prints one line per event.
11
11
 
12
- Coverage is what it buys over the poll. A worker that finishes goes idle and a worker that crashes disappears, so a trigger reading pull requests alone stays silent through the second, and the roster read is the half `poll.ts` cannot make. It ran a full afternoon over four concurrent workers and caught every transition, while the three-minute poll it replaced reported no movement five times in a row.
12
+ - A new pull request
13
+ - A worker whose name, branch, or status changed
14
+ - A worker that dropped out of the roster
13
15
 
14
- It classifies nothing and routes nothing. A line it prints says a pull request opened or a worker moved, and the routing block in `orchestrator-poll.md` is still what decides whether a review follows, so the two compose rather than replace each other.
16
+ ### What it buys over the poll
15
17
 
16
- Every session in the repository holding a branch other than the base one counts as a worker, whoever launched it. The prototype matched the `orchestrator-` prefix instead, which reads a dispatched worker and misses every hand-launched one. A failed read of either source reports itself on a `watch:` line and leaves the baseline untouched, since reading an empty result as current state would report every worker gone on the pass after.
18
+ A worker that finishes goes idle and one that crashes disappears, so a trigger reading pull requests alone stays silent through the second. The roster read is the half `poll.ts` cannot make.
19
+
20
+ - It ran a full afternoon over four concurrent workers and caught every transition, while the three-minute poll it replaced reported no movement five times running
21
+ - It classifies and routes nothing, so the routing block in `orchestrator-poll.md` still decides whether a review follows and the two compose
22
+
23
+ ### Who counts as a worker
24
+
25
+ Every session in the repository holding a branch other than the base one counts as a worker, whoever launched it, since matching the `orchestrator-` prefix would miss every hand-launched one.
26
+
27
+ A failed read of either source reports itself on a `watch:` line and leaves the baseline untouched, since reading an empty result as current state would report every worker gone on the pass after.
17
28
 
18
29
  ## The stall alarm
19
30
 
20
- `watch.ts` prints `WORKER-STOPPED <name> <branch> <dwell>s` once a `waiting` row crosses `STALL_THRESHOLD_S`, and `WORKER-UNMEASURABLE <name> <branch>` for one whose record carries neither timestamp the dwell falls back to. Both are prints, not alerts, so the operator learns of one only when a session already reading the loop's output relays it further. The toolkit ships no notification verb, since the surface a stall reaches the operator through is a session tool rather than a command a shell loop can call.
31
+ `watch.ts` prints `WORKER-STOPPED <name> <branch> <dwell>s` once a `waiting` row crosses `STALL_THRESHOLD_S`. It prints `WORKER-UNMEASURABLE <name> <branch>` for a row whose record carries neither timestamp the dwell falls back to.
32
+
33
+ - Both are prints, not alerts, so the operator learns of one only when a session already reading the output relays it
34
+ - The toolkit ships no notification verb, since a stall reaches the operator through a session tool rather than a command a shell loop can call
35
+
36
+ ### Two levels of confidence
37
+
38
+ The two lines carry different confidence, and the push says so rather than treating them as one signal.
39
+
40
+ - `WORKER-STOPPED` fires only once the dwell has crossed the threshold, so it reports a wait already confirmed long
41
+ - `WORKER-UNMEASURABLE` has no dwell to threshold on, so it fires on the first pass meeting a stampless `waiting` row, whether it sat five seconds or fifty minutes
42
+
43
+ ### Pushing the notification
44
+
45
+ On meeting either line, push a notification to the operator through whatever surface the client offers, `PushNotification` in this repository's client and one example among the surfaces a different client exposes.
21
46
 
22
- The two lines carry different confidence and the push has to say so rather than treat them as one signal. `WORKER-STOPPED` fires only once the dwell has already crossed the threshold, so it reports a wait already confirmed long. `WORKER-UNMEASURABLE` has no dwell to threshold on, so it fires on the first pass that meets a `waiting` row carrying neither stamp, whether that row has sat five seconds or fifty minutes.
47
+ - Name the worker, the branch, which line fired, and the dwell where `WORKER-STOPPED` carries one
48
+ - Send it once per stall, as `watch.ts` prints it once, rather than on every interval the row stays stopped
23
49
 
24
- On meeting either line, push a notification to the operator through whatever notification surface the client offers, `PushNotification` in this repository's client and one example among the surfaces a different client exposes. Name the worker, the branch, which of the two lines fired, and the dwell where `WORKER-STOPPED` carries one, and send it once per stall the same way `watch.ts` prints it once, rather than repeating it on every interval the row stays stopped.
50
+ ### The open bound
25
51
 
26
- The bound stays open. The alarm reaches the operator only through the controller's own read, so a controller mid-turn does not see the line for as long as the turn runs, and a controller that is itself stopped never does. Neither case closes here, since the watch loop and the notification surface both live inside the same session that has to be free to act on either.
52
+ The alarm reaches the operator only through the controller's own read, so a controller mid-turn misses the line for as long as the turn runs, and a stopped controller never sees it. Neither case closes here, since the loop and the notification surface both live inside the session that has to be free to act.