@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
@@ -42,6 +42,8 @@ Does not govern:
42
42
 
43
43
  ### What to leave out
44
44
 
45
+ A body describes the new behavior and nothing the diff or the commits already say.
46
+
45
47
  - Do not describe historical behavior or unchanged code. Describe new behavior only.
46
48
  - Do not include future promises or speculative documentation
47
49
  - Do not explain obvious changes (formatting, renaming variables)
@@ -54,38 +56,49 @@ Does not govern:
54
56
 
55
57
  ### Context section
56
58
 
57
- - `## Technical context` (optional): 1-2 lines of architectural reasoning explaining why, not what
59
+ `## Technical context` is optional and carries 1-2 lines of architectural reasoning explaining why, not what.
60
+
58
61
  - Omit Technical context for docs, config, or trivial changes
59
62
  - Use bullet points for multiple reasons, one sentence for a single reason
60
63
 
61
64
  ### Testing section
62
65
 
63
- - `## Testing` (optional): specify exact commands or test cases run
66
+ `## Testing` is optional and names the exact commands or test cases run.
67
+
64
68
  - Omit Testing for docs, config, or trivial sync changes
65
69
  - Use checkboxes, never prose. See Testing discipline for which box gets ticked.
66
70
 
67
71
  ### Reviewer section and visuals
68
72
 
69
- - `## For the reviewer` (optional): what the reviewing session should confirm, one bullet per request
73
+ `## For the reviewer` is optional and lists what the reviewing session should confirm, one bullet per request.
74
+
70
75
  - Visuals: include only when they clarify architecture, UI, or complex logic flows
71
- - The list is closed. A body carries the sections above and nothing after the last of them, which covers a trailer a harness appends once the body is composed. `canon labels scan` holds the list: it fails a level-two heading outside the five above, and a body missing `## Summary` or `## Key changes`. A review body and a release-please body are exempt.
76
+ - The list is closed, so a body carries nothing after its last section, including a trailer a harness appends once the body is composed
77
+ - `canon labels scan` fails a level-two heading outside the five above, and a body missing `## Summary` or `## Key changes`
78
+ - A review body and a release-please body are exempt
72
79
 
73
80
  ## Testing discipline
74
81
 
75
82
  - Run the check before writing its line. A `- [ ]` reports a check that has not run rather than one that is planned.
76
83
  - Tick the box and state the observed result. `- [x] npm test passes, 42 tests` beats `- [ ] run npm test`.
77
84
  - Quote the count or output the run reported, never a figure carried from elsewhere.
78
- - A ticked box describes the tree as it stands, not as it stood when it was written. A later commit that removes or replaces what it names makes the box false, and the branch that made that commit corrects it in the same pass, the same as any other stale claim in the body.
85
+ - A ticked box describes the tree as it stands. A later commit removing or replacing what it names makes the box false.
86
+ - The branch that made that commit corrects the box in the same pass, as with any other stale claim in the body
79
87
 
80
88
  ### Human-only boxes
81
89
 
82
- - Leave a box unchecked only when a human is required, and name which human and why on the same line.
83
- - Human-only covers visual or aesthetic judgment, anything needing credentials or a live third-party service, anything needing a second machine or a fresh OS, and judgment about whether a boundary or an abstraction reads correctly. The agent runs everything else.
84
- - What makes a human required is a capability the agent lacks, never the cost of the run. Authorizing a spend is the operator's and performing the run is not, so an arm the repository ships a harness for gets driven once the operator has cleared the spend, and the box records what it returned.
85
- - A tool refusal that actually fired is a capability gap, and the line says which refusal rather than naming the cost behind it. A refusal predicted and never met is not one.
90
+ Leave a box unchecked only when a human is required, and name which human and why on the same line. The agent runs everything else.
91
+
92
+ - Human-only covers visual or aesthetic judgment, credentials or a live third-party service, and a second machine or a fresh OS
93
+ - It also covers judgment about whether a boundary or an abstraction reads correctly
94
+ - A human is required by a capability the agent lacks, never the cost of the run. Authorizing a spend is the operator's and performing the run is not.
95
+ - An arm the repository ships a harness for gets driven once the operator has cleared the spend, and the box records what it returned
96
+ - A tool refusal that actually fired is a capability gap, and the line names the refusal rather than the cost. A refusal predicted and never met is not one.
86
97
 
87
98
  ### Live sessions and reviewer requests
88
99
 
100
+ A live agent session is never the human a box waits on.
101
+
89
102
  - A live agent session is not a human. A box reading `needs a live session driving the skill` names the thing writing the description, so that run is owed rather than blocked.
90
103
  - Put a request for the reviewer under `## For the reviewer`. It is a request rather than unfinished testing, so it never appears as an unchecked Testing box.
91
104
 
@@ -97,6 +110,8 @@ Does not govern:
97
110
 
98
111
  ### Template
99
112
 
113
+ Every section a body may carry, in order.
114
+
100
115
  ```markdown
101
116
  ## Summary
102
117
 
@@ -124,6 +139,8 @@ Does not govern:
124
139
 
125
140
  ### Correct
126
141
 
142
+ Each line's comment names the rule it follows.
143
+
127
144
  ```markdown
128
145
  ## Summary
129
146
 
@@ -151,6 +168,8 @@ Update auth middleware to enforce jwt expiration checks. # imperative + direct o
151
168
 
152
169
  ### Incorrect
153
170
 
