@erclx/canon 5.5.0 → 5.7.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/codebase-layout/REQUIREMENT.md +3 -0
- package/claude/skills/codebase-layout/SKILL.md +28 -0
- package/claude/skills/codebase-layout/references/adopted.md +6 -0
- package/claude/skills/plan-feature/REQUIREMENT.md +4 -0
- package/claude/skills/plan-feature/SKILL.md +4 -0
- package/claude/skills/review-craft/references/ui.md +2 -0
- package/claude/skills/review-pr/SKILL.md +2 -2
- package/claude/skills/review-ui/REQUIREMENT.md +54 -0
- package/claude/skills/review-ui/SKILL.md +108 -0
- package/claude/skills/review-ui/references/driving.md +50 -0
- package/claude/skills/review-ui/references/post.md +60 -0
- package/claude/skills/review-ui/scripts/pw.sh +60 -0
- package/claude/skills/role-orchestrator/SKILL.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +15 -1
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +6 -3
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +10 -4
- package/claude/skills/role-orchestrator/scripts/poll.sh +72 -10
- package/claude/skills/role-reviewer/REQUIREMENT.md +2 -2
- package/claude/skills/role-reviewer/SKILL.md +8 -5
- package/claude/skills/teach-workspace/REQUIREMENT.md +3 -0
- package/claude/skills/teach-workspace/SKILL.md +2 -1
- package/claude/skills/teach-workspace/references/lesson-craft.md +8 -1
- package/claude/skills/test-craft/REQUIREMENT.md +4 -1
- package/claude/skills/test-craft/SKILL.md +20 -2
- package/claude/skills/test-craft/references/adopted.md +3 -1
- package/claude/skills/ui-checklist/REQUIREMENT.md +1 -0
- package/claude/skills/ui-checklist/SKILL.md +11 -1
- package/docs/agents/index.md +1 -1
- package/docs/agents/skills-audit.md +6 -3
- package/docs/workflow/operating-model.md +1 -1
- package/docs/workflow/skill-map.md +9 -8
- package/package.json +1 -1
- package/src/claude/cases/workflow.ts +5 -0
- package/src/claude/skills-audit.ts +81 -1
- package/src/commands/claude.ts +33 -0
- package/src/gate/measures.ts +43 -1
- package/src/gate/stages.ts +9 -0
- package/standards/index.md +1 -0
- package/standards/skill-practice.md +51 -0
- package/standards/skill.md +3 -1
- package/tooling/web/seeds/.cspell/tech-stack.txt +1 -0
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
---
|
|
2
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
|
|
3
|
+
description: When a pull request's review leaves this session for a reviewer dispatched under role-reviewer, when a UI reviewer goes beside it, what stays in place below both code triggers, and how the cross-branch pass per wave reaches each brief
|
|
4
4
|
---
|
|
5
5
|
|
|
6
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
7
|
|
|
8
|
-
## The two triggers
|
|
8
|
+
## The two code triggers
|
|
9
9
|
|
|
10
10
|
Either one dispatches the pull request's review to a reviewer under `role-reviewer`, first pass included.
|
|
11
11
|
|
|
12
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
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
14
|
|
|
15
|
-
|
|
15
|
+
## The UI trigger
|
|
16
|
+
|
|
17
|
+
A third trigger sends a second reviewer rather than moving the first. A pull request whose evidence record carries a checklist takes a UI reviewer under `review-ui`, dispatched beside the code review whichever way the two triggers above decide it, 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.
|
|
18
|
+
|
|
19
|
+
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 the draft mark waits on both, per the draft-lift boundary in the skill body.
|
|
20
|
+
|
|
21
|
+
Nothing counts any of the three triggers. 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
22
|
|
|
17
23
|
## What stays in place
|
|
18
24
|
|
|
@@ -26,4 +32,4 @@ Hand what it finds to each reviewer as facts in the brief, per `### What the bri
|
|
|
26
32
|
|
|
27
33
|
## Launching the reviewer
|
|
28
34
|
|
|
29
|
-
Take the reviewer shape in `orchestrator-launch.md
|
|
35
|
+
Take the reviewer shape in `orchestrator-launch.md`, or its UI reviewer shape for the UI trigger. 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 goes back the same way, per `orchestrator-handback.md`.
|
|
@@ -32,17 +32,17 @@ if [ -z "$BASE_REF" ]; then
|
|
|
32
32
|
fi
|
|
33
33
|
BASE_BRANCH="${BASE_REF#origin/}"
|
|
34
34
|
|
|
35
|
-
# These
|
|
36
|
-
# writes `## Review` and `## Review closed`, and states the full
|
|
35
|
+
# These eight strings are owned elsewhere and pinned here. `review-pr`
|
|
36
|
+
# writes `## Review` and `## Review closed`, and states the full eight-heading
|
|
37
37
|
# set once, beside the threshold it already states once. `review-address`
|
|
38
38
|
# writes `## Review response`, `## Rebase`, and `## Post-review findings`, the
|
|
39
39
|
# last for a finding a worker produces after a close-out rather than in answer
|
|
40
40
|
# to one already on the thread. `canon pr evidence`, run through `git-pr` and
|
|
41
|
-
# `git-followup`, writes `## Evidence`.
|
|
42
|
-
#
|
|
43
|
-
# across.
|
|
41
|
+
# `git-followup`, writes `## Evidence`. `review-ui` writes `## UI review` and
|
|
42
|
+
# `## UI review closed`. All these surfaces ship separately, so a heading added
|
|
43
|
+
# in any of them breaks a test here that no check reaches across.
|
|
44
44
|
#
|
|
45
|
-
# All
|
|
45
|
+
# All four families match on the first line alone so the tests stay
|
|
46
46
|
# symmetric. The reply family carries `## Rebase` and `## Post-review
|
|
47
47
|
# findings` beside `## Review response` because neither answers a comment
|
|
48
48
|
# already on the thread, which is why both were kept outside the `## Review`
|
|
@@ -167,6 +167,28 @@ JQ_SCOPE_FALLBACK='
|
|
|
167
167
|
end
|
|
168
168
|
'
|
|
169
169
|
|
|
170
|
+
# The UI family is posted as a pull request review the way the code family is,
|
|
171
|
+
# so it is read off `.reviews` rather than `.comments`. No verb parses it, so
|
|
172
|
+
# the filter here is its only reader. The newest UI heading decides the state,
|
|
173
|
+
# and the head it covered comes from the `review-ui` marker on the body's last
|
|
174
|
+
# line, since the submission stamp moves onto a commit pushed while the pass
|
|
175
|
+
# drove. A body carrying no marker falls back to that stamp.
|
|
176
|
+
JQ_UI_STATE='
|
|
177
|
+
[ .reviews[]
|
|
178
|
+
| select((.body // "") | split("\n")[0] | rtrimstr("\r")
|
|
179
|
+
| . == "## UI review" or . == "## UI review closed")
|
|
180
|
+
] | last
|
|
181
|
+
| if . == null then "none none"
|
|
182
|
+
else (.body | split("\n")[0] | rtrimstr("\r")
|
|
183
|
+
| if . == "## UI review" then "open" else "closed" end) as $state
|
|
184
|
+
| ([ .body | split("\n")[] | rtrimstr("\r") | select(. != "") ]
|
|
185
|
+
| last // ""
|
|
186
|
+
| (capture("^<!-- review-ui: head=(?<sha>[0-9a-f]{7,40}) -->$").sha)
|
|
187
|
+
// null) as $marked
|
|
188
|
+
| $state + " " + ($marked // .commit.oid // "none")
|
|
189
|
+
end
|
|
190
|
+
'
|
|
191
|
+
|
|
170
192
|
# An open pass this old has nobody on it. The cycle it has to clear is a review
|
|
171
193
|
# landing and a worker pushing a follow-up, measured between ten and thirty
|
|
172
194
|
# minutes across a day of runs on 2026-08-14, so two hours sits about four times
|
|
@@ -278,6 +300,19 @@ snapshot() {
|
|
|
278
300
|
unmatched_count=${unmatched_state%% *}
|
|
279
301
|
unmatched_heading=${unmatched_state#* }
|
|
280
302
|
|
|
303
|
+
# One token, so the heading above stays the line's last field and keeps its
|
|
304
|
+
# spaces. A marker may name a short sha, so coverage is a prefix match.
|
|
305
|
+
ui_read=$(jq -r "$JQ_UI_STATE" <<<"$payload")
|
|
306
|
+
ui_heading=${ui_read%% *}
|
|
307
|
+
ui_commit=${ui_read#* }
|
|
308
|
+
if [ "$ui_heading" = none ]; then
|
|
309
|
+
ui_state=none
|
|
310
|
+
elif [ "$ui_commit" != none ] && [[ "$head" == "$ui_commit"* ]]; then
|
|
311
|
+
ui_state="$ui_heading-head-${ui_commit:0:7}"
|
|
312
|
+
else
|
|
313
|
+
ui_state="$ui_heading-behind-${ui_commit:0:7}"
|
|
314
|
+
fi
|
|
315
|
+
|
|
281
316
|
# `gh pr view --json mergeable` reports UNKNOWN until GitHub finishes
|
|
282
317
|
# computing it, which is exactly when a poll asks. merge-tree answers
|
|
283
318
|
# locally against the base this machine has, so it never returns UNKNOWN.
|
|
@@ -295,7 +330,7 @@ snapshot() {
|
|
|
295
330
|
merges=conflict
|
|
296
331
|
fi
|
|
297
332
|
|
|
298
|
-
echo "$n $head ${prior:-none} $resp $merges $review_state $reply_at $unmatched_count $unmatched_heading"
|
|
333
|
+
echo "$n $head ${prior:-none} $resp $merges $review_state $reply_at $unmatched_count $ui_state $unmatched_heading"
|
|
299
334
|
done
|
|
300
335
|
}
|
|
301
336
|
|
|
@@ -312,7 +347,7 @@ CHANGED=0
|
|
|
312
347
|
# would fire on every later run and the board would never read "No movement."
|
|
313
348
|
FINAL=""
|
|
314
349
|
|
|
315
|
-
while read -r n head prior resp merges heading age pass_at reply_at unmatched_count unmatched_heading; do
|
|
350
|
+
while read -r n head prior resp merges heading age pass_at reply_at unmatched_count ui unmatched_heading; do
|
|
316
351
|
[ -z "$n" ] && continue
|
|
317
352
|
state=$heading
|
|
318
353
|
old=$(grep "^$n " "$STATE" || true)
|
|
@@ -330,7 +365,7 @@ while read -r n head prior resp merges heading age pass_at reply_at unmatched_co
|
|
|
330
365
|
echo "OPENED #$n at ${head:0:7}, $merges against $BASE_BRANCH"
|
|
331
366
|
fi
|
|
332
367
|
CHANGED=1
|
|
333
|
-
FINAL+="$n $head $prior $resp $merges $state $unmatched_count"$'\n'
|
|
368
|
+
FINAL+="$n $head $prior $resp $merges $state $unmatched_count $ui"$'\n'
|
|
334
369
|
continue
|
|
335
370
|
fi
|
|
336
371
|
old_head=$(echo "$old" | cut -d' ' -f2)
|
|
@@ -342,6 +377,9 @@ while read -r n head prior resp merges heading age pass_at reply_at unmatched_co
|
|
|
342
377
|
# classifies a thread already past the threshold rather than waiting a run.
|
|
343
378
|
old_heading=$(echo "$old" | cut -d' ' -f6)
|
|
344
379
|
old_unmatched=$(echo "$old" | cut -d' ' -f7)
|
|
380
|
+
# Written from the first run that read a UI pass, so an older baseline yields
|
|
381
|
+
# empty and the first UI state this script sees is reported as new.
|
|
382
|
+
old_ui=$(echo "$old" | cut -d' ' -f8)
|
|
345
383
|
|
|
346
384
|
# A conflict arrives from the base moving, not from the branch, so it is
|
|
347
385
|
# reported on the transition rather than only when the head changes.
|
|
@@ -363,6 +401,30 @@ while read -r n head prior resp merges heading age pass_at reply_at unmatched_co
|
|
|
363
401
|
CHANGED=1
|
|
364
402
|
fi
|
|
365
403
|
|
|
404
|
+
# The UI pass reports on its transition, the way CONFLICT does, since its
|
|
405
|
+
# state moves on a post or on a push and either one is the moment it is owed
|
|
406
|
+
# an action. A carried line supplies no state, so nothing fires on it. A
|
|
407
|
+
# verdict a push left behind reports separately from MOVED above, since it
|
|
408
|
+
# owes a fresh UI pass rather than a code re-review. The state carries the
|
|
409
|
+
# covered commit, so a second UI pass at a new head reads as a transition even
|
|
410
|
+
# when its heading repeats.
|
|
411
|
+
if [ -n "$ui" ] && [ "$ui" != none ] && [ "$ui" != "$old_ui" ]; then
|
|
412
|
+
ui_heading=${ui%%-*}
|
|
413
|
+
ui_commit=${ui##*-}
|
|
414
|
+
case "$ui" in
|
|
415
|
+
open-head-*)
|
|
416
|
+
echo "UI-OPEN #$n open at $ui_commit"
|
|
417
|
+
;;
|
|
418
|
+
closed-head-*)
|
|
419
|
+
echo "UI-CLOSED #$n closed at $ui_commit"
|
|
420
|
+
;;
|
|
421
|
+
*)
|
|
422
|
+
echo "UI-STALE #$n $ui_heading at $ui_commit, behind ${head:0:7}"
|
|
423
|
+
;;
|
|
424
|
+
esac
|
|
425
|
+
CHANGED=1
|
|
426
|
+
fi
|
|
427
|
+
|
|
366
428
|
if [ "$head" != "$old_head" ]; then
|
|
367
429
|
if [ "$prior" = "none" ]; then
|
|
368
430
|
echo "MOVED #$n -> ${head:0:7}, never reviewed"
|
|
@@ -427,7 +489,7 @@ while read -r n head prior resp merges heading age pass_at reply_at unmatched_co
|
|
|
427
489
|
# re-enters next run and STALLED oscillates instead of reporting once.
|
|
428
490
|
state=reported
|
|
429
491
|
fi
|
|
430
|
-
FINAL+="$n $head $prior $resp $merges $state $unmatched_count"$'\n'
|
|
492
|
+
FINAL+="$n $head $prior $resp $merges $state $unmatched_count ${ui:-$old_ui}"$'\n'
|
|
431
493
|
done <<<"$NEW"
|
|
432
494
|
|
|
433
495
|
while read -r n _rest; do
|
|
@@ -40,7 +40,7 @@ a tree the pull request never changed.
|
|
|
40
40
|
## Must
|
|
41
41
|
|
|
42
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
|
|
43
|
+
- Bound the writes to the comment `review-pr` posts and the body file it names, or for a UI reviewer to what `review-ui` posts and drives from, and name the tracked file, branch, worktree, board, and commit as outside them
|
|
44
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
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
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
|
|
@@ -56,7 +56,7 @@ a tree the pull request never changed.
|
|
|
56
56
|
- Restate `review-craft`'s criteria, which apply to every reviewer alike rather than varying by role
|
|
57
57
|
- Restate a boundary `role-orchestrator`, `role-worker`, or `role-planner` states about itself
|
|
58
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
|
|
59
|
+
- Post outside `review-pr` and `review-ui`, since every reader of the review headings breaks at once when one pass invents its own
|
|
60
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
61
|
|
|
62
62
|
## Guards
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
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
|
|
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` for the code and `review-ui` for the running app, to review local changes, which is `review-branch`, or to make the cross-branch call across a wave.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Role reviewer
|
|
7
7
|
|
|
8
8
|
This session reads one pull request it did not write and posts a verdict on it.
|
|
9
9
|
It runs `review-pr` against the change, posts the comment that skill composes,
|
|
10
|
-
and hands back the count.
|
|
10
|
+
and hands back the count. Launched as a UI reviewer, it runs `review-ui` instead,
|
|
11
|
+
which drives the pull request's checklist in the running app and posts its own
|
|
12
|
+
comment.
|
|
11
13
|
|
|
12
14
|
It does not fix what it finds, it does not decide what merges before what, and
|
|
13
15
|
it does not merge. Those belong to the worker holding the branch, to the
|
|
@@ -21,7 +23,7 @@ from here.
|
|
|
21
23
|
|
|
22
24
|
## Where the session stands
|
|
23
25
|
|
|
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.
|
|
26
|
+
- Write the review comment through `review-pr` and the body file it names under `.canon/tmp/pr/review/`, and nothing else. A UI reviewer writes the comment `review-ui` posts, its body file, and the browser's snapshots and frames, all under `.canon/tmp/pr/review-ui/`. A tracked file, a branch, a worktree, a board file, and a commit all sit outside what this session may touch.
|
|
25
27
|
- 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
28
|
- 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
29
|
- 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.
|
|
@@ -32,6 +34,7 @@ from here.
|
|
|
32
34
|
- 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
35
|
- 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
36
|
- 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.
|
|
37
|
+
- Read none of the above as a UI reviewer. `review-ui` states its own reads, being the checklist and the address, and a UI pass that has read the diff drives towards what it expects the code to do.
|
|
35
38
|
- 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
39
|
|
|
37
40
|
## The board is read-only
|
|
@@ -44,7 +47,7 @@ from here.
|
|
|
44
47
|
The controlling session cannot watch this pass, so two messages are owed and
|
|
45
48
|
nothing else.
|
|
46
49
|
|
|
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.
|
|
50
|
+
- Announce the pass as `review-pr` Step 5 returns, or as `review-ui` reports its count line, 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
51
|
- Send a block out as a message before it becomes an interactive prompt.
|
|
49
52
|
- 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
53
|
|
|
@@ -61,7 +64,7 @@ where exactly one does, and say the addressee was inferred.
|
|
|
61
64
|
## Refusing is part of the job
|
|
62
65
|
|
|
63
66
|
- 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
|
|
67
|
+
- Refuse to lift the pull request's draft mark. Posting `## Review closed` or `## UI review closed` closes that 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
68
|
- 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
69
|
- Carry the evidence with a refusal. Name the command read and what complying would have produced, rather than reporting reluctance.
|
|
67
70
|
- 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.
|
|
@@ -13,6 +13,8 @@ It picks the next topic from the subject's own order rather than from what the l
|
|
|
13
13
|
|
|
14
14
|
It also produces one output where two are needed. A page written to be worked through once and a page written to be looked up later have different lifetimes and different readers, and merging them yields material that is disposable and gets kept, or durable and carries a quiz nobody can promote. Writing the durable half in a format the authoring gates do not read costs a conversion at the moment it matters most, which is the moment someone tries to promote it.
|
|
15
15
|
|
|
16
|
+
A lesson on a structure can also point at one and draw none. Nothing asks the author whether the subject is a relationship, boundary, path, or before-and-after, so a lesson on layers and ports tells the learner to draw arrows and ships none, and nothing records whether prose was a choice or an omission.
|
|
17
|
+
|
|
16
18
|
A session that does record something records the wrong thing. It writes what was taught rather than what the learner retrieved, and a tally of errors carries none of the misconception a later session would work against.
|
|
17
19
|
|
|
18
20
|
The lesson then reaches nobody. It is a page carrying a stylesheet and a script, and the only thing a session hands over is a file path, which an editor preview opens with neither. The learner reads unstyled markup and takes it for the lesson, or opens nothing at all, and either way the session reports the lesson as delivered. A path is also the wrong unit once a workspace holds several pages, since the learner wants the one they are on rather than the folder it sits in.
|
|
@@ -31,6 +33,7 @@ Two failures land specifically on where the folder sits. A workspace resolved ag
|
|
|
31
33
|
- Place each lesson from the learning records rather than from the subject's order, and open with retrieval on the last wrong answer
|
|
32
34
|
- Split the output by lifetime, sending the worked-through half to lessons and the looked-up half to reference pages in the format the authoring gates read
|
|
33
35
|
- Record the wrong answer itself rather than the count, since that is what the next session places the learner from
|
|
36
|
+
- Decide each lesson's figure before writing its body, drawing it or recording in the reply the one-line reason prose carries it, so a structure lesson never ships with neither
|
|
34
37
|
- Report progress against the mission's success lines, so a mission can be called finished
|
|
35
38
|
- Hand the learner a link that opens the workspace in a real browser on every run, reading it back from the verb that served it rather than composing one, since the port a preview lands on is not the port it asked for
|
|
36
39
|
- Propose a destination for each durable page by who owns its subject, and wait for the operator rather than routing on the session's own reading
|
|
@@ -105,7 +105,7 @@ Write the correct option first, then present the options in the order `order` re
|
|
|
105
105
|
|
|
106
106
|
### The quiz, the teach-back block, and the lesson body
|
|
107
107
|
|
|
108
|
-
Read `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` before writing the lesson. `## Quiz construction` and `## Teach back` there fix the markup `canon teach nav`'s stepper gates on, so a quiz in any other shape shows every question at once and nothing reports it. `## Building the lesson body` carries the four marker pairs, the render, nav, stylesheet, and glossary verbs, and the rule against composing any of them by hand when a verb does not resolve. Keep every quiz answer the same length, so formatting leaks no clue about which one is correct.
|
|
108
|
+
Read `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` before writing the lesson. `## Quiz construction` and `## Teach back` there fix the markup `canon teach nav`'s stepper gates on, so a quiz in any other shape shows every question at once and nothing reports it. `## Building the lesson body` carries the four marker pairs, the render, nav, stylesheet, and glossary verbs, and the rule against composing any of them by hand when a verb does not resolve. Keep every quiz answer the same length, so formatting leaks no clue about which one is correct. Decide the figure first, by `## Diagrams` there.
|
|
109
109
|
|
|
110
110
|
### Hand over a link, never a path
|
|
111
111
|
|
|
@@ -158,6 +158,7 @@ Read `${CLAUDE_SKILL_DIR}/references/promotion.md` first. It carries what may be
|
|
|
158
158
|
Lesson: .canon/teach/<nn>-<topic>/lessons/<nnnn>-<slug>.html
|
|
159
159
|
Reference: .canon/teach/<nn>-<topic>/reference/<slug>.md
|
|
160
160
|
Record: .canon/teach/<nn>-<topic>/learning-records/<nnnn>-<slug>.md
|
|
161
|
+
Figure: <drawn through draft-figure, or the one-line reason prose carries it>
|
|
161
162
|
Progress: <n> of <m> success lines met
|
|
162
163
|
Open: [<the url the serve verb reported>](<the same url>)
|
|
163
164
|
```
|
|
@@ -36,7 +36,14 @@ Every element competes with the material for attention.
|
|
|
36
36
|
|
|
37
37
|
## Diagrams
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
Decide the figure once per lesson, before writing the body.
|
|
40
|
+
|
|
41
|
+
1. Name the one relationship, boundary, path, or before-and-after the lesson is about. A lesson about none ends here, with `Figure: none, <why it names no structure>` on the reply.
|
|
42
|
+
2. Hold it against the bar in `${CLAUDE_SKILL_DIR}/../../standards/figures.md`, which also carries the drawing rules.
|
|
43
|
+
3. Draw it through `canon:draft-figure` into a `raw` block in the body, before the quiz entry and never inside it or after its feedback, which breaks the stepper's gating. Report it, never hand-draw, when that skill does not resolve.
|
|
44
|
+
4. Or write one line on why prose carries it better, such as a structure an earlier lesson gave.
|
|
45
|
+
|
|
46
|
+
A structure lesson takes step 3 or 4, never neither. Put the outcome on the reply's `Figure:` line, off the lesson page. Never draw to satisfy the step, or on every section (`## Restraint`).
|
|
40
47
|
|
|
41
48
|
## Quiz construction
|
|
42
49
|
|
|
@@ -13,6 +13,8 @@ The one surface that did pick a layer picked the expensive one. The UI test skil
|
|
|
13
13
|
|
|
14
14
|
The failure is measured on a real target. A single-page portfolio site carried 219 end to end tests against 4 unit test files, an inverted pyramid. Its suite could not raise its worker count without failing between 11 and 24 tests on every retry, because timing-sensitive assertions sat at the layer where CI load decides the result. One copy edit failed three engines because the copy was asserted in a browser run.
|
|
15
15
|
|
|
16
|
+
A stated rule is also one a session can talk itself out of. Each test in that suite sat where it did for a reason that sounded fine at the time, such as the end to end spec already being open or a pause quieting a run that flaked under load, and nothing in front of the session answered the reason.
|
|
17
|
+
|
|
16
18
|
Moving the guidance into a path-scoped rule does not reach the session that needs it. A path-scoped rule loads when a session reads a matching file and not when it creates one, measured in three headless runs, so a rule scoped to test files is silent on the first test of every feature.
|
|
17
19
|
|
|
18
20
|
## Must
|
|
@@ -25,6 +27,7 @@ Moving the guidance into a path-scoped rule does not reach the session that need
|
|
|
25
27
|
- Promise a middle layer for behavior a simulated DOM cannot render, naming the real-browser component runners, so a static site is not left choosing between a simulated DOM that computes no layout and a whole-site run
|
|
26
28
|
- Repeat in the end to end reference the two floors a session writing its first spec never loads through the path-scoped rule, being the `scrollend` settle and motion reduced by default
|
|
27
29
|
- Record the external patterns adopted and declined with the reason for each, so a later session extends the position instead of re-deriving it
|
|
30
|
+
- Close with a table of the excuses a session gives for the wrong layer or a weak test, each with its rebuttal, and the red flags a session can see mid-work, so the reasons that produced the inverted pyramid meet an answer before the test lands
|
|
28
31
|
- Trigger on writing or changing any test, after implementing as well as before, since regression tests and end to end tests are mostly written after the code exists
|
|
29
32
|
|
|
30
33
|
## Must not
|
|
@@ -34,7 +37,7 @@ Moving the guidance into a path-scoped rule does not reach the session that need
|
|
|
34
37
|
- Restate the structure floors the testing rule already carries, such as arrange, act, assert, one behavior per test, isolation, and no snapshots
|
|
35
38
|
- Restate the settle, guard, and run-scope rules the end to end rules carry, beyond the two floors named above
|
|
36
39
|
- Run the red, green, refactor procedure or decide its order, which `test-first` owns
|
|
37
|
-
- Import an external skill's tone, such as a law stated as absolute or
|
|
40
|
+
- Import an external skill's tone, such as a law stated as absolute, or an excuse row rebutting an objection no session has raised
|
|
38
41
|
- Be reached only by an author typing its name. The intended non-author callers are `test-first`'s first step and a description matching any request to write or change a test. A test written in a session that never loaded this skill is the evidence the trigger is too weak, and nothing answers that before the skill has run.
|
|
39
42
|
|
|
40
43
|
## Guards
|
|
@@ -57,9 +57,27 @@ Read the one reference matching the layer the table picked, before writing the f
|
|
|
57
57
|
|
|
58
58
|
Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidance or arguing against a rule in it. It records which external patterns were adopted, which declined, and why.
|
|
59
59
|
|
|
60
|
-
##
|
|
60
|
+
## Excuses and rebuttals
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
| Excuse | Rebuttal |
|
|
63
|
+
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
64
|
+
| The end to end spec is already open, so add the case there | An open file is not a layer. Read the row off the behavior, and a loading, empty, or error state is a component. |
|
|
65
|
+
| The test is small, so its layer does not matter | A small test at the wrong layer is run by every later pass, and moving it costs a second test. |
|
|
66
|
+
| The copy is what the user sees, so assert it in a browser | Copy asserted in a browser run fails every engine on one wording change. Assert copy at unit. |
|
|
67
|
+
| It only flakes under CI load, so add a pause | A pause hides the condition the run is waiting on. Settle on the condition, or move the assertion down a layer. |
|
|
68
|
+
| A mock is quicker to set up than the real collaborator | A mock proves how the code is built. Take a real collaborator or a fake first. |
|
|
69
|
+
|
|
70
|
+
## Red flags
|
|
71
|
+
|
|
72
|
+
- You are opening an end to end spec to add a state rather than a journey.
|
|
73
|
+
- The expected value comes from calling the function under test.
|
|
74
|
+
- A sleep, a timeout, or a retry count is going in to make a run pass.
|
|
75
|
+
- The only assertion is that a double was called.
|
|
76
|
+
- You picked the layer before naming what production change makes the test fail.
|
|
77
|
+
|
|
78
|
+
## Before handing over
|
|
79
|
+
|
|
80
|
+
Run the final filter over every test written this session, checking each line. A test that fails one is rewritten or cut, never kept with a note.
|
|
63
81
|
|
|
64
82
|
- **Mirror assertion.** The expected value is computed by the code under test. Write the literal the behavior should produce.
|
|
65
83
|
- **Change detector.** The assertion pins a constant, a message's wording, or a markup shape no caller depends on.
|
|
@@ -25,6 +25,8 @@ External sources were read and filtered rather than imported. This file is the r
|
|
|
25
25
|
|
|
26
26
|
**Kent Beck's desiderata as background.** The twelve properties at [testdesiderata.com](https://testdesiderata.com/) trade against each other. "Behavioral" and "structure-insensitive" together are the whole of "test behavior, not implementation", which is why the body states that pair as asserting through the public surface.
|
|
27
27
|
|
|
28
|
+
**Excuses, red flags, and a closing checklist.** From `addyosmani/agent-skills@2686b620`, [`docs/skill-anatomy.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/docs/skill-anatomy.md): Common Rationalizations, Red Flags, and Verification. Adopted as the three closing sections every practice skill carries, with the final filter as the closing checklist. This reverses an earlier decline of the excuses table. That decline objected to arguments against imagined objections, so each row here rebuts an excuse this skill's requirement records a session acting on, such as extending the open end to end spec or adding a pause for a run that flakes under load.
|
|
29
|
+
|
|
28
30
|
### Per layer
|
|
29
31
|
|
|
30
32
|
**Component query and wait rules.** Role queries first, user events over synthetic ones, one assertion per wait, no side effects inside a wait ([Common mistakes](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)). Adopted in `component.md` with the library names removed from the rules.
|
|
@@ -37,7 +39,7 @@ External sources were read and filtered rather than imported. This file is the r
|
|
|
37
39
|
|
|
38
40
|
**Delete the code written before its test.** `superpowers`'s test-driven skill tells a session to delete implementation written ahead of a failing test. Declined: this toolkit audits the order after the fact with its test-order verb and reports rather than destroys, since deleting working code punishes the session without restoring the evidence the red run would have given.
|
|
39
41
|
|
|
40
|
-
**
|
|
42
|
+
**An iron law.** Both external test-driven skills carry an "Iron Law" stated as absolute. Declined for tone: this toolkit states a rule once with its reason.
|
|
41
43
|
|
|
42
44
|
**One skill per layer.** A unit skill, a component skill, and an end to end skill each loaded on its own trigger. Declined because the layer has to be chosen before the right skill can load, so the choice ends up restated in all three or in a fourth skill that is this one.
|
|
43
45
|
|
|
@@ -21,6 +21,7 @@ The automatable half has its own gap, and it is no longer this skill's to close
|
|
|
21
21
|
|
|
22
22
|
- Split every change into visual-only and automatable before writing anything
|
|
23
23
|
- Write the checklist for the visual-only half, each item an action and the result a person is looking for
|
|
24
|
+
- Give each item what a driver needs to run it without guessing: the route, the width where the change can differ by width, an action verb to open on, a `(taste)` marker on a judgment of look or feel, and the setup or a `(local only)` marker for a state the page does not open in
|
|
24
25
|
- Name every automatable change shipping with no test, with the layer `test-craft` would place it at, as a section of the same file
|
|
25
26
|
- Write the file to the `.canon/tmp/handoff/ui-checklist/<slug>.md` handoff at the main worktree root, overwriting
|
|
26
27
|
- Report that there is nothing to verify rather than manufacturing a checklist to show work
|
|
@@ -28,9 +28,19 @@ Group visual items by feature area. Use `- [ ]` checkbox syntax, and write each
|
|
|
28
28
|
|
|
29
29
|
**<Feature area>**
|
|
30
30
|
|
|
31
|
-
- [ ] <
|
|
31
|
+
- [ ] <route>[, <width>]: <verb> <target> → <expected visual result>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
Write each box so a session driving the running app can run it without guessing:
|
|
35
|
+
|
|
36
|
+
- **Route.** Name where the box is driven, as a path or the control that reaches it. A box naming no route is driven from the address the driver opens, so a single-page app with no routing needs no invented path. Write "from the page the app opens on" when a state is reached by a sequence rather than a URL.
|
|
37
|
+
- **Width.** Name the width a box is driven at only when the change can make it differ by width, the same test the widths block below uses for omission. A box about copy or color renders the same everywhere, so leave the width off rather than inventing one.
|
|
38
|
+
- **Verb.** Open on an action a driver performs, such as "scroll to", "click", "resize to", or "tab to". Never open on "read" or "look at", which name no action.
|
|
39
|
+
- **Taste.** End the line with `(taste)` when the result is a judgment of look or feel rather than a fact a driver can observe. A driver reports such a box as needing a person's eyes instead of passing it.
|
|
40
|
+
- **Setup.** A box needing a state the page does not open in states the setup inline. When a hosted preview cannot reach that state, such as a stopped service or a seeded record, end the line with `(local only)` instead.
|
|
41
|
+
|
|
42
|
+
The checkbox stays `- [ ]` followed by the action and the result, since the evidence comment carries ticked boxes forward by that shape.
|
|
43
|
+
|
|
34
44
|
## The widths block
|
|
35
45
|
|
|
36
46
|
A screenshot shows one width, so a reviewer cannot tell from the picture alone whether any other width was looked at. When a change touches layout, spacing, or anything responsive, put this block above the visual items, since it frames what the screenshots beside it can support:
|
package/docs/agents/index.md
CHANGED
|
@@ -50,7 +50,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
50
50
|
- [Scripting](scripting.md): The runtime catalogs that replace hardcoded names, what each carries, and a headless invocation per domain
|
|
51
51
|
- [Sessions transfer](sessions-transfer.md): Moving a session to another machine, the export bundle and its manifest, placing it with import, the refusal reasons, and what a resume on the target depends on
|
|
52
52
|
- [Sessions](sessions.md): Resolving live peer sessions to the worktree and branch each holds, reading which row is the caller, the liveness confidence field, what each session surface can see, and where moving a session to another machine is described
|
|
53
|
-
- [Skill audit](skills-audit.md): Measuring both skill corpora against standards
|
|
53
|
+
- [Skill audit](skills-audit.md): Measuring both skill corpora against the skill standards, the checks it reads, the requirement gate that is the only failing one, and the drift verb that names bodies rewritten since a ref
|
|
54
54
|
- [Citation reach](skills-reach.md): Reporting the skill bodies that cite a path no target project receives, which corpus the verb reads, the ownership key that decides what counts, the one-word qualifier that marks a citation as decided, and why the verb reports instead of gating
|
|
55
55
|
- [Standard success criteria](standards-audit.md): Reading the corpus against the success-criterion gate, the two headings it accepts, why the check scopes to arrival rather than the whole corpus, and the exit codes it sets
|
|
56
56
|
- [State-scoped risk](state-scoped-risk.md): Reading committed state rather than an arriving change, the shipped-tree corpus the secret scan reads, what it keys on and how a deliberate value is exempted, the advisory check and its network failure mode, and why one gates while the other reports
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Skill audit
|
|
3
|
-
description: Measuring both skill corpora against standards
|
|
3
|
+
description: Measuring both skill corpora against the skill standards, the checks it reads, the requirement gate that is the only failing one, and the drift verb that names bodies rewritten since a ref
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Skill audit
|
|
7
7
|
|
|
8
|
-
`canon claude skills audit [path]` reports both skill corpora against the rules `standards/skill.md` and `standards/skill-
|
|
8
|
+
`canon claude skills audit [path]` reports both skill corpora against the rules `standards/skill.md`, `standards/skill-requirement.md`, and `standards/skill-practice.md` state mechanically. It reads and reports. Fixing what it finds is separate work.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
canon claude skills audit
|
|
@@ -36,6 +36,7 @@ Each check traces to a line in the standard.
|
|
|
36
36
|
- Folder name in kebab-case
|
|
37
37
|
- Each `REQUIREMENT.md` declaring `Gap` and `Must`, matched at any heading level
|
|
38
38
|
- No ISO date in `SKILL.md` or any file under `references/`, reported as `datedProvenance` in the JSON record's `findings`
|
|
39
|
+
- Each listed practice skill closing with `## Excuses and rebuttals`, `## Red flags`, and `## Before handing over`, and carrying `references/adopted.md`, reported as `practiceShape`
|
|
39
40
|
|
|
40
41
|
A body whose frontmatter does not parse reports as declaring neither field rather than ending the run, so one malformed file cannot hide the corpus behind it. A key present with an empty value reads as absent, since a blank `name` would otherwise report as a name disagreeing with every folder. A folder carrying no requirement is reported once under presence rather than counted again for the sections it therefore lacks.
|
|
41
42
|
|
|
@@ -43,6 +44,8 @@ The date check reads prose alone. A date inside a fence or a code span is exampl
|
|
|
43
44
|
|
|
44
45
|
Each finding names the file and the line, such as `claude/skills/<name>/references/<file>.md line 12: <date>`. A date after "measured" or "verified" reports like any other, unlike the context audit, because a skill body states the rule a session follows today rather than a reading of the tree.
|
|
45
46
|
|
|
47
|
+
The practice check reads only the skills the audit lists, which the JSON record carries as `checkpoints.practiceSkills`. The list names folders under the toolkit's shipped `claude/skills/` corpus alone, so a project's own skill is never read as a practice skill and a same-named folder under `.claude/skills/` produces no finding. Where `claude/skills/` resolves, a listed folder it does not hold reports as a missing skill, so a renamed or misspelled entry cannot pass unread. Each closing section matches only as an exact H2 outside a fence, so an H3 or a heading carrying more words reports as missing.
|
|
48
|
+
|
|
46
49
|
## What it leaves alone
|
|
47
50
|
|
|
48
51
|
The report names its own blind spots on every run, including the run where everything passed. Whether each `Must` traces to a stated gap is the rule in the requirement standard worth the most and no parser reads it. Whether a gap states an observed failure rather than an intent, and whether a description routes, are the same kind of judgment. The 150-line body checkpoint is the one mechanical rule still absent here, and adding it would print a count rather than a defect, since the standard makes it a prompt to look with nothing enforcing it.
|
|
@@ -53,7 +56,7 @@ A check with no rule behind it prints an opinion as a defect, which is where the
|
|
|
53
56
|
|
|
54
57
|
## Exit codes
|
|
55
58
|
|
|
56
|
-
Exit codes are `0` for a clean run, `1` for a refusal, and `2` for a skill folder carrying no `REQUIREMENT.md`. Only presence sets a failing code. Name, description, folder, requirement-section,
|
|
59
|
+
Exit codes are `0` for a clean run, `1` for a refusal, and `2` for a skill folder carrying no `REQUIREMENT.md`. Only presence sets a failing code. Name, description, folder, requirement-section, dated-provenance, and practice shape findings print and return `0`, because each is a judgment a reader settles and failing a push on one would make the check something to route around. In the toolkit, two `bun run check` stages read the same report in-process and fail a push on dated provenance and on practice shape, since its own corpus is held at zero on both.
|
|
57
60
|
|
|
58
61
|
## The requirement gate
|
|
59
62
|
|
|
@@ -72,7 +72,7 @@ One feature travels this path end to end.
|
|
|
72
72
|
|
|
73
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.
|
|
74
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.
|
|
75
|
-
3. A reviewer
|
|
75
|
+
3. A reviewer under `role-reviewer`, or the orchestrator, posts `review-pr` findings, and `review-ui` drives any visual checklist beside it.
|
|
76
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.
|
|
77
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.
|
|
78
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.
|
|
@@ -79,14 +79,15 @@ This page is the corpus the coverage claim is measured against: every name `cano
|
|
|
79
79
|
|
|
80
80
|
## After the pull request opens
|
|
81
81
|
|
|
82
|
-
| Skill | When to use
|
|
83
|
-
| ---------------------- |
|
|
84
|
-
| `canon:review-pr` | From an independent session, to post findings on the PR itself
|
|
85
|
-
| `canon:review-
|
|
86
|
-
| `canon:
|
|
87
|
-
| `canon:git-
|
|
88
|
-
| `canon:git-
|
|
89
|
-
| `canon:git-
|
|
82
|
+
| Skill | When to use |
|
|
83
|
+
| ---------------------- | ---------------------------------------------------------------------- |
|
|
84
|
+
| `canon:review-pr` | From an independent session, to post findings on the PR itself |
|
|
85
|
+
| `canon:review-ui` | Beside the code review, to drive the PR's checklist in the running app |
|
|
86
|
+
| `canon:review-address` | On the worker's side, to fix posted findings and push a follow-up |
|
|
87
|
+
| `canon:git-followup` | For a small self-review edit on a branch whose PR is already open |
|
|
88
|
+
| `canon:git-split` | When a branch turns out to carry unrelated commits |
|
|
89
|
+
| `canon:git-issue` | When something surfaced that belongs on the tracker rather than here |
|
|
90
|
+
| `canon:git-worktree` | After a PR merges, to list worktrees and reclaim the slot |
|
|
90
91
|
|
|
91
92
|
## Run several tracks at once
|
|
92
93
|
|
package/package.json
CHANGED
|
@@ -100,6 +100,11 @@ export const WORKFLOW_CASES: readonly SkillCase[] = [
|
|
|
100
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
101
|
expect: 'role-reviewer',
|
|
102
102
|
},
|
|
103
|
+
{
|
|
104
|
+
prompt:
|
|
105
|
+
'Open the preview for that pull request and click through each box on its visual checklist, then post what happened.',
|
|
106
|
+
expect: 'review-ui',
|
|
107
|
+
},
|
|
103
108
|
{
|
|
104
109
|
prompt:
|
|
105
110
|
'The screencast draft is finished. Turn it into an actual video now.',
|