@erclx/canon 5.40.0 → 5.42.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 (187) hide show
  1. package/README.md +34 -17
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/references/adopted.md +34 -14
  4. package/claude/skills/auto-ship/REQUIREMENT.md +2 -0
  5. package/claude/skills/auto-ship/SKILL.md +28 -2
  6. package/claude/skills/auto-ship/references/draft-mark.md +32 -6
  7. package/claude/skills/auto-ship/references/failure-recovery.md +15 -13
  8. package/claude/skills/auto-ship/references/fan-in.md +59 -0
  9. package/claude/skills/auto-ship/references/tier-failures.md +31 -10
  10. package/claude/skills/auto-ship/references/ui-checklist.md +9 -4
  11. package/claude/skills/auto-ship/references/worktree-name.md +9 -3
  12. package/claude/skills/build-in-slices/references/adopted.md +35 -21
  13. package/claude/skills/canvas-board/references/canvas.md +17 -6
  14. package/claude/skills/canvas-board/references/design.md +26 -7
  15. package/claude/skills/code-craft/references/adopted.md +58 -20
  16. package/claude/skills/codebase-layout/references/adopted.md +49 -16
  17. package/claude/skills/codebase-layout/references/frontend.md +11 -4
  18. package/claude/skills/codebase-layout/references/tests.md +4 -2
  19. package/claude/skills/context-fold/references/classify.md +10 -15
  20. package/claude/skills/context-fold/references/completion-report.md +11 -9
  21. package/claude/skills/context-fold/references/context-refresh.md +26 -9
  22. package/claude/skills/context-fold/references/unusable-baseline.md +5 -3
  23. package/claude/skills/create-rule/REQUIREMENT.md +5 -0
  24. package/claude/skills/create-rule/SKILL.md +9 -1
  25. package/claude/skills/create-rule/references/checklist.md +26 -0
  26. package/claude/skills/create-rule/references/rule.md +98 -20
  27. package/claude/skills/create-skill/SKILL.md +1 -0
  28. package/claude/skills/create-skill/references/skill-disclosure.md +10 -2
  29. package/claude/skills/create-skill/references/skill-frontmatter.md +43 -0
  30. package/claude/skills/create-skill/references/skill-paths.md +7 -4
  31. package/claude/skills/create-skill/references/skill-practice.md +6 -3
  32. package/claude/skills/create-skill/references/skill-requirement.md +4 -2
  33. package/claude/skills/create-skill/references/skill.md +67 -44
  34. package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
  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 +54 -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-figure/references/architecture-set.md +7 -3
  58. package/claude/skills/draft-figure/references/figures.md +8 -6
  59. package/claude/skills/draft-figure/references/hand-drawn.md +3 -1
  60. package/claude/skills/draft-figure/references/mermaid-path.md +19 -9
  61. package/claude/skills/draft-figure/references/mermaid.md +10 -5
  62. package/claude/skills/draft-ready/references/ready.md +22 -15
  63. package/claude/skills/git-branch/REQUIREMENT.md +17 -6
  64. package/claude/skills/git-branch/SKILL.md +63 -7
  65. package/claude/skills/git-branch/references/branch.md +11 -1
  66. package/claude/skills/git-branch/references/slug.md +17 -5
  67. package/claude/skills/git-commit/references/commit.md +8 -0
  68. package/claude/skills/git-commit/references/versioning.md +23 -17
  69. package/claude/skills/git-followup/REQUIREMENT.md +1 -1
  70. package/claude/skills/git-followup/SKILL.md +5 -6
  71. package/claude/skills/git-issue/references/issue.md +29 -16
  72. package/claude/skills/git-pr/REQUIREMENT.md +1 -5
  73. package/claude/skills/git-pr/SKILL.md +11 -22
  74. package/claude/skills/git-pr/references/final-command.md +21 -8
  75. package/claude/skills/git-pr/references/labels.md +45 -28
  76. package/claude/skills/git-pr/references/pr.md +28 -9
  77. package/claude/skills/git-pr/references/publish.md +42 -28
  78. package/claude/skills/git-pr/references/task-number.md +20 -8
  79. package/claude/skills/git-ship/SKILL.md +1 -1
  80. package/claude/skills/plan-feature/references/batches.md +48 -1
  81. package/claude/skills/plan-feature/references/plan-lifecycle.md +10 -3
  82. package/claude/skills/plan-feature/references/plan.md +59 -20
  83. package/claude/skills/plan-groundwork/references/groundwork-spikes.md +4 -1
  84. package/claude/skills/plan-groundwork/references/groundwork.md +14 -16
  85. package/claude/skills/plan-intake/references/intake.md +29 -24
  86. package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
  87. package/claude/skills/plan-intake-answer/SKILL.md +1 -2
  88. package/claude/skills/pr-evidence/REQUIREMENT.md +40 -0
  89. package/claude/skills/pr-evidence/SKILL.md +53 -0
  90. package/claude/skills/pr-evidence/references/evidence.md +150 -0
  91. package/claude/skills/review-address/references/post-review-findings.md +10 -3
  92. package/claude/skills/review-address/references/rebase-conflicts.md +22 -7
  93. package/claude/skills/review-address/references/rest-reads.md +3 -1
  94. package/claude/skills/review-craft/references/adopted.md +35 -18
  95. package/claude/skills/review-craft/references/security.md +42 -7
  96. package/claude/skills/review-craft/references/ui.md +23 -8
  97. package/claude/skills/review-pr/SKILL.md +6 -6
  98. package/claude/skills/review-pr/references/body-variants.md +29 -9
  99. package/claude/skills/review-pr/references/close-out.md +20 -5
  100. package/claude/skills/review-pr/references/key-changes.md +27 -3
  101. package/claude/skills/review-pr/references/post.md +83 -31
  102. package/claude/skills/review-pr/references/scope.md +54 -19
  103. package/claude/skills/review-ui/SKILL.md +2 -0
  104. package/claude/skills/review-ui/references/close-out.md +49 -0
  105. package/claude/skills/review-ui/references/driving.md +24 -4
  106. package/claude/skills/review-ui/references/post.md +43 -13
  107. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +67 -17
  108. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +81 -40
  109. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +52 -15
  110. package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +48 -26
  111. package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +12 -13
  112. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +72 -36
  113. package/claude/skills/role-orchestrator/references/orchestrator-output.md +12 -4
  114. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +64 -24
  115. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +80 -26
  116. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +41 -18
  117. package/claude/skills/role-orchestrator/references/orchestrator-resume.md +19 -7
  118. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +22 -12
  119. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +15 -6
  120. package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +25 -7
  121. package/claude/skills/role-orchestrator/references/orchestrator-watch.md +34 -8
  122. package/claude/skills/role-orchestrator/scripts/poll.ts +16 -24
  123. package/claude/skills/role-worker/REQUIREMENT.md +2 -0
  124. package/claude/skills/role-worker/SKILL.md +17 -0
  125. package/claude/skills/search-craft/references/adopted.md +18 -6
  126. package/claude/skills/session-map/references/session.md +26 -7
  127. package/claude/skills/session-worktree/references/main-root-writes.md +25 -8
  128. package/claude/skills/systematic-debugging/references/adopted.md +30 -16
  129. package/claude/skills/target-check/references/domains.md +39 -11
  130. package/claude/skills/target-setup/references/detect.md +80 -65
  131. package/claude/skills/target-setup/references/indexes.md +8 -6
  132. package/claude/skills/task-board/references/board.md +86 -30
  133. package/claude/skills/task-board/references/decline.md +29 -13
  134. package/claude/skills/task-board/references/tasks-decline.md +12 -5
  135. package/claude/skills/task-board/references/tasks.md +65 -33
  136. package/claude/skills/task-complete/references/archive.md +41 -17
  137. package/claude/skills/task-complete/references/receipt-sweep.md +23 -9
  138. package/claude/skills/task-complete/references/unusable-baseline.md +10 -3
  139. package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
  140. package/claude/skills/teach-workspace/SKILL.md +1 -2
  141. package/claude/skills/teach-workspace/references/glossary.md +6 -2
  142. package/claude/skills/teach-workspace/references/lesson-build.md +44 -16
  143. package/claude/skills/teach-workspace/references/lesson-craft.md +12 -7
  144. package/claude/skills/teach-workspace/references/pedagogy.md +6 -3
  145. package/claude/skills/teach-workspace/references/promotion-fold.md +17 -11
  146. package/claude/skills/teach-workspace/references/promotion.md +31 -8
  147. package/claude/skills/teach-workspace/references/revisit.md +8 -2
  148. package/claude/skills/teach-workspace/references/teach.md +17 -9
  149. package/claude/skills/test-craft/references/adopted.md +48 -14
  150. package/claude/skills/test-craft/references/component.md +7 -4
  151. package/claude/skills/test-craft/references/e2e.md +25 -7
  152. package/claude/skills/test-craft/references/unit.md +3 -1
  153. package/claude/skills/test-first/references/adopted.md +12 -4
  154. package/claude/skills/ui-checklist/REQUIREMENT.md +1 -1
  155. package/claude/skills/ui-checklist/SKILL.md +1 -1
  156. package/claude/skills/video-craft/references/adopted.md +62 -18
  157. package/claude/skills/write-human/references/adopted.md +21 -8
  158. package/docs/workflow/parallel-features.md +2 -1
  159. package/docs/workflow/skill-map.md +2 -1
  160. package/package.json +1 -1
  161. package/src/claude/cases/git.ts +4 -0
  162. package/src/claude/cases/workflow.ts +5 -0
  163. package/src/commands/pr.ts +174 -37
  164. package/src/commands/records.ts +11 -3
  165. package/src/context/shape-gated.ts +1 -0
  166. package/src/markdown/scope.ts +150 -2
  167. package/src/pr/frames.ts +53 -9
  168. package/src/pr/lift.ts +6 -3
  169. package/src/pr/review-state.ts +182 -0
  170. package/src/records/validate.ts +1 -0
  171. package/src/tasks/answers.ts +79 -2
  172. package/src/tasks/fan-in.ts +176 -0
  173. package/src/tasks/stack.ts +1 -1
  174. package/tooling/astro/reference.md +80 -39
  175. package/tooling/base/reference.md +63 -32
  176. package/tooling/base/seeds/canon/context/ci.md +7 -15
  177. package/tooling/base/seeds/canon/context/development.md +14 -14
  178. package/tooling/claude/reference.md +40 -22
  179. package/tooling/cloudflare/reference.md +31 -12
  180. package/tooling/go/reference.md +47 -23
  181. package/tooling/nextjs/reference.md +52 -19
  182. package/tooling/php/reference.md +35 -16
  183. package/tooling/python/reference.md +47 -30
  184. package/tooling/shell/reference.md +6 -5
  185. package/tooling/vite-react/reference.md +49 -21
  186. package/tooling/web/reference.md +130 -70
  187. 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
  }