171
+ Each line's comment names the rule it breaks.
172
+
154
173
  ```markdown
155
174
  ## Summary
156
175
 
@@ -7,7 +7,7 @@ description: Scan an author runs against finished text, the cross-reference form
7
7
 
8
8
  ## Scope
9
9
 
10
- Governs the scan an author runs against finished text on its way out, the form a pull request or issue reference takes in every destination, and the responses available when a source it reaches for cannot be read. It is an attribute standard rather than a document-type one, so it applies wherever no automated check covers the text, whether that text is leaving through a channel or sitting in the repository, and it carries no template because a scan has no document to shape.
10
+ Governs the scan an author runs against finished text on its way out, the form a pull request or issue reference takes in every destination, and the response when a source the scan reaches for cannot be read. As an attribute standard it applies wherever no automated check covers the text, and carries no template.
11
11
 
12
12
  Does not govern:
13
13
 
@@ -18,68 +18,82 @@ Does not govern:
18
18
 
19
19
  ## When it runs
20
20
 
21
- Wherever text leaves through a channel no automated check covers, the author is the only gate and runs this scan. Text sent to another service, written to a path the project's checks exclude, and text inside a fenced block are the usual cases. The surface that publishes the text is what knows which gap applies, so it names its own rather than reading one here.
21
+ Wherever text leaves through a channel no automated check covers, the author is the only gate and runs this scan. Text sent to another service, text written to a path the checks exclude, and text inside a fenced block are the usual cases.
22
22
 
23
- Run the scan as an explicit step against the finished text. Having read the underlying rules before drafting does not cover it, because the check has to happen after the text exists.
23
+ - The surface publishing the text knows which gap applies, so it names its own rather than reading one here
24
+ - Run the scan as an explicit step against the finished text, since the check has to happen after the text exists
24
25
 
25
- Scope every check below by destination. Text published to a remote takes all of them. Text staying in the repository takes the character bans alone, since those hold wherever the text lands, and skips whichever check depends on the reader holding something only this checkout carries. The two checks below that depend on it say so under their own headings.
26
+ ### Scope by destination
27
+
28
+ Text published to a remote takes every check below. Text staying in the repository takes the character bans alone, since those hold wherever the text lands.
29
+
30
+ - Phase labels and board identifiers depend on the reader holding this checkout, so repository text skips both
31
+ - Session links depend on the reader holding the account, a narrower dependency stated under their own heading
26
32
 
27
33
  ## Banned characters
28
34
 
29
35
  `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md` holds the character bans. Read it at scan time rather than working the sets from memory, then scan the drafted text and rewrite each occurrence.
30
36
 
31
- `canon labels scan` fails on these characters in a title or body, outside a code span or a link, so the scan is the check and the read above is the reason. It holds a pull request and a posted review alike.
32
-
33
- Restructure the sentence rather than substituting the character. A semicolon swapped for a period leaves both clauses in the order the semicolon chose, which is the shape the ban exists to remove.
37
+ - `canon labels scan` fails on these characters in a title or body outside a code span or a link, for a pull request and a posted review alike
38
+ - Restructure the sentence rather than substituting the character, since a semicolon swapped for a period keeps the shape the ban exists to remove
34
39
 
35
40
  ## Phase labels
36
41
 
37
42
  `${CLAUDE_SKILL_DIR}/../git-commit/references/versioning.md` holds the label rule and the table of surfaces. Read it at scan time rather than working the format from memory.
38
43
 
39
- This check is one of the two the destination rule above scopes. The reader inside the repository has the task board and the reader on a remote does not.
44
+ The reader inside the repository has the task board and the reader on a remote does not, so this check is scoped by destination.
40
45
 
41
46
  ## Board identifiers
42
47
 
43
- A phase label is one way text names the board, and a path under a record root is the other. Both resolve for a reader holding this checkout and neither resolves for anyone else, so this check is the second one the destination rule scopes.
48
+ A phase label is one way text names the board, and a path under a record root is the other. Both resolve for a reader holding this checkout and for nobody else, so this check is scoped by destination too.
44
49
 
45
- Two shapes get past a reader scanning for a bare label. A code span quoting a label is still the label, so read a span whose whole content is one as a hit and leave a longer token inside a span alone, which is a fixture name rather than a reference. The second shape is a path under a record root, gitignored and therefore absent from every clone, so `.canon/feedback/` names a folder the remote's reader cannot open.
50
+ - A code span whose whole content is a label is still the label and a hit. A longer token inside a span is a fixture name and stays.
51
+ - A path under a record root is gitignored and absent from every clone, so `.canon/feedback/` names a folder the remote's reader cannot open
52
+ - Tracked `canon/` and `.claude/` paths are no hit, since `canon/context/surfaces/governance.md` resolves everywhere
53
+ - Every path under `.canon/` is a hit whichever folder it names, since one ignore line covers the root whole
46
54
 
47
- Under the tracked `canon/` and `.claude/` folders there is no hit, since `canon/context/surfaces/governance.md` resolves everywhere. `.canon/` carries no such carve-out: one ignore line covers the root whole, so every path beneath it is a hit regardless of which folder names it.
55
+ ### Fixing a hit
48
56
 
49
- Rewrite a hit to name what the reader can reach rather than deleting it. A row's subject stated plainly replaces its label, and what a record folder holds, said in a sentence, replaces its path.
57
+ Rewrite a hit to name what the reader can reach rather than deleting it. State a row's subject plainly in place of its label, and say in a sentence what a record folder holds in place of its path.
50
58
 
51
- `canon labels scan` runs this check and the phase-label one over a pull request title and body, and over a posted review's own text once one is submitted. Any other channel, a plain issue comment among them, is still the author's own scan.
59
+ `canon labels scan` runs this check and the phase-label one over a pull request title and body, and over a posted review's text once submitted. Any other channel, a plain issue comment among them, is still the author's own scan.
52
60
 
53
61
  ## Session links
54
62
 
55
- A link to one Claude Code session names the session that wrote the text rather than the change the text describes. It enters because the harness tells the composing session to end its published text with one, so the author writes it deliberately and it reads as required rather than as a slip. That is what carries it past a scan the same author runs, and it is why a rule stating the ban does not reach the case: the session is following an instruction it was given, and reads its own compliance as correct.
56
-
57
- This check depends on the reader holding the account rather than the checkout, which is narrower than the dependency the destination rule above scopes. A reader inside this checkout opens a record path and still cannot open a session, since the session resolves for the one account that started it and for nobody else. The scoping still sits at the invocation site, because `canon labels scan` reads a pull request title and body and reaches no other text.
58
-
59
- Delete a hit rather than rewriting it. The other two checks replace a hit with what the reader can reach instead, and a session has no such form, so what stands in its place is the body already written above it.
63
+ A link to one Claude Code session names the session that wrote the text rather than the change it describes. The harness tells the composing session to end its published text with one, so the author writes it deliberately and reads that compliance as correct. That is how it passes a scan the same author runs.
60
64
 
61
- Removing the link before a merge does not substitute for never writing it. One branch removed it, read the live body back clean, and the squashed commit landed carrying it anyway off an earlier snapshot, which is permanent on the trunk.
65
+ - The session resolves only for the account that started it, so a reader inside this checkout still cannot open it
66
+ - The scoping sits at the invocation site, because `canon labels scan` reads a pull request title and body and no other text
67
+ - Delete a hit rather than rewriting it, since a session has no reachable form and the body above it already stands in its place
68
+ - Removing it before a merge is no substitute for never writing it, since a squash can land it from an earlier snapshot, permanently on the trunk
62
69
 
63
70
  ## Cross-reference form
64
71
 
65
- A number referring to a pull request or an issue takes the form its destination renders. Write it bare where the destination auto-links it, and in backticks where it does not. Both spellings are correct, each in one place, so a reference moved from one destination to the other is rewritten rather than copied.
72
+ A number referring to a pull request or an issue takes the form its destination renders. Write it bare where the destination auto-links it and in backticks where it does not, so a reference moved between destinations is rewritten rather than copied.
66
73
 
67
- Text published to a remote is the auto-linking half: a pull request body, an issue body, a comment on either, and a commit message. Write `#123` there, and `owner/repo#123` where the reference crosses repositories, which the same auto-linking reaches. A markdown file browsed from the repository tree is the other half, where neither spelling links and the backticked one marks the number as an identifier. <!-- canon-allow-reference: the two spellings this section defines, which a qualified form would destroy -->
74
+ | Destination | Form |
75
+ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
76
+ | Pull request or issue body, a comment on either, a commit | `#123`, or `owner/repo#123` across repositories <!-- canon-allow-reference: the two spellings this section defines, which a qualified form would destroy --> |
77
+ | A markdown file browsed from the repository tree | the number in backticks, since neither spelling links there |
78
+ | Content installed into another repository | qualified against a different, resolvable repository, or no number |
68
79
 
