@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.
Files changed (152) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/auto-ship/SKILL.md +29 -115
  3. package/claude/skills/auto-ship/references/draft-mark.md +30 -0
  4. package/claude/skills/auto-ship/references/failure-recovery.md +27 -0
  5. package/claude/skills/auto-ship/references/tier-failures.md +26 -0
  6. package/claude/skills/auto-ship/references/verb-absent.md +37 -0
  7. package/claude/skills/auto-ship/references/worktree-name.md +22 -0
  8. package/claude/skills/backlog-triage/REQUIREMENT.md +47 -0
  9. package/claude/skills/backlog-triage/SKILL.md +139 -0
  10. package/claude/skills/bash-script/SKILL.md +1 -1
  11. package/claude/skills/bash-script/references/patterns.md +0 -99
  12. package/claude/skills/bash-script/references/prompts.md +100 -0
  13. package/claude/skills/canon-rollout/SKILL.md +6 -6
  14. package/claude/skills/context-fold/REQUIREMENT.md +75 -0
  15. package/claude/skills/context-fold/SKILL.md +162 -0
  16. package/claude/skills/{docs-fold → context-fold}/references/anchor-sweep.md +1 -1
  17. package/claude/skills/{docs-fold → context-fold}/references/classify.md +4 -2
  18. package/claude/skills/context-fold/references/context-refresh.md +48 -0
  19. package/claude/skills/context-fold/references/promoted-pages.md +29 -0
  20. package/claude/skills/context-fold/references/receipt-sweep.md +43 -0
  21. package/claude/skills/context-fold/references/unusable-baseline.md +25 -0
  22. package/claude/skills/{docs-fold → context-fold}/references/wireframe-sweep.md +1 -1
  23. package/claude/skills/create-skill/SKILL.md +1 -1
  24. package/claude/skills/create-snippet/SKILL.md +1 -1
  25. package/claude/skills/create-standard/SKILL.md +1 -1
  26. package/claude/skills/design-extract/SKILL.md +1 -1
  27. package/claude/skills/design-taste/REQUIREMENT.md +2 -2
  28. package/claude/skills/docs-fold/REQUIREMENT.md +8 -58
  29. package/claude/skills/docs-fold/SKILL.md +3 -278
  30. package/claude/skills/docs-sync/REQUIREMENT.md +1 -1
  31. package/claude/skills/docs-sync/SKILL.md +2 -2
  32. package/claude/skills/draft-context/REQUIREMENT.md +2 -2
  33. package/claude/skills/draft-context/SKILL.md +4 -4
  34. package/claude/skills/draft-docs/REQUIREMENT.md +1 -1
  35. package/claude/skills/draft-docs/SKILL.md +1 -1
  36. package/claude/skills/draft-figure/SKILL.md +1 -1
  37. package/claude/skills/draft-readme/SKILL.md +1 -1
  38. package/claude/skills/draft-wiki/SKILL.md +1 -1
  39. package/claude/skills/draft-wireframes/REQUIREMENT.md +1 -1
  40. package/claude/skills/draft-wireframes/SKILL.md +3 -3
  41. package/claude/skills/git-issue/SKILL.md +1 -1
  42. package/claude/skills/git-issue/references/issue.md +1 -1
  43. package/claude/skills/git-pr/SKILL.md +9 -147
  44. package/claude/skills/git-pr/references/evidence.md +114 -0
  45. package/claude/skills/git-pr/references/labels.md +20 -0
  46. package/claude/skills/git-pr/references/task-number.md +26 -0
  47. package/claude/skills/git-ship/SKILL.md +1 -1
  48. package/claude/skills/git-stage/SKILL.md +1 -1
  49. package/claude/skills/memory-capture/REQUIREMENT.md +2 -2
  50. package/claude/skills/memory-capture/SKILL.md +6 -6
  51. package/claude/skills/memory-review/REQUIREMENT.md +1 -1
  52. package/claude/skills/memory-review/SKILL.md +5 -101
  53. package/claude/skills/memory-review/references/later-phases.md +108 -0
  54. package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
  55. package/claude/skills/restate-plainly/REQUIREMENT.md +1 -1
  56. package/claude/skills/review-address/REQUIREMENT.md +1 -1
  57. package/claude/skills/review-address/SKILL.md +5 -4
  58. package/claude/skills/review-branch/REQUIREMENT.md +1 -0
  59. package/claude/skills/review-branch/SKILL.md +6 -7
  60. package/claude/skills/review-craft/REQUIREMENT.md +43 -0
  61. package/claude/skills/review-craft/SKILL.md +50 -0
  62. package/claude/skills/review-craft/references/security.md +21 -0
  63. package/claude/skills/review-craft/references/ui.md +72 -0
  64. package/claude/skills/review-pr/REQUIREMENT.md +1 -0
  65. package/claude/skills/review-pr/SKILL.md +1 -1
  66. package/claude/skills/review-pr/references/post.md +1 -1
  67. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
  68. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -0
  69. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
  70. package/claude/skills/role-planner/REQUIREMENT.md +1 -1
  71. package/claude/skills/session-resume/REQUIREMENT.md +1 -1
  72. package/claude/skills/session-worktree/SKILL.md +4 -10
  73. package/claude/skills/standards-audit/SKILL.md +1 -1
  74. package/claude/skills/task-board/REQUIREMENT.md +1 -1
  75. package/claude/skills/task-board/SKILL.md +6 -80
  76. package/claude/skills/task-board/references/archive.md +54 -0
  77. package/claude/skills/task-board/references/decline.md +40 -0
  78. package/claude/skills/teach-workspace/SKILL.md +8 -105
  79. package/claude/skills/teach-workspace/references/lesson-craft.md +51 -1
  80. package/claude/skills/teach-workspace/references/promotion.md +41 -0
  81. package/claude/skills/write-human/REQUIREMENT.md +7 -4
  82. package/claude/skills/write-human/SKILL.md +4 -2
  83. package/claude/skills/write-human/references/machine-tells.md +1 -1
  84. package/claude/skills/write-human/references/source-material.md +5 -2
  85. package/docs/agents/architecture-record.md +26 -0
  86. package/docs/agents/audits.md +1 -1
  87. package/docs/agents/commands.md +87 -154
  88. package/docs/agents/context-audit-checks.md +2 -20
  89. package/docs/agents/context-audit.md +1 -1
  90. package/docs/agents/context-classify.md +1 -1
  91. package/docs/agents/drift-surfaces.md +192 -0
  92. package/docs/agents/index.md +12 -4
  93. package/docs/agents/install-and-sync.md +2 -181
  94. package/docs/agents/markdown-audit-weight.md +73 -0
  95. package/docs/agents/markdown-audit.md +11 -104
  96. package/docs/agents/migrate.md +34 -0
  97. package/docs/agents/pr-local.md +6 -3
  98. package/docs/agents/records-stale.md +62 -0
  99. package/docs/agents/records.md +5 -1
  100. package/docs/agents/sandbox.md +1 -1
  101. package/docs/agents/tasks-archive.md +81 -0
  102. package/docs/agents/tasks-plans.md +147 -0
  103. package/docs/agents/tasks-validate.md +131 -0
  104. package/docs/agents/tasks.md +6 -333
  105. package/docs/target-projects.md +4 -4
  106. package/docs/workflow/ai-workflow.md +33 -27
  107. package/governance/rules/claude/500-prose.md +1 -1
  108. package/governance/rules/claude/501-markdown.md +3 -3
  109. package/governance/rules/core/045-memory.md +1 -1
  110. package/package.json +1 -1
  111. package/src/autoship/paths.ts +3 -2
  112. package/src/claude/cases/setup.ts +1 -1
  113. package/src/claude/cases/workflow.ts +27 -1
  114. package/src/commands/audits.ts +2 -2
  115. package/src/commands/markdown.ts +7 -9
  116. package/src/commands/pr.ts +11 -4
  117. package/src/commands/records.ts +146 -0
  118. package/src/commands/sandbox.ts +6 -4
  119. package/src/context/classify/extract.ts +1 -1
  120. package/src/context/classify/ollama.ts +1 -1
  121. package/src/context/classify/run.ts +1 -1
  122. package/src/gate/measures.ts +5 -5
  123. package/src/gate/stages.ts +0 -1
  124. package/src/markdown/bans.ts +11 -68
  125. package/src/markdown/gate.ts +1 -1
  126. package/src/markdown/scan.ts +7 -88
  127. package/src/migrate/skill-names.ts +15 -2
  128. package/src/records/stale.ts +243 -0
  129. package/src/sandbox/expect.ts +1 -1
  130. package/src/tasks/archive.ts +28 -4
  131. package/src/tasks/record.ts +1 -1
  132. package/src/tasks/validate.ts +36 -3
  133. package/standards/docs.md +1 -1
  134. package/standards/index.md +1 -1
  135. package/standards/markdown.md +5 -7
  136. package/standards/memory.md +13 -1
  137. package/standards/pr.md +1 -1
  138. package/standards/publish.md +1 -1
  139. package/standards/readme.md +2 -2
  140. package/standards/tasks.md +1 -1
  141. package/tooling/astro/reference.md +1 -1
  142. package/tooling/base/configs/.husky/post-merge +1 -1
  143. package/tooling/base/configs/scripts/verify.sh +2 -2
  144. package/tooling/base/seeds/canon/context/development.md +1 -1
  145. package/tooling/claude/reference.md +1 -1
  146. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +5 -6
  147. package/tooling/go/reference.md +1 -1
  148. package/tooling/nextjs/reference.md +1 -1
  149. package/tooling/php/reference.md +1 -1
  150. package/tooling/python/reference.md +1 -1
  151. package/tooling/vite-react/reference.md +1 -1
  152. 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 `docs-fold` the same way capture does rather than editing the entry here.
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 `/docs-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.
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 below rewrite items inside an existing receipt rather than authoring one, so none of them opens it.
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 phase
102
+ ## Challenge, Discuss, Apply, and Cleanup phases
103
103
 
104
- 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.
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 `docs-fold` owns
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 words, characters, and spellings, which `markdown.md` states and the audit gates
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 `docs-fold` owns
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 `docs-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, `docs-fold` flags it rather than creating one.
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 `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for
111
- the banned words, and keep each mapping to a line or two.
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 the banned words, 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
+ 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. Bugs and edge cases
65
- 2. Error handling gaps
66
- 3. Logic flaws that will cause problems when the code is extended
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 `docs-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.
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
- Review the diff and files for the same axes as `review-branch` (bugs, edge cases, error handling, logic flaws, security, rule violations, checkout assumptions in a shipped file), then add the three lenses a self-review structurally cannot apply:
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 the banned words: cut editorializing, and keep every sentence load-bearing. Match this shape on a first pass:
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:docs-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.
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