@erclx/canon 5.41.0 → 5.43.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 (220) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/api-design/references/adopted.md +34 -14
  3. package/claude/skills/auto-ship/REQUIREMENT.md +1 -0
  4. package/claude/skills/auto-ship/SKILL.md +24 -4
  5. package/claude/skills/auto-ship/references/draft-mark.md +32 -6
  6. package/claude/skills/auto-ship/references/failure-recovery.md +15 -13
  7. package/claude/skills/auto-ship/references/tier-failures.md +31 -10
  8. package/claude/skills/auto-ship/references/ui-checklist.md +9 -4
  9. package/claude/skills/auto-ship/references/worktree-name.md +9 -3
  10. package/claude/skills/build-in-slices/references/adopted.md +35 -21
  11. package/claude/skills/canvas-board/references/canvas.md +17 -6
  12. package/claude/skills/canvas-board/references/design.md +26 -7
  13. package/claude/skills/ci-workflow/REQUIREMENT.md +2 -1
  14. package/claude/skills/ci-workflow/SKILL.md +12 -2
  15. package/claude/skills/ci-workflow/references/workflows.md +12 -9
  16. package/claude/skills/code-craft/references/adopted.md +58 -20
  17. package/claude/skills/codebase-layout/references/adopted.md +49 -16
  18. package/claude/skills/codebase-layout/references/frontend.md +11 -4
  19. package/claude/skills/codebase-layout/references/tests.md +4 -2
  20. package/claude/skills/context-fold/references/classify.md +10 -15
  21. package/claude/skills/context-fold/references/completion-report.md +11 -9
  22. package/claude/skills/context-fold/references/context-refresh.md +26 -9
  23. package/claude/skills/context-fold/references/unusable-baseline.md +5 -3
  24. package/claude/skills/create-rule/REQUIREMENT.md +5 -0
  25. package/claude/skills/create-rule/SKILL.md +10 -1
  26. package/claude/skills/create-rule/references/checklist.md +26 -0
  27. package/claude/skills/create-rule/references/rule.md +98 -20
  28. package/claude/skills/create-skill/SKILL.md +1 -0
  29. package/claude/skills/create-skill/references/skill-disclosure.md +10 -2
  30. package/claude/skills/create-skill/references/skill-frontmatter.md +43 -0
  31. package/claude/skills/create-skill/references/skill-paths.md +7 -4
  32. package/claude/skills/create-skill/references/skill-practice.md +6 -3
  33. package/claude/skills/create-skill/references/skill-requirement.md +4 -2
  34. package/claude/skills/create-skill/references/skill.md +67 -44
  35. package/claude/skills/decision-escalate/SKILL.md +1 -2
  36. package/claude/skills/deploy-app/references/vercel.md +2 -1
  37. package/claude/skills/deprecation-migration/references/adopted.md +44 -25
  38. package/claude/skills/design-taste/references/adopted.md +9 -1
  39. package/claude/skills/design-taste/references/craft.md +3 -1
  40. package/claude/skills/design-taste/references/kinds.md +8 -7
  41. package/claude/skills/design-taste/references/preflight.md +12 -0
  42. package/claude/skills/design-taste/references/systems.md +7 -6
  43. package/claude/skills/design-taste/references/tells.md +24 -25
  44. package/claude/skills/design-taste/references/vocabulary.md +7 -5
  45. package/claude/skills/document-health/references/axes.md +55 -30
  46. package/claude/skills/draft-and-pick/references/live-arms.md +2 -2
  47. package/claude/skills/draft-doc/references/context.md +4 -3
  48. package/claude/skills/draft-doc/references/docs.md +6 -3
  49. package/claude/skills/draft-doc/references/readme/agent-facing.md +6 -0
  50. package/claude/skills/draft-doc/references/readme/application.md +8 -2
  51. package/claude/skills/draft-doc/references/readme/cli.md +5 -1
  52. package/claude/skills/draft-doc/references/readme/library.md +4 -0
  53. package/claude/skills/draft-doc/references/readme/plugin.md +9 -1
  54. package/claude/skills/draft-doc/references/readme.md +30 -13
  55. package/claude/skills/draft-doc/references/requirements.md +17 -4
  56. package/claude/skills/draft-doc/references/wiki-kind.md +20 -10
  57. package/claude/skills/draft-doc/references/wiki.md +1 -1
  58. package/claude/skills/draft-figure/references/architecture-set.md +7 -3
  59. package/claude/skills/draft-figure/references/figures.md +8 -6
  60. package/claude/skills/draft-figure/references/hand-drawn.md +3 -1
  61. package/claude/skills/draft-figure/references/mermaid-path.md +19 -9
  62. package/claude/skills/draft-figure/references/mermaid.md +10 -5
  63. package/claude/skills/draft-ready/references/ready.md +22 -15
  64. package/claude/skills/git-branch/references/branch.md +11 -1
  65. package/claude/skills/git-branch/references/slug.md +17 -5
  66. package/claude/skills/git-commit/references/commit.md +9 -5
  67. package/claude/skills/git-commit/references/versioning.md +23 -17
  68. package/claude/skills/git-followup/REQUIREMENT.md +1 -1
  69. package/claude/skills/git-followup/SKILL.md +5 -6
  70. package/claude/skills/git-issue/references/issue.md +29 -16
  71. package/claude/skills/git-pr/REQUIREMENT.md +1 -5
  72. package/claude/skills/git-pr/SKILL.md +11 -22
  73. package/claude/skills/git-pr/references/final-command.md +21 -8
  74. package/claude/skills/git-pr/references/labels.md +45 -28
  75. package/claude/skills/git-pr/references/pr.md +29 -9
  76. package/claude/skills/git-pr/references/publish.md +42 -28
  77. package/claude/skills/git-pr/references/task-number.md +20 -8
  78. package/claude/skills/git-ship/SKILL.md +1 -1
  79. package/claude/skills/plan-feature/SKILL.md +1 -1
  80. package/claude/skills/plan-feature/references/plan-lifecycle.md +10 -3
  81. package/claude/skills/plan-feature/references/plan.md +58 -21
  82. package/claude/skills/plan-groundwork/references/groundwork-spikes.md +4 -1
  83. package/claude/skills/plan-groundwork/references/groundwork.md +14 -16
  84. package/claude/skills/plan-intake/references/intake.md +29 -24
  85. package/claude/skills/pr-evidence/REQUIREMENT.md +40 -0
  86. package/claude/skills/pr-evidence/SKILL.md +53 -0
  87. package/claude/skills/pr-evidence/references/evidence.md +150 -0
  88. package/claude/skills/review-address/references/post-review-findings.md +10 -3
  89. package/claude/skills/review-address/references/rebase-conflicts.md +15 -7
  90. package/claude/skills/review-address/references/rest-reads.md +3 -1
  91. package/claude/skills/review-craft/references/adopted.md +35 -18
  92. package/claude/skills/review-craft/references/security.md +42 -7
  93. package/claude/skills/review-craft/references/ui.md +23 -8
  94. package/claude/skills/review-pr/SKILL.md +6 -6
  95. package/claude/skills/review-pr/references/body-variants.md +29 -9
  96. package/claude/skills/review-pr/references/close-out.md +20 -5
  97. package/claude/skills/review-pr/references/key-changes.md +27 -3
  98. package/claude/skills/review-pr/references/post.md +83 -31
  99. package/claude/skills/review-pr/references/scope.md +54 -19
  100. package/claude/skills/review-ui/references/close-out.md +7 -5
  101. package/claude/skills/review-ui/references/driving.md +24 -4
  102. package/claude/skills/review-ui/references/post.md +43 -15
  103. package/claude/skills/role-orchestrator/SKILL.md +2 -0
  104. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +67 -17
  105. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +80 -40
  106. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +52 -15
  107. package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +48 -26
  108. package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +12 -13
  109. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +72 -36
  110. package/claude/skills/role-orchestrator/references/orchestrator-output.md +16 -4
  111. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +64 -24
  112. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +80 -26
  113. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +41 -18
  114. package/claude/skills/role-orchestrator/references/orchestrator-resume.md +19 -7
  115. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +22 -12
  116. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +15 -6
  117. package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +25 -7
  118. package/claude/skills/role-orchestrator/references/orchestrator-watch.md +34 -8
  119. package/claude/skills/role-orchestrator/scripts/poll.ts +16 -24
  120. package/claude/skills/role-planner/REQUIREMENT.md +1 -1
  121. package/claude/skills/role-planner/SKILL.md +3 -3
  122. package/claude/skills/role-worker/REQUIREMENT.md +3 -0
  123. package/claude/skills/role-worker/SKILL.md +34 -2
  124. package/claude/skills/search-craft/REQUIREMENT.md +1 -1
  125. package/claude/skills/search-craft/SKILL.md +2 -2
  126. package/claude/skills/search-craft/references/adopted.md +18 -6
  127. package/claude/skills/session-map/references/session.md +26 -7
  128. package/claude/skills/session-worktree/references/main-root-writes.md +25 -8
  129. package/claude/skills/systematic-debugging/references/adopted.md +30 -16
  130. package/claude/skills/target-check/references/domains.md +39 -11
  131. package/claude/skills/target-setup/references/detect.md +80 -65
  132. package/claude/skills/target-setup/references/indexes.md +8 -6
  133. package/claude/skills/task-board/references/board.md +86 -30
  134. package/claude/skills/task-board/references/decline.md +29 -13
  135. package/claude/skills/task-board/references/tasks-decline.md +12 -5
  136. package/claude/skills/task-board/references/tasks.md +65 -33
  137. package/claude/skills/task-complete/references/archive.md +41 -17
  138. package/claude/skills/task-complete/references/receipt-sweep.md +23 -9
  139. package/claude/skills/task-complete/references/unusable-baseline.md +10 -3
  140. package/claude/skills/teach-workspace/references/glossary.md +6 -2
  141. package/claude/skills/teach-workspace/references/lesson-build.md +44 -16
  142. package/claude/skills/teach-workspace/references/lesson-craft.md +12 -7
  143. package/claude/skills/teach-workspace/references/pedagogy.md +6 -3
  144. package/claude/skills/teach-workspace/references/promotion-fold.md +17 -11
  145. package/claude/skills/teach-workspace/references/promotion.md +31 -8
  146. package/claude/skills/teach-workspace/references/revisit.md +8 -2
  147. package/claude/skills/teach-workspace/references/teach.md +17 -9
  148. package/claude/skills/test-craft/references/adopted.md +48 -14
  149. package/claude/skills/test-craft/references/component.md +7 -4
  150. package/claude/skills/test-craft/references/e2e.md +25 -7
  151. package/claude/skills/test-craft/references/unit.md +3 -1
  152. package/claude/skills/test-first/references/adopted.md +12 -4
  153. package/claude/skills/ui-checklist/REQUIREMENT.md +1 -1
  154. package/claude/skills/ui-checklist/SKILL.md +1 -1
  155. package/claude/skills/video-craft/references/adopted.md +62 -18
  156. package/claude/skills/write-human/references/adopted.md +21 -8
  157. package/docs/agents/audits.md +1 -0
  158. package/docs/agents/migrate.md +11 -8
  159. package/docs/target/migrations.md +11 -0
  160. package/docs/workflow/parallel-features.md +1 -1
  161. package/docs/workflow/skill-map.md +1 -0
  162. package/governance/detect.toml +4 -0
  163. package/governance/rules/canon/context.md +2 -1
  164. package/governance/rules/canon/plan.md +3 -5
  165. package/governance/rules/canon/scratch.md +3 -1
  166. package/governance/rules/canon/task-scope.md +2 -1
  167. package/governance/rules/canon/tasks.md +2 -1
  168. package/governance/rules/canon/worktrees.md +5 -2
  169. package/governance/rules/claude/output.md +7 -4
  170. package/governance/rules/claude/skill.md +6 -4
  171. package/governance/rules/tooling/ci-workflow.md +6 -39
  172. package/governance/rules/ui/design-reference.md +37 -0
  173. package/governance/rules/writing/markdown.md +2 -1
  174. package/package.json +6 -6
  175. package/src/audits/catalog.ts +42 -0
  176. package/src/claude/cases/workflow.ts +5 -0
  177. package/src/claude/settings.ts +8 -4
  178. package/src/commands/claude.ts +11 -1
  179. package/src/commands/gov.ts +198 -0
  180. package/src/commands/migrate.ts +121 -2
  181. package/src/commands/pr.ts +146 -105
  182. package/src/commands/tooling.ts +3 -3
  183. package/src/commands/worktrees.ts +49 -0
  184. package/src/gate/stages.ts +15 -0
  185. package/src/gov/audit.ts +440 -0
  186. package/src/listeners/belongs.ts +21 -0
  187. package/src/listeners/machine.ts +93 -0
  188. package/src/listeners/parse.ts +41 -0
  189. package/src/markdown/scope.ts +144 -0
  190. package/src/migrate/session-defaults.ts +138 -0
  191. package/src/pr/lift.ts +6 -3
  192. package/src/pr/local.ts +4 -69
  193. package/src/pr/review-state.ts +182 -0
  194. package/src/sync/check.ts +15 -0
  195. package/src/tooling/stamp.ts +56 -12
  196. package/src/worktrees/stop.ts +92 -0
  197. package/tooling/base/configs/.github/workflows/phase-label-gate.yml +6 -2
  198. package/tooling/base/configs/commitlint.config.js +0 -20
  199. package/tooling/base/reference.md +1 -1
  200. package/tooling/base/seeds/.github/workflows/verify.yml +4 -1
  201. package/tooling/claude/reference.md +13 -7
  202. package/tooling/claude/seeds/.claude/settings.json +4 -0
  203. package/tooling/claude/user/settings.template.json +0 -4
  204. package/tooling/cloudflare/configs/.github/workflows/deploy.yml +5 -5
  205. package/tooling/public/configs/.github/dependabot.yml +12 -0
  206. package/tooling/public/configs/.github/workflows/release-please.yml +30 -0
  207. package/tooling/public/manifest.toml +8 -0
  208. package/tooling/public/reference.md +53 -0
  209. package/tooling/public/seeds/.github/ISSUE_TEMPLATE/bug.yml +48 -0
  210. package/tooling/public/seeds/.github/ISSUE_TEMPLATE/config.yml +5 -0
  211. package/tooling/public/seeds/.github/ISSUE_TEMPLATE/feature.yml +16 -0
  212. package/tooling/public/seeds/.release-please-manifest.json +3 -0
  213. package/tooling/public/seeds/CONTRIBUTING.md +50 -0
  214. package/tooling/public/seeds/LICENSE +21 -0
  215. package/tooling/public/seeds/SECURITY.md +13 -0
  216. package/tooling/public/seeds/release-please-config.json +12 -0
  217. package/tooling/shell/configs/.github/workflows/shell.yml +4 -1
  218. package/tooling/web/configs/.github/workflows/readme-screenshot.yml +6 -3
  219. package/tooling/web/configs/.github/workflows/verify.yml +15 -12
  220. package/claude/skills/git-pr/references/evidence.md +0 -124