69
- Content that installs into another repository is the third destination, and it splits on which repository the number names. A skill body loads from a plugin cache and a docs page is read through `canon docs`, so the reader holds their own repository rather than the one a bare number belongs to. Qualifying a number against a different, resolvable repository fixes that, since the reader can open that repository even without this one.
80
+ A commit message takes the bare form even though the log links nothing, since the remote is what the form is chosen for. Text quoted from another surface keeps the spelling it arrived with, since rewriting it reports the source as saying something it never said.
70
81
 
71
- Qualifying it against `erclx/canon` fixes nothing, because a reader holding only the plugin cache or the published package still cannot open this repository's own history. A same-repository citation takes no number here at all, bare or qualified. State the fact the citation was standing in for instead, and where the identifier is the only trace of a one-off incident rather than a reproducible count, carry it into the `canon/context/` entry that owns the surface.
82
+ ### Installed content
72
83
 
73
- Write `owner/repo#123` and `owner/repo@abc1234` for a citation of a different, resolvable repository, across every such surface. `canon gate run` fails a push on a bare reference there, and a line whose bare form is the point carries `canon-allow-reference: <reason>` on itself or on the line above.
84
+ A skill body loads from a plugin cache and a docs page is read through `canon docs`, so the reader holds their own repository rather than the one a bare number belongs to.
74
85
 
75
- Choose the number over the sha where the citation names a decided change, since a pull request number resolves to the diff and the review behind it. Take the sha only for a tree or measurement state, the `Measured at <sha>` shape a context entry already uses. The choice holds for both spellings this section fixes, the bare form a remote auto-links and the qualified form a cross-repository citation carries.
86
+ - Write `owner/repo#123` and `owner/repo@abc1234` for a different, resolvable repository, which the reader can open without this one
87
+ - Qualifying against `erclx/canon` fixes nothing, since a reader holding the cache or the package still cannot open this repository's history
88
+ - A same-repository citation takes no number, so state the fact it stood in for, and carry a one-off incident's identifier into the `canon/context/` entry owning the surface
89
+ - `canon gate run` fails a push on a bare reference there, and a line whose bare form is the point carries `canon-allow-reference: <reason>` on itself or the line above
76
90
 
77
- A commit message takes the bare form even though it is also read through the log, where nothing links. The remote is what the form is chosen for, since a reader in the log loses only a link that plain text never carried.
91
+ ### Number or sha
78
92
 
