@erclx/canon 4.120.0 → 4.122.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/auto-ship/SKILL.md +29 -115
- package/claude/skills/auto-ship/references/draft-mark.md +30 -0
- package/claude/skills/auto-ship/references/failure-recovery.md +27 -0
- package/claude/skills/auto-ship/references/tier-failures.md +26 -0
- package/claude/skills/auto-ship/references/verb-absent.md +37 -0
- package/claude/skills/auto-ship/references/worktree-name.md +22 -0
- package/claude/skills/backlog-triage/REQUIREMENT.md +47 -0
- package/claude/skills/backlog-triage/SKILL.md +139 -0
- package/claude/skills/bash-script/SKILL.md +1 -1
- package/claude/skills/bash-script/references/patterns.md +0 -99
- package/claude/skills/bash-script/references/prompts.md +100 -0
- package/claude/skills/canon-rollout/SKILL.md +6 -6
- package/claude/skills/context-fold/REQUIREMENT.md +75 -0
- package/claude/skills/context-fold/SKILL.md +162 -0
- package/claude/skills/{docs-fold → context-fold}/references/anchor-sweep.md +1 -1
- package/claude/skills/{docs-fold → context-fold}/references/classify.md +4 -2
- package/claude/skills/context-fold/references/context-refresh.md +48 -0
- package/claude/skills/context-fold/references/promoted-pages.md +29 -0
- package/claude/skills/context-fold/references/receipt-sweep.md +43 -0
- package/claude/skills/context-fold/references/unusable-baseline.md +25 -0
- package/claude/skills/{docs-fold → context-fold}/references/wireframe-sweep.md +1 -1
- package/claude/skills/create-skill/SKILL.md +1 -1
- package/claude/skills/create-snippet/SKILL.md +1 -1
- package/claude/skills/create-standard/SKILL.md +1 -1
- package/claude/skills/design-extract/SKILL.md +1 -1
- package/claude/skills/design-taste/REQUIREMENT.md +2 -2
- package/claude/skills/docs-fold/REQUIREMENT.md +8 -58
- package/claude/skills/docs-fold/SKILL.md +3 -278
- package/claude/skills/docs-sync/REQUIREMENT.md +1 -1
- package/claude/skills/docs-sync/SKILL.md +2 -2
- package/claude/skills/draft-context/REQUIREMENT.md +2 -2
- package/claude/skills/draft-context/SKILL.md +4 -4
- package/claude/skills/draft-docs/REQUIREMENT.md +1 -1
- package/claude/skills/draft-docs/SKILL.md +1 -1
- package/claude/skills/draft-figure/SKILL.md +1 -1
- package/claude/skills/draft-readme/SKILL.md +1 -1
- package/claude/skills/draft-wiki/SKILL.md +1 -1
- package/claude/skills/draft-wireframes/REQUIREMENT.md +1 -1
- package/claude/skills/draft-wireframes/SKILL.md +3 -3
- package/claude/skills/git-issue/SKILL.md +1 -1
- package/claude/skills/git-issue/references/issue.md +1 -1
- package/claude/skills/git-pr/SKILL.md +9 -147
- package/claude/skills/git-pr/references/evidence.md +114 -0
- package/claude/skills/git-pr/references/labels.md +20 -0
- package/claude/skills/git-pr/references/task-number.md +26 -0
- package/claude/skills/git-ship/SKILL.md +1 -1
- package/claude/skills/git-stage/SKILL.md +1 -1
- package/claude/skills/memory-capture/REQUIREMENT.md +2 -2
- package/claude/skills/memory-capture/SKILL.md +6 -6
- package/claude/skills/memory-review/REQUIREMENT.md +1 -1
- package/claude/skills/memory-review/SKILL.md +5 -101
- package/claude/skills/memory-review/references/later-phases.md +108 -0
- package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
- package/claude/skills/restate-plainly/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/SKILL.md +5 -4
- package/claude/skills/review-branch/REQUIREMENT.md +1 -0
- package/claude/skills/review-branch/SKILL.md +6 -7
- package/claude/skills/review-craft/REQUIREMENT.md +43 -0
- package/claude/skills/review-craft/SKILL.md +50 -0
- package/claude/skills/review-craft/references/security.md +21 -0
- package/claude/skills/review-craft/references/ui.md +72 -0
- package/claude/skills/review-pr/REQUIREMENT.md +1 -0
- package/claude/skills/review-pr/SKILL.md +1 -1
- package/claude/skills/review-pr/references/post.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -0
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
- package/claude/skills/role-planner/REQUIREMENT.md +1 -1
- package/claude/skills/session-resume/REQUIREMENT.md +1 -1
- package/claude/skills/session-worktree/SKILL.md +4 -10
- package/claude/skills/standards-audit/SKILL.md +1 -1
- package/claude/skills/task-board/REQUIREMENT.md +1 -1
- package/claude/skills/task-board/SKILL.md +6 -80
- package/claude/skills/task-board/references/archive.md +54 -0
- package/claude/skills/task-board/references/decline.md +40 -0
- package/claude/skills/teach-workspace/SKILL.md +8 -105
- package/claude/skills/teach-workspace/references/lesson-craft.md +51 -1
- package/claude/skills/teach-workspace/references/promotion.md +41 -0
- package/claude/skills/write-human/REQUIREMENT.md +7 -4
- package/claude/skills/write-human/SKILL.md +4 -2
- package/claude/skills/write-human/references/machine-tells.md +1 -1
- package/claude/skills/write-human/references/source-material.md +5 -2
- package/docs/agents/architecture-record.md +26 -0
- package/docs/agents/audits.md +1 -1
- package/docs/agents/commands.md +87 -154
- package/docs/agents/context-audit-checks.md +2 -20
- package/docs/agents/context-audit.md +1 -1
- package/docs/agents/context-classify.md +1 -1
- package/docs/agents/drift-surfaces.md +192 -0
- package/docs/agents/index.md +12 -4
- package/docs/agents/install-and-sync.md +2 -181
- package/docs/agents/markdown-audit-weight.md +73 -0
- package/docs/agents/markdown-audit.md +11 -104
- package/docs/agents/migrate.md +34 -0
- package/docs/agents/pr-local.md +6 -3
- package/docs/agents/records-stale.md +62 -0
- package/docs/agents/records.md +5 -1
- package/docs/agents/sandbox.md +1 -1
- package/docs/agents/tasks-archive.md +81 -0
- package/docs/agents/tasks-plans.md +147 -0
- package/docs/agents/tasks-validate.md +131 -0
- package/docs/agents/tasks.md +6 -333
- package/docs/target-projects.md +4 -4
- package/docs/workflow/ai-workflow.md +33 -27
- package/governance/rules/claude/500-prose.md +1 -1
- package/governance/rules/claude/501-markdown.md +3 -3
- package/governance/rules/core/045-memory.md +1 -1
- package/package.json +1 -1
- package/src/autoship/paths.ts +3 -2
- package/src/claude/cases/setup.ts +1 -1
- package/src/claude/cases/workflow.ts +27 -1
- package/src/commands/audits.ts +2 -2
- package/src/commands/markdown.ts +7 -9
- package/src/commands/pr.ts +11 -4
- package/src/commands/records.ts +146 -0
- package/src/commands/sandbox.ts +6 -4
- package/src/context/classify/extract.ts +1 -1
- package/src/context/classify/ollama.ts +1 -1
- package/src/context/classify/run.ts +1 -1
- package/src/gate/measures.ts +5 -5
- package/src/gate/stages.ts +0 -1
- package/src/markdown/bans.ts +11 -68
- package/src/markdown/gate.ts +1 -1
- package/src/markdown/scan.ts +7 -88
- package/src/migrate/skill-names.ts +15 -2
- package/src/records/stale.ts +243 -0
- package/src/sandbox/expect.ts +1 -1
- package/src/tasks/archive.ts +28 -4
- package/src/tasks/record.ts +1 -1
- package/src/tasks/validate.ts +36 -3
- package/standards/docs.md +1 -1
- package/standards/index.md +1 -1
- package/standards/markdown.md +5 -7
- package/standards/memory.md +13 -1
- package/standards/pr.md +1 -1
- package/standards/publish.md +1 -1
- package/standards/readme.md +2 -2
- package/standards/tasks.md +1 -1
- package/tooling/astro/reference.md +1 -1
- package/tooling/base/configs/.husky/post-merge +1 -1
- package/tooling/base/configs/scripts/verify.sh +2 -2
- package/tooling/base/seeds/canon/context/development.md +1 -1
- package/tooling/claude/reference.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +5 -6
- package/tooling/go/reference.md +1 -1
- package/tooling/nextjs/reference.md +1 -1
- package/tooling/php/reference.md +1 -1
- package/tooling/python/reference.md +1 -1
- package/tooling/vite-react/reference.md +1 -1
- package/tooling/web/reference.md +1 -1
|
@@ -58,7 +58,7 @@ Read in parallel from the project root. Skip any file or folder that does not ex
|
|
|
58
58
|
|
|
59
59
|
`.canon/memory/` is a holding pen. Default every entry to promote or retire on review. Skip is the rare exception, reserved for active task overlap or user-type memories with no in-repo target.
|
|
60
60
|
|
|
61
|
-
`memory-capture` routes a project fact naming a domain with a context entry to that entry, so a pen filled since routing shipped is mostly feedback: rules about how to work, which no context entry owns. Propose against what the pen holds rather than expecting the older mix. An entry carried from before routing may still name a domain that has a context entry, and that entry's action is **Promote to a context entry**, which hands it to `
|
|
61
|
+
`memory-capture` routes a project fact naming a domain with a context entry to that entry, so a pen filled since routing shipped is mostly feedback: rules about how to work, which no context entry owns. Propose against what the pen holds rather than expecting the older mix. An entry carried from before routing may still name a domain that has a context entry, and that entry's action is **Promote to a context entry**, which hands it to `context-fold` the same way capture does rather than editing the entry here.
|
|
62
62
|
|
|
63
63
|
For each in-scope entry (see Scope), pick one action:
|
|
64
64
|
|
|
@@ -67,7 +67,7 @@ For each in-scope entry (see Scope), pick one action:
|
|
|
67
67
|
- In a target project, append the rule to an existing file under `.claude/rules/project/` with `Edit`, since a project rule is project-owned and sync never overwrites it, or hand off to the `create-rule` skill when no existing file fits.
|
|
68
68
|
- **Promote to a skill body**: the rule fires only when editing a specific path-scoped domain. Name the target skill.
|
|
69
69
|
- **Promote to a standards file**: the rule is an authoring reference that belongs in the project's own standards folder as `<domain>.md`.
|
|
70
|
-
- **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `canon/context/index.md`. Append it to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/
|
|
70
|
+
- **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `canon/context/index.md`. Append it to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, in the format `memory-capture` writes, and tell the user to run `/context-fold` from a branch. Do not edit the context entry here. A project-identity or command fact takes this action when a context entry owns the subject, such as a development entry for commands, and **Retire** otherwise, naming a hand edit to `CLAUDE.md` as the reason. Memory review does not write the root file itself.
|
|
71
71
|
- **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning), never a cross-domain behavior rule. Do not author the rule file inline. Never edit the synced `.claude/rules/` copies of toolkit rules, because `canon gov sync` overwrites them. Stop at handoff. This and **Promote to an always-loaded rule** never both claim one entry: class names the topic (coding-standards routes here), firing axis names the rest (applies-every-session routes to the rule promote).
|
|
72
72
|
- In the toolkit repo, point the user at `internal-governance` and `${CLAUDE_SKILL_DIR}/../../standards/rule.md`, which own the source-of-truth rules under `governance/rules/`.
|
|
73
73
|
- In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`.
|
|
@@ -91,7 +91,7 @@ Rules that resist crisp one-line phrasing default to **Retire** over promote. Ne
|
|
|
91
91
|
|
|
92
92
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
93
93
|
|
|
94
|
-
Write the full proposal to `.canon/memory/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four phases
|
|
94
|
+
Write the full proposal to `.canon/memory/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline. Read `${CLAUDE_SKILL_DIR}/references/receipt-format.md` for the file structure, the item template, and how each action type varies the body. The four later phases rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
|
|
95
95
|
|
|
96
96
|
A phase changing items reads the receipt, applies every change for that phase, and writes the whole file back in one command. Batching is what keeps a per-item rewrite from costing a full read each time, and it is the only route from a linked worktree, where the guard above rules out editing a line in place.
|
|
97
97
|
|
|
@@ -99,105 +99,9 @@ Tell the user `✅ Wrote proposal to .canon/memory/review/memory-review-<slug>.m
|
|
|
99
99
|
|
|
100
100
|
Rewrite the review file in place whenever the proposal changes mid-review. The file stays the source of truth for the current decisions.
|
|
101
101
|
|
|
102
|
-
## Challenge
|
|
102
|
+
## Challenge, Discuss, Apply, and Cleanup phases
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
107
|
-
2. For each promote item, apply three tests:
|
|
108
|
-
- **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
|
|
109
|
-
- **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
|
|
110
|
-
- **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to retire.
|
|
111
|
-
3. Rewrite the review file in place with the updated actions and a one-line reason under each flip.
|
|
112
|
-
|
|
113
|
-
## Discuss phase
|
|
114
|
-
|
|
115
|
-
Trigger: user says "discuss", "respond to questions", or any `Decision:` value contains `?` or an unrecognized verb. No mutations to memory files or targets. Review file only. Multi-round.
|
|
116
|
-
|
|
117
|
-
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
118
|
-
2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
|
|
119
|
-
- Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
|
|
120
|
-
- Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
|
|
121
|
-
- Leave the H2 emoji as 📝 pending.
|
|
122
|
-
3. Skip items whose `Decision:` is `apply`, `skip`, `defer`, or empty.
|
|
123
|
-
4. End with: `💬 Discussed: <nums> | ⏩ Skipped (committed or empty): <nums>`. Remind the user to refine `Decision:` lines and re-ping with "discuss" for another round, or "apply" when ready to commit.
|
|
124
|
-
|
|
125
|
-
Do not act on any item. Do not archive memory files. Do not edit promotion targets. Discuss only.
|
|
126
|
-
|
|
127
|
-
## Apply phase
|
|
128
|
-
|
|
129
|
-
Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked promotion targets and moves memory files into the archive.
|
|
130
|
-
|
|
131
|
-
Before applying any item, check the worktree state:
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
[ "$(git rev-parse --git-dir 2>/dev/null)" = "$(git rev-parse --git-common-dir 2>/dev/null)" ] && echo "MAIN" || echo "LINKED"
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
If the result is `MAIN`, stop and tell the user: `❌ Apply phase mutates tracked files. Run /session-worktree first.` Discuss and Challenge phases only touch `.canon/review/` scratch and run from anywhere.
|
|
138
|
-
|
|
139
|
-
Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules/core/` and `governance/rules/core/` and is the only route that may author into either. In a target project, hand off to `create-rule` with no load, since `internal-governance` is a toolkit-internal skill under `.claude/skills/` that a target project never has. An `Edit` appending to an existing file under `.claude/rules/project/` needs no load either.
|
|
140
|
-
|
|
141
|
-
Promotions are a separate concern from any feature in flight. Keep the promoted edits on their own commit. Do not fold an always-loaded-rule or skill-body change into a feature's commits, because a feature reviewer should not have to vet a change to how the agent operates.
|
|
142
|
-
|
|
143
|
-
For each item, parse the `Decision:` line:
|
|
144
|
-
|
|
145
|
-
- `apply` (or affirmative): run the proposed action, flip emoji to ✅.
|
|
146
|
-
- `skip`: leave the memory in place, flip emoji to ⏭.
|
|
147
|
-
- `defer` or empty: leave 📝 pending, take no action.
|
|
148
|
-
- Contains `?` or unrecognized verb: leave 📝 pending, take no action. Do not respond. Discussion is the Discuss phase's job.
|
|
149
|
-
|
|
150
|
-
Free-form text after the verb is a reason. Capture it in the receipt but do not let it change the action. When committing an item, strip any empty `Take:` line so the receipt stays clean. `Take:` lines with content stay as discussion history.
|
|
151
|
-
|
|
152
|
-
Action by action type:
|
|
153
|
-
|
|
154
|
-
- **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file. A promote to an always-loaded rule in the toolkit repo never reaches this line: it stops as a handoff to `internal-governance`, the same as **Hand off** below, and archives only on the user's explicit confirmation.
|
|
155
|
-
- **Promote to a context entry**: append the fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, then archive the memory file. `docs-fold` folds it in on its next run from a branch, which is what keeps one skill writing context entries.
|
|
156
|
-
- **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
|
|
157
|
-
- **Retire**: archive the memory file.
|
|
158
|
-
|
|
159
|
-
Archiving means creating `.canon/memory/archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and a plain `mv`, routed the way `session-worktree` states for a main-root move. Never delete a memory entry. Nothing recovers one from a gitignored folder.
|
|
160
|
-
|
|
161
|
-
Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
An archive move is a shell `mv`, which skips the index hook the way `session-worktree` states. Without this call the index keeps a row per archived entry and drifts exactly the way the hand-appended one did. Run it once after the last move rather than per item.
|
|
168
|
-
|
|
169
|
-
Apply promotion edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole promotion target.
|
|
170
|
-
|
|
171
|
-
This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the guard instead.
|
|
172
|
-
|
|
173
|
-
As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the file here. The sweep below decides whether it goes.
|
|
174
|
-
|
|
175
|
-
**Chat shortcut:** the user replies with `all`, `none`, a comma-separated list of numbers, or `skip <nums>`. Write the matching verb into the `Decision:` slot of every item the reply names, `apply` for `all` or a bare list and `skip` for a `skip` reply, then run the parse above against the file. A reply of `none` writes nothing. A slot the reply does not name keeps its own value, so the receipt stays the source of truth and an empty slot still means take no action.
|
|
176
|
-
|
|
177
|
-
### Sweep the receipt
|
|
178
|
-
|
|
179
|
-
Count the items still pending once the parse above has run. An item is pending when its H2 carries 📝, or when its H2 carries no status emoji and its `Decision:` slot holds nothing the parse above would act on or skip, since a receipt written by hand or by an older binary may lack the marker. Apply leaves one pending on `defer`, on empty, and on any unrecognized verb, so a receipt reaching this point may still be holding decisions.
|
|
180
|
-
|
|
181
|
-
Leave the receipt in place when any remain. When none do, collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, which owns what a fold writes and which entry types take one.
|
|
182
|
-
|
|
183
|
-
`docs-fold` Step 9 sweeps the same folder on the same rule once per shipped branch, and either may reach a receipt first. Whichever does, the other finds no file and moves on.
|
|
184
|
-
|
|
185
|
-
End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Omit empty buckets. If anything is pending, remind the user they can refine `Decision:` lines and re-ping, run "discuss" for question items, or commit a skip with `skip <nums>` in chat.
|
|
186
|
-
|
|
187
|
-
## Cleanup phase
|
|
188
|
-
|
|
189
|
-
Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
|
|
190
|
-
|
|
191
|
-
Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `docs-fold` Step 9 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/memory/archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
|
|
192
|
-
|
|
193
|
-
If no `.canon/memory/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
|
|
194
|
-
|
|
195
|
-
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still pending, by the test the Apply sweep states, stop and name the pending numbers.
|
|
196
|
-
2. Collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, folding each ⏭ skipped item before the file goes. The fold happens wherever a receipt is collected, so this phase runs the same rule the Apply sweep does.
|
|
197
|
-
3. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
|
|
198
|
-
4. Leave every memory entry in the pen. A skip records the decline on the entry and keeps the file, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
|
|
199
|
-
|
|
200
|
-
Do not promote or archive a memory entry. The skip fold is the one rewrite this phase makes, and it records a decline on an entry that stays in the pen.
|
|
104
|
+
Each later phase runs on its own invocation against a receipt Propose already wrote, picked by the table above. Read `${CLAUDE_SKILL_DIR}/references/later-phases.md` on reaching any of them, for the phase's trigger, what it may mutate, its procedure, and the line it ends on. Challenge and Discuss rewrite the review file only, Apply stops on the main worktree, and Cleanup removes one receipt.
|
|
201
105
|
|
|
202
106
|
## After completion
|
|
203
107
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Memory review later phases
|
|
3
|
+
description: The Challenge, Discuss, Apply, and Cleanup phases of memory-review, each run on its own invocation against a receipt the Propose phase already wrote
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory review later phases
|
|
7
|
+
|
|
8
|
+
The phases of `memory-review` after Propose. The session reads this file when the phase table in the skill picks Challenge, Discuss, Apply, or Cleanup, and reads only the section for that phase. The skill's Guards still hold for every phase here.
|
|
9
|
+
|
|
10
|
+
## Challenge phase
|
|
11
|
+
|
|
12
|
+
Trigger: user says "challenge the promotes", "challenge before apply", or asks for a high-bar pass. Run before Apply. No mutations to memory files or promotion targets. Review file only.
|
|
13
|
+
|
|
14
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
15
|
+
2. For each promote item, apply three tests:
|
|
16
|
+
- **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
|
|
17
|
+
- **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
|
|
18
|
+
- **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to retire.
|
|
19
|
+
3. Rewrite the review file in place with the updated actions and a one-line reason under each flip.
|
|
20
|
+
|
|
21
|
+
## Discuss phase
|
|
22
|
+
|
|
23
|
+
Trigger: user says "discuss", "respond to questions", or any `Decision:` value contains `?` or an unrecognized verb. No mutations to memory files or targets. Review file only. Multi-round.
|
|
24
|
+
|
|
25
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root.
|
|
26
|
+
2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
|
|
27
|
+
- Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
|
|
28
|
+
- Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
|
|
29
|
+
- Leave the H2 emoji as 📝 pending.
|
|
30
|
+
3. Skip items whose `Decision:` is `apply`, `skip`, `defer`, or empty.
|
|
31
|
+
4. End with: `💬 Discussed: <nums> | ⏩ Skipped (committed or empty): <nums>`. Remind the user to refine `Decision:` lines and re-ping with "discuss" for another round, or "apply" when ready to commit.
|
|
32
|
+
|
|
33
|
+
Do not act on any item. Do not archive memory files. Do not edit promotion targets. Discuss only.
|
|
34
|
+
|
|
35
|
+
## Apply phase
|
|
36
|
+
|
|
37
|
+
Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked promotion targets and moves memory files into the archive.
|
|
38
|
+
|
|
39
|
+
Before applying any item, check the worktree state:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
[ "$(git rev-parse --git-dir 2>/dev/null)" = "$(git rev-parse --git-common-dir 2>/dev/null)" ] && echo "MAIN" || echo "LINKED"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If the result is `MAIN`, stop and tell the user: `❌ Apply phase mutates tracked files. Run /session-worktree first.` Discuss and Challenge phases only touch `.canon/review/` scratch and run from anywhere.
|
|
46
|
+
|
|
47
|
+
Before applying a promote to an always-loaded rule in the toolkit repo, load `internal-governance`, which owns `internal/rules/core/` and `governance/rules/core/` and is the only route that may author into either. In a target project, hand off to `create-rule` with no load, since `internal-governance` is a toolkit-internal skill under `.claude/skills/` that a target project never has. An `Edit` appending to an existing file under `.claude/rules/project/` needs no load either.
|
|
48
|
+
|
|
49
|
+
Promotions are a separate concern from any feature in flight. Keep the promoted edits on their own commit. Do not fold an always-loaded-rule or skill-body change into a feature's commits, because a feature reviewer should not have to vet a change to how the agent operates.
|
|
50
|
+
|
|
51
|
+
For each item, parse the `Decision:` line:
|
|
52
|
+
|
|
53
|
+
- `apply` (or affirmative): run the proposed action, flip emoji to ✅.
|
|
54
|
+
- `skip`: leave the memory in place, flip emoji to ⏭.
|
|
55
|
+
- `defer` or empty: leave 📝 pending, take no action.
|
|
56
|
+
- Contains `?` or unrecognized verb: leave 📝 pending, take no action. Do not respond. Discussion is the Discuss phase's job.
|
|
57
|
+
|
|
58
|
+
Free-form text after the verb is a reason. Capture it in the receipt but do not let it change the action. When committing an item, strip any empty `Take:` line so the receipt stays clean. `Take:` lines with content stay as discussion history.
|
|
59
|
+
|
|
60
|
+
Action by action type:
|
|
61
|
+
|
|
62
|
+
- **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file. A promote to an always-loaded rule in the toolkit repo never reaches this line: it stops as a handoff to `internal-governance`, the same as **Hand off** below, and archives only on the user's explicit confirmation.
|
|
63
|
+
- **Promote to a context entry**: append the fact to `.canon/tmp/handoff/memory-routing/<slug>.md` at the main worktree root, then archive the memory file. `context-fold` folds it in on its next run from a branch, which is what keeps one skill writing context entries.
|
|
64
|
+
- **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
|
|
65
|
+
- **Retire**: archive the memory file.
|
|
66
|
+
|
|
67
|
+
Archiving means creating `.canon/memory/archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Send the `mkdir -p` and a plain `mv`, routed the way `session-worktree` states for a main-root move. Never delete a memory entry. Nothing recovers one from a gitignored folder.
|
|
68
|
+
|
|
69
|
+
Do not hand-edit `.canon/memory/index.md`. Once every archive move is done, regenerate it instead:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
canon indexes regen --no-stage --root <main-root> <main-root>/.canon/memory/index.md
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
An archive move is a shell `mv`, which skips the index hook the way `session-worktree` states. Without this call the index keeps a row per archived entry and drifts exactly the way the hand-appended one did. Run it once after the last move rather than per item.
|
|
76
|
+
|
|
77
|
+
Apply promotion edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole promotion target.
|
|
78
|
+
|
|
79
|
+
This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the skill's heredoc guard instead.
|
|
80
|
+
|
|
81
|
+
As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the file here. The sweep below decides whether it goes.
|
|
82
|
+
|
|
83
|
+
**Chat shortcut:** the user replies with `all`, `none`, a comma-separated list of numbers, or `skip <nums>`. Write the matching verb into the `Decision:` slot of every item the reply names, `apply` for `all` or a bare list and `skip` for a `skip` reply, then run the parse above against the file. A reply of `none` writes nothing. A slot the reply does not name keeps its own value, so the receipt stays the source of truth and an empty slot still means take no action.
|
|
84
|
+
|
|
85
|
+
### Sweep the receipt
|
|
86
|
+
|
|
87
|
+
Count the items still pending once the parse above has run. An item is pending when its H2 carries 📝, or when its H2 carries no status emoji and its `Decision:` slot holds nothing the parse above would act on or skip, since a receipt written by hand or by an older binary may lack the marker. Apply leaves one pending on `defer`, on empty, and on any unrecognized verb, so a receipt reaching this point may still be holding decisions.
|
|
88
|
+
|
|
89
|
+
Leave the receipt in place when any remain. When none do, collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, which owns what a fold writes and which entry types take one.
|
|
90
|
+
|
|
91
|
+
`context-fold` Step 9 sweeps the same folder on the same rule once per shipped branch, and either may reach a receipt first. Whichever does, the other finds no file and moves on.
|
|
92
|
+
|
|
93
|
+
End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Omit empty buckets. If anything is pending, remind the user they can refine `Decision:` lines and re-ping, run "discuss" for question items, or commit a skip with `skip <nums>` in chat.
|
|
94
|
+
|
|
95
|
+
## Cleanup phase
|
|
96
|
+
|
|
97
|
+
Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
|
|
98
|
+
|
|
99
|
+
Cleanup folds one receipt's skips and removes that receipt, and does nothing else. It is the fallback route now that Apply and `context-fold` Step 9 each collect a resolved receipt on their own, so it reaches a file those two left behind rather than being the only collector. Apply is still the only phase that moves a memory entry out of the pen, and it does so per approved item into `.canon/memory/archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
|
|
100
|
+
|
|
101
|
+
If no `.canon/memory/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
|
|
102
|
+
|
|
103
|
+
1. Read the latest `.canon/memory/review/memory-review-*.md` at the main root and confirm Apply has run against it. If any item is still pending, by the test the Apply sweep states, stop and name the pending numbers.
|
|
104
|
+
2. Collect it per the collection rule in `${CLAUDE_SKILL_DIR}/../../standards/memory.md`, folding each ⏭ skipped item before the file goes. The fold happens wherever a receipt is collected, so this phase runs the same rule the Apply sweep does.
|
|
105
|
+
3. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
|
|
106
|
+
4. Leave every memory entry in the pen. A skip records the decline on the entry and keeps the file, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
|
|
107
|
+
|
|
108
|
+
Do not promote or archive a memory entry. The skip fold is the one rewrite this phase makes, and it records a decline on an entry that stays in the pen.
|
|
@@ -35,4 +35,4 @@ Without this skill, implementation starts before anyone knows what it touches. A
|
|
|
35
35
|
|
|
36
36
|
- Executing the plan, which is the ship pipeline
|
|
37
37
|
- Task-board state, which `task-board` owns. A plan links to its task and does not create one.
|
|
38
|
-
- Reconciling the planning docs after the work lands, which `
|
|
38
|
+
- Reconciling the planning docs after the work lands, which `context-fold` owns
|
|
@@ -38,4 +38,4 @@ A restatement also fails in a way a rewrite does not. A run that compresses by d
|
|
|
38
38
|
- Drafting or revising a passage, which is `write-human` on a markdown edit
|
|
39
39
|
- Measuring cadence in finished output, which `canon markdown audit` reports from package data
|
|
40
40
|
- Rewriting a document into a file, which is a proposal against the source rather than a restatement of it
|
|
41
|
-
- The banned
|
|
41
|
+
- The banned characters, which `markdown.md` states and the audit gates
|
|
@@ -52,6 +52,6 @@ A declined finding fails on a third axis, which is where its reason ends up. A w
|
|
|
52
52
|
|
|
53
53
|
- Writing the review, which `review-pr` owns. The split is by side of the channel: that one posts findings from an independent session and this one is the worker's return leg.
|
|
54
54
|
- Staging, committing, and pushing the follow-up, which `git-followup` owns under this skill's direction
|
|
55
|
-
- Refreshing the `.claude/` docs the fixes made stale, which `
|
|
55
|
+
- Refreshing the `.claude/` docs the fixes made stale, which `context-fold` owns
|
|
56
56
|
- Re-reviewing its own fixes, which hands back to the orchestrator
|
|
57
57
|
- Re-reading a rewritten branch, which `review-pr` absorbs by testing whether the prior reviewed commit still reaches the head and paying for a full pass when it does not
|
|
@@ -46,7 +46,7 @@ Do not push a red follow-up.
|
|
|
46
46
|
|
|
47
47
|
## Step 4: refresh stale docs
|
|
48
48
|
|
|
49
|
-
The fixes may have changed or added behavior that `.claude/` context entries, docs, or wireframes describe. Refresh them with the `
|
|
49
|
+
The fixes may have changed or added behavior that `.claude/` context entries, docs, or wireframes describe. Refresh them with the `context-fold` skill, which maps the changed files to the entries that reference them and rewrites the stale sections. Do not reimplement that mapping here. When a fix adds a new capability with no existing entry, `context-fold` flags it rather than creating one.
|
|
50
50
|
|
|
51
51
|
## Step 5: rebase a stale branch
|
|
52
52
|
|
|
@@ -107,8 +107,9 @@ the write and the post. Note any `.claude/` docs refreshed as a result of the
|
|
|
107
107
|
fixes.
|
|
108
108
|
|
|
109
109
|
The reply is a rendered-for-human GitHub surface, so load the `write-human`
|
|
110
|
-
skill for voice, follow
|
|
111
|
-
|
|
110
|
+
skill for voice and word choice, follow
|
|
111
|
+
`${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for punctuation, and keep each
|
|
112
|
+
mapping to a line or two.
|
|
112
113
|
|
|
113
114
|
Open the body with the `## Review response` heading so it anchors as a section
|
|
114
115
|
distinct from human threads and stays subordinate to the `## Review` heading the
|
|
@@ -244,7 +245,7 @@ Do not merge. Hand back to the orchestrator for re-review.
|
|
|
244
245
|
|
|
245
246
|
## Post-review findings
|
|
246
247
|
|
|
247
|
-
Not everything worth reaching the reviewing session surfaces inside the numbered flow above. A worker that settled a risk, filed a follow-up, or found something else worth reporting after Step 7 already closed the review posts it directly rather than waiting on a review pass that has nothing left to trigger it. Write the body the way Step 6 writes a reply: load `write-human` for voice, follow `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for
|
|
248
|
+
Not everything worth reaching the reviewing session surfaces inside the numbered flow above. A worker that settled a risk, filed a follow-up, or found something else worth reporting after Step 7 already closed the review posts it directly rather than waiting on a review pass that has nothing left to trigger it. Write the body the way Step 6 writes a reply: load `write-human` for voice and word choice, follow `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for punctuation, and run the `${CLAUDE_SKILL_DIR}/../../standards/publish.md` scan before posting with `canon labels scan --body-file .canon/tmp/pr/reply/reply-<number>.md`.
|
|
248
249
|
|
|
249
250
|
Open with `## Post-review findings` rather than `## Review response`, since nothing on the thread is being answered. `review-pr` states the full heading set this belongs to and routes it the same as a response: `role-orchestrator`'s poll picks it up and sends the reviewing session back for a pass. Close the body with `🤖 Addressed by Claude Code` on its own line, matching the reply's footer.
|
|
250
251
|
|
|
@@ -15,6 +15,7 @@ Without this skill, a branch ships on the confidence of the session that wrote i
|
|
|
15
15
|
- Resolve the base ref once, preferring the remote over local `main`, and reuse it in the guard and the read
|
|
16
16
|
- Say when the baseline is unusable and name the narrowed scope, rather than letting a clean summary read as a clean branch
|
|
17
17
|
- Flag only what will cause incorrect behavior or break a documented rule
|
|
18
|
+
- Apply `canon:review-craft`'s axes and evidence bar, rendered output included, rather than carrying an axis list of its own
|
|
18
19
|
- Grade every finding, since the caller gates on the counts rather than on the prose
|
|
19
20
|
- Write the report to disk under a branch-derived slug, so what the ship step reads outlives the session
|
|
20
21
|
|
|
@@ -59,14 +59,13 @@ Read each file from the changed file list. Skip deleted files. Run reads in para
|
|
|
59
59
|
|
|
60
60
|
## Step 4: review and persist
|
|
61
61
|
|
|
62
|
+
Invoke `canon:review-craft` before reading the diff for findings, whatever the diff's size. It carries what to look for and the evidence bar, rendered output included, and this step carries no axis list of its own to fall back on. Report it rather than proceeding silently when the skill does not resolve.
|
|
63
|
+
|
|
62
64
|
Review the full diff and changed file contents for:
|
|
63
65
|
|
|
64
|
-
1.
|
|
65
|
-
2.
|
|
66
|
-
3.
|
|
67
|
-
4. Security issues relevant to the project context
|
|
68
|
-
5. Violations of rules from `.claude/rules/` that apply to the changed files
|
|
69
|
-
6. When the diff touches a file this project ships to a target holding none of its own history: a repository-relative path, a phase label naming a gitignored board, a same-repository pull request or commit reference, or a layout, stack, or config-path claim true of this checkout but stated as if it were general
|
|
66
|
+
1. Every axis `canon:review-craft` states, held to its evidence bar
|
|
67
|
+
2. Violations of rules from `.claude/rules/` that apply to the changed files
|
|
68
|
+
3. When the diff touches a file this project ships to a target holding none of its own history: a repository-relative path, a phase label naming a gitignored board, a same-repository pull request or commit reference, or a layout, stack, or config-path claim true of this checkout but stated as if it were general
|
|
70
69
|
|
|
71
70
|
Use `CLAUDE.md`, `canon/REQUIREMENTS.md`, `canon/ARCHITECTURE.md`, and the auto-loaded `.claude/rules/` as project context to inform what is intentional vs problematic. Do not fix, rewrite, or suggest refactors outside the scope of a finding.
|
|
72
71
|
|
|
@@ -122,7 +121,7 @@ If there are no findings, write `✅ No findings.` to the file with a timestamp.
|
|
|
122
121
|
|
|
123
122
|
The `.canon/review/` directory is gitignored. Do not stage or commit the file.
|
|
124
123
|
|
|
125
|
-
The report is disposable. It outlives the ship chain that reads it, and `
|
|
124
|
+
The report is disposable. It outlives the ship chain that reads it, and `context-fold` sweeps it once the branch it names is gone, because the durable record of what a review found is the comment `review-pr` posts on the pull request. A review run on a branch that never opens one leaves nothing behind once that branch is gone, so fold anything worth keeping into the pull request body or a task finding while the report is still on disk.
|
|
126
125
|
|
|
127
126
|
### Chat output
|
|
128
127
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-craft
|
|
3
|
+
description: Why every review needs one stated set of axes and an evidence bar, and where that judgment stops short of the procedures that run a review
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review craft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, what a review looks for is seven words copied between two procedure bodies: bugs, edge cases, error handling, logic flaws, security. Nothing states design and scope, what breaks in a consumer outside the diff, developer experience, executable prose, a doc the change made stale, which security classes to check, or how much evidence a finding needs before it is reported.
|
|
11
|
+
|
|
12
|
+
The miss is measured. On a seeded branch that deleted a dirty-tree guard while the README two headings below the edited hunk still promised it, two runs of the local review found the removed guard and called the README clean. Security was not the gap: both runs caught the planted injection and the unpinned package under the one-word axis.
|
|
13
|
+
|
|
14
|
+
Rendered output is the larger hole. `git-pr` posts an `## Evidence` comment through `canon pr evidence`, carrying base and head screenshots and a checklist a reviewer ticks. The pull request review named that heading only in its heading set, and no step opened an image. On a seeded pull request whose narrow head screenshot shows the navigation running off the edge while a ticked box claims it collapses, the review filed the finding off the stylesheet diff and said it had not rendered the page. On a styling change with no screenshot at all, on a project whose trunk keeps them, it did not mention the absence.
|
|
15
|
+
|
|
16
|
+
## Must
|
|
17
|
+
|
|
18
|
+
- Open with the one fact the change's safety rests on, read on a ladder of asserted, pointed at, walked through, tested, and reproduced
|
|
19
|
+
- State the axes in reading order: design and scope, correctness and edge cases, what breaks outside the diff, tests, security, rendered output, developer experience and operations, and executable prose
|
|
20
|
+
- Require every consumer of a changed contract to be listed and checked, and every doc the diff touches to be read whole for a claim the change made false
|
|
21
|
+
- State a design finding as a concrete cost, so it survives the procedure's filter against subjective suggestions
|
|
22
|
+
- Carry the evidence bar: confirm against the file at the reviewed head, quote a cited rule, name the breaking input, and drop what a gate owns or what rests on unread state
|
|
23
|
+
- Carry security as classes with an exclusion list, in a reference loaded when the diff reaches one
|
|
24
|
+
- Open the evidence images on a rendered change through `git show` at the row's own sha, never through the embedded address, within a stated read budget
|
|
25
|
+
- Test each ticked checklist box against an opened image, and name a ticked box no image covers as untested
|
|
26
|
+
- Flag a rendered change that carries no screenshot, as a finding where the trunk already keeps them and as a question elsewhere
|
|
27
|
+
- Read the posted comment rather than running `canon pr evidence`, which compares the local checkout's diff and names the wrong change from a reviewing session not on the branch
|
|
28
|
+
|
|
29
|
+
## Must not
|
|
30
|
+
|
|
31
|
+
- State a severity or a posting rule. `review-pr` and `review-branch` each own a ladder, and the two define `should-fix` differently.
|
|
32
|
+
- Restate the high-signal filter either procedure carries
|
|
33
|
+
- Name a repository-specific capture layout, width list, or folder. The evidence marker and `canon/wireframes/` are target contracts, and everything else is the project's.
|
|
34
|
+
- Carry a per-surface reference beyond security and rendered output before a measured miss asks for one
|
|
35
|
+
|
|
36
|
+
## Out of scope
|
|
37
|
+
|
|
38
|
+
- Running a review, reading the diff, posting findings, and grading them: `review-branch` and `review-pr`
|
|
39
|
+
- The high-signal filter and the severity ladder, which stay in each procedure body
|
|
40
|
+
- Which layer a test belongs at: `test-craft`
|
|
41
|
+
- Capturing screenshots or writing the visual checklist: `canon pr evidence` and `ui-checklist`
|
|
42
|
+
- A dispatched reviewer session that loads this skill, which a later trial decides
|
|
43
|
+
- A deliberate full security audit: the built-in `security-review`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-craft
|
|
3
|
+
description: Carries what a code review looks for and how much evidence a finding needs, from design and scope through breakage outside the diff, developer experience, executable prose, stale docs, security classes, and rendered output checked against the screenshots a pull request carries. Use when reviewing a change, when a review procedure loads it for its axes, or when asked "what should a review look for", "what does a good review check", "how sure do I need to be before flagging this", or "did the review look at the screenshots". Do NOT use to run a review, post it, or grade its findings, which is `review-branch` for local work and `review-pr` for a pull request, and do NOT use for a deliberate full security audit, which is the built-in `security-review`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review craft
|
|
7
|
+
|
|
8
|
+
A review with no stated axes reads the changed lines for bugs and stops there. What breaks in a consumer the diff never opened, a doc the change made false a section away from its hunk, or a screenshot showing the opposite of what a ticked box claims all go unread. This skill carries the judgment: what to look for, in what order, and how sure to be before calling it a finding.
|
|
9
|
+
|
|
10
|
+
The procedure that loaded this skill owns everything else: which files to read, the filter that decides what gets reported, the severity ladder, and where the report goes. Nothing here grades a finding or posts one.
|
|
11
|
+
|
|
12
|
+
## Open with the one fact the change's safety rests on
|
|
13
|
+
|
|
14
|
+
Name the single claim that, if false, makes this change unsafe to merge, then say how far the change proves it. Read the proof on this ladder, weakest first:
|
|
15
|
+
|
|
16
|
+
- **Asserted.** The description or a comment says so.
|
|
17
|
+
- **Pointed at.** It names the code or the test that would show it.
|
|
18
|
+
- **Walked through.** The reasoning traces the path and holds.
|
|
19
|
+
- **Tested.** A test in the diff fails if the claim is false.
|
|
20
|
+
- **Reproduced.** Someone ran it and recorded what happened.
|
|
21
|
+
|
|
22
|
+
A risky claim resting on assertion alone is where the review spends its reading. A trivial one needs no more than asserted.
|
|
23
|
+
|
|
24
|
+
## Read the axes in this order
|
|
25
|
+
|
|
26
|
+
An axis whose condition the diff meets is not optional. When axis 5 or 6 names a reference and its condition holds, read that reference before moving to the next axis, however clear the diff looks without it.
|
|
27
|
+
|
|
28
|
+
1. **Design and scope.** Does the change do one thing, is it more complex than the problem needs, and does it build what nobody asked for? State a design finding as a concrete cost, such as a second path nobody calls, a layer with one caller, or a flag no caller passes, never as a preference.
|
|
29
|
+
2. **Correctness and edge cases.** The empty input, the boundary value, the refused call, the second run, the concurrent run, and the error path a caller actually meets.
|
|
30
|
+
3. **What breaks outside the diff.** List every consumer of a changed contract, whether a function signature, a file format, a flag, an output shape, or a heading another tool matches, and check the change against each one. Then list each behavior the diff removes or changes, such as a guard, a refusal, a default, or an output, and search every doc the diff touches, in full rather than at the hunk, for a sentence still promising the old behavior. File that sentence as a finding against the doc, quoting it and naming its section, since the doc is what goes wrong for the next reader.
|
|
31
|
+
4. **Tests.** Hand each test the change adds or edits to `canon:test-craft` and its final filter. Report it rather than proceeding silently when that skill does not resolve.
|
|
32
|
+
5. **Security.** Read `${CLAUDE_SKILL_DIR}/references/security.md` when the diff runs a command, writes a file, handles input from outside the process, touches a secret, adds a dependency, or changes a default a consumer installs.
|
|
33
|
+
6. **Rendered output.** Read `${CLAUDE_SKILL_DIR}/references/ui.md` when the diff touches a file that paints, such as markup, a stylesheet, a component, a template, or a design token, or when the pull request carries an evidence comment. A finding read off a stylesheet diff says what the author changed, and only the screenshot says what a user sees, so the reference opens the images and checks whether any exist.
|
|
34
|
+
7. **Developer experience and operations.** Ports, hooks, scripts, config, and scaffold defaults a consumer installs. A new required step nobody documented, a default that fails on a clean machine, or a hook that slows every commit is a finding even when the code is correct.
|
|
35
|
+
8. **Executable prose.** A skill body, a rule, or a prompt is instructions a model runs. Read it the way you read code: a step that races another, a precondition it never states, a branch with no exit, and two instructions that contradict each other are bugs.
|
|
36
|
+
|
|
37
|
+
## Hold every finding to the evidence bar
|
|
38
|
+
|
|
39
|
+
- Confirm each finding against the file at the reviewed head before grading it. A finding read off the diff alone misses the guard three lines outside the hunk.
|
|
40
|
+
- Quote the rule when a finding cites one, with its file, so the author can check the claim without finding the rule first.
|
|
41
|
+
- Name the input or the state that breaks, not only the line. A finding with no failing case is a suspicion.
|
|
42
|
+
- Drop what a linter, a type checker, or a gate in the project already owns. The gate reports it with more certainty than a review can.
|
|
43
|
+
- Drop a finding resting on state you did not read. Say what you would need to read instead.
|
|
44
|
+
|
|
45
|
+
## What this delegates
|
|
46
|
+
|
|
47
|
+
- Which files a pass reads, the high-signal filter, the severity ladder, and where findings go: `review-branch` for local work and `review-pr` for a pull request
|
|
48
|
+
- Which layer a test belongs at and what makes it good: `test-craft`
|
|
49
|
+
- Writing what a reviewer should look at on a rendered change: `ui-checklist`
|
|
50
|
+
- A deliberate full security audit of a codebase: the built-in `security-review`
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Security classes
|
|
2
|
+
|
|
3
|
+
Read each class against the diff. A class the diff does not reach is skipped, not reported as clean. Name the input that reaches the sink and the path it takes, since a class named with no path is a suspicion rather than a finding.
|
|
4
|
+
|
|
5
|
+
## Classes to check
|
|
6
|
+
|
|
7
|
+
- **Shell and command injection.** A value from an argument, an environment variable, a file, or a network response reaching a shell: through `eval`, an unquoted expansion, a string built into a command, or a subprocess call that takes a single command string. Quoting the variable at the call site is the fix to look for.
|
|
8
|
+
- **Path traversal in a file write.** A path built from outside input and written without being resolved and checked against the directory it must stay inside. A `..` segment, an absolute path, and a symlink inside the target each escape a naive join.
|
|
9
|
+
- **Secrets and personal data leaving the process.** A token, a key, a password, or personal data reaching a log line, an error message, a session transcript, a published page, a pull request comment, or a sync to a remote. Check what a debug line prints and what a verbose flag adds.
|
|
10
|
+
- **Supply chain.** One-shot package execution of an unpinned version, which runs whatever the registry serves that day. A new dependency, and what its install scripts run. A lockfile that changes without a manifest change.
|
|
11
|
+
- **Time of check to time of use on a file write.** An existence or permission check followed by a write to the same path in a later step, and a predictable name in a shared temporary directory. Another process can swap the path in between.
|
|
12
|
+
- **Insecure defaults a consumer installs.** A config, a scaffold, or a seed that turns a check off, opens a port on every interface, grants a broad permission, or ships a placeholder secret. The consumer inherits the default without reading it.
|
|
13
|
+
|
|
14
|
+
## Excluded
|
|
15
|
+
|
|
16
|
+
Do not report these as security findings. Raise one as a correctness finding only when the diff shows a concrete failing case.
|
|
17
|
+
|
|
18
|
+
- Denial of service, rate limiting, and resource exhaustion
|
|
19
|
+
- Generic input validation with no proven impact
|
|
20
|
+
- Open redirects
|
|
21
|
+
- A theoretical attack needing access the attacker would already need to have
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Rendered output
|
|
2
|
+
|
|
3
|
+
A screenshot is the one artifact that shows what a change paints. Reading the markup and the styles tells you what the author meant, and the image tells you what happened. Open the images rather than inferring them from the diff.
|
|
4
|
+
|
|
5
|
+
## When it applies
|
|
6
|
+
|
|
7
|
+
The diff touches a file that paints: markup, a stylesheet, a component or template, a design token file, a rendered document source, or a path a `canon/wireframes/` surface file names. Or the pull request carries an evidence comment, whatever the diff touches.
|
|
8
|
+
|
|
9
|
+
## First, check that a screenshot exists
|
|
10
|
+
|
|
11
|
+
Run this before any other section, since a pass that finds nothing to open otherwise reads the stylesheet instead and reports as if it had looked. Read its answer before composing any report or body, never in the same batch as the write, since what it decides is a finding the report has to carry.
|
|
12
|
+
|
|
13
|
+
Read `gh pr view <number> --json comments,headRefOid` and take the comment whose body carries a `<!-- pr-evidence: head=<sha> -->` marker. Match the marker, never the first line, since the body opens with a `**Preview:**` line when the project has a preview address.
|
|
14
|
+
|
|
15
|
+
Flag the change as shipping no screenshot when it paints and the pull request carries no marked comment, carries one with no `## Evidence` section, or carries only a checklist posted alone. Then decide how to raise it by whether the project keeps captures, which is the same test `canon pr evidence` applies:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
git ls-tree -r --name-only <base> | grep -E '(^|/)evidence/.*\.(png|jpe?g|gif|webp|avif|svg)$' | head -1
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- A path prints: the project keeps captures and this change skipped them. File it as a finding against the pull request.
|
|
22
|
+
- Nothing prints: raise it as a question with no severity, since a project with no capture harness would otherwise take the flag on every styling change.
|
|
23
|
+
|
|
24
|
+
Stop reading this reference once the flag is raised, since there is nothing to open. Otherwise continue with the comment in hand.
|
|
25
|
+
|
|
26
|
+
## Reading the comment
|
|
27
|
+
|
|
28
|
+
Compare the marker's head with `headRefOid`. When it trails, the images describe an older head. Name which later commits touched a painting file, and read the images as evidence about that older head only.
|
|
29
|
+
|
|
30
|
+
## Opening the images
|
|
31
|
+
|
|
32
|
+
Each row embeds `github.com/<repo>/blob/<sha>/<path>?raw=true`. A session cannot fetch that address from a private repository, so never follow it and never report an image you did not open. Fetch the head instead:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git fetch -q origin pull/<number>/head
|
|
36
|
+
mkdir -p .canon/tmp/pr/review/evidence/<number>
|
|
37
|
+
git show <sha>:<path> > .canon/tmp/pr/review/evidence/<number>/<side>-<name>.png
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Take the sha from the row, so the base and head sides are exactly what the comment shows. Then open each file with the file-reading tool. A `*(new)*` base cell has no before image.
|
|
41
|
+
|
|
42
|
+
## How many to open
|
|
43
|
+
|
|
44
|
+
Open at most 12 images per pass, filled in this order:
|
|
45
|
+
|
|
46
|
+
1. Every image a ticked checklist box or the `Seen at:` line names
|
|
47
|
+
2. The head side of each state at its narrowest and widest captured width, in one theme
|
|
48
|
+
3. The base side, only for a state whose head image looks wrong or whose diff was meant to change appearance
|
|
49
|
+
|
|
50
|
+
A second theme earns a read only when the diff touches a color token. Name the states left unopened on one line, as a note rather than a finding, so the reader knows what the pass did not see.
|
|
51
|
+
|
|
52
|
+
## Comparing
|
|
53
|
+
|
|
54
|
+
Read `canon/wireframes/index.md` and open only the surface files the evidence states map to. Check each opened image for the layout, the order of regions, and the behavior at that width the surface file states. Check `canon/DESIGN.md` for the tokens the image makes visible: color, type scale, spacing, and component rules.
|
|
55
|
+
|
|
56
|
+
Read the width and theme from whatever the image path carries, and fix no width list, since which widths matter belongs to the project. Skip a comparison silently when the project has no wireframe or design file.
|
|
57
|
+
|
|
58
|
+
A finding names the wireframe or design-file line the image breaks, never a taste.
|
|
59
|
+
|
|
60
|
+
## The checklist
|
|
61
|
+
|
|
62
|
+
The `## What to look at` block between the `pr-checklist` markers is the author's claim about what was verified.
|
|
63
|
+
|
|
64
|
+
- Test each ticked box against an opened image showing the state and width it names. Flag a box whose image contradicts it, quoting the box.
|
|
65
|
+
- A ticked box no image covers is untested rather than confirmed, and the finding says so.
|
|
66
|
+
- Read the `**Widths:**` block's `Seen at:` line against the widths the images carry.
|
|
67
|
+
- Test only the rows the current comment shows. A box ticked on an earlier head can describe images the comment no longer carries.
|
|
68
|
+
- Leave unchecked boxes to the procedure's own read of the description.
|
|
69
|
+
|
|
70
|
+
## With no pull request
|
|
71
|
+
|
|
72
|
+
A local review has no comment to read. Read each changed image under an `evidence/` path segment from the working tree, and its base side with `git show <base>:<path>`. Read the checklist handoff at `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root when it exists. A painting change with no changed evidence image takes the flag from the first section, decided by the same `git ls-tree` test.
|
|
@@ -22,6 +22,7 @@ Scoping a later pass off GitHub's review stamp skipped real work. On 2026-09-07
|
|
|
22
22
|
- Detect the pass from the thread rather than taking it from the caller, matching the heading for equality so a neighboring comment cannot be read as a prior pass
|
|
23
23
|
- Scope a later pass to the commits added since the prior one, once that commit is confirmed to still reach the head
|
|
24
24
|
- Apply the integration, contract, and consumer lenses a self-review structurally cannot
|
|
25
|
+
- Apply `canon:review-craft`'s axes and evidence bar, rendered output included, rather than carrying an axis list of its own
|
|
25
26
|
- Read each test the branch added or changed against `canon:test-craft`'s final filter, scoped to those files and never the suite
|
|
26
27
|
- Post the closing pass even with nothing to report, since a review left unanswered reads as one nobody closed
|
|
27
28
|
- State a withdrawal or a regrade on the thread with the fact that settled it, since a finding dropped in silence reads the same as one nobody answered
|
|
@@ -63,7 +63,7 @@ Read `${CLAUDE_SKILL_DIR}/references/scope.md` for finding the commit and verdic
|
|
|
63
63
|
|
|
64
64
|
## Step 3: review
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Invoke `canon:review-craft` with the skill tool now, and read nothing for findings until it has loaded, whatever the diff's size. It carries what to look for and how much evidence a finding needs, rendered output included, and this step carries no axis list of its own to fall back on. Read the diff and files against its axes. Add the two that stay here: rule violations, and checkout assumptions in a shipped file. Report it rather than proceeding silently when the skill does not resolve. Then add the three lenses a self-review structurally cannot apply:
|
|
67
67
|
|
|
68
68
|
- Integration: does this fit the board's order, the shared wiring seam, and any sibling PR in flight?
|
|
69
69
|
- Contract: does a contract downstream features depend on land correctly, and should the plan itself be questioned?
|
|
@@ -13,7 +13,7 @@ Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a
|
|
|
13
13
|
|
|
14
14
|
When `<prior-oid>` from Step 2 equals `headRefOid`, the head repeats and the folder already holds `body-<number>-<short-sha>.md`. Add a third segment taking the id of the reply Step 2 resolved, giving `body-<number>-<short-sha>-r<comment-id>.md`, which is `<body-file>` on that path. That satisfies both prohibitions above rather than carving an exception into either. Step 2 already stopped the pass when that resolution came back empty, so reaching this line means the comment id is in hand.
|
|
15
15
|
|
|
16
|
-
The comment is a rendered-for-human GitHub surface, so load the `write-human` skill for voice and follow `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for
|
|
16
|
+
The comment is a rendered-for-human GitHub surface, so load the `write-human` skill for voice and word choice and follow `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for punctuation: cut editorializing, and keep every sentence load-bearing. Match this shape on a first pass:
|
|
17
17
|
|
|
18
18
|
```markdown
|
|
19
19
|
## Review
|
|
@@ -70,7 +70,7 @@ Take the comparison at the file path rather than at a folder above it. `canon ta
|
|
|
70
70
|
|
|
71
71
|
The finding names which row contributed the containing path, and a bare-folder cell reports as a claim of its own beside the findings. Read that output as a candidate list, settle each pair by file, and narrow the cell that over-claimed rather than discounting the collision it caused.
|
|
72
72
|
|
|
73
|
-
A declared set is what a branch sets out to write rather than a bound on it, so this gate clears against a prediction and the branch outgrows it hours later. A track can cross the set it cleared against and still merge clean, which is a gate reporting disjoint while a real overlap stood. Two classes account for nearly all of the crossing. The ship chain's own steps write past every plan, since `canon:
|
|
73
|
+
A declared set is what a branch sets out to write rather than a bound on it, so this gate clears against a prediction and the branch outgrows it hours later. A track can cross the set it cleared against and still merge clean, which is a gate reporting disjoint while a real overlap stood. Two classes account for nearly all of the crossing. The ship chain's own steps write past every plan, since `canon:context-fold` refreshes whichever context entry a change reaches and `canon:docs-sync` reaches the public docs, and neither surface is one a planner can name before the change exists. The drift stages `bun run check` regenerates and asserts are the second, together with the test and sandbox siblings a source change drags in. Nothing here prevents either, because the files at issue are written long after this gate clears. What reads the other end is `canon tasks plan-reach`, which `canon:git-ship` runs at step 5 against the branch's own diff, so a crossing this gate could not see is named before the pull request opens rather than after it merges.
|
|
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
|
|