@@ -85,7 +85,8 @@ export const STALE_AFTER = 7200
85
85
  // so a heading added in one of them breaks a test here that no check reaches
86
86
  // across. The review family reaches this file through `canon pr review-state`,
87
87
  // so its two headings are pinned only for the fallback that answers a target
88
- // whose CLI predates that verb.
88
+ // whose CLI predates that verb. The UI family reaches it through the same
89
+ // record and is pinned nowhere here.
89
90
  const REVIEW_HEADINGS = ['## Review', '## Review closed']
90
91
  const REPLY_HEADINGS = [
91
92
  '## Review response',
@@ -95,8 +96,6 @@ const REPLY_HEADINGS = [
95
96
  // An evidence comment answers no review, so it stays out of the reply family
96
97
  // and is excluded from the unmatched filter on its own.
97
98
  const KNOWN_HEADINGS = [...REVIEW_HEADINGS, ...REPLY_HEADINGS, '## Evidence']
98
- const UI_HEADINGS = ['## UI review', '## UI review closed']
99
- const UI_MARKER = /^<!-- review-ui: head=([0-9a-f]{7,40}) -->$/
100
99
 
101
100
  const firstLine = (body: null | string | undefined): string =>
102
101
  (body ?? '').split('\n')[0].replace(/\r$/, '')
@@ -200,29 +199,22 @@ export const scopeFallback = (payload: Payload, now: number): Scope => {
200
199
  }
201
200
 
202
201
  /**
203
- * The UI family is posted as a pull request review, so it is read off
204
- * `reviews`. The newest UI heading decides the state, and the head it covered
205
- * comes from the marker on the body's last line, since the submission stamp
206
- * moves onto a commit pushed while the pass drove. A marker may name a short
207
- * sha, so coverage is a prefix match.
202
+ * Reads the UI family off the verb's record, so the poll and the lift agree on
203
+ * which head a close covers, a close carried across unpainted pushes included.
204
+ * A record carrying no `ui` object is a refusal or a CLI predating the field,
205
+ * and reads as unread, which leaves the baseline's value standing.
208
206
  */
209
- export const uiState = (payload: Payload, head: string): string => {
210
- const last = (payload.reviews ?? [])
211
- .filter((review) => UI_HEADINGS.includes(firstLine(review.body)))
212
- .at(-1)
213
- if (last === undefined) return 'none'
207
+ export const uiFromVerb = (record: unknown): string => {
208
+ if (typeof record !== 'object' || record === null) return ''
209
+ const ui = (record as Record<string, unknown>).ui
210
+ if (typeof ui !== 'object' || ui === null) return ''
214
211
 
215
- const heading = firstLine(last.body) === '## UI review' ? 'open' : 'closed'
216
- const lastLine = (last.body ?? '')
217
- .split('\n')
218
- .map((line) => line.replace(/\r$/, ''))
219
- .filter((line) => line !== '')
220
- .at(-1)
221
- const marked = lastLine === undefined ? null : UI_MARKER.exec(lastLine)
222
- const commit = marked?.[1] ?? last.commit?.oid ?? 'none'
223
- const covered = commit !== 'none' && head.startsWith(commit)
212
+ const fields = ui as Record<string, unknown>
213
+ if (fields.state !== 'open' && fields.state !== 'closed') return 'none'
214
+ const commit = typeof fields.commit === 'string' ? fields.commit : 'none'
215
+ const covered = fields.isCovered === true && commit !== 'none'
224
216
 
225
- return `${heading}-${covered ? 'head' : 'behind'}-${commit.slice(0, 7)}`
217
+ return `${fields.state}-${covered ? 'head' : 'behind'}-${commit.slice(0, 7)}`
226
218
  }
227
219
 
228
220
  /** Takes the first ten fields and ignores the rest, so a short or padded line still reads. */
@@ -792,7 +784,7 @@ const buildRow = (
792
784
  resp: replies.count,
793
785
  stale: stale.stale,
794
786
  staleFiles: stale.files,
795
- ui: uiState(payload, head),
787
+ ui: uiFromVerb(record),
796
788
  unmatchedCount: unmatched.count,
797
789
  unmatchedHeading: unmatched.heading,
798
790
  }
@@ -61,7 +61,7 @@ four carried at least one, caught only because the planner ran
61
61
  - Owe an announcement when the record lands, carrying the path and what the row got wrong, since the controller cannot watch the read happen
62
62
  - Owe a message before a block becomes an interactive prompt, since a session already waiting on input never reaches the tool round an inbound message drains at
63
63
  - Keep correcting the dispatcher a first-class move carrying its evidence, since a trial corrected a brief's premise, planned every row anyway, and carried the consequence into a plan question
64
- - Carry a talk clause for a launch whose operator is in the session, putting each open question to them, recording a settled pick in place, and owing a close message when they end the conversation, since a cold planner's halting rules contradict a brief that asks it to talk
64
+ - Carry a talk clause for a launch whose operator is in the session, putting each open question to them, recording a settled pick in place, sending an ask about a row now building to the controller rather than the worker, and owing a close message when they end the conversation, since a cold planner's halting rules contradict a brief that asks it to talk
65
65
  - Point at each of the three skills for its record's shape and the steps that write it
66
66
  - Defer the addressee resolution to `session-relay` and keep only the last-rung inference, which discriminates differently here than it does for a worker because a session in this role holds no feature branch either
67
67
 
@@ -101,10 +101,10 @@ One rung stays here because it differs between roles. Inference takes the sessio
101
101
 
102
102
  A launch whose brief says it is a talk session puts the operator in this one. Everything above holds, and the clause below changes how questions are answered and when the role ends. A launch carrying no such sentence takes none of this.
103
103
 
104
- - Put each open question to the operator through the structured question surface before writing the record, and record a settled pick in place per the plan standard
105
- - Never fill an `- Answer:` slot the operator did not answer
104
+ - Put each open question to the operator through the structured question surface before writing the record
105
+ - Record each pick per `### Overrides and settled questions` in `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`
106
106
  - Keep answering under `plan-feature`'s discussion rounds after the record lands, since the operator launched this session to keep talking.
107
- - Owe the landing announcement as usual, plus a close message when the operator ends the conversation.
107
+ - Owe the landing announcement as usual, plus a close message when the operator ends the conversation. Send an ask about a building row to the controller, never the worker.
108
108
  - Skip the before-prompt block message for a question put to the operator in the session. Keep it for a block the operator cannot answer, since a controller learns of a stall only from a message.
109
109
 
110
110
  The operator being present is an assumption the launch carries. A talk planner whose operator has walked away waits silently on its first question, so say what the session is waiting on in the turn it stops.
@@ -29,11 +29,14 @@ The draft mark fails from both ends. On 2026-08-31 four sessions re-drafted a pu
29
29
  - Owe an announcement the moment the pull request opens, carrying the number, the branch, and the task, since that transition is the one interval only the worker can observe
30
30
  - Carry a row the build turned up in the pull request announcement, and send it alone only when the session ends before a pull request opens, since the worker files no task file of its own and the channel is the row's only route
31
31
  - Carry a fan-in member's branch and head commit in its done message in place of a pull request number, and end its role at the push, since a member opens no pull request and its integrator fixes what the merge surfaces
32
+ - Send the controller the `canon pr review-state` record when a wait for the reviews times out, rather than waiting on, since a worker improvising that read stalled silently with both reviewers idle behind it
32
33
  - Owe a message before a block becomes an interactive prompt, since a session already waiting on input never reaches the tool round an inbound message drains at
33
34
  - Defer the addressee resolution to `session-relay` and keep only the operator ask and the last-rung inference, which discriminates here because a worker holds a feature branch and a controller does not, and which falls back to the roster and says so, since an operator's own launch names nobody
34
35
  - Keep refusing a dispatcher a first-class move carrying its evidence, since the halts measured so far were correct and the cost of each fell where it belonged
35
36
  - State that a held body may be older than the branch under it, since a plugin skill loads from the marketplace cache rather than from the working tree
36
37
  - Carry a talk clause for a launch whose operator is in the session, asking them at a judgment call and sending a close message when they end the conversation, since a cold worker's halt-toward-the-controller and merge-ends-the-role rules contradict a brief that asks it to talk
38
+ - Freeze the plan's scope at dispatch, sorting a late ask into a defect to fix, a follow-up row to report, or an addition the operator's word admits with its re-review cost stated, since intake 155 measured about four UI review rounds on one pull request from late asks, each re-running both reviews
39
+ - Own the local preview server for a painted diff, started as a tracked background command before the pull request opens, since a `no-server` read leaves the evidence comment and the UI reviewer without an address on the one path nobody watched being built (erclx/frameboard#1 and erclx/frameboard#4)
37
40
  - Point at `session-worktree`, `auto-ship`, and `review-address` for the steps each already owns
38
41
 
39
42
  ## Must not
@@ -36,9 +36,32 @@ A ready folder and the draft mark each carry work another session already did, s
36
36
 
37
37
  ### Overriding a plan question
38
38
 
39
- Rewrite an unanswered question's `- Suggested:` line as `overridden at execution to <pick>,` plus the measurement when this build decides against it, leaving `- Answer:` blank, per `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`.
39
+ Follow `### Overrides and settled questions` in `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md` when this build decides against a suggestion.
40
40
 
41
- Put the same deviation in one line under the open task's `## Findings`, opening with the bold source-and-date label `${CLAUDE_SKILL_DIR}/../task-board/references/tasks.md` fixes.
41
+ Open the task's `## Findings` line for an override with the bold source-and-date label `${CLAUDE_SKILL_DIR}/../task-board/references/tasks.md` fixes.
42
+
43
+ ### The preview server
44
+
45
+ A painted pull request needs a server in this worktree for `canon pr local` to find, and this session is the one with a lifetime to own it. `auto-ship` Step 5 decides whether the diff is painted, so this body restates no file test.
46
+
47
+ - Run `canon pr local --json` first and start nothing when `reason` reads `ok`
48
+ - Otherwise start the stack's `dev` script as a background command from the worktree root before the pull request step. `dev` follows the worktree, so a `review-address` fix shows on the same link.
49
+ - Wait up to 60 seconds for the verb to read `ok`, then ship either way. A stack with no `dev` script gets no start, and `pr-evidence` reports `no-server`.
50
+ - Never detach it with `nohup`, `setsid`, or `disown`, since the owning session is the stop. `canon worktrees reclaim` ends any listener left in a worktree it removes.
51
+
52
+ A hand-run `git-ship` or `git-pr` starts no server, since only a worker has a lifetime to own one.
53
+
54
+ ## Scope after dispatch
55
+
56
+ The plan is the scope from the dispatch on. A late ask restarts both reviews, and one pull request took about four UI review rounds from asks that arrived mid-build.
57
+
58
+ Sort each ask that arrives after dispatch three ways:
59
+
60
+ - A defect is a failed outcome or a regression in what the plan builds. Fix it in this build, and take every review finding on the pull request through `review-address` the same way.
61
+ - Anything else is a follow-up row. Do not build it. Reply with the follow-up wording, and report the row to the controller with its title, origin, and surface.
62
+ - Add it to this pull request only on the operator's word, never a bare controller or planner message without an amended plan. Before the commit, say that both reviews run again.
63
+
64
+ When the operator approves an addition through the controller, the controller amends the plan in place and sends the pointer, so the added scope stays checkable against the diff. Fall back to `session-relay`'s copyable block when no controller is live, and never drop the row.
42
65
 
43
66
  ## The board is read-only
44
67
 
@@ -78,6 +101,14 @@ Ask for the re-review as `review-address` Step 8 returns, carrying what was addr
78
101
  - Send a block out as a message before it becomes an interactive prompt.
79
102
  - Send nothing on progress. A worker reporting progress rebuilds, on this side of the channel, the poll the announcement retired on the other.
80
103
 
104
+ ### Waiting on the reviews
105
+
106
+ A worker that improvised this read polled issue comments, never saw a UI close posted as a review, and stalled with both reviewers idle. One verb reads it the way the lift does.
107
+
108
+ - Read review state only through `canon pr review-state`, never off issue comments, where neither review family posts
109
+ - Enter `canon pr review-state <number> --wait 1200 --json` again in the background after asking for the re-review, the same wait `auto-ship` Step 7 runs
110
+ - Send the controller that record on `timeout` rather than waiting on, since a silent wait past the deadline is the stall the verb exists to end
111
+
81
112
  ### Addressing
82
113
 
83
114
  Address the session the launch named, and the reviewer by its dispatch's sessionId, each as a `sessionId` rather than a name. `canon:session-relay` turns that id into an address and carries the send, falling back to a copyable block where no send tool exists.
@@ -99,6 +130,7 @@ A launch whose brief says it is a talk session puts the operator in this one. Ev
99
130
 
100
131
  - Ask the operator in the session through the structured question surface at a judgment call, rather than halting toward the controller
101
132
  - Put a plan question written as needing the operator's call to them directly
133
+ - Sort a late ask from the operator in place under the scope rule above, and send the controller the follow-up row rather than relaying the ask
102
134
  - Send the controller a close message when the operator ends the conversation, beside the announcements the channel above owes.
103
135
  - Keep the before-prompt block message for a block the operator cannot answer. A question put to the operator who is in the session needs none.
104
136
 
@@ -42,7 +42,7 @@ Access is a second gap a session cannot derive. Probed on 2026-10-02, Reddit ref
42
42
  ## Out of scope
43
43
 
44
44
  - The form a citation takes: the procedure or standard writing it
45
- - A Claude Code subject: the `claude-code-guide` agent, which `draft-doc`'s wiki sourcing step already routes to
45
+ - A Claude Code subject: a direct fetch of `https://code.claude.com/docs/llms.txt` and the `.md` page it names, as `draft-doc`'s wiki sourcing step already does
46
46
  - Image generation, which makes a picture rather than finding a source
47
47
  - Loading on every web search rather than on a research-shaped request: a hook matching `WebSearch`, planned on its own
48
48
  - Whether a session already scopes searches without the skill, which only a run on a fresh research request without it would show
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: search-craft
3
- description: Carries the thinking step a session takes before it searches outside the project, naming the field, deriving who that field treats as authoritative, and running a search scoped to those sources beside an open one, plus a dated note on which sites refuse access. Use before any outside search for evidence, papers, documentation, statistics, or opinion, when a procedure loads it at its sourcing step, or when asked "find me the strongest evidence on X", "where should I look for this", "what does the research say", "find papers on", "look up the docs for", or "what are people saying about". Do NOT use to format a citation, which belongs to the surface writing it, to source a Claude Code subject, which is the `claude-code-guide` agent, or to generate an image, which is not search.
3
+ description: Carries the thinking step a session takes before it searches outside the project, naming the field, deriving who that field treats as authoritative, and running a search scoped to those sources beside an open one, plus a dated note on which sites refuse access. Use before any outside search for evidence, papers, documentation, statistics, or opinion, when a procedure loads it at its sourcing step, or when asked "find me the strongest evidence on X", "where should I look for this", "what does the research say", "find papers on", "look up the docs for", or "what are people saying about". Do NOT use to format a citation, which belongs to the surface writing it, to source a Claude Code subject, which is a direct fetch of Anthropic's docs index, or to generate an image, which is not search.
4
4
  metadata:
5
5
  family: build
6
6
  ---
@@ -87,6 +87,6 @@ These flags fire after the search has run.
87
87
  ## What this delegates
88
88
 
89
89
  - The form a citation takes: the surface writing it, such as the standard the procedure writes to
90
- - A Claude Code subject: the `claude-code-guide` agent, which `draft-doc`'s wiki sourcing step routes to
90
+ - A Claude Code subject: a direct fetch of `https://code.claude.com/docs/llms.txt` and the `.md` page it names, as `draft-doc`'s wiki sourcing step does
91
91
  - Generating an image: whatever draws the surface, since making one is not search
92
92
  - Access code a session needs repeatedly: a `canon` verb, never a script in this skill
@@ -9,19 +9,31 @@ Three third-party research skills were read before this one was written. None of
9
9
 
10
10
  ## Adopted
11
11
 
12
- **Recording each route's failure.** [aghori3004/claude-research-stack](https://github.com/aghori3004/claude-research-stack) keeps one `research-sources` skill that orders sources cheapest first and writes down how each one fails. Adopted as the access note, which records a refusal a session hit rather than leaving the next session to learn it by failing.
12
+ ### Recording each route's failure
13
13
 
14
- **Calling the tools directly.** The same skill ships no wrapper scripts, so it calls the command-line tools and servers it names. Adopted as the rule to reach a keyless API with a plain request rather than writing a wrapper for one search.
14
+ [aghori3004/claude-research-stack](https://github.com/aghori3004/claude-research-stack) keeps one `research-sources` skill that orders sources cheapest first and writes down how each one fails. Adopted as the access note, which records a refusal a session hit rather than leaving the next session to learn it by failing.
15
15
 
16
- **Treating a paid route as the operator's call.** [rohunvora/x-research-skill](https://github.com/rohunvora/x-research-skill) reaches X through the official API at a cost per search page. Adopted as the stop before any route that pays or logs in, since that cost is one the operator decides rather than one a session discovers.
16
+ ### Calling the tools directly
17
+
18
+ The same skill ships no wrapper scripts, so it calls the command-line tools and servers it names. Adopted as the rule to reach a keyless API with a plain request rather than writing a wrapper for one search.
19
+
20
+ ### Treating a paid route as the operator's call
21
+
22
+ [rohunvora/x-research-skill](https://github.com/rohunvora/x-research-skill) reaches X through the official API at a cost per search page. Adopted as the stop before any route that pays or logs in, since that cost is one the operator decides rather than one a session discovers.
17
23
 
18
24
  ## Declined
19
25
 
20
- **A directory of sites per category.** None of the three is one, and each earns its keep on access and cost instead. A site list also rots with nobody noticing, so the body derives a field's authorities per question rather than reading them off a list.
26
+ ### A directory of sites per category
27
+
28
+ None of the three is one, and each earns its keep on access and cost instead. A site list also rots with nobody noticing, so the body derives a field's authorities per question rather than reading them off a list.
29
+
30
+ ### Reaching walled sites through a logged-in browser
31
+
32
+ `claude-research-stack` reaches Reddit and X through a desktop Chrome session holding the operator's login. Declined because the body never suggests working around a login.
21
33
 
22
- **Reaching walled sites through a logged-in browser.** `claude-research-stack` reaches Reddit and X through a desktop Chrome session holding the operator's login. Declined because the body never suggests working around a login.
34
+ ### A bundled engine
23
35
 
24
- **A bundled engine.** [mvanhorn/last30days-skill](https://github.com/mvanhorn/last30days-skill) is a Python engine with its own test suite and paid aggregators behind it. Declined because a skill here ships no code, and access a session needs repeatedly becomes a `canon` verb.
36
+ [mvanhorn/last30days-skill](https://github.com/mvanhorn/last30days-skill) is a Python engine with its own test suite and paid aggregators behind it. Declined because a skill here ships no code, and access a session needs repeatedly becomes a `canon` verb.
25
37
 
26
38
  ## Stated by no source
27
39
 
@@ -5,9 +5,11 @@ description: Filename and location, the sections a handoff carries, the write an
5
5
 
6
6
  # Session map reference
7
7
 
8
- Applies to `.canon/tasks/session-<slug>.md`. A session writes one before a compaction, because a compaction keeps conclusions and drops the reasoning that produced them. It is rewritten whenever the session that owns it learns something the next session would otherwise re-derive, and it is optional: a project whose sessions never approach a compaction carries none.
8
+ Applies to `.canon/tasks/session-<slug>.md`. A session writes one before a compaction, because a compaction keeps conclusions and drops the reasoning that produced them.
9
9
 
10
- Any session writes one. The role a session holds decides which sections it adds on top of the core, never whether it may write at all.
10
+ - Rewrite it whenever its owner learns something the next session would otherwise re-derive
11
+ - It is optional, and a project whose sessions never approach a compaction carries none
12
+ - Any session writes one. The role a session holds decides which sections it adds over the core, never whether it may write.
11
13
 
12
14
  ## Contents
13
15
 
@@ -70,14 +72,31 @@ Add a section only for content that fits none of the three and would otherwise b
70
72
 
71
73
  The `session-map` skill is the invocable route onto this procedure and holds no role, so a session reaching for a handoff without knowing this document exists still lands here. A session that arrives at this document directly follows the steps below unchanged.
72
74
 
73
- 1. Run `canon claude skills drift <the commit this session started from>` and record what it names under `## Standing cautions`. A skill body enters a session once and re-invoking the skill does not re-read the file, so the drift is worst at exactly this moment and a name here is a body the session has been following out of date. Recording a name is not acting on it, and the verb misses a body this session edited and has not committed. This step belongs to session length rather than to any role, so every writer runs it, and a refusal names the boundary of what the verb can read rather than a fault.
74
- 2. Recover that commit from how long the session has been running with `git log -1 --format=%H --before='<duration> ago'`, rounding the duration up rather than down. Nothing on the machine records it. A ref older than the oldest load over-reports, and confirming a name costs one read of the body, so the generous end is the safe one and a guess at the exact commit is not worth making. An empty result means no commit predates the window, so take the oldest commit the history holds and say which of the two the ref came from.
75
- 3. Write only what a compaction destroys and no other artifact already carries. The board holds the ordering and what each task waits on, a task file holds its own findings, and a measurement folder holds its track.
75
+ 1. Run `canon claude skills drift <the commit this session started from>` and record what it names under `## Standing cautions`.
76
+ 2. Recover that commit with `git log -1 --format=%H --before='<duration> ago'`, rounding the session's running time up rather than down.
77
+ 3. Write only what a compaction destroys and no other artifact already carries. The board holds the ordering, a task file its findings, and a measurement folder its track.
76
78
  4. Cite a commit, a task, or a file and line for every claim, so the next session can tell a read from a recall.
77
- 5. Fill a section from reasoning the session actually holds. A session with no cross-feature picture that fills `## State` from what is already in git has written a summary of the tree, which the reader can produce faster than they can read it.
79
+ 5. Fill a section from reasoning the session actually holds.
78
80
 
79
81
  Do not restate the board, and do not summarize the work that shipped, since version control already carries it.
80
82
 
83
+ ### Why the drift step
84
+
85
+ A skill body enters a session once, and re-invoking the skill does not re-read the file. Drift is worst at this moment, so a name here is a body the session followed out of date.
86
+
87
+ - Recording a name is not acting on it, and the verb misses a body this session edited and has not committed
88
+ - The step belongs to session length rather than any role, so every writer runs it. A refusal names the boundary of what the verb can read rather than a fault.
89
+
90
+ ### Recovering the start commit
91
+
92
+ Nothing on the machine records the start commit. A ref older than the oldest load over-reports, and confirming a name costs one read of the body, so the generous end is safe and an exact guess is not worth making.
93
+
94
+ An empty result means no commit predates the window. Take the oldest commit the history holds, and say which of the two the ref came from.
95
+
96
+ ### Filling from what the session holds
97
+
98
+ A session with no cross-feature picture that fills `## State` from git has written a summary of the tree. The reader produces that faster than they can read it.
99
+
81
100
  ## Reading one back
82
101
 
83
102
  - Read the newest map in the folder, by modification time, and treat it as the previous session's scratch rather than as a source
@@ -90,7 +109,7 @@ Do not restate the board, and do not summarize the work that shipped, since vers
90
109
  - Let the adding surface fix where its own section sits, so a role can place one between core sections where that reads better. The core order holds among the core sections alone.
91
110
  - Keep a section out of the core when a session holding no such role would leave it unfilled. An unfilled section teaches a reader to skip the file.
92
111
  - Cite the route onto `## Writing one` rather than restating the procedure, so the extension is the only thing the adding surface carries and the two cannot fall out of step
93
- - Carry a resume instruction inside the map itself when the routing to that instruction is what a compaction takes. The map survives what the instruction was loaded from, so each reaches a reader the other cannot.
112
+ - Carry a resume instruction inside the map when a compaction takes the routing to it. The map survives what the instruction was loaded from, so each reaches a reader the other cannot.
94
113
 
95
114
  ## Template
96
115
 
@@ -8,17 +8,34 @@ Shared session scratch, being `.canon/plans/`, `.canon/review/`, and `.canon/tas
8
8
  ## The refusal
9
9
 
10
10
  - The refusal is tool-scoped rather than path-scoped. `Edit` and `Write` are refused for every main-root path, `Read` resolves there normally, and `Bash` writes there.
11
- - A background session that entered no worktree at all meets the identical refusal writing to the main root, since the guard gates on isolation rather than on sitting inside a linked worktree.
12
- - The refusal names session isolation and points at a worktree copy. That copy is a second gitignored file no later session reads, so never take the redirect. The redirected write reports success, which is how a file gets lost with nothing saying so.
11
+ - A background session that entered no worktree meets the identical refusal, since the guard gates on isolation rather than on sitting inside a linked worktree.
12
+ - The refusal points at a worktree copy, a second gitignored file no later session reads, so never take the redirect
13
+ - The redirected write reports success, which is how a file gets lost with nothing saying so
13
14
 
14
15
  ## Route by what the write does to the file
15
16
 
16
- - A whole-file create goes out as one plain `Bash` command carrying a heredoc. Send `mkdir -p` for a missing folder as its own command first, since a `&&` compound is refused for complexity.
17
- - When the heredoc itself is refused, which can happen on a body quoting shell syntax, a session inside a linked worktree can `Write` the file there and copy it out with a two-argument `cp` to the main-root path. The copy carries no syntax to inspect.
18
- - A background session that entered no worktree has nothing to `Write` into, so it sends a short file as one `printf '%s\n'` command carrying each line as an argument. When the file is too long for that, it reports the refusal rather than taking the redirect.
19
- - A change inside a file that already exists goes through a `canon` verb that resolves the main root in-process, such as `canon tasks outcome` or `canon tasks pull-request`. Where no verb covers the edit, read the whole file and write it back whole through the heredoc route. Never reach for a stream editor, which rewrites the line it anchored to and exits zero on a non-match.
20
- - A delete or a move runs as one plain `rm` or `mv` per call rather than chained.
17
+ Each kind of write takes one route, and none of them is a stream editor.
18
+
19
+ | Write | Route |
20
+ | -------------------- | -------------------------------------------------------------------------------------------------------------- |
21
+ | Whole-file create | One plain `Bash` command carrying a heredoc |
22
+ | Change inside a file | A `canon` verb resolving the main root in-process, such as `canon tasks outcome` or `canon tasks pull-request` |
23
+ | Delete or move | One plain `rm` or `mv` per call rather than chained |
24
+
25
+ - Send `mkdir -p` for a missing folder as its own command first, since a `&&` compound is refused for complexity
26
+ - Where no verb covers an edit, read the whole file and write it back whole through the heredoc route
27
+ - Never reach for a stream editor, which rewrites the line it anchored to and exits zero on a non-match
28
+
29
+ ### When the heredoc is refused
30
+
31
+ A heredoc can be refused on a body quoting shell syntax. The fallback depends on whether the session has a worktree to write into.
32
+
33
+ - Inside a linked worktree, `Write` the file there and copy it out with a two-argument `cp` to the main-root path. The copy carries no syntax to inspect.
34
+ - A background session that entered no worktree sends a short file as one `printf '%s\n'` command carrying each line as an argument
35
+ - When the file is too long for that, report the refusal rather than taking the redirect
21
36
 
22
37
  ## The index cost
23
38
 
24
- A shell write skips every `PostToolUse` hook, since those match `Write|Edit|MultiEdit` and never fire on `Bash`. That costs nothing on `.canon/plans/` and `.canon/review/`, which no hook indexes, and costs the generated `index.md` on `.canon/tasks/`. Regenerate positionally after a shell write there, by an explicit `canon indexes regen` call, unless the verb that made the write already calls it, as `canon tasks archive` does.
39
+ A shell write skips every `PostToolUse` hook, since those match `Write|Edit|MultiEdit` and never fire on `Bash`. No hook indexes `.canon/plans/` or `.canon/review/`, so the cost lands on the generated `index.md` under `.canon/tasks/` alone.
40
+
41
+ Regenerate positionally after a shell write there, by an explicit `canon indexes regen` call. Skip it when the verb that made the write already calls it, as `canon tasks archive` does.
@@ -11,34 +11,48 @@ External sources were read and filtered rather than imported. This file is the r
11
11
 
12
12
  ### The four phases
13
13
 
14
- **Investigate, find the pattern, hypothesize, fix.** From `obra/superpowers@8ca22db`, [`skills/systematic-debugging/SKILL.md`](https://github.com/obra/superpowers/blob/8ca22dba9a94f28898bbce59f2537ff4d87c747d/skills/systematic-debugging/SKILL.md), 283 lines at that commit. The four-phase spine, the no-fix-before-investigation rule, and the three-attempt stop come from it, restated in a fraction of the length. Nothing records the commit the original port read, so this pin names the one read when the ledger was written rather than the one the port used.
14
+ **Investigate, find the pattern, hypothesize, fix.** From `obra/superpowers@8ca22db`, [`skills/systematic-debugging/SKILL.md`](https://github.com/obra/superpowers/blob/8ca22dba9a94f28898bbce59f2537ff4d87c747d/skills/systematic-debugging/SKILL.md), 283 lines at that commit.
15
15
 
16
- ### The investigation lifts
16
+ - The four-phase spine, the no-fix-before-investigation rule, and the three-attempt stop come from it, restated in a fraction of the length
17
+ - Nothing records the commit the original port read, so this pin names the one read when the ledger was written rather than the one the port used
17
18
 
18
- Each from `addyosmani/agent-skills@2686b620`, [`skills/debugging-and-error-recovery/SKILL.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/skills/debugging-and-error-recovery/SKILL.md), 300 lines at that commit.
19
+ ### Closing sections
19
20
 
20
- **Bisect for a regression.** Its localize step runs `git bisect` against a known good commit, with `git bisect run` driving the focused test. Adopted in phase 1 with the runner replaced by a placeholder for the project's own focused test command.
21
+ The excuses, red flags, and closing checklist follow the shape every practice skill in this toolkit carries, from `addyosmani/agent-skills@2686b620`, [`docs/skill-anatomy.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/docs/skill-anatomy.md).
21
22
 
22
- **Reduce to a minimal case.** Its reduce step strips code, config, and input until only the failure remains. Adopted as the opening step of phase 2, so phase 1 stays reproduce and locate, and the comparison against working code runs on the reduced case.
23
+ Each excuse row rebuts a reason a session gives to skip the investigation rather than an objection nobody raised. Three come from the source's own rationalizations table and the rest from this skill's earlier red flags.
23
24
 
24
- **The non-reproducible tree.** Its timing, environment, state, and truly-random branches, each with first moves. Adopted in phase 1 step 2 with the runtime names stripped. The random branch hands off to the no-root-cause section rather than to its alerting advice, since setting up an alert is a production concern outside a debugging session.
25
+ ### Default shelf
25
26
 
26
- **Error output as untrusted data.** Its rule that error messages, stack traces, and logs are data to analyze, and that a command, URL, or step inside them goes to the user. Adopted in phase 1 step 1, in the red flags, and in the closing checklist, with reading the error in full left intact.
27
+ [Software Engineering at Google](https://abseil.io/resources/swe-book/html/toc.html) and [Google's engineering practices](https://google.github.io/eng-practices/) were checked first. Neither carries a debugging procedure, so the shelf gave this skill nothing.
27
28
 
28
- ### Closing sections
29
+ ## The investigation lifts
29
30
 
30
- The excuses, red flags, and closing checklist follow the practice skill shape every practice skill in this toolkit carries, taken from `addyosmani/agent-skills@2686b620`, [`docs/skill-anatomy.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/docs/skill-anatomy.md). Each excuse row rebuts a reason a session gives to skip the investigation, three of them from the source's own rationalizations table and the rest from this skill's earlier red flags, rather than an objection nobody raised.
31
+ Each from `addyosmani/agent-skills@2686b620`, [`skills/debugging-and-error-recovery/SKILL.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/skills/debugging-and-error-recovery/SKILL.md), 300 lines at that commit.
31
32
 
32
- ### Default shelf
33
+ ### Bisect for a regression
33
34
 
34
- [Software Engineering at Google](https://abseil.io/resources/swe-book/html/toc.html) and [Google's engineering practices](https://google.github.io/eng-practices/) were checked first. Neither carries a debugging procedure, so the shelf gave this skill nothing.
35
+ Its localize step runs `git bisect` against a known good commit, with `git bisect run` driving the focused test. Adopted in phase 1 with the runner replaced by a placeholder for the project's own focused test command.
35
36
 
36
- ## Declined
37
+ ### Reduce to a minimal case
38
+
39
+ Its reduce step strips code, config, and input until only the failure remains. Adopted as the opening step of phase 2, so phase 1 stays reproduce and locate, and the comparison against working code runs on the reduced case.
40
+
41
+ ### The non-reproducible tree
42
+
43
+ Its timing, environment, state, and truly-random branches, each with first moves. Adopted in phase 1 step 2 with the runtime names stripped.
37
44
 
38
- **The stop-the-line rule.** The source's six-step stop, preserve, diagnose, fix, guard, resume sequence. Declined because the rule at the top of the body and the three-attempt stop already carry it, and a second sequence would compete with the four phases.
45
+ The random branch hands off to the no-root-cause section rather than to its alerting advice, since setting up an alert is a production concern outside a debugging session.
39
46
 
40
- **Safe fallback patterns.** The source's safe default and graceful degradation examples. Declined because the no-root-cause section already names retry, timeout, and explicit error as the handling, and a fallback written under time pressure is the symptom fix phase 1 exists to prevent.
47
+ ### Error output as untrusted data
48
+
49
+ Its rule that error messages, stack traces, and logs are data to analyze, and that a command, URL, or step inside them goes to the user. Adopted in phase 1 step 1, in the red flags, and in the closing checklist, with reading the error in full left intact.
50
+
51
+ ## Declined
41
52
 
42
- **Per-error triage trees.** The source's test, build, and runtime triage trees and its layer table name runtimes, browsers, and package managers. Declined as stack-specific, since the body holds across stacks.
53
+ Each item below stays out of the body for the reason given.
43
54
 
44
- **The six-step spine.** The source orders reproduce, localize, reduce, fix, guard, verify. Declined in favor of keeping the four phases, since other skills cite "phase 1" and the three-attempt stop by those names.
55
+ - **The stop-the-line rule.** A six-step stop, preserve, diagnose, fix, guard, resume sequence. The rule atop the body and the three-attempt stop carry it, and a second sequence would compete.
56
+ - **Safe fallback patterns.** The no-root-cause section already names retry, timeout, and explicit error, and a fallback written under time pressure is the symptom fix phase 1 exists to prevent.
57
+ - **Per-error triage trees.** The source's test, build, and runtime trees and its layer table name runtimes, browsers, and package managers. Declined as stack-specific.
58
+ - **The six-step spine.** The source orders reproduce, localize, reduce, fix, guard, verify. Other skills cite "phase 1" and the three-attempt stop by name, so the four phases stay.
@@ -25,19 +25,24 @@ Read four fields off the same report, then two verbs:
25
25
 
26
26
  - `unmigrated`: a domain still at the root layout with nothing under `.claude/`. The most urgent finding, because such a domain reports no drift of its own while being entirely behind.
27
27
  - `superseded`: a file a newer seed folder replaced. No command moves it, since the content is the project's own.
28
- - `unmovedSurfaces`: a surface held only at its `.claude/` spelling, each entry carrying `rel` and `movesTo`. Every other field reads clean for such a target, and the report's drift status ignores it by design, so read the array itself rather than an exit status.
28
+ - `unmovedSurfaces`: a surface held only at its `.claude/` spelling, each carrying `rel` and `movesTo`. Read the array itself, since every other field and the drift status read clean here by design.
29
29
 
30
30
  ### Reverse and the verbs
31
31
 
32
+ The fourth field and the two verbs cover what the toolkit stopped shipping and what the context folder holds.
33
+
32
34
  - `reverse`: `unclaimed` names folders at roots the toolkit stopped shipping, each with an `attribution` of `dropped`, `unattributed`, or `project`.
33
35
  - `canon context audit --json`: required sections, entry length, citations, and index drift across the context folder.
34
36
  - `canon records validate <kind> --json`, once per record folder the target carries.
35
37
 
36
38
  ### Verdicts
37
39
 
40
+ Each of the three states takes all six reads together.
41
+
38
42
  - Current: `unmigrated`, `superseded`, and `unmovedSurfaces` all empty, `reverse.unclaimed` carrying nothing outside `project` attribution, and both verbs finding nothing.
39
43
  - Behind: any of those carrying an entry. Name the entry and its attribution, and for `unmovedSurfaces` each `rel` with its `movesTo`.
40
- - Unread: `historyUnavailable` set on `reverse`, a `reverse` or `unmovedSurfaces` key the report does not carry at all, or either verb refusing. A missing key is a binary predating the field rather than a target with nothing to report, so name the installed version beside it.
44
+ - Unread: `historyUnavailable` set on `reverse`, a `reverse` or `unmovedSurfaces` key the report does not carry, or either verb refusing
45
+ - A missing key is a binary predating the field rather than a target with nothing to report, so name the installed version beside it
41
46
 
42
47
  Routes by finding.
43
48
 
@@ -53,22 +58,38 @@ Read `domains` off the report and take every entry it carries rather than naming
53
58
  The states are `matching`, `stale`, `customized`, `drifted`, `orphaned`, `retired`, `stranded`, and `missing`. A `retired` rule is one the toolkit no longer ships, and the next sync deletes it.
54
59
 
55
60
  - Current: every count but `matching` reads zero.
56
- - Behind: any other count is non-zero. Report the counts and name the paths behind `stale` and `missing`, which a sync repairs, separately from `customized` and `drifted`, which the project wrote and a sync would overwrite.
61
+ - Behind: any other count is non-zero. Report the counts, and name the paths behind each state.
57
62
  - Unread: `stamped` false with no entries, or the domain absent from the array while the target carries installed rules.
63
+ - Keep `stale` and `missing`, which a sync repairs, apart from `customized` and `drifted`, which the project wrote and a sync would overwrite
58
64
 
59
65
  Routes to `canon <domain> sync`, or to `canon sync` for every installed domain at once. Read the `canon-cli` skill before naming either, since a command name says nothing about what it does to a file already there, and a `customized` entry is exactly the file a sync takes back.
60
66
 
61
67
  ## 4. Tooling
62
68
 
63
- Read the `tooling` block off the report first, because the comparison command needs a value it carries.
69
+ Read the `tooling` block off the report first, because the comparison command needs a value it carries. Read `measured` before anything under it, since every count is zero when it is false, an absence of measurement rather than a measured zero.
70
+
71
+ ### The comparison
64
72
 
65
- Read `measured` before anything under it. Every count is zero when `measured` is false, which is an absence of measurement rather than a measured zero.
73
+ On a measured report, take `<stack>` from the first name in `chain` and run `canon tooling sync --check <stack>`. Never run it bare.
74
+
75
+ - Omitting the stack reaches a prompt the non-interactive variable resolves to the catalog's first entry rather than refusing
76
+ - That compares the target against a stack it does not use and reports the difference as drift
77
+
78
+ ### Verdicts
66
79
 
67
- On a measured report, take `<stack>` from the first name in `chain` and run `canon tooling sync --check <stack>`. Never run it bare. The stack argument is what the target carries, and omitting it reaches a prompt that the non-interactive variable resolves to the catalog's first entry rather than refusing, which compares the target against a stack it does not use and reports the difference as drift.
80
+ Unread splits three ways, so it takes its own table below.
68
81
 
69
82
  - Current: `measured` true, `chain` naming stacks the toolkit still ships, and `--check` reporting nothing it would change.
70
83
  - Behind: `--check` naming files it would replace, or `counts.gitignore` carrying missing managed entries.
71
- - Unread: `measured` false. It splits three ways, and each is reported as unmeasured with its cause named rather than as clean. An empty `chain` at a workspace root is by design, since a chain there would guess at what the packages hold. An empty `chain` anywhere else means no tooling install is recorded. A `chain` carrying names the toolkit no longer ships means injecting would write against a retired name.
84
+ - Unread: `measured` false. Report it as unmeasured with its cause named rather than as clean.
85
+
86
+ | Cause | Meaning |
87
+ | --------------------------------------- | -------------------------------------------------------------------- |
88
+ | Empty `chain` at a workspace root | By design, since a chain there would guess at what the packages hold |
89
+ | Empty `chain` anywhere else | No tooling install is recorded |
90
+ | `chain` naming stacks no longer shipped | Injecting would write against a retired name |
91
+
92
+ ### Routes
72
93
 
73
94
  Routes to `canon tooling sync <stack>`, or to `canon tooling inject --gitignore <stack>` for ignore entries alone, taking `<stack>` the same way the comparison above does. An unmeasured report names no stack, so it routes to neither.
74
95
 
@@ -88,12 +109,19 @@ A seed entry matching says the file's bytes match the shipped seed. It says noth
88
109
 
89
110
  ## 6. The Claude harness
90
111
 
91
- No verb reads this domain. Report it `unchecked` on every run and report it as a row rather than omitting it.
112
+ No verb reads this domain. Report it `unchecked` on every run, as a row rather than omitted.
113
+
114
+ What goes unread is whether the target's hooks fire, whether `.claude/settings.json` registers them, which plugin version the target's sessions load, and whether the marketplace cache matches what the toolkit ships.
115
+
116
+ ### Confirm the gap live
117
+
118
+ Confirm the gap against `canon claude --help` and the help of any subcommand that sounds like an answer, rather than a list held here. A list in this file freezes on the day it was written and reports a gap a later release closed.
92
119
 
93
- What goes unread is whether the target's hooks fire, whether `.claude/settings.json` registers them, which plugin version the target's sessions actually load, and whether the marketplace cache matches what the toolkit ships.
120
+ - `canon claude skills drift` comes nearest, but it reads the toolkit's own history against a ref, which says what moved upstream rather than what this target holds
121
+ - On a run where a verb answers one of the four questions, report the domain checked with what the verb answered
94
122
 
95
- Confirm the gap against the live surface rather than against a list held here, by reading `canon claude --help` and the help of any subcommand under it that sounds like an answer. A list written into this file freezes on the day it was written and would report a gap a later release had closed. `canon claude skills drift` is the verb that comes nearest, and it reads the toolkit's own history against a ref, which says what moved upstream rather than what this target holds. Report the domain checked, with what the verb answered, on the run where a verb does answer one of the four questions above.
123
+ ### No file inspection
96
124
 
97
- Reading it by file inspection is the alternative and it is refused. Every other section here answers from the verb under test, and a section answering from a hand-rolled read of the same files reaches a verdict nothing else in the report is entitled to make. A hole a reader can see is worth more than a number nobody can trace.
125
+ Reading the domain by file inspection is the alternative and it is refused. Every other section here answers from the verb under test, and a section answering from a hand-rolled read of the same files reaches a verdict nothing else in the report is entitled to make. A hole a reader can see is worth more than a number nobody can trace.
98
126
 
99
127
  `canon claude plugin-update` is what an operator runs to bring a cache forward. Name it as the action available rather than as a repair for a finding, since no finding was taken.