79
- Text quoted from another surface keeps the spelling it arrived with. A reference inside a quotation belongs to what is being quoted rather than to the text doing the quoting, so rewriting it reports the source as having said something it never said.
93
+ Choose the number where the citation names a decided change, since it resolves to the diff and the review behind it. Take the sha only for a tree or measurement state, the `Measured at <sha>` shape a context entry already uses. The choice holds for the bare and the qualified spelling alike.
80
94
 
81
95
  ## An unreadable source
82
96
 
83
97
  Stop and name the source when one this scan reaches for cannot be read. Do not scan what resolved and report the result.
84
98
 
85
- A run that covers half its sources and says nothing is worse than one that visibly did not happen, because the surfaces running this scan are the ones that describe themselves as the only gate. A clean result from a half-run scan is read as coverage.
99
+ A half-run scan that says nothing is worse than one that visibly did not happen, because the surfaces running this scan describe themselves as the only gate. Its clean result is read as coverage.
@@ -7,22 +7,34 @@ description: How git-pr writes the pull request number the final command printed
7
7
 
8
8
  The last step of `git-pr` before its report, reached on every run whose final command printed a number.
9
9
 
10
- Write the `number` the final command printed onto the task the branch is closing. Do not resolve it again. A final command that refused on a head mismatch printed no number, so this step writes nothing on that run. `${CLAUDE_SKILL_DIR}/REQUIREMENT.md` states why: a lookup that resolves by branch alone can return a closed pull request sharing that head, so the number is resolved once and reused rather than re-derived.
10
+ Write the `number` the final command printed onto the task the branch is closing, and never resolve it again. A lookup by branch alone can return a closed pull request sharing that head, per `${CLAUDE_SKILL_DIR}/REQUIREMENT.md`. A final command that refused on a head mismatch printed no number, so this step writes nothing on that run.
11
11
 
12
- The task is the one whose `Plan:` line names the plan this branch implemented. Name that plan by its file, which is `.canon/plans/feature-<slug>.md` at the main worktree root with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. `plan-feature` writes the plan under the branch slug, so the two correspond on any branch that came through the plan-to-execute path. When the session already knows which plan it implemented, because a caller read it earlier in the chain, use that filename instead of re-deriving.
12
+ ## Name the plan
13
+
14
+ The task is the one whose `Plan:` line names the plan this branch implemented. That plan is `.canon/plans/feature-<slug>.md` at the main worktree root, with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`.
15
+
16
+ - `plan-feature` writes the plan under the branch slug, so the two correspond on any branch that came through the plan-to-execute path
17
+ - When a caller earlier in the chain already read the plan, use that filename instead of re-deriving
18
+ - The slug is a guess at the plan rather than a fact about the task, so the verb re-checks it against the board and refuses on a near miss
13
19
 
14
20
  ```bash
15
21
  canon tasks pull-request <number> --plan feature-<slug> --json
16
22
  ```
17
23
 
18
- The slug is a guess at which plan this branch carries rather than a fact about the task, which is why the verb re-checks it against the board and refuses instead of writing on a near miss. A branch whose slug names no plan file falls to the silent skip below, the same as one whose plan no task cites.
24
+ ## What the verb writes
25
+
26
+ The verb resolves the board at the main worktree root in-process, the root `session-worktree` resolves on entry. It is the route because the write edits an existing main-root file, which `session-worktree` routes through a verb.
27
+
28
+ - It adds `Pull request: #NNN` under the task's `Plan:`, `Groundwork:`, `Intake:`, or `Issue:` lines, and corrects the number in place when the line exists
29
+ - A line already reading as a list of `#NNN` entries takes the new number appended, reported as `appended`, so a task shipped in slices keeps every pull request
30
+ - The same write drops this branch from the `Pending branch:` line `canon tasks outcome` wrote, which lets the merge-time archive close the task
19
31
 
20
- The verb resolves the board at the main worktree root in-process, adds `Pull request: #NNN` under the `Plan:`, `Groundwork:`, `Intake:`, or `Issue:` lines the task already carries, and corrects the number in place when the line exists. This is the route because the write is an edit inside an existing main-root file, which `session-worktree` routes through a verb. That root is the one `session-worktree` resolves on entry.
32
+ ## Refusals
21
33
 
22
- The correction reaches only a line that does not read as a list of `#NNN` entries. A line that does takes the new number appended rather than replaced, reported as `appended`, so a task shipped in slices keeps every pull request.
34
+ Skip silently when the record is `ok: false` and `reason` is `no-board`, `no-match`, or `ambiguous`, meaning no board, no task naming the plan, or more than one. A guessed write would compound each, since a wrong match archives the wrong task unattended once the branch merges. Report any other refusal rather than swallowing it.
23
35
 
24
- The same write drops this branch from the task's `Pending branch:` line, which `canon tasks outcome` wrote when the branch ticked an outcome, so this step is what lets the merge-time archive close the task.
36
+ A branch whose slug names no plan file lands on `no-match`, the same as one whose plan no task cites.
25
37
 
26
- Skip this silently when the record is `ok: false` and `reason` is `no-board`, `no-match`, or `ambiguous`. Those are the three cases a guessed write would compound: no board, no task naming the plan, or more than one. One pull request names one task, and a wrong match archives the wrong task unattended once the branch merges. Report any other refusal rather than swallowing it.
38
+ ## Why the number
27
39
 