@@ -28,6 +28,8 @@ The draft mark fails from both ends. On 2026-08-31 four sessions re-drafted a pu
28
28
  - State the shared board as read-only for a building session and name what it does instead when a row is owed, since a task file with no row is a dropped task and placing the row is the controlling session's call
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
+ - 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
31
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
32
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
33
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
@@ -61,6 +61,14 @@ Announce the pull request as the ship chain's pull request step returns, carryin
61
61
  - Say the reach was unread rather than clear when the installed binary carries no such subcommand, and leave the undeclared list to the pull request
62
62
  - Carry a row this build turned up with its title, origin, and surface. Send it alone only when the session ends before a pull request opens.
63
63
 
64
+ ### A fan-in member
65
+
66
+ A member of a fan-in set opens no pull request, so its done message stands in for the announcement. `auto-ship` sends it after the push.
67
+
68
+ - Carry the branch, the head commit, and the integrator the plan names in place of a pull request number
69
+ - Carry no reach, since the integrator's announcement carries it once for the whole set
70
+ - An integrator is an ordinary worker and owes the announcement above
71
+
64
72
  ### Re-review and blocks
65
73
 
66
74
  Ask for the re-review as `review-address` Step 8 returns, carrying what was addressed and the PR's new CI state. That transition is the other moment only this session knows, and the message starts the re-review.
@@ -70,6 +78,14 @@ Ask for the re-review as `review-address` Step 8 returns, carrying what was addr
70
78
  - Send a block out as a message before it becomes an interactive prompt.
71
79
  - Send nothing on progress. A worker reporting progress rebuilds, on this side of the channel, the poll the announcement retired on the other.
72
80
 
81
+ ### Waiting on the reviews
82
+
83
+ 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.
84
+
85
+ - Read review state only through `canon pr review-state`, never off issue comments, where neither review family posts
86
+ - 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
87
+ - 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
88
+
73
89
  ### Addressing
74
90
 
75
91
  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.
@@ -117,5 +133,6 @@ Never concede on the name alone or proceed as if the sets never collided. A work
117
133
  ## Lifetime
118
134
 
119
135
  - The role runs from the worktree entry to the merge of the branch it built, and nothing carries to a second row, which is a new build under a new plan
136
+ - A fan-in member's role ends at its push, since the integrator merges the branch and fixes on its own branch whatever the merge surfaces
120
137
  - A talk session outlives the merge and ends when the operator says the conversation is over
121
138
  - Treat this body as possibly older than the branch under it. A plugin skill loads from the marketplace cache, so a session changing its own skills may hold the copy from before the last update.
@@ -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.