@erclx/canon 4.124.0 → 4.125.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.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -1
- package/claude/skills/role-orchestrator/SKILL.md +11 -9
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +2 -0
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +18 -3
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +4 -4
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +29 -0
- package/claude/skills/role-reviewer/REQUIREMENT.md +75 -0
- package/claude/skills/role-reviewer/SKILL.md +73 -0
- package/claude/skills/role-worker/SKILL.md +1 -1
- package/docs/workflow/operating-model.md +11 -12
- package/docs/workflow/parallel-features.md +1 -1
- package/docs/workflow/skill-map.md +1 -0
- package/package.json +1 -1
- package/src/claude/cases/workflow.ts +5 -0
- package/claude/skills/role-orchestrator/references/orchestrator-review-fallback.md +0 -18
|
@@ -83,6 +83,7 @@ Dispatch parts from what it checked in three ways. The gate and the worker each
|
|
|
83
83
|
- Carry the dispatcher's `sessionId` in the launch prompt, since a worker owed two messages has no property on the roster that resolves a controller and a name goes stale inside the window it builds in
|
|
84
84
|
- Report each self-dispatch and the row it fired against loudly enough to follow, since a person no longer watches the launch step happen
|
|
85
85
|
- Stop dispatching once `## Run now` is empty or every row in it reads claimed, rather than waking again to fire on a board nobody is clearing
|
|
86
|
+
- Dispatch a pull request's review, first pass included, to `role-reviewer` on load or on executable content, a skill body included, and keep one cross-branch pass per wave here, since a warm pass holding a wave skims what a cold one reads
|
|
86
87
|
|
|
87
88
|
## Must not
|
|
88
89
|
|
|
@@ -112,7 +113,7 @@ Dispatch parts from what it checked in three ways. The gate and the worker each
|
|
|
112
113
|
## Out of scope
|
|
113
114
|
|
|
114
115
|
- Writing the plan itself, which `plan-feature` owns and this session runs rather than reimplements
|
|
115
|
-
- Reviewing a worker's pull request, which `review-pr` owns
|
|
116
|
+
- Reviewing a worker's pull request, which `review-pr` owns, and the bounds of a reviewer dispatched to run it, which `role-reviewer` owns
|
|
116
117
|
- Entering the worktree a build runs in, which the worker opens for itself whether a human launched it or this session dispatched it
|
|
117
118
|
- The worker's half of the channel and the boundaries a building session holds, which `role-worker` states where that session reads them
|
|
118
119
|
- The operating model this enacts, which the toolkit's own docs hold
|
|
@@ -61,9 +61,9 @@ Report the state of play in the invocation block, and open every later sweep rep
|
|
|
61
61
|
2. Decide parallelism and merge order. Note which plans touch a shared wiring seam so their PRs merge in sequence, not at once.
|
|
62
62
|
3. Verify the plan against the tree. Reading it is not enough, since a plan goes stale from whatever merged after it was written. Grep for each construct it names and count the sites against the count it claims. Check that every phase label it cites is still open. Open each file it describes rather than trusting its account of the contents. Correct the plan before handing it over.
|
|
63
63
|
4. Hand off. Read `${CLAUDE_SKILL_DIR}/references/orchestrator-dispatch.md` and follow it: check the branch is unclaimed, check the row's file set against every track in flight, then dispatch a background worker with `claude --bg`. Fall back to the human-launch line it replaces when the check refuses, the sets overlap, or a stated reason serializes the row behind something already out.
|
|
64
|
-
5. Review the PR. When a worker opens a PR,
|
|
64
|
+
5. Review the PR. When a worker opens a PR, its first pass runs through `review-pr` in a reviewer dispatched under `role-reviewer` when `### The review dispatch` below fires, and in this session otherwise. Either is the deep, independent pass. The worker's autoship self-review was only the green gate.
|
|
65
65
|
- Learning that a PR moved is the mechanical half, so read `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` and run the poll under the condition it states rather than checking the board by hand. That runbook holds the routing and the trigger, and a summary of it here is a second source that drifts from it.
|
|
66
|
-
6. Dispatch the handback. A pass posting anything owed, a finding at any severity or a testing question, tells the session holding that branch to run `review-address`, rather than waiting for a person to relay it. Re-review when the worker's own message says the address pass finished, per the channel `role-worker` states, rather than polling for an answer nothing else marks as landed. Once a pass posts `## Review closed`, lift the pull request's draft mark yourself, per Boundaries below. Then the human merges. Tell the trailing worker to rebase when its branch shares a seam with the merged one.
|
|
66
|
+
6. Dispatch the handback. A pass posting anything owed, a finding at any severity or a testing question, tells the session holding that branch to run `review-address`, rather than waiting for a person to relay it. Re-review when the worker's own message says the address pass finished, per the channel `role-worker` states, rather than polling for an answer nothing else marks as landed, and send the re-review back to the dispatched reviewer when one took the first pass. Once a pass posts `## Review closed`, lift the pull request's draft mark yourself, per Boundaries below. Then the human merges. Tell the trailing worker to rebase when its branch shares a seam with the merged one.
|
|
67
67
|
- Read `${CLAUDE_SKILL_DIR}/references/orchestrator-handback.md` on reaching this step. It holds how the message is addressed and worded, what to do when no live session holds the branch, and where a worker's reply goes.
|
|
68
68
|
|
|
69
69
|
A plan written here is written against a tree several branches are already changing, so it names the file set of every track in flight as a constraint, one set per track, read from the Touches column of that track's row. State for each set which of the two acts it forbids, per Constraints in `${CLAUDE_SKILL_DIR}/../../standards/plan.md`. A bare path list leaves the worker guessing, which is how a plan ends up forbidding the repair of a citation the change broke.
|
|
@@ -75,7 +75,7 @@ Stamp the block with the commit this session read the tree at, which the same se
|
|
|
75
75
|
- Run one orchestrator at a time. The board is gitignored, so a second session sees none of this one's writes: two task files land minutes apart under different labels for the same work, one session archives a task mid-sweep in the other, and each archives a plan the other had retargeted. An Owner column does not fix this, since neither session can read the other's rows.
|
|
76
76
|
- Do not implement features in this session. Hand the plan to a worker.
|
|
77
77
|
- Do not merge. Recommend merge or changes. The human merges.
|
|
78
|
-
- Lift a pull request's draft mark once this session
|
|
78
|
+
- Lift a pull request's draft mark once its review closes, whether this session or a reviewer it dispatched closed it, acting directly on the pull request rather than dispatching a worker to do it. `role-worker` and `role-reviewer` state the mirroring refusal: neither can verify who is asking or whether review actually closed, so the act stays with this session.
|
|
79
79
|
- Do not spawn a worker with the Agent tool. An in-process subagent shares this session's context and cannot be steered or reached independently, which breaks the property this boundary protects rather than the mechanism it names. The launch in `orchestrator-launch.md` is a separate `claude --bg` process with its own worktree and its own PR, so it preserves that property instead.
|
|
80
80
|
- Dispatch a background worker only once the collision check in `orchestrator-dispatch.md` clears and the row's file set is disjoint from every track in flight. Colliding with an existing worktree or session is what the check exists to catch rather than a judgment call this session makes case by case. No fixed count binds how many tracks run at once, and Parallelism below states what does.
|
|
81
81
|
- Do not edit tracked files from this session, at any size. The boundary offers no proportionality exception and nothing enforces it.
|
|
@@ -138,10 +138,12 @@ stack derives it from the worktree it runs in through `scripts/worktree-port.sh`
|
|
|
138
138
|
Read that value rather than assigning one, and set `WORKTREE_PORT_OFFSET` by
|
|
139
139
|
hand only when two worktrees derive the same offset.
|
|
140
140
|
|
|
141
|
-
### The review
|
|
141
|
+
### The review dispatch
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
Review splits by what each side can see. A reviewer dispatched under
|
|
144
|
+
`role-reviewer` takes the per-pull-request read, first pass included, when the
|
|
145
|
+
load is past what this session can hold or the change touches executable or
|
|
146
|
+
security surface. Below both, this session reviews in place. It keeps one
|
|
147
|
+
cross-branch pass per wave either way, over file sets, the board, and merge
|
|
148
|
+
order. Read `${CLAUDE_SKILL_DIR}/references/orchestrator-review-dispatch.md` on
|
|
149
|
+
every first pass for the trigger and how that pass reaches each brief.
|
|
@@ -74,7 +74,7 @@ A declared set is what a branch sets out to write rather than a bound on it, so
|
|
|
74
74
|
|
|
75
75
|
Disjointness is necessary and not sufficient, so hold a candidate whose sets do not touch when a stated reason serializes it, and write the reason on the hold. One row creating a skill and another auditing that catalog and counting it write nothing in common, and dispatching both still leaves the audit counting a denominator that moves underneath it. Nothing verifies that a reason was written, so the rule holds only while the dispatcher applies it.
|
|
76
76
|
|
|
77
|
-
What binds past that is review attention rather than a count, and `## Parallelism` in the skill body states it along with the cap an operator can set for a session. The one number this skill carries is the review
|
|
77
|
+
What binds past that is review attention rather than a count, and `## Parallelism` in the skill body states it along with the cap an operator can set for a session. 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.
|
|
78
78
|
|
|
79
79
|
## Pick the model
|
|
80
80
|
|
|
@@ -13,6 +13,8 @@ Read this at loop step 6, once a review pass has posted anything owed and the se
|
|
|
13
13
|
- Name the skill for the reader to run rather than writing an invocation, which arrives as text
|
|
14
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 docs pr-reads` 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.
|
|
15
15
|
|
|
16
|
+
A re-review goes back 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`. When none is live, launch a fresh reviewer through the reviewer shape in `orchestrator-launch.md` or review in place, under the same trigger `orchestrator-review-dispatch.md` states, rather than messaging a name that no longer answers.
|
|
17
|
+
|
|
16
18
|
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, report the invocation for the human, 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.
|
|
17
19
|
|
|
18
20
|
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.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Orchestrator launch runbook
|
|
3
|
-
description: The launch every dispatch kind shares, being the build, review-address, and
|
|
3
|
+
description: The launch every dispatch kind shares, being the build, review-address, planning, and reviewer templates, the session name and controller id each carries, why the command sits at position zero, and what the brief may carry
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Run this once `orchestrator-dispatch.md` has cleared a row, or from its planning or
|
|
6
|
+
Run this once `orchestrator-dispatch.md` has cleared a row, or from its planning, review-address, or reviewer shape below when that runbook's checks do not bind. The model each template names comes from `## Pick the model` in that runbook.
|
|
7
7
|
|
|
8
8
|
## Dispatch
|
|
9
9
|
|
|
@@ -34,7 +34,7 @@ Put a command whose skill carries `disable-model-invocation: true` at position z
|
|
|
34
34
|
|
|
35
35
|
Never depend on the `Skill` tool route for a flagged skill. A refusal there tells the session not to replicate the workflow by other means, so a refused worker stops with a clean worktree, which is the correct outcome. The refusal is sticky inside a session, so recovery belongs to whoever writes the next prompt: re-dispatch onto the same branch with the build template above.
|
|
36
36
|
|
|
37
|
-
The review
|
|
37
|
+
The review-address, planning, and reviewer shapes below depend on no expansion at all. None of `role-worker`, `review-address`, `role-planner`, `plan-feature`, `role-reviewer`, or `review-pr` carries the flag, so all three correctly keep their leading word regardless of the delimiter or the position it sits at.
|
|
38
38
|
|
|
39
39
|
The same rule reaches a human relay. Hand an operator one message carrying one command at position zero, since two chained blocks pasted as separate messages can land as one, where everything after the first command's name reads as that command's argument and the second never fires.
|
|
40
40
|
|
|
@@ -45,6 +45,7 @@ The prompt carries pointers and standing context, and stops there. The branch an
|
|
|
45
45
|
- Name the addressee and what it is owed, which the two message clauses above already do.
|
|
46
46
|
- Carry standing context this session holds that a cold one cannot derive, such as a constraint settled in conversation that never reached the plan.
|
|
47
47
|
- Leave out anything scope-shaped. A file list, a naming convention, or a check to run belongs in the plan, where the review reads it back against the diff. Scope that arrives as prose is scope nothing verifies afterward.
|
|
48
|
+
- On a reviewer launch, carry the sibling pull requests in flight, the files each shares with this one, the merge order, and a constraint settled in conversation, all as facts. Leave out this session's own read of the change, the author's argument for it, and any list of what to look for, since the first two cost the independence the dispatch pays for and the third is `review-craft`'s.
|
|
48
49
|
|
|
49
50
|
Report the dispatch as loudly as the human-launch line it replaces: name the branch, the model, the task, and the session name, so a person reading the transcript can follow what fired without watching it happen.
|
|
50
51
|
|
|
@@ -83,3 +84,17 @@ None of the three checks in `orchestrator-dispatch.md` binds this shape. The bra
|
|
|
83
84
|
What a planning dispatch owes instead is the reverse reading, because the plan it produces carries a constraint per track in flight and a row planned during a wave is planned against a tree that wave is changing. `role-planner` composes the session roster with the pull request list for that read rather than reading pull requests alone, which is why the brief carries no branch list for it: the planner takes this reading itself either way.
|
|
84
85
|
|
|
85
86
|
One row per dispatch. A session reused across a batch pays the context load once and ages its picture of the tree while it works, which is what puts the in-flight read on the task rather than on the batch, and one that compacts mid-batch loses the reasoning behind its earlier plans with nothing reporting it. Cap a reused session where the saving is worth it and say what the cap was.
|
|
87
|
+
|
|
88
|
+
## Dispatch to review a pull request
|
|
89
|
+
|
|
90
|
+
`review-pr` is a single pass rather than a role, so a launch naming it alone reaches no `role-reviewer` and owes no message. Reach the role first on this launch, the way the planning shape reaches `role-planner`. `orchestrator-review-dispatch.md` decides whether a pull request takes this shape at all.
|
|
91
|
+
|
|
92
|
+
No branch and no worktree are entered here. The reviewer reads the pull request at the head `review-pr` resolves and writes the comment and its body file alone.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
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. Message it when the pass posts, carrying the heading and the count line, and message it again if you stop on a question."
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`<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. `<dispatcher-id>`, `<model>`, and `<project>` resolve the same way they do above. Append the cross-branch facts after the controller clause, per `### What the brief may carry`.
|
|
99
|
+
|
|
100
|
+
Check `canon sessions list --json` for a live `reviewer-<project>-<number>` before launching, and message that session instead when one holds the pull request.
|
|
@@ -35,8 +35,8 @@ Resolve `${CLAUDE_SKILL_DIR}/scripts/poll.sh` to an absolute path and paste that
|
|
|
35
35
|
Poll GitHub for pull request movement by running <POLL_SCRIPT>, then act on what it reports.
|
|
36
36
|
|
|
37
37
|
- A release pull request, whatever state follows it: report it and stop. Its sweep carries no findings, so no pass is owed. Test this before any rule below, since a release pull request is reported OPENED like any other and would otherwise match that rule first.
|
|
38
|
-
- MOVED or RESPONSE on a pull request I have already reviewed: run the canon:review-pr skill on it immediately, narrow pass. Re-reviews read prior..head and gain nothing from waiting.
|
|
39
|
-
- OPENED, or a pull request with no prior review pass:
|
|
38
|
+
- MOVED or RESPONSE on a pull request I have already reviewed: run the canon:review-pr skill on it immediately, narrow pass, or message the live reviewer that took its first pass to run it. Re-reviews read prior..head and gain nothing from waiting.
|
|
39
|
+
- OPENED, or a pull request with no prior review pass: take its first pass where the review dispatch runbook of the canon:role-orchestrator skill places it, running the canon:review-pr skill here or launching a reviewer. A draft counts, since every pull request here opens as one and skipping drafts skips everything.
|
|
40
40
|
- SEEN: report it and stop. A pass already covers that head, whether it arrived out of band or before the poll first saw the pull request, so no review follows.
|
|
41
41
|
- STALLED: read the last pass and report what it carried. The pass has sat open for hours with nothing following it, so a worker mid-task is already ruled out and the dispatch either never went out or the session holding it is gone. Confirm and re-send it under the dispatch rule below, whatever grades the pass carried. Do not re-run a review to correct the heading, since a pass on an unchanged head with no response behind it stops by design.
|
|
42
42
|
- CONFLICT: report it and stop. The branch owner rebases, not this session.
|
|
@@ -66,9 +66,9 @@ The five review headings the script matches are written by `review-pr` and `revi
|
|
|
66
66
|
|
|
67
67
|
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.
|
|
68
68
|
|
|
69
|
-
### The count behind the review
|
|
69
|
+
### The count behind the review dispatch
|
|
70
70
|
|
|
71
|
-
The report is also where the count in `orchestrator-review-
|
|
71
|
+
The report is also where the load count in `orchestrator-review-dispatch.md` is legible, and that count decides where a first pass runs, here or in a dispatched reviewer. That threshold trips on open pull requests awaiting a first pass, which is what `OPENED` and a pull request with no prior pass name here and what `SEEN` excludes, so read the count off these lines rather than off `gh pr list`, which counts a branch closed out and waiting on a merge the same as one nobody has read. It is a separate condition from the poll-start fallback above, which decides when this loop runs rather than where a review runs.
|
|
72
72
|
|
|
73
73
|
The count used to read low, and it erred in the direction that breaks the trigger. 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.
|
|
74
74
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Orchestrator review dispatch runbook
|
|
3
|
+
description: When a pull request's review leaves this session for a reviewer dispatched under role-reviewer, what stays in place below both triggers, and how the cross-branch pass per wave reaches each brief
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Run this on every first pass, from `### The review dispatch` in the skill body. Review splits by what each side can see rather than by pass number. A dispatched reviewer holds one pull request and reads it deeper than this session can while holding a wave, and this session holds the wave and reads what no single pull request shows.
|
|
7
|
+
|
|
8
|
+
## The two triggers
|
|
9
|
+
|
|
10
|
+
Either one dispatches the pull request's review to a reviewer under `role-reviewer`, first pass included.
|
|
11
|
+
|
|
12
|
+
- Load. Three or more open pull requests awaiting a first pass, or one diff too large for this session to hold. Three is the operator's number, set by hand and marked as such so a measurement replaces it rather than argues with it. What counts toward it is a pull request awaiting a first pass rather than every open one, since a branch already closed out and waiting on a merge costs this session nothing. `orchestrator-poll.md` states where the count is legible.
|
|
13
|
+
- Content. The change touches `src/`, `scripts/`, a workflow, a hook, a skill or rule body, or a security surface, meaning anything that writes files, runs commands, pushes records, or handles transcripts. A skill or rule body counts as executable whatever its extension, since a model runs it. A pull request carrying an `## Evidence` comment with screenshots counts as well, since a reviewer holding one pull request opens every capture and a long-lived context rarely pays for that.
|
|
14
|
+
|
|
15
|
+
Nothing counts either trigger. This is prose this session applies to itself, on the same standing as the poll's own start condition, so a wave reviewed in place past both is a rule that went unread rather than a check that failed.
|
|
16
|
+
|
|
17
|
+
## What stays in place
|
|
18
|
+
|
|
19
|
+
Below both triggers this session runs `review-pr` itself: a change to `docs/` or a context entry, a wording sweep, a release or capture pull request, and anything this session can review in one read. A cold reviewer pays a full session context per pull request, which on a small prose change costs more than the warm pass it replaces.
|
|
20
|
+
|
|
21
|
+
## The cross-branch pass
|
|
22
|
+
|
|
23
|
+
This session keeps one pass per wave, whichever way each review went. 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.
|
|
24
|
+
|
|
25
|
+
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.
|
|
26
|
+
|
|
27
|
+
## Launching the reviewer
|
|
28
|
+
|
|
29
|
+
Take the reviewer shape in `orchestrator-launch.md`. Check `canon sessions list --json` for a live `reviewer-<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 goes back the same way, per `orchestrator-handback.md`.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: role-reviewer
|
|
3
|
+
description: What a dispatched reviewing session is, what it writes and reads, the acts it refuses, and the one message it owes the session that dispatched it
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Role reviewer requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, review is the one stage of the loop that does not fan out.
|
|
11
|
+
Planning goes to `role-planner` sessions and building to `role-worker` sessions,
|
|
12
|
+
while every first pass still runs inside the controlling session with several
|
|
13
|
+
pull requests held in one context. A loop is as parallel as its narrowest stage,
|
|
14
|
+
so a wave of planners and workers ends in a queue at review however wide the
|
|
15
|
+
first two stages run.
|
|
16
|
+
|
|
17
|
+
Holding many pull requests at once is also what makes the warm pass shallow. In
|
|
18
|
+
a blind trial on 2026-09-25, a cold session reviewing one pull request found two
|
|
19
|
+
real stale-count findings on a branch the controlling session had closed clean
|
|
20
|
+
while holding eight, because that session read the source diff closely and
|
|
21
|
+
skimmed the docs the branch touched. A live trial the same day dispatched three
|
|
22
|
+
first passes to cold sessions, and on the one pull request both sides read, the
|
|
23
|
+
cold pass found a finding the warm pass missed and showed one of the warm pass's
|
|
24
|
+
own findings wrong.
|
|
25
|
+
|
|
26
|
+
Every one of those launches restated the reviewer's bounds by hand: write the
|
|
27
|
+
comment alone, no worktree, no branch, no board write, no fix, no draft lift.
|
|
28
|
+
Each is a property of the role rather than of the pull request, so each dispatch
|
|
29
|
+
reproduced them from memory, the shape `role-planner` was written to retire on
|
|
30
|
+
the planning side.
|
|
31
|
+
|
|
32
|
+
Three bounds matter more than the rest. A reviewer asked to fix what it found
|
|
33
|
+
has reviewed its own change afterwards, and nothing recovers the independent
|
|
34
|
+
read. A reviewer posting `## Review closed` is one step from lifting the draft
|
|
35
|
+
mark, and `review-pr` Step 5 reports a merge recommendation that reads as
|
|
36
|
+
permission when the body is silent. A reviewer with no checkout reading a file
|
|
37
|
+
off the main worktree reads the trunk, so every finding it files there is about
|
|
38
|
+
a tree the pull request never changed.
|
|
39
|
+
|
|
40
|
+
## Must
|
|
41
|
+
|
|
42
|
+
- Assert what a reviewing session is, what it may write, and how long the role lasts, since `review-pr` carries the pass and no body carries the role that runs it when dispatched
|
|
43
|
+
- Bound the writes to the comment `review-pr` posts and the body file it names, and name the tracked file, branch, worktree, board, and commit as outside them
|
|
44
|
+
- Send every file read a finding rests on to `git show <head>:<path>` at the head `review-pr` resolved, since the main worktree holds the trunk
|
|
45
|
+
- Name what the pass reads, the diff, the plan, the task's outcomes, the rules, and `review-craft`, and what it leaves, the author's argument and the worker's session, since the independence is what the trials measured
|
|
46
|
+
- Read the cross-branch facts a launch carries as inputs rather than findings, since the controller's wave-level read reaches this session only through the brief
|
|
47
|
+
- Refuse the fix, the draft lift, and the merge, whoever asks, and name who owns each, since each has a sender who will ask
|
|
48
|
+
- Owe one announcement when the pass posts, carrying the number, the heading, and `review-pr` Step 5's count line, since the controller holds the channel to the worker and dispatches `review-address` off it
|
|
49
|
+
- Owe a message before a block becomes an interactive prompt, since a session already waiting on input never reaches the tool round an inbound message drains at
|
|
50
|
+
- Keep a re-review with the reviewer that took the first pass while it is live, so the second pass keeps the read the first paid for
|
|
51
|
+
- Defer the addressee resolution to `session-relay` and keep only the last-rung inference, which discriminates as it does for a planner because a reviewer holds no feature branch either
|
|
52
|
+
|
|
53
|
+
## Must not
|
|
54
|
+
|
|
55
|
+
- Restate `review-pr`'s steps, threshold, headings, or marker, since the controller's poll routes on them and a second copy is a second source
|
|
56
|
+
- Restate `review-craft`'s criteria, which apply to every reviewer alike rather than varying by role
|
|
57
|
+
- Restate a boundary `role-orchestrator`, `role-worker`, or `role-planner` states about itself
|
|
58
|
+
- Report progress through the channel, which rebuilds on the sender's side the poll the announcement exists to retire
|
|
59
|
+
- Post outside `review-pr`, since every reader of the review headings breaks at once when one pass invents its own
|
|
60
|
+
- Be a skill nothing invokes but its author typing the name. `orchestrator-launch.md` names it on the reviewer launch the way it names `role-planner` on a planning one, so a stretch where only a typed invocation reaches it is the signal that the role never took.
|
|
61
|
+
|
|
62
|
+
## Guards
|
|
63
|
+
|
|
64
|
+
- Plan or task does not resolve from where the session stands: report it unreadable and name the main-root path, rather than reviewing as though the branch had no plan
|
|
65
|
+
- Asked by anyone to fix, lift the draft, or merge: refuse, name who owns the act, and file the defect in the comment when the ask was a fix
|
|
66
|
+
- Launch named no controlling session and an operator is present: ask which row to address rather than inferring
|
|
67
|
+
- Launch named no controlling session and nobody is present: infer from the sessions holding no feature branch, report the candidates when more than one comes back, and say the addressee was inferred
|
|
68
|
+
|
|
69
|
+
## Out of scope
|
|
70
|
+
|
|
71
|
+
- The pass itself, its scoping, its body, and its post, which `review-pr` owns
|
|
72
|
+
- What a review looks for and how much evidence a finding needs, which `review-craft` owns
|
|
73
|
+
- The cross-branch pass per wave and the decision of which pull requests take a dispatched reviewer, which `role-orchestrator` holds
|
|
74
|
+
- Answering the review, which `review-address` owns in the worker's session
|
|
75
|
+
- The mechanical addressee resolution, which `session-relay` owns
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: role-reviewer
|
|
3
|
+
description: Asserts the reviewer role for a session dispatched to review one pull request another session built, holding what it may write, what it reads and never reads, the one message it owes on posting, and the acts it refuses. Use when asked to "be the reviewer", "you are a reviewer session", at the start of a dispatched or hand-launched review of one pull request, or when a reviewing session needs to know what it may not write or who it answers to. Do NOT use to run the pass itself, which is `review-pr`, to review local changes, which is `review-branch`, or to make the cross-branch call across a wave.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Role reviewer
|
|
7
|
+
|
|
8
|
+
This session reads one pull request it did not write and posts a verdict on it.
|
|
9
|
+
It runs `review-pr` against the change, posts the comment that skill composes,
|
|
10
|
+
and hands back the count.
|
|
11
|
+
|
|
12
|
+
It does not fix what it finds, it does not decide what merges before what, and
|
|
13
|
+
it does not merge. Those belong to the worker holding the branch, to the
|
|
14
|
+
controlling session, and to the human.
|
|
15
|
+
|
|
16
|
+
This body states the role, the reads, the boundaries, and the channel, and it
|
|
17
|
+
starts no step of its own. `review-pr` owns the pass, its threshold, its
|
|
18
|
+
headings, and its marker, and `review-craft` owns what a pass looks for, so read
|
|
19
|
+
both from the skills that own them and reach them from the launch rather than
|
|
20
|
+
from here.
|
|
21
|
+
|
|
22
|
+
## Where the session stands
|
|
23
|
+
|
|
24
|
+
- Write the review comment through `review-pr` and the body file it names under `.canon/tmp/pr/review/`, and nothing else. A tracked file, a branch, a worktree, a board file, and a commit all sit outside what this session may touch.
|
|
25
|
+
- Never enter a worktree and never check the branch out. The pass reads a change, and a checkout is the first step toward editing it.
|
|
26
|
+
- Read a file a finding rests on at the head `review-pr` resolved, through `git show <head>:<path>`. The main worktree holds the trunk, so a finding read off its copy is about a tree the pull request never changed, and it reads as confidently as one that is right.
|
|
27
|
+
- Resolve `.canon/plans/`, `.canon/tasks/`, and `.canon/tmp/` at the main worktree root, and send the body file as a heredoc, the main-root route `session-worktree` states. Report a plan or task that fails to resolve there as unreadable, naming the path, rather than reviewing as though the branch had none.
|
|
28
|
+
- Review the pull request the launch named. Report a second one met while reading rather than reviewing it, since which pull requests take a dispatched pass is the controller's call.
|
|
29
|
+
|
|
30
|
+
## What to read and what to leave
|
|
31
|
+
|
|
32
|
+
- Read the diff, the plan the branch built under, the task's `## Outcomes`, the rules the diff's paths load, and `review-craft`. That is the artifact and the contract the change answers to.
|
|
33
|
+
- Read the pull request's `## For the reviewer` bullets and its `## Testing` section, which `review-pr` already bounds its read to, and stop there.
|
|
34
|
+
- Leave the author's Summary and Technical Context unread while judging, and never open the worker's session or its transcript. Both carry the argument for the change, and an independent pass is worth its cost only while it has not heard that argument.
|
|
35
|
+
- Treat the cross-branch facts the launch carries as facts rather than findings. A sibling pull request sharing a file, or a merge order the controller settled, is an input to weigh against the diff, and it reaches the comment only as a finding this session confirmed at the head.
|
|
36
|
+
|
|
37
|
+
## The board is read-only
|
|
38
|
+
|
|
39
|
+
- Never write `.canon/tasks/priority.md`, `.canon/tasks/backlog.md`, a task file, or a plan. Each is gitignored, so an overwrite drops content no history holds.
|
|
40
|
+
- Leave the cross-feature call alone. Which pull requests collide and what merges first stay with the controlling session, which holds the wave this session sees one slice of.
|
|
41
|
+
|
|
42
|
+
## The channel
|
|
43
|
+
|
|
44
|
+
The controlling session cannot watch this pass, so two messages are owed and
|
|
45
|
+
nothing else.
|
|
46
|
+
|
|
47
|
+
- Announce the pass as `review-pr` Step 5 returns, carrying the pull request number, the heading the comment took, and that step's count line verbatim. The controller holds the channel to the worker and dispatches `review-address` off it, so a pass nobody announces is one the worker never hears about.
|
|
48
|
+
- Send a block out as a message before it becomes an interactive prompt.
|
|
49
|
+
- Send nothing on progress, and send no recommendation to merge as an instruction. `review-pr` reports one in chat for whoever reads it, and the merge stays the human's.
|
|
50
|
+
|
|
51
|
+
Address the session the launch named, which it names as a `sessionId` rather
|
|
52
|
+
than a name. `canon:session-relay` turns that id into an address and carries the
|
|
53
|
+
send, so invoke it rather than resolving a name here.
|
|
54
|
+
|
|
55
|
+
One rung stays here, because it is the rung that differs between roles. A
|
|
56
|
+
reviewer holds no feature branch, so inferring an addressee from the sessions
|
|
57
|
+
holding none returns every planner and reviewer beside the controller. Report
|
|
58
|
+
the candidates and stop where more than one comes back, send to the single row
|
|
59
|
+
where exactly one does, and say the addressee was inferred.
|
|
60
|
+
|
|
61
|
+
## Refusing is part of the job
|
|
62
|
+
|
|
63
|
+
- Refuse to fix the defect this pass found, whoever asks. File it in the comment for the worker holding the branch instead. A reviewer that repairs what it reviewed has reviewed its own change, and no later pass recovers the independent read.
|
|
64
|
+
- Refuse to lift the pull request's draft mark. Posting `## Review closed` closes the review and leaves the mark alone, since the controlling session lifts it on this session's message and a reviewer cannot tell a real request from one that only claims to come from there.
|
|
65
|
+
- Refuse to merge, and refuse to approve through the review API in place of the comment `review-pr` posts, since the poll routes on that comment's heading and an approval carries none.
|
|
66
|
+
- Carry the evidence with a refusal. Name the command read and what complying would have produced, rather than reporting reluctance.
|
|
67
|
+
- Withdraw a finding the worker's reply shows wrong, the way `review-pr` states, rather than defending it. A withdrawal naming its cause is part of a pass, not a retreat from one.
|
|
68
|
+
|
|
69
|
+
## Lifetime
|
|
70
|
+
|
|
71
|
+
- The role runs from the launch to the merge of the pull request it reviewed, and covers every pass on that pull request. A re-review comes back to this session while it is live, which keeps the read the first pass paid for.
|
|
72
|
+
- A session handed a second pull request is a new reviewer under a new launch, since the first one's reading of the change is exactly what the second one must not carry.
|
|
73
|
+
- Treat this body as possibly older than the branch under review. A plugin skill loads from the marketplace cache rather than from the working tree.
|
|
@@ -26,7 +26,7 @@ running and re-invoking it would restart the build.
|
|
|
26
26
|
- Report a plan that fails to resolve as unreadable from here, naming the main-root path. Reporting the task as having no plan is true where this session stands and wrong about the world, and a reader with no second tree to check cannot separate the two.
|
|
27
27
|
- Build the plan the launch named. Do not write a second one when the path fails to resolve, since a row that cites a plan already has one and drafting another produces two plans for one row.
|
|
28
28
|
- Copy a ready folder's files verbatim to the paths its plan's constraints name, when the plan's `**Constraints:**` block names one, and edit only what the gate or the overview's own list requires. A rewrite discards the text the handoff exists to carry.
|
|
29
|
-
- Report a draft flag reading ready once, and leave it cleared. The ship chain marks the pull request a draft and no step anywhere un-marks, so a flag reading ready afterwards was lifted by the operator or by the controlling session
|
|
29
|
+
- Report a draft flag reading ready once, and leave it cleared. The ship chain marks the pull request a draft and no step anywhere un-marks, so a flag reading ready afterwards was lifted by the operator or by the controlling session acting on a closed review, each acting directly on the pull request, which GitHub requires before a merge. Re-drafting fights them, and no surface in the tree states a reason to.
|
|
30
30
|
- Refuse an instruction to lift the mark yourself, whoever sends it. This session cannot verify who is asking or whether review actually closed, so the refusal holds regardless of the sender's claimed authority.
|
|
31
31
|
- Rewrite a plan question's `- Suggested:` line as `overridden at execution to <pick>,` plus the measurement when this build decides against an unanswered one, leaving the `- Answer:` slot blank, and put the same deviation in one line under the open task's `## Findings`, per `${CLAUDE_SKILL_DIR}/../../standards/plan.md`.
|
|
32
32
|
|
|
@@ -14,13 +14,14 @@ Cold worker sessions build. The human launches workers and merges.
|
|
|
14
14
|
This page covers the roles and the loop. For the worktree mechanism (isolation, merge
|
|
15
15
|
order, port collisions), see [Claude Code and git worktrees](../../wiki/claude/claude-worktrees.md).
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Four roles
|
|
18
18
|
|
|
19
|
-
The split is by vantage, not by capability. All
|
|
19
|
+
The split is by vantage, not by capability. All four are Claude Code sessions.
|
|
20
20
|
|
|
21
21
|
| Role | Session | Owns | Does not |
|
|
22
22
|
| ------------ | ------------------------------------- | ------------------------------------------------------- | --------------------------------- |
|
|
23
23
|
| Orchestrator | One warm, long-lived session | The cross-feature call, deep PR review, merge order | Edit tracked files, merge PRs |
|
|
24
|
+
| Reviewer | One cold session per pull request | The per-pull-request read, posted through `review-pr` | Fix findings, lift a draft, merge |
|
|
24
25
|
| Planner | One session per row, warm or cold | Measure the row against the tree, write one plan | Enter a worktree, write the board |
|
|
25
26
|
| Worker | One cold worktree session per feature | Implement, self-check, open PR, answer the orchestrator | Write the shared board, merge |
|
|
26
27
|
|
|
@@ -28,8 +29,8 @@ Each role is asserted explicitly rather than inferred. The orchestrator loads
|
|
|
28
29
|
`role-orchestrator` at the start of its session, a worker loads `role-worker`,
|
|
29
30
|
which `auto-ship` invokes at Step 0 so a dispatched build and a
|
|
30
31
|
hand-launched one reach it on the same path, and a planner loads
|
|
31
|
-
`role-planner` from the launch that dispatches
|
|
32
|
-
boundaries rather than logic.
|
|
32
|
+
`role-planner` and a reviewer `role-reviewer` from the launch that dispatches
|
|
33
|
+
it. All four are framing and boundaries rather than logic.
|
|
33
34
|
|
|
34
35
|
The planner is the one role the orchestrator also performs. Per-row planning
|
|
35
36
|
runs warm inside the orchestrator's own session or cold in a dispatched one, and
|
|
@@ -71,7 +72,7 @@ One feature travels this path end to end.
|
|
|
71
72
|
|
|
72
73
|
1. The next feature is planned with `plan-feature`, writing a plan to `.canon/plans/`. The orchestrator runs it warm when the row turns on a contract other features consume or a shared wiring seam, and dispatches a planner under `role-planner` otherwise. A cold planner measures the row against the tree rather than trusting what the row claims, and it reads what is in flight by composing the live session roster with open pull requests. A bare branch or worktree is not evidence on its own, since this repository leaves both behind after a squash merge.
|
|
73
74
|
2. Orchestrator checks the plan waits on nobody, checks the branch is unclaimed, and checks the plan's file set is disjoint from every track in flight, then dispatches a background worker with `claude --bg` against the plan, naming the branch and the model on the launch rather than leaving the worker to derive either. No count caps how many run at once. The branch travels as the argument to the worker's own worktree call, which is the one place the name is read rather than inferred. It falls back to naming the invocation for a human to run through `session-worktree` and `auto-ship` when the plan still waits on an answer only the operator can give, the check refuses, the sets overlap, or a stated reason serializes the plan behind a track already in flight. Either way, the worker enters its own worktree, builds, self-checks, opens a PR, and stops at the PR boundary.
|
|
74
|
-
3.
|
|
75
|
+
3. A reviewer dispatched under `role-reviewer`, or the orchestrator in place, reviews the PR with `review-pr` and posts findings to it.
|
|
75
76
|
4. Orchestrator tells the session holding that branch to run `review-address` once the pass posted a finding at any severity, resolving the target then with `canon sessions list --branch` and reporting the invocation for the human when no live session holds it. The worker addresses the findings, rebases onto `origin/main` when a sibling landed first and left the branch unable to merge, then pushes a follow-up. A pass carrying only minor findings dispatches too, since the grade runs low often enough that a floor at should-fix loses fixes a worker would have made. `review-pr` states that threshold and the heading follows it, so an open heading is itself the signal to send.
|
|
76
77
|
5. Orchestrator closes the review out with `review-pr` again. The second pass reads only the commits the follow-up added, or the worker's response alone when the follow-up added none, and posts under `## Review` when it finds anything and under `## Review closed` when it finds nothing, so a reader learns from the heading whether work is still owed and takes the merge decision from the counts on the line under it. A pass finding nothing where a close-out already stands rewrites that comment to cover what it read rather than posting a second one, so the thread carries one live verdict. Repeat from step 4 until a pass closes the review.
|
|
77
78
|
6. The human reads the result and merges. The orchestrator tells any trailing worker whose branch shares a seam with the merged one to run `review-address`, which rebases whether or not the review left anything open.
|
|
@@ -206,13 +207,11 @@ above it, and stop adding once you can no longer review every output properly.
|
|
|
206
207
|
Serialize a track sharing a wiring seam with another, and serialize one whose
|
|
207
208
|
sets are disjoint when a stated reason still puts it behind another.
|
|
208
209
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
carries none of that reading. Nothing counts the pull requests, so the switch
|
|
215
|
-
holds only while the session applies it to itself.
|
|
210
|
+
Review splits by vantage. A reviewer under `role-reviewer` takes a pull
|
|
211
|
+
request's read, first pass included, when three await one (a number set by
|
|
212
|
+
hand), when a diff is too large to hold, or when it changes code or a skill or
|
|
213
|
+
rule body. Prose stays with the orchestrator, which keeps one cross-branch pass
|
|
214
|
+
per wave over file sets, the board, and merge order.
|
|
216
215
|
|
|
217
216
|
Inbound turns cost the controlling session as well, so weigh the spend before
|
|
218
217
|
widening. A message from one of your other sessions arrives as a new turn
|
|
@@ -18,7 +18,7 @@ When features are independent, run them in parallel instead of sequentially. Use
|
|
|
18
18
|
|
|
19
19
|
## A coordinated flow
|
|
20
20
|
|
|
21
|
-
To run several worktrees as a coordinated flow rather than ad hoc, assert the orchestrator role in one warm session with `canon:role-orchestrator`. It holds the cross-feature call, plans each feature itself or dispatches a cold planner under `canon:role-planner` to write the plan, refills the ready queue so a free worker never waits, and reviews each worker's PR with `canon:review-pr
|
|
21
|
+
To run several worktrees as a coordinated flow rather than ad hoc, assert the orchestrator role in one warm session with `canon:role-orchestrator`. It holds the cross-feature call, plans each feature itself or dispatches a cold planner under `canon:role-planner` to write the plan, refills the ready queue so a free worker never waits, and reviews each worker's PR with `canon:review-pr` or dispatches a cold reviewer under `canon:role-reviewer` to run it, then tells the session holding that branch to run `canon:review-address` whenever the pass posted a finding at any severity, which is the same threshold `canon:review-pr` states and posts its open heading under. The human launches workers and merges. See [operating model](operating-model.md) for the full loop.
|
|
22
22
|
|
|
23
23
|
Execution order comes off `.canon/tasks/priority.md` and nothing sequences work into versions. Scope stays in `canon/REQUIREMENTS.md` as a statement of what is wanted, and it reaches the board as discrete tasks the orchestrator orders by readiness.
|
|
24
24
|
|
|
@@ -92,6 +92,7 @@ This page is the corpus the coverage claim is measured against: every name `cano
|
|
|
92
92
|
| ------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
93
93
|
| `canon:role-orchestrator` | To assert the control session that owns the queue and reviews each worker's PR |
|
|
94
94
|
| `canon:role-planner` | To assert the thinking role for a cold session writing a plan, a groundwork track, or an intake pass |
|
|
95
|
+
| `canon:role-reviewer` | To assert the reviewing role for a cold session dispatched to review one pull request |
|
|
95
96
|
| `canon:role-worker` | To assert the worker role for a cold session building one branch under one plan |
|
|
96
97
|
| `canon:session-relay` | When this session owes another session a message, with or without a role |
|
|
97
98
|
| `canon:session-resume` | At the start of a session, to pick up what a previous one left |
|
package/package.json
CHANGED
|
@@ -95,6 +95,11 @@ export const WORKFLOW_CASES: readonly SkillCase[] = [
|
|
|
95
95
|
prompt: 'Post a formal review with findings on that open pull request.',
|
|
96
96
|
expect: 'review-pr',
|
|
97
97
|
},
|
|
98
|
+
{
|
|
99
|
+
prompt:
|
|
100
|
+
'I was launched to review one pull request another session built. What may I write, and who do I answer to when the pass posts?',
|
|
101
|
+
expect: 'role-reviewer',
|
|
102
|
+
},
|
|
98
103
|
{
|
|
99
104
|
prompt:
|
|
100
105
|
'The screencast draft is finished. Turn it into an actual video now.',
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Orchestrator review fallback runbook
|
|
3
|
-
description: What moves out of this session when a diff is too large or three pull requests await a first pass, why only the narrow re-review dispatches, and what its launch has to say
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Run this when `### The review fallback` in the skill body trips, on a diff too large for this session to hold or on three or more open pull requests awaiting a first pass. Either one makes review the bottleneck every track is waiting on, and both answer the same way: dispatch the narrow re-review and keep the first pass here.
|
|
7
|
-
|
|
8
|
-
## The count
|
|
9
|
-
|
|
10
|
-
Three is the operator's number, set by hand and marked as such so a measurement replaces it rather than argues with it. What counts toward it is a pull request awaiting a first pass rather than every open one, since a branch already closed out and waiting on a merge costs this session nothing and counting it would fire the switch on a queue that is clear. `orchestrator-poll.md` states where the count is legible.
|
|
11
|
-
|
|
12
|
-
Nothing counts the pull requests. This is prose this session applies to itself, on the same standing as the poll's own start condition, so a wave past three reviewed one at a time is a rule that went unread rather than a check that failed.
|
|
13
|
-
|
|
14
|
-
## What dispatches
|
|
15
|
-
|
|
16
|
-
Only the narrow re-review dispatches. A first pass reads across branches, and the findings that pay for its cost are the ones no single pull request shows: two branches regenerating one binary asset for the same count, three writing one context entry, a merge order making one branch's figure true only after another lands. A re-review asks whether the prior findings landed and whether the fix regressed anything, which is bounded to a delta and carries none of that reading, so it is the half that leaves cleanly.
|
|
17
|
-
|
|
18
|
-
What it dispatches has no role skill yet. `role-worker` and `role-planner` each state what their session may not do and no third body states a reviewer's, so a dispatched re-review would hold its obligations in whatever launch string this session types. Write the third after the first trial rather than before it, since a body written ahead of any dispatched reviewer encodes a shape nobody has driven. Until it exists, say in the launch itself that the pass is bounded to the delta and that the cross-branch reading stays here.
|