28
- The number is what lets the merge close the task. Every merge on `main` is a squash carrying it in the subject, so the number survives where a branch name does not, and `post-merge` reads it back to call `canon tasks archive`. Writing it here rather than at worktree time is what makes it a pull request number rather than a branch the squash discards.
40
+ Every merge on `main` is a squash carrying the number in its subject, so the number survives where a branch name does not. `post-merge` reads it back to call `canon tasks archive`, which is why this step runs at pull request time rather than at worktree time.
@@ -89,7 +89,7 @@ On a `passing` wake, run `canon pr evidence <number> --check --json` against the
89
89
  | Any other `reason`, such as `gh-failed` | Stop and report it, since an unread thread is not a settled one |
90
90
  | No record, or an unknown flag error | The binary predates `--check`, so report the thread unread and continue without claiming it was checked |
91
91
 
92
- On `owed`, run the named steps from `canon:git-pr`'s `references/evidence.md`, evidence first and then preview, and re-read with the same command. Continue only on `settled`, and stop on any other reading with the `reason` and the `owed` list, never looping back.
92
+ On `owed`, invoke `canon:pr-evidence` with the number, which runs the evidence step first and then the preview the thread owes, and re-read with the same command. Continue only on `settled`, and stop on any other reading with the `reason` and the `owed` list, never looping back.
93
93
 
94
94
  A refused preview step or a failed deploy leaves `preview` owed on the re-read, so that is the stop and not a retry. The read is a closing step, so the draft mark stays the only thing between steps 8 and 9, and a caller closing on its own block waits on the same wake.
95
95
 
@@ -9,7 +9,7 @@ Applies to a feature plan that sequences its work into more than one batch. A de
9
9
 
10
10
  ## One batch, one file
11
11
 
12
- One batch is one pull request, and one pull request is one plan file, named for its own concern rather than a numeric suffix. `canon tasks plan-branch` derives one branch from one plan filename.
12
+ One batch is one pull request, and one pull request is one plan file, named for its own concern rather than a numeric suffix. `canon tasks plan-branch` derives one branch from one plan filename. A fan-in member is the exception, keeping its own file and branch and opening no pull request, per `## Fan-in`.
13
13
 
14
14
  - A `**Batch N**` sub-heading inside one file's `**Files to touch:**` shares that branch across every batch, so the first merge strands the rest
15
15
  - Write a plan opening five batches as five files before the first line of any of them
@@ -44,3 +44,50 @@ Slice a batch by one user-visible path end to end rather than by layer, so each
44
44
  - Sequence the riskiest batch first, so the batch most likely to change the plan is built while every later batch can still move
45
45
  - Sequence a sweep last, even when it is the riskiest. A batch rewriting files earlier batches touched forces every batch behind it into one review anywhere else.
46
46
  - Keep each batch's commits contiguous once the work starts, since a batch interrupted by another cannot be lifted onto its own branch afterward
47
+
48
+ ## Fan-in
49
+
50
+ A fan-in builds batches in parallel and ships them as one pull request. Each member builds on its own branch and opens none, and one integrator merges every member branch, resolves the shared lines once, and opens the pull request. The trade is one large review, read one merge commit at a time, in place of a review and a rebase per batch.
51
+
52
+ ### When to fan in
53
+
54
+ Fan in when the split was made for speed rather than meaning. Every one of these holds:
55
+
56
+ - One task with one outcome, so no batch is a feature on its own
57
+ - The batches share edge files, such as a gated-paths list or an index, so separate pull requests rebase each other on every merge
58
+ - No batch needs to ship, be reviewed, or be reverted alone
59
+
60
+ Keep separate pull requests when the pieces are independent features, when one needs its own review or revert, when one may stall and hold the rest, or when the combined diff is too large to review even one merge commit at a time. Batches that build on each other stack or fold, per `## Dependent batches`, since a member stacks on nothing.
61
+
62
+ ### Declaring the set
63
+
64
+ Each side names the other in its `**Constraints:**`, and `canon records validate plans` reports `fan-in-unmatched` wherever the two disagree.
65
+
66
+ - A member writes ``Fan-in member of `feature-<integrator>` ``, naming one integrator
67
+ - The integrator writes ``Fans in `feature-<a>`, `feature-<b>`, and `feature-<c>` ``, in the order it merges them
68
+ - The task's `Plan:` line cites every member and the integrator, since the merge archives only the plans that line cites and a live integrator listing archived members reports `fan-in-unmatched`
69
+ - The integrator is its own plan, since its writes, being the shared lists, the citer repoints, and the index regeneration, need a `**Files to touch:**` of their own
70
+
71
+ `canon tasks plan-answers` holds a member whose integrator is missing or does not list it with a `Fan-in set` entry. It holds the integrator with a `Fan-in pending` entry until every member branch is on origin.
72
+
73
+ ### Dispatching the set
74
+
75
+ The members of one set dispatch together by design, since they share edge files and the integrator resolves those lines once. A shared file between members is never a hold.
76
+
77
+ - Hold the integrator on a dependency until `plan-answers` reads it launchable
78
+ - Re-read it after a fetch on each member's done message, which carries the branch and head commit in place of a pull request
79
+ - Never read a member with no pull request as stalled, since a member opens none
80
+
81
+ ### What a member writes
82
+
83
+ A member builds, verifies, pushes its branch, and announces it done. A pushed branch is the done signal, so a member pushes once, at the end.
84
+
85
+ A member may edit the shared lists and regenerate the indexes on its own branch, since the pre-push check fails a member that deletes a path a gated list still names. The integrator resolves those lines once at merge.
86
+
87
+ ### What the integrator writes
88
+
89
+ The integrator merges each member branch with `git merge --no-ff` in the order its bullet lists, resolving conflicts by the rules a rebase follows. It then writes its own files, regenerates the indexes once, and opens the pull request.
90
+
91
+ - Say in the pull request body that each member is one merge commit, so a reviewer reads `git log --first-parent` one member at a time
92
+ - Fix a semantic conflict a merge surfaces on the integrator's branch, since a member has no pull request to fix it on
93
+ - Delete each member branch on origin with `git push origin --delete <branch>` once the pull request merges
@@ -30,7 +30,14 @@ A plan lost to deletion, or carrying two answers to one question, fails both.
30
30
  ## Lifecycle
31
31
 
32
32
  - Write the plan before implementation starts, and treat it as the scope of the run that executes it. A subject that has to be measured before anyone can plan against it takes a measurement track first.
33
- - Keep every plan at one root. A plan copied into each parallel working tree forks, and the copies answer the same question differently.
34
- - Amend the plan in place when a decision changes mid-flight. Do not append a second passage narrating the change, which leaves a reader to work out which of two answers is current. An execution-time deviation from a suggestion is one such amendment, and the suggested-and-answer contract in `plan.md` fixes which line takes it.
35
- - Move the plan to `.canon/plans/archive/` when the work it describes ships or is declined. Never delete it, because the plan is where the rejected alternative is written down. A flat `.claude/plans-archive/` sibling is the older layout.
36
33
  - Write the plan in the same session that opens the task it serves. The session executing it later inherits reasoning it would otherwise re-derive.
34
+ - Keep every plan at one root. A plan copied into each parallel working tree forks, and the copies answer the same question differently.
35
+
36
+ ### Amending and archiving
37
+
38
+ A plan changes in place and leaves only by a move.
39
+
40
+ - Amend the plan in place when a decision changes mid-flight, never appending a passage narrating the change, which leaves two answers to reconcile
41
+ - An execution-time deviation from a suggestion is one such amendment, and the suggested-and-answer contract in `plan.md` fixes which line takes it
42
+ - Move the plan to `.canon/plans/archive/` when its work ships or is declined, and never delete it, since it records the rejected alternative
43
+ - A flat `.claude/plans-archive/` sibling is the older layout.
@@ -50,13 +50,21 @@ A plan failing these is non-conforming even when it satisfies every shape rule b
50
50
  ## Filename and slug
51
51
 
52
52
  - Name the file `feature-<slug>.md`, with `<slug>` two to four kebab-case words naming the concern.
53
- - Write one concern per file. A request spanning two independent concerns takes two plans rather than one bundling both, since a bundled plan cannot be executed by two sessions or abandoned by half.
54
- - A staged batch is a concern of its own and takes its own file rather than a `**Batch N**` sub-heading inside one plan's `**Files to touch:**`. One plan filename derives one branch, so batches sharing a file have nothing to open a pull request against once the first merges. State a batch's dependency on the ones before it in its own `**Constraints:**`. A batch that stacks on another and shares most of its files with it folds into that batch as contiguous commits on one branch rather than taking a file, unless its constraints carry ``Judged apart from `feature-<parent>`: <reason>`` with a reason after the colon. `canon records validate plans` reports `stack-foldable` for a stacked batch that has neither.
53
+ - Write one concern per file, since a plan bundling two cannot be executed by two sessions or abandoned by half
55
54
  - Derive the slug from the concern rather than from a branch, because the plan is written before the branch exists.
56
- - Give the branch that executes the plan the same slug. A later surface finds the plan from the branch name and finds nothing when the two spellings differ.
55
+ - Give the executing branch the same slug, since a later surface finds the plan from the branch name and finds nothing when the spellings differ
57
56
 
58
57
  A plan carries no frontmatter. Its filename is the whole of its identity, so a folder of plans is read by name rather than by a generated catalog.
59
58
 
59
+ ### Staged batches
60
+
61
+ A staged batch is a concern of its own and takes its own file rather than a `**Batch N**` sub-heading inside one plan's `**Files to touch:**`. One plan filename derives one branch, so batches sharing a file have nothing to open a pull request against once the first merges.
62
+
63
+ - State a batch's dependency on the ones before it in its own `**Constraints:**`
64
+ - A batch stacking on another and sharing most of its files folds into that batch as contiguous commits on one branch, rather than taking a file
65
+ - It takes a file anyway when its constraints carry ``Judged apart from `feature-<parent>`: <reason>`` with a reason after the colon
66
+ - `canon records validate plans` reports `stack-foldable` for a stacked batch that has neither
67
+
60
68
  ## Sections
61
69
 
62
70
  The document opens with `# Feature: <short title>` and one paragraph stating what is being built and why now. The sections below follow in this order.
@@ -73,60 +81,86 @@ The document opens with `# Feature: <short title>` and one paragraph stating wha
73
81
  | `**Sources:**` | the outside sources a decision rests on, each with its quoted passage | When a decision rests on an outside source |
74
82
 
75
83
  - Write each marker as the table gives it. `Summary` opens the prose a reader scans, so it takes an H2, and the others are labels over lists rather than sections of prose.
76
- - A section written in the other spelling is still that section, since `## Risks` and `**Risks:**` name one thing. Write the table's form in a new plan and leave an existing plan's spelling alone. Either spelling breaks a depth run.
84
+ - A section in the other spelling is still that section, since `## Risks` and `**Risks:**` name one thing, and either spelling breaks a depth run
85
+ - Write the table's form in a new plan and leave an existing plan's spelling alone
77
86
  - Write `None identified.` under a required section with nothing to report rather than dropping the marker. A dropped section and an unconsidered one read identically.
78
87
  - Aim `## Summary` at a person scanning the plan, not at the session executing it. The other sections carry what execution needs.
79
88
 
80
89
  ### Files to touch entries
81
90
 
82
- - Give every `**Files to touch:**` entry a backticked path and something said about it. A bare path states scope and not intent, and the reason is what an executing session checks its edit against. Lead with the path or lead with a label carrying the path, whichever reads better for the entry.
83
- - Separate the two halves with a colon, and keep every path the entry declares ahead of it. What sits before the colon reads as a target, so both sides of a rename belong there and a file merely cited by the reason does not.
84
- - Read the list as what the branch sets out to write rather than as a bound on it, since the doc syncs at ship write past it on nearly every branch. `canon tasks plan-reach <plan>` reads the branch back against this list and every other live plan.
91
+ Give every `**Files to touch:**` entry a backticked path and something said about it. A bare path states scope and not intent, and the reason is what an executing session checks its edit against.
92
+
93
+ - Lead with the path or with a label carrying the path, whichever reads better for the entry
94
+ - Separate the two halves with a colon, and keep every path the entry declares ahead of it, since what sits before the colon reads as a target
95
+ - Both sides of a rename belong before the colon, and a file merely cited by the reason does not
96
+ - Read the list as what the branch sets out to write rather than a bound, since the doc syncs at ship write past it on nearly every branch
97
+ - `canon tasks plan-reach <plan>` reads the branch back against this list and every other live plan
85
98
 
86
99
  ### Measured claims
87
100
 
88
- - State every count and every claim about the tree as measured during the pass that wrote the plan. A figure carried in from a summary or an earlier session is the most common way a plan ships the wrong scope.
89
- - Prefer a short plan over a padded one. A section filled to look thorough costs the reader the same attention as one that matters.
101
+ State every count and every claim about the tree as measured during the pass that wrote the plan. A figure carried in from a summary or an earlier session is the most common way a plan ships the wrong scope.
102
+
103
+ Prefer a short plan over a padded one. A section filled to look thorough costs the reader the same attention as one that matters.
90
104
 
91
105
  ### Constraints
92
106
 
93
107
  Work in flight reaches a plan as a hold or as a shared path. A hold leaves a surface alone and says which of two acts it forbids, rather than leaving the executing session to guess. Neither act is forbidden over a shared path.
94
108
 
95
- - Write a hold only for a dependency, a contract the other track consumes, a relocation, or a sweep, which a rebase cannot settle mechanically. A bare shared file is none of these, and forbidding it sends a worker to concede a file the change needs.
109
+ Write a hold only for a dependency, a contract the other track consumes, a relocation, or a sweep, which a rebase cannot settle mechanically. A bare shared file is none of these, and forbidding it sends a worker to concede a file the change needs.
110
+
96
111
  - Forbid conforming that surface to whatever shape the change introduces, which keeps the branch to one concern.
97
- - Never forbid retargeting a pointer the change breaks. A rename, a split, or a deletion that leaves a citation behind ships a dangling reference, so repairing it is required work rather than scope creep.
112
+ - Never forbid retargeting a pointer the change breaks, since a rename, split, or deletion leaving a citation behind ships a dangling reference
98
113
  - Decide both acts for every surface a hold names, not for one file among its siblings.
99
114
  - Write a shared path as the track, the path, and the branch that rebases, being the one merging second. The executing session edits the file and keeps both sides on the rebase.
100
115
 
116
+ ### Stamping a constraint
117
+
101
118
  A constraint measured against work in flight expires when that work merges, as a shared-path line does, so stamp the block with what it was measured against.
102
119
 
103
120
  - Give the stamp its own leading bullet, written as Measured against `<commit>` on <YYYY-MM-DD>. One stamp covers the whole block.
104
- - Stamp the commit rather than the track names or a date alone. The constraint already names each track, and a date does not separate two plans written on either side of a merge.
105
- - Re-test a stamped constraint before honoring it with `git fetch origin main --quiet && git log <commit>..origin/main --oneline -- <the paths the constraint names>`. Any commit it reports means the track landed and the constraint is dead. Fetch and scope the log to the paths in the same command, since a stale ref reads a dead constraint as live and a squashed subject names no track.
121
+ - Stamp the commit rather than the track names or a date alone, since a date does not separate two plans written either side of a merge
106
122
  - Read an unstamped constraint as unverified rather than as live, and confirm it against the open pull request list for the named paths.
107
123
 
124
+ Re-test a stamped constraint before honoring it, fetching and scoping the log in one command, since a stale ref reads a dead constraint as live and a squashed subject names no track. Any commit it reports means the track landed and the constraint is dead.
125
+
126
+ ```bash
127
+ git fetch origin main --quiet && git log <commit>..origin/main --oneline -- <the paths the constraint names>
128
+ ```
129
+
130
+ ### Fan-in and ready constraints
131
+
132
+ A batch in a fan-in set declares its side in a constraint bullet, ``Fan-in member of `feature-<integrator>` `` on a member and ``Fans in `feature-<a>`, `feature-<b>` `` on the integrator. `batches.md` holds when to fan in, and `canon records validate plans` reports `fan-in-unmatched` for a set whose two sides disagree.
133
+
108
134
  A constraint naming a `.canon/ready/` folder is a third shape beside the hold and the shared path. It makes that folder's files the verbatim source for the paths this plan's `**Files to touch:**` lists, per `ready.md`, so the executing session copies those paths rather than authoring them.
109
135
 
110
136
  ### Verification
111
137
 
138
+ Every outcome reaches the review with its proof named.
139
+
112
140
  - Name, for each outcome, the test or the command that proves it, as one bullet leading with the outcome and ending on the command in backticks.
113
141
  - Write a command a later session can run as given, from the project root. A description of what would be checked leaves the executing session to invent the check.
114
142
  - Name the visual check where no test reaches, and say it is visual, so a reader can tell a proof from a look.
115
143
 
116
144
  ### Risks
117
145
 
118
- - Name the collision rather than the category. A risk a reader cannot act on is padding.
119
- - Where the work establishes a resource with more than one consumer, list the consumers and mark each one read or write. A policy stated over that resource has to hold for the writers and not only for the consumer that prompted it.
120
- - Where the work changes a contract another track consumes, such as an exported signature, a verb's flags or record, or a config key, name the contract and list each consumer. The dispatcher reads this bullet for the contract hold, so a change left out reaches it as a clean shared file.
146
+ Name the collision rather than the category, since a risk a reader cannot act on is padding.
147
+
148
+ - For a resource with more than one consumer, list the consumers and mark each read or write, so a policy over it holds for every writer
149
+ - For a changed contract another track consumes, such as an exported signature, a verb's flags or record, or a config key, name it and list each consumer
150
+ - The dispatcher reads that contract bullet for the hold, so a change left out reaches it as a clean shared file
121
151
 
122
152
  ### Review focus
123
153
 
154
+ This section is where the planner's understanding of the risk reaches the review pass.
155
+
124
156
  - Name each input or state that would break the change if the implementation got it wrong, one bullet each, with what the change must do there.
125
- - Write it for the reviewer rather than the builder, since this section is where the planner's understanding of the risk reaches the review pass.
157
+ - Write it for the reviewer rather than the builder
126
158
  - Keep it apart from `**Risks:**`. A risk is something the work might collide with, and a focus item is something the finished diff must be shown to handle.
127
159
 
128
160
  ### Sources
129
161
 
162
+ A source earns an entry only once someone opened it.
163
+
130
164
  - Give each entry a link, the decision it backs, and the passage relied on in double quotes.
131
165
  - Mark a source that could not be fetched `unverified` and never quote it. A quote for a page nobody opened is the failure this section exists to prevent.
132
166
  - Cite no source that was found and not opened, following the lead rule in `groundwork.md`.
@@ -156,14 +190,19 @@ An execution that deviates rewrites the suggestion into the form below, leaving
156
190
 
157
191
  ### Preference questions and answers
158
192
 
193
+ The suggestion line is the planner's, and the answer line belongs to whoever owns the call.
194
+
159
195
  - Write `- Suggested: needs your call, <why>` where the answer turns on preference rather than on a technical default. Fabricating a default there hides an open question behind an accepted answer.
160
196
  - Never fill an `- Answer:` slot on behalf of the person who owns it. Recording the pick as the suggestion is what the suggestion line is for.
161
197
 
162
198
  ### Overrides and settled questions
163
199
 
164
- - Rewrite the `- Suggested:` line to the pick execution made when it deviates from an unanswered question, and leave the slot blank. The prohibition above reaches the answer line alone, so the suggestion line is where a deviation goes.
165
- - Open the rewritten text with `overridden at execution to <pick>,` and follow it with the measurement that moved the pick. The fixed phrase is what tells an override from an authored suggestion, which routinely carries a number too.
166
- - Take a deviation from an answered question back to whoever answered it rather than rewriting either line. A filled slot is a decision already made, and a suggestion rewritten under one leaves the plan holding two picks with no default resolving them.
200
+ A deviation from an unanswered question rewrites the `- Suggested:` line to the pick execution made and leaves the slot blank, since the prohibition above reaches the answer line alone.
201
+
202
+ - Open the rewritten text with `overridden at execution to <pick>,` and follow it with the measurement that moved the pick
203
+ - The fixed phrase tells an override from an authored suggestion, which routinely carries a number too
204
+ - Take a deviation from an answered question back to whoever answered it rather than rewriting either line
205
+ - A filled slot is a decision already made, and a suggestion rewritten under one leaves two picks with no default resolving them
167
206
  - Answer in place when a question is settled in conversation, so the file and the decision do not disagree.
168
207
 
169
208
  The plan is archived at ship, so the same deviation takes one line in the open task's `## Findings` naming what shipped. The plan holds why the pick moved and the task holds what the tree now has.
@@ -31,7 +31,8 @@ The file is optional, since measuring what is already there settles most questio
31
31
  Each spike carries four things:
32
32
 
33
33
  - The open question it answers, named by file and number. A spike attached to no question is a runaway.
34
- - The method, stated fully enough for a later reader to re-run it. Name the fixture and where it lived, since an arm pointed at a fixture inside the project measured the project, plus the exact command and the repetition count.
34
+ - The method, stated fully enough for a later reader to re-run it, with the exact command and the repetition count.
35
+ - The fixture and where it lived, since an arm pointed at a fixture inside the project measured the project
35
36
  - The result, and which question it closes. Record a spike that settles nothing too, so a later pass does not pay for it twice.
36
37
  - The measured cost, even for a single read, and the caveats bounding what the result proves. Cost is a report rather than a limit, and it makes the next spike estimable.
37
38
 
@@ -47,6 +48,8 @@ A file a reader opens to verify how a result was produced or what it showed live
47
48
 
48
49
  Open no other subfolder: `spikes/`, `web/`, and `research/` fold into these three, with a fetched page in `clones/` and a reference-site screenshot in `evidence/`.
49
50
 
51
+ ### Harnesses and read checks
52
+
50
53
  Reach for a test harness the project already carries before building one. An experiment no existing harness can express is a finding for the folder, not a new abstraction.
51
54
 
52
55
  Never count transcript matches to show a file was read. An instruction naming a path puts it in the transcript whether or not anything opened it, so the check is the tool call.