@erclx/canon 5.55.0 → 5.56.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 (67) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/SKILL.md +8 -10
  4. package/claude/skills/auto-ship/SKILL.md +4 -5
  5. package/claude/skills/auto-ship/references/failure-recovery.md +37 -17
  6. package/claude/skills/auto-ship/references/tier-failures.md +9 -7
  7. package/claude/skills/auto-ship/references/worktree-name.md +8 -5
  8. package/claude/skills/backlog-triage/SKILL.md +10 -10
  9. package/claude/skills/backlog-triage/references/apply.md +6 -6
  10. package/claude/skills/context-fold/references/classify.md +17 -4
  11. package/claude/skills/create-rule/references/rule.md +4 -0
  12. package/claude/skills/create-skill/SKILL.md +2 -2
  13. package/claude/skills/deploy-app/SKILL.md +2 -0
  14. package/claude/skills/deprecation-migration/SKILL.md +7 -9
  15. package/claude/skills/document-health/references/axes.md +1 -1
  16. package/claude/skills/git-followup/SKILL.md +16 -5
  17. package/claude/skills/git-issue/references/issue.md +9 -11
  18. package/claude/skills/git-pr/references/publish.md +4 -5
  19. package/claude/skills/git-split/SKILL.md +11 -4
  20. package/claude/skills/markdown-craft/SKILL.md +1 -1
  21. package/claude/skills/markdown-craft/references/markdown.md +2 -2
  22. package/claude/skills/markdown-craft/references/tables.md +9 -7
  23. package/claude/skills/plan-feature/SKILL.md +2 -0
  24. package/claude/skills/plan-feature/references/plan.md +2 -0
  25. package/claude/skills/review-address/SKILL.md +9 -7
  26. package/claude/skills/review-craft/SKILL.md +7 -9
  27. package/claude/skills/review-craft/references/adopted.md +10 -8
  28. package/claude/skills/review-pr/SKILL.md +2 -0
  29. package/claude/skills/review-pr/references/key-changes.md +8 -6
  30. package/claude/skills/review-ui/references/driving.md +10 -8
  31. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +6 -4
  32. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +9 -3
  33. package/claude/skills/role-reviewer/SKILL.md +5 -5
  34. package/claude/skills/search-craft/SKILL.md +5 -7
  35. package/claude/skills/session-worktree/SKILL.md +2 -0
  36. package/claude/skills/session-worktree/references/main-root-writes.md +2 -0
  37. package/claude/skills/systematic-debugging/SKILL.md +9 -9
  38. package/claude/skills/systematic-debugging/references/adopted.md +1 -1
  39. package/claude/skills/task-board/SKILL.md +2 -4
  40. package/claude/skills/task-board/references/tasks.md +5 -5
  41. package/claude/skills/task-complete/references/archive.md +5 -2
  42. package/claude/skills/test-craft/SKILL.md +2 -0
  43. package/claude/skills/test-craft/references/adopted.md +2 -0
  44. package/claude/skills/ui-checklist/SKILL.md +8 -9
  45. package/claude/skills/write-doc/SKILL.md +8 -8
  46. package/claude/skills/write-doc/references/readme.md +2 -0
  47. package/claude/skills/write-doc/references/wiki-kind.md +11 -4
  48. package/docs/agents/context-audit.md +16 -14
  49. package/docs/agents/markdown-audit.md +11 -4
  50. package/docs/agents/migrate.md +15 -13
  51. package/docs/agents/output-shape.md +2 -0
  52. package/docs/target/migrations.md +3 -3
  53. package/docs/workflow/operating-model.md +2 -0
  54. package/package.json +1 -1
  55. package/src/commands/markdown.ts +25 -29
  56. package/src/labels/density.ts +5 -46
  57. package/src/markdown/density.ts +41 -6
  58. package/src/markdown/scope.ts +6 -1
  59. package/src/markdown/structure.ts +18 -9
  60. package/src/markdown/tables.ts +32 -18
  61. package/src/process/harness.ts +8 -0
  62. package/src/process/seeded-package.ts +21 -0
  63. package/src/serve/static.ts +2 -60
  64. package/tooling/base/reference.md +7 -6
  65. package/tooling/claude/reference.md +7 -5
  66. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +7 -6
  67. package/src/serve/live.ts +0 -113
@@ -90,13 +90,15 @@ Once the fixes are commits, re-run step 5's staleness test against the new head.
90
90
 
91
91
  Write a summary reply to `.canon/tmp/pr/reply/reply-<number>.md`, keyed on the PR number so two sessions addressing different pull requests never overwrite each other. Load `write-human` for voice, follow `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md`, and keep each mapping to one line.
92
92
 
93
- | Part | Content |
94
- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
95
- | Heading | `## Review response`, distinct from human threads and subordinate to the review's own `## Review` |
96
- | Summary | One sentence. After a step 5 rebase, say so and name files resolved by hand and those the regen rebuilt, since the next review is a full pass. |
97
- | Findings | One line per finding under 200 characters, naming its outcome and the commit that carries it, in the shape below |
98
- | Docs | Any `.claude/` docs refreshed as a result of the fixes |
99
- | Close | `🤖 Addressed by Claude Code` on its own line, so the reply reads as a machine pass rather than a human sign-off |
93
+ | Part | Content |
94
+ | -------- | ---------------------------------------------------------------------------------------------------------------- |
95
+ | Heading | `## Review response`, distinct from human threads and subordinate to the review's own `## Review` |
96
+ | Summary | One sentence, plus the rebase note below |
97
+ | Findings | One line per finding under 200 characters, naming its outcome and the commit that carries it, in the shape below |
98
+ | Docs | Any `.claude/` docs refreshed as a result of the fixes |
99
+ | Close | `🤖 Addressed by Claude Code` on its own line, so the reply reads as a machine pass rather than a human sign-off |
100
+
101
+ After a step 5 rebase, the summary says so and names the files resolved by hand and those the regen rebuilt, since the next review is a full pass.
100
102
 
101
103
  ```markdown
102
104
  - **<severity>**, `<file>` line <n>: fixed in `<sha>`. <What now holds, in one sentence.>
@@ -87,15 +87,13 @@ Three scope checks follow the walk:
87
87
 
88
88
  ## Excuses and rebuttals
89
89
 
90
- | Excuse | Rebuttal |
91
- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
92
- | The tests pass, so the change works | Read what the diff did to the tests first. A test skipped, deleted, or stripped of its assertions passes by proving nothing. |
93
- | The hunk reads clean, so the review is done | The hunk is where the author looked. A consumer, a doc a section away, and the commit that added a removed guard are not in it. |
94
- | The checker passes on the branch | Read the checker's config and the inline suppressions in the diff. A path excluded from the run passes by not being read. |
95
- | It was split into smaller functions, so it is simpler | Count the concepts a reader holds before and after. Moved complexity reads as simpler only to the person who moved it. |
96
- | Nothing calls it, so deleting it is safe | Read why it was added. Code nobody calls today can still be guarding a path nobody exercised in the change. |
97
- | The description says it is faster | A claimed speedup with no measurement, or one run each side, is asserted. Ask for runs that beat the noise. |
98
- | The change only touches styles, so the screenshots can wait | A stylesheet diff says what changed and only the image says what a user sees. Open them, or say none exist. |
90
+ - **The tests pass, so the change works.** Read what the diff did to the tests first. A test skipped, deleted, or stripped of its assertions passes by proving nothing.
91
+ - **The hunk reads clean, so the review is done.** The hunk is where the author looked. A consumer, a doc a section away, and the commit that added a removed guard are not in it.
92
+ - **The checker passes on the branch.** Read the checker's config and the inline suppressions in the diff. A path excluded from the run passes by not being read.
93
+ - **It was split into smaller functions, so it is simpler.** Count the concepts a reader holds before and after. Moved complexity reads as simpler only to the person who moved it.
94
+ - **Nothing calls it, so deleting it is safe.** Read why it was added. Code nobody calls today can still be guarding a path nobody exercised in the change.
95
+ - **The description says it is faster.** A claimed speedup with no measurement, or one run each side, is asserted. Ask for runs that beat the noise.
96
+ - **The change only touches styles, so the screenshots can wait.** A stylesheet diff says what changed and only the image says what a user sees. Open them, or say none exist.
99
97
 
100
98
  ## Red flags
101
99
 
@@ -13,14 +13,16 @@ The `addyosmani/agent-skills` citations below all pin commit `addyosmani/agent-s
13
13
 
14
14
  ### Design and scope
15
15
 
16
- **The design procedure.** The nine ordered steps under the design axis draw on four sources, each restated without a language, a framework, or a transport so the walk holds on any stack.
16
+ **The design procedure.** The nine ordered steps under the design axis draw on four sources, each restated without a language, a framework, or a transport so the walk holds on any stack. Each source below carries the step it backs.
17
17
 
18
- | Source | Step it backs |
19
- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
20
- | Ousterhout's deep modules, information hiding, and pass-through methods, [A Philosophy of Software Design](https://web.stanford.edu/~ouster/cgi-bin/book.php) | Asking what each unit hides, and flagging a unit that passes its arguments straight through |
21
- | Parnas's criterion that a boundary hides a decision likely to change, [On the Criteria To Be Used in Decomposing Systems into Modules](https://dl.acm.org/doi/10.1145/361598.361623) | The opening step, naming the next likely change and counting what it touches |
22
- | Beck's design rules as Fowler records them, especially no duplication and fewest elements, [BeckDesignRules](https://martinfowler.com/bliki/BeckDesignRules.html) | The one-place step, and matching each pattern to a problem the code has today |
23
- | Google's reviewer guide on design, complexity, and over-engineering, [What to look for in a code review](https://google.github.io/eng-practices/review/reviewer/looking-for.html) | The frame for the whole walk, and the reason a speculative abstraction is a finding |
18
+ - Ousterhout's deep modules, information hiding, and pass-through methods, [A Philosophy of Software Design](https://web.stanford.edu/~ouster/cgi-bin/book.php)
19
+ - Backs asking what each unit hides, and flagging a unit that passes its arguments straight through
20
+ - Parnas's criterion that a boundary hides a decision likely to change, [On the Criteria To Be Used in Decomposing Systems into Modules](https://dl.acm.org/doi/10.1145/361598.361623)
21
+ - Backs the opening step, naming the next likely change and counting what it touches
22
+ - Beck's design rules as Fowler records them, especially no duplication and fewest elements, [BeckDesignRules](https://martinfowler.com/bliki/BeckDesignRules.html)
23
+ - Backs the one-place step, and matching each pattern to a problem the code has today
24
+ - Google's reviewer guide on design, complexity, and over-engineering, [What to look for in a code review](https://google.github.io/eng-practices/review/reviewer/looking-for.html)
25
+ - Backs the frame for the whole walk, and the reason a speculative abstraction is a finding
24
26
 
25
27
  The procedure stays in the body rather than a reference, since every review reads the design axis and a reference would cost a read on every run.
26
28
 
@@ -55,7 +57,7 @@ From `skills/security-and-hardening/SKILL.md`, the threat model first and the de
55
57
 
56
58
  ### Closing sections
57
59
 
58
- The excuses, red flags, and closing checklist follow the shape every practice skill in this toolkit carries, from [`docs/skill-anatomy.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/docs/skill-anatomy.md). Each excuse row rebuts a reason a review stops at the hunk, such as passing tests against a test the diff skipped.
60
+ The excuses, red flags, and closing checklist follow the shape every practice skill in this toolkit carries, from [`docs/skill-anatomy.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/docs/skill-anatomy.md). Each excuse rebuts a reason a review stops at the hunk, such as passing tests against a test the diff skipped.
59
61
 
60
62
  ## Declined
61
63
 
@@ -33,6 +33,8 @@ Both headings anchor as a section distinct from human threads. The full set is e
33
33
  | Evidence | `## Evidence` | `canon pr evidence`, through `pr-evidence` from `git-pr` and `git-followup` |
34
34
  | UI | `## UI review`, `## UI review closed` | `review-ui`, posted as a review beside this one and read by nothing here |
35
35
 
36
+ Three notes qualify the table.
37
+
36
38
  - The reply headings in order answer a finding, report a stale branch resolved without one, and carry a finding a worker produced after a close-out
37
39
  - `## Evidence` answers no comment on the thread, so the poll leaves it out of the unclassified count rather than reading it as a reply owing a re-review
38
40
  - A comment under any other heading reaches the poll as unclassified rather than as silence, so an invented ninth heading is a gap the next run reports
@@ -13,12 +13,14 @@ Test what `## Key changes` claims against the diff it describes, with `canon pr
13
13
 
14
14
  Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. Each field the record carries takes its own reading.
15
15
 
16
- | Field | Reading |
17
- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
18
- | `unmet` | a `should-fix` finding under the `**PR body**` block the stale box takes, one per path, quoting the `preview` bullet and the `head` |
19
- | `unnamed` | read for yourself and raise nothing off the count |
20
- | `unresolved` | reported nowhere, since it was judged in neither direction |
21
- | `incidental` | reported nowhere, since it owes no bullet |
16
+ | Field | Reading |
17
+ | ------------ | -------------------------------------------------------------------------------------- |
18
+ | `unmet` | a `should-fix` finding under the `**PR body**` block the stale box takes, one per path |
19
+ | `unnamed` | read for yourself and raise nothing off the count |
20
+ | `unresolved` | reported nowhere, since it was judged in neither direction |
21
+ | `incidental` | reported nowhere, since it owes no bullet |
22
+
23
+ Each `unmet` finding quotes the `preview` bullet and the `head`.
22
24
 
23
25
  ### Before filing an unmet path
24
26
 
@@ -45,14 +45,16 @@ A taste box takes the shot twice, once per theme, naming the theme in the file a
45
45
 
46
46
  ## The four verdicts
47
47
 
48
- Each box takes exactly one.
49
-
50
- | Verdict | When | Evidence it carries |
51
- | ------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52
- | pass or fail, read | The result is a fact the page reports | The value read, quoted, such as `scrollWidth 436 against clientWidth 320` |
53
- | pass or fail, frame | The result has a stated criterion only an image settles | The matching evidence stem or the pushed frame's link, inline under the failed box's heading, and what the frame shows, in words |
54
- | needs eyes | The box ends in `(taste)` | The dark and the light shot as a pair, each the matching evidence stem or a pushed frame's link, and what the frames showed, with nothing about whether it looks right |
55
- | not driven | The state could not be reached | The reason, such as an unreachable address, a `(local only)` box on a hosted preview, or a target the snapshot does not hold |
48
+ Each box takes exactly one, keyed here by the state it answers.
49
+
50
+ - **pass or fail, read.** The result is a fact the page reports.
51
+ - The evidence is the value read, quoted, such as `scrollWidth 436 against clientWidth 320`.
52
+ - **pass or fail, frame.** The result has a stated criterion only an image settles.
53
+ - The evidence is the matching evidence stem or the pushed frame's link, inline under the failed box's heading, and what the frame shows, in words.
54
+ - **needs eyes.** The box ends in `(taste)`.
55
+ - The evidence is the dark and the light shot as a pair, each the matching evidence stem or a pushed frame's link, and what the frames showed, with nothing about whether it looks right.
56
+ - **not driven.** The state could not be reached.
57
+ - The evidence is the reason, such as an unreachable address, a `(local only)` box on a hosted preview, or a target the snapshot does not hold.
56
58
 
57
59
  A fail names what was expected beside what was read. A not driven never reads as a fail, since it says the pass could not look rather than that the page is wrong. Its reason says whether the cause sits on the page or off it, since only a cause on the page opens the heading Step 7 picks.
58
60
 
@@ -9,10 +9,12 @@ Re-test every parked row as orchestrator. A blocker cell is a measurement taken
9
9
 
10
10
  Two triggers start this pass, and they differ in scope rather than in procedure.
11
11
 
12
- | Trigger | Scope |
13
- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
14
- | `orchestrator-sweep.md` sends the rows `canon tasks validate` listed untested | Those rows alone, since a merge changes the tree under every parked row and the validator already re-took the two kinds it settles |
15
- | An idle session, with nothing merged, workers building, and no pull request awaiting a first pass | Every parked row, since no event narrowed them, plus every `backlog.md` row, which carries no blocker cell for the validator to name |
12
+ - **Sweep.** `orchestrator-sweep.md` sends the rows `canon tasks validate` listed untested.
13
+ - Scope: those rows alone, since a merge changes the tree under every parked row and the validator already re-took the two kinds it settles
14
+ - **Idle.** The session has nothing merged, workers building, and no pull request awaiting a first pass.
15
+ - Scope: every parked row, since no event narrowed them, plus every `backlog.md` row, which carries no blocker cell for the validator to name
16
+
17
+ Three points hold for both triggers.
16
18
 
17
19
  - Neither trigger is a scheduler. `orchestrator-poll.md` owns the one recurring trigger, and a second loop firing into a static board is the always-on failure it warns about.
18
20
  - The sweep asks which parked row to promote next, taking the blocker cell as read, and this pass asks whether the cell is still true
@@ -25,10 +25,14 @@ The third trigger reaches a window the first two cannot. A session with three wo
25
25
  - Run `task-complete` to archive one the hook left in place
26
26
  - A task whose outcomes are standing policy never closes, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason and archive once that branch merges
27
27
  - Encoding it from this session would write a tracked file, which `## Boundaries` in the skill body forbids
28
- - An outcome marked `- [ ] Operator check: <outcome>` never blocks the archive. The hook prints no record, so read the archived file's `Operator check:` lines into the report's `Operator checks:` line and leave them unticked.
29
- - A merged task whose only open outcomes another repository owes, or that an operator owns and nobody marked, never archives, since `canon tasks archive` refuses `open-outcomes`. Strike each one on the task file as `- ~~<outcome>~~ <reason>`, with the reason on the same line, then archive. The task files are gitignored scratch, so this session may edit them.
28
+ - An outcome marked `- [ ] Operator check: <outcome>` never blocks the archive, so leave it unticked
29
+ - The hook prints no record, so read the archived file's `Operator check:` lines into the report's `Operator checks:` line
30
+ - A merged task whose only open outcomes another repository owes, or that an operator owns and nobody marked, never archives, since `canon tasks archive` refuses `open-outcomes`
31
+ - Strike each one on the task file as `- ~~<outcome>~~ <reason>` with the reason on the same line, then archive. The task files are gitignored scratch, so this session may edit them.
30
32
  - Strike only an outcome the operator or another repository owes. An open outcome this repository owes stays on the board, and the task stays with it.
31
- - Send a struck outcome that another repository owes to that repository's orchestrator through `session-relay`, which resolves the address, and let the receiver file it with `task-board` on its own board. `task-board` here would file it on this board. Name it in the report for the operator when no such session is live.
33
+ - Send a struck outcome that another repository owes to that repository's orchestrator through `session-relay`, which resolves the address
34
+ - Let the receiver file it with `task-board` on its own board, since `task-board` here would file it on this board
35
+ - Name it in the report for the operator when no such session is live
32
36
  - List every struck outcome in the report's `Struck:` line, so the work is carried by a named owner rather than lost to the strike
33
37
  4. Read `.canon/tasks/priority.md` and count the `## Up next` rows whose `Waiting on` has cleared, since a blocked row is no reserve. `## Run now` is what is running, so keep one in reserve beyond it.
34
38
  5. Promote from the top of `## Needs a plan`, where the last sweep recorded what to plan next.
@@ -69,6 +73,8 @@ Write `.canon/tasks/priority.md` through the `canon tasks` verbs alone, each rea
69
73
  | A row up or down inside its group | `canon tasks move <stem> --before <stem>` |
70
74
  | What a row waits on, or why it sits there | `canon tasks block <stem> "<reason>"` |
71
75
 
76
+ The points below govern writing the board through those verbs.
77
+
72
78
  - `place` removes the task's backlog line in the same call, so a row never sits on both surfaces or on neither
73
79
  - Demoting a row to `backlog.md` has no verb yet. Add the backlog line first, then delete the row with the file-editing tool, which errors on a non-match.
74
80
  - Put the reason a row sits where it does in its Waiting on cell through `block`, since a row promoted with the cell left alone carries an order the next sweep cannot check
@@ -19,11 +19,11 @@ This body states the role, the reads, the boundaries, and the channel, and start
19
19
 
20
20
  The session writes its comment and nothing tracked. Each kind of reviewer writes only these:
21
21
 
22
- | Reviewer | May write |
23
- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
24
- | Code | The comment through `review-pr` and the body file it names under `.canon/tmp/pr/review/` |
25
- | UI | The comment `review-ui` posts, its body file, and the browser's snapshots and frames under `.canon/tmp/pr/review-ui/`, plus `canon pr tick` on boxes it passed |
26
- | Either | The draft flag, through `canon pr lift` and no other way |
22
+ - **Code:** the comment through `review-pr` and the body file it names under `.canon/tmp/pr/review/`
23
+ - **UI:** the comment `review-ui` posts, its body file, and the browser's snapshots and frames under `.canon/tmp/pr/review-ui/`, plus `canon pr tick` on boxes it passed
24
+ - **Either:** the draft flag, through `canon pr lift` and no other way
25
+
26
+ The rules below close off everything else.
27
27
 
28
28
  - A tracked file, a branch, a worktree, a board file, and a commit all sit outside what this session may touch
29
29
  - Never enter a worktree or check the branch out. The pass reads a change, and a checkout is the first step toward editing it.
@@ -54,13 +54,11 @@ Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidan
54
54
 
55
55
  ## Excuses and rebuttals
56
56
 
57
- | Excuse | Rebuttal |
58
- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
59
- | The model already knows the good sites | It does, and it does not use that knowledge unprompted. Left to rank, a search puts guides written to rank above a field's reference pages. |
60
- | One search was enough | One search gives nothing to check a wrong fact against. The scoped search is what catches the open summary's error. |
61
- | The open results look authoritative | Ranking rewards pages written to rank, so advocates and thin guides sit beside the field's own record and tilt the summary. |
62
- | I scoped it, so every result is in scope | The domain filter is not strict, so a scoped search can return results from outside its list. |
63
- | The summary already answers it | A summary paraphrases. Fetch the page when two summaries disagree, since that is where the error sits. |
57
+ - **The model already knows the good sites.** It does, and it does not use that knowledge unprompted. Left to rank, a search puts guides written to rank above a field's reference pages.
58
+ - **One search was enough.** One search gives nothing to check a wrong fact against. The scoped search is what catches the open summary's error.
59
+ - **The open results look authoritative.** Ranking rewards pages written to rank, so advocates and thin guides sit beside the field's own record and tilt the summary.
60
+ - **I scoped it, so every result is in scope.** The domain filter is not strict, so a scoped search can return results from outside its list.
61
+ - **The summary already answers it.** A summary paraphrases. Fetch the page when two summaries disagree, since that is where the error sits.
64
62
 
65
63
  ## Red flags
66
64
 
@@ -73,6 +73,8 @@ Resolve `<type>` here too, since Step 3 previews it and Step 5 renames onto it,
73
73
  | A plan, through tier 1 or tier 2 | The `type` field of `canon tasks plan-branch <plan> --json` |
74
74
  | A branch, a bare user name, or anything else | `feat` |
75
75
 
76
+ The points below govern how the type is read.
77
+
76
78
  - The verb is the reading because a type read off a plan's sections is a judgment two sessions can grade differently, and the verb answers the same for both
77
79
  - Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero
78
80
  - Take `feat` and say the verb did not answer where it refuses, the record has no `type`, or the binary has no `plan-branch`
@@ -22,6 +22,8 @@ Each kind of write takes one route, and none of them is a stream editor.
22
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
23
  | Delete or move | One plain `rm` or `mv` per call rather than chained |
24
24
 
25
+ Three habits keep those routes from being refused or silently wrong.
26
+
25
27
  - Send `mkdir -p` for a missing folder as its own command first, since a `&&` compound is refused for complexity
26
28
  - Where no verb covers an edit, read the whole file and write it back whole through the heredoc route
27
29
  - Never reach for a stream editor, which rewrites the line it anchored to and exits zero on a non-match
@@ -23,7 +23,9 @@ No fixes without root-cause investigation first. If phase 1 is incomplete, no fi
23
23
  - State. Run the case alone and again after the others, and look for shared caches, globals, and fixtures one case leaks into the next.
24
24
  - None of these. Add logging at the suspect and record the conditions of each occurrence, which hands off to the no-root-cause section below rather than to a fix.
25
25
  3. Check what changed. Run `git diff` and `git log --oneline -10` from the project root to see recent changes.
26
- - For a regression with a known good commit, bisect rather than reading the log by eye: `git bisect start HEAD <good commit>`, then `git bisect run <the project's focused test command>` where a test reproduces the failure. Run `git bisect reset` once it names the commit, since bisect leaves the checkout on an old one.
26
+ - For a regression with a known good commit, bisect rather than reading the log by eye, with `git bisect start HEAD <good commit>`
27
+ - Where a test reproduces the failure, run `git bisect run <the project's focused test command>`
28
+ - Run `git bisect reset` once it names the commit, since bisect leaves the checkout on an old one
27
29
  4. For multi-component systems, add instrumentation at each component boundary and run once to see which layer fails before investigating further.
28
30
  5. Trace bad values backward to their source. Fix at the origin, not the symptom.
29
31
 
@@ -69,14 +71,12 @@ Most "no root cause" conclusions are incomplete investigations. Exhaust phase 1
69
71
 
70
72
  ## Excuses and rebuttals
71
73
 
72
- | Excuse | Rebuttal |
73
- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
74
- | "I know what the bug is, so I'll just fix it" | Then reproducing it costs a minute. When the reading is wrong, the fix moves the symptom and reports success over a cause still in place. |
75
- | "Quick fix for now, investigate later" | Later never reads the code again. The quick fix becomes the record of what the bug was, and it names the wrong place. |
76
- | "It's probably flaky, rerun it" | A rerun that passes says the failure is intermittent, not that it is gone. Take the timing, environment, or state branch in phase 1. |
77
- | "It works on my machine" | That is the environment branch's first data point. Diff versions, config, and data against where it fails rather than closing on it. |
78
- | "The error says to run this, so I'll run it" | The error is data about the failure. Whatever wrote it is the thing that is broken, so surface the step to the user rather than running it. |
79
- | "I'll verify manually instead of a test" | A manual check leaves nothing behind. The failing test is what shows the fix reached the cause, and what catches the bug's return. |
74
+ - **"I know what the bug is, so I'll just fix it."** Then reproducing it costs a minute. When the reading is wrong, the fix moves the symptom and reports success over a cause still in place.
75
+ - **"Quick fix for now, investigate later."** Later never reads the code again. The quick fix becomes the record of what the bug was, and it names the wrong place.
76
+ - **"It's probably flaky, rerun it."** A rerun that passes says the failure is intermittent, not that it is gone. Take the timing, environment, or state branch in phase 1.
77
+ - **"It works on my machine."** That is the environment branch's first data point. Diff versions, config, and data against where it fails rather than closing on it.
78
+ - **"The error says to run this, so I'll run it."** The error is data about the failure. Whatever wrote it is the thing that is broken, so surface the step to the user rather than running it.
79
+ - **"I'll verify manually instead of a test."** A manual check leaves nothing behind. The failing test is what shows the fix reached the cause, and what catches the bug's return.
80
80
 
81
81
  ## Red flags
82
82
 
@@ -20,7 +20,7 @@ External sources were read and filtered rather than imported. This file is the r
20
20
 
21
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).
22
22
 
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
+ Each excuse 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.
24
24
 
25
25
  ### Default shelf
26
26
 
@@ -74,10 +74,8 @@ Write `.canon/tasks/vXX.Y-<slug>.md` under the claimed label, reading the file f
74
74
 
75
75
  A task file with no row is a dropped task, so name its surface in the same pass that creates it. The test and both file shapes are in `${CLAUDE_SKILL_DIR}/references/board.md`.
76
76
 
77
- | Task | Surface |
78
- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
79
- | Plausibly planned within the next few waves | A row under `## Needs a plan` in `.canon/tasks/priority.md`, through `canon tasks place <stem> --group needs-a-plan --waiting "<reason>"` |
80
- | Anything else | A line in `.canon/tasks/backlog.md`, which is unordered |
77
+ - A task plausibly planned within the next few waves takes a row under `## Needs a plan` in `.canon/tasks/priority.md`, through `canon tasks place <stem> --group needs-a-plan --waiting "<reason>"`.
78
+ - Any other task takes a line in `.canon/tasks/backlog.md`, which is unordered.
81
79
 
82
80
  Position the row against its siblings with `--before <stem>` or `--after <stem>`, and state what it ranks against in the reason.
83
81
 
@@ -147,11 +147,11 @@ A task with no origin is lost context or work nobody decided to do. The reverse
147
147
 
148
148
  `Plan:` points at `../plans/feature-<slug>.md` while the task is open. Retarget both halves of the link as things move rather than dropping it, so a completed task still leads to its reasoning.
149
149
 
150
- | State | Target |
151
- | ----------------------------- | --------------------------------------- |
152
- | Open | `../plans/feature-<slug>.md` |
153
- | Shipped, plan archived | `../plans/archive/feature-<slug>.md` |
154
- | Task archived a folder deeper | `../../plans/archive/feature-<slug>.md` |
150
+ - Open: `../plans/feature-<slug>.md`
151
+ - Shipped, plan archived: `../plans/archive/feature-<slug>.md`
152
+ - Task archived a folder deeper: `../../plans/archive/feature-<slug>.md`
153
+
154
+ Three rules cover the line itself:
155
155
 
156
156
  - One plan per task, or one per slice as distinct plans on one line. A plan cited by two tasks is a misfile.
157
157
  - `canon tasks plan-link <task> <plan>` writes or corrects the line, and `--add` appends a slice's plan, so it is never hand-edited
@@ -56,8 +56,11 @@ An empty `plans` means the task cited no live plan, or a sibling still holds eve
56
56
  Each reason has one resolution, and none of them is to archive around it.
57
57
 
58
58
  - `open-outcomes`: the named outcomes are unmarked or genuinely open. Run `task-complete` when the work shipped unmarked, and leave the task on the board when the outcome is real.
59
- - An outcome only the operator can check is marked `- [ ] Operator check: <outcome>` rather than struck, which the archive passes and the record lists under `operatorChecks`. The mark has to land before the pull request opens.
60
- - Abandoned work, an outcome another repository owes, and an operator outcome nobody marked in time take the strike. The orchestrator's merge sweep strikes it with its reason and lists it in the report, per `${CLAUDE_SKILL_DIR}/../role-orchestrator/references/orchestrator-refill.md`, and the archive then runs. An outcome this repository owes is never struck for that.
59
+ - An outcome only the operator can check is marked `- [ ] Operator check: <outcome>` rather than struck, so the archive passes it and lists it under `operatorChecks`
60
+ - The mark has to land before the pull request opens
61
+ - Abandoned work, an outcome another repository owes, and an operator outcome nobody marked in time take the strike
62
+ - The orchestrator's merge sweep strikes it with its reason and lists it in the report, per `${CLAUDE_SKILL_DIR}/../role-orchestrator/references/orchestrator-refill.md`, and the archive then runs
63
+ - An outcome this repository owes is never struck for that
61
64
  - `ambiguous`: two tasks name one pull request, the misfile `${CLAUDE_SKILL_DIR}/references/tasks.md` rules out. Resolve the citation by hand, since no sweep repairs it.
62
65
  - `earlier-slice`: the number is listed on the task but is not the last. Leave the task on the board, and its last slice's merge archives it.
63
66
 
@@ -31,6 +31,8 @@ Size a test by what it touches rather than by what it covers. Pick the first row
31
31
  | Rendered behavior: states, interactions, conditional rendering, validation, focus | Component |
32
32
  | A journey across routes, or what only a real browser renders: layout, scroll, motion | End to end |
33
33
 
34
+ Four rules govern how a session reads the table.
35
+
34
36
  - Read the row off the behavior, never off the file. A component file holding a pure formatter takes a unit test for the formatter.
35
37
  - Split a behavior that spans rows. Test the copy at unit and the render at component, rather than asserting both in one browser run.
36
38
  - Write the lower test when a higher one catches a break no lower test did. A red end to end run with every unit and component test green names a missing lower test.
@@ -19,6 +19,8 @@ Three sources settle which layer a test belongs at and how the decision table re
19
19
  | Sizing by what a test touches | Google's small, medium, and large sizes ([Software Engineering at Google, ch. 11](https://abseil.io/resources/swe-book/html/ch11.html)) |
20
20
  | The component layer carrying UI weight | Kent C. Dodds's trophy ([Write tests](https://kentcdodds.com/blog/write-tests)) and Testing Library's [guiding principles](https://testing-library.com/docs/guiding-principles) |
21
21
 
22
+ Each source below is read for what it settles.
23
+
22
24
  - Fowler writes a lower test when a higher one catches what no lower one did. It is the body's layer rule and the decision table's reason.
23
25
  - Google's sizes name what a test may touch rather than cover. The table keys on the same, so it transfers across stacks without naming a runner.
24
26
  - Testing Library holds that tests resembling use give more confidence
@@ -33,15 +33,14 @@ The evidence comment already heads the list with `## What to look at`, so the fi
33
33
  - [ ] <route>[, <width>]: <verb> <target> → <expected visual result>
34
34
  ```
35
35
 
36
- Write each box so a session driving the running app can run it without guessing:
37
-
38
- | Part | Rule |
39
- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
40
- | Route | A path or the control that reaches it. A box naming none is driven from the address the driver opens. Write "from the page the app opens on" for a state reached by a sequence. |
41
- | Width | Only when the change can differ by width, such as layout, spacing, or anything responsive. Copy, color, or a state rendering the same everywhere leaves it off. |
42
- | Verb | An action a driver performs, such as "scroll to", "click", "resize to", or "tab to". Never "read" or "look at", which name no action. |
43
- | Taste | End the line with `(taste)` when the result is a judgment of look or feel. A driver reports such a box as needing a person's eyes rather than passing it. |
44
- | Setup | State inline any setup the page does not open in. End the line with `(local only)` when a hosted preview cannot reach that state, such as a stopped service or a seeded record. |
36
+ Write each box so a session driving the running app can run it without guessing, with one rule for each part:
37
+
38
+ - **Route.** A path or the control that reaches it. A box naming none is driven from the address the driver opens.
39
+ - Write "from the page the app opens on" for a state reached by a sequence.
40
+ - **Width.** Only when the change can differ by width, such as layout, spacing, or anything responsive. Copy, color, or a state rendering the same everywhere leaves it off.
41
+ - **Verb.** An action a driver performs, such as "scroll to", "click", "resize to", or "tab to". Never "read" or "look at", which name no action.
42
+ - **Taste.** End the line with `(taste)` when the result is a judgment of look or feel. A driver reports such a box as needing a person's eyes rather than passing it.
43
+ - **Setup.** State inline any setup the page does not open in. End the line with `(local only)` when a hosted preview cannot reach that state, such as a stopped service or a seeded record.
45
44
 
46
45
  When the plan cites `canon/design/<surface>/` under `**Design references:**`, name the reference as the comparison on each box for that surface, such as "→ matches `canon/design/<surface>/` in light and dark". The reviewer then judges the build against the accepted design instead of against taste.
47
46
 
@@ -13,12 +13,12 @@ Drafts one brand-new project document end to end: resolve its kind, read the sta
13
13
 
14
14
  Each kind has one standard and one reference. Load the reference for the resolved kind and no other, since every step below that differs by kind lives there.
15
15
 
16
- | Kind | Lands at | Standard | Reference |
17
- | ------- | -------------------------------------------------------- | ----------------------------------------------------------- | --------------------------------------------- |
18
- | docs | a page under `docs/` | `${CLAUDE_SKILL_DIR}/../docs-sync/references/docs.md` | `${CLAUDE_SKILL_DIR}/references/docs.md` |
19
- | context | an entry under `canon/context/` | `${CLAUDE_SKILL_DIR}/../context-fold/references/context.md` | `${CLAUDE_SKILL_DIR}/references/context.md` |
20
- | wiki | a reference page on a subject owned outside this project | `${CLAUDE_SKILL_DIR}/references/wiki.md` | `${CLAUDE_SKILL_DIR}/references/wiki-kind.md` |
21
- | readme | a `README.md`, at the root or in a folder | `${CLAUDE_SKILL_DIR}/../docs-sync/references/readme.md` | `${CLAUDE_SKILL_DIR}/references/readme.md` |
16
+ - **docs** lands at a page under `docs/`. Standard `${CLAUDE_SKILL_DIR}/../docs-sync/references/docs.md`, reference `${CLAUDE_SKILL_DIR}/references/docs.md`.
17
+ - **context** lands at an entry under `canon/context/`. Standard `${CLAUDE_SKILL_DIR}/../context-fold/references/context.md`, reference `${CLAUDE_SKILL_DIR}/references/context.md`.
18
+ - **wiki** lands at a reference page on a subject owned outside this project. Standard `${CLAUDE_SKILL_DIR}/references/wiki.md`, reference `${CLAUDE_SKILL_DIR}/references/wiki-kind.md`.
19
+ - **readme** lands at a `README.md`, at the root or in a folder. Standard `${CLAUDE_SKILL_DIR}/../docs-sync/references/readme.md`, reference `${CLAUDE_SKILL_DIR}/references/readme.md`.
20
+
21
+ Resolve the kind from the request by the rules below.
22
22
 
23
23
  - Read the kind off the destination the request names: a path, a folder, or the document's own name, such as "a context entry" or "a wiki page".
24
24
  - Ask which kind when the request names no destination, offering the candidates the subject fits with the likeliest first
@@ -30,10 +30,10 @@ Each kind has one standard and one reference. Load the reference for the resolve
30
30
 
31
31
  Read these in parallel, from the project root where a path is relative:
32
32
 
33
- - The kind's standard from the table above: the reader the document serves, its frontmatter, its structure, and what it links out to rather than restates
33
+ - The kind's standard from the kind list above: the reader the document serves, its frontmatter, its structure, and what it links out to rather than restates
34
34
  - `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md`: punctuation and formatting for all generated text
35
35
  - The `write-human` skill: voice, rhythm, and sentence construction for all generated text
36
- - The kind's reference from the table above
36
+ - The kind's reference from the kind list above
37
37
 
38
38
  ## Guards
39
39
 
@@ -23,6 +23,8 @@ Read the target if it exists, and branch on its headings.
23
23
  | Carries no H1, or only headings restating the scaffolding tool | Generator output | Continue, drafting over it rather than syncing its sections |
24
24
  | Does not exist | Nothing to read | Continue |
25
25
 
26
+ Three notes qualify those routes.
27
+
26
28
  - On the authored branch, report rather than offering to overwrite it or to conform it, since the project's own citations into its README are invisible from here
27
29
  - A hand-authored README opening with a badge block, or a title the H1 test misses, falls into the no-H1 branch the same as a scaffold page
28
30
  - The Confirm step catches that case before the write, so it is load-bearing. Never skip it on the reasoning that the guard already decided.
@@ -17,10 +17,17 @@ If `<wiki-root>` does not resolve, say so and ask whether to create it before dr
17
17
 
18
18
  The standard sets two tests and a page has to pass both. Run them before drafting anything, since a page failing either is non-conforming however well it is written.
19
19
 
20
- | Test | Fails on | Refusal |
21
- | ------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
22
- | Owned outside this repository | A subject describing how this repository works | `❌ <subject> is owned by this project, so it belongs in the docs surface or a context entry. Re-run write-doc naming that destination.` |
23
- | Owned by the vendor the folder split covers | A third-party tool or a vendor-neutral concept, however reference-like it reads | `❌ <subject> is outside the wiki's folder split. Route it to the docs surface or a skill body rather than adding a second folder for it.` |
20
+ The first test is owned outside this repository, and it fails on a subject describing how this repository works. Refuse with this line:
21
+
22
+ ```plaintext
23
+ ❌ <subject> is owned by this project, so it belongs in the docs surface or a context entry. Re-run write-doc naming that destination.
24
+ ```
25
+
26
+ The second test is owned by the vendor the folder split covers, and it fails on a third-party tool or a vendor-neutral concept, however reference-like it reads. Refuse with this line:
27
+
28
+ ```plaintext
29
+ ❌ <subject> is outside the wiki's folder split. Route it to the docs surface or a skill body rather than adding a second folder for it.
30
+ ```
24
31
 
25
32
  On the first test, offer the docs or context kind of this skill. The standard names one owner and one subfolder for the second.
26
33
 
@@ -22,19 +22,19 @@ canon context audit tooling/base/seeds --gate
22
22
 
23
23
  ## Output
24
24
 
25
- | Check | Reports | Reaches | Finding |
26
- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------- |
27
- | Citations | A path into an audited folder that resolves nowhere | Every audited folder | Gates always |
28
- | Requirements record | Words past the cap the record states as `This record holds at most 600 words.` | `canon/REQUIREMENTS.md` | Gates past a stated cap, never under `--citations-only` |
29
- | Required sections | An entry missing `Overview` or `Layout`. A split folder answers by any sibling | `canon/context/` | Gates under `--gate` |
30
- | Closed set | An H2 outside `Overview`, `Layout`, and `Gotchas`, under `extraSections` | `canon/context/` | Gates under `--gate` |
31
- | Shape | `retired-section`, `gotcha-count`, `gotcha-heading`, `gotcha-paragraph`, `layout-heading`, `layout-bullets`, `layout-paragraphs`, `layout-depth` | `canon/context/` | Gates under `--gate` in a `SHAPE_GATED_FOLDERS` folder only |
32
- | Index drift | An entry its index does not link, or a link resolving to nothing | Every audited folder | Gates under `--gate` |
33
- | Coverage | A folder directly under a code root that no Layout names, one with a Layout H3 in two entries, and a declared root matching nothing, under `coverage` | `canon/context/` | Gates under `--gate`, never under `--citations-only` |
34
- | Reference form | A backticked bare filename matching a sibling entry, under `bareReferences` | Split folders | Reports |
35
- | Length | An entry past about 150 rendered lines at 80 columns, with its `causes` | Every audited folder | Reports |
36
- | Tables | Six or more body rows whose first column mostly carries a path, command, or link | Every audited folder | Reports |
37
- | Provenance | A date, change number, or release label. A date after measured, verified, driven, passed, or fired is excluded | `canon/context/` | Reports |
25
+ | Check | Reports | Reaches | Finding |
26
+ | ------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------- |
27
+ | Citations | A path into an audited folder that resolves nowhere | Every audited folder | Gates always |
28
+ | Requirements record | Words past the cap the record states as `This record holds at most 600 words.` | `canon/REQUIREMENTS.md` | Gates past a stated cap, never under `--citations-only` |
29
+ | Required sections | An entry missing `Overview` or `Layout`. A split folder answers by any sibling | `canon/context/` | Gates under `--gate` |
30
+ | Closed set | An H2 outside `Overview`, `Layout`, and `Gotchas`, under `extraSections` | `canon/context/` | Gates under `--gate` |
31
+ | Shape | A break of the entry shape, in any kind listed under the table | `canon/context/` | Gates under `--gate` in a `SHAPE_GATED_FOLDERS` folder only |
32
+ | Index drift | An entry its index does not link, or a link resolving to nothing | Every audited folder | Gates under `--gate` |
33
+ | Coverage | A folder directly under a code root no Layout names, a Layout H3 in two entries, or an unmatched root, under `coverage` | `canon/context/` | Gates under `--gate`, never under `--citations-only` |
34
+ | Reference form | A backticked bare filename matching a sibling entry, under `bareReferences` | Split folders | Reports |
35
+ | Length | An entry past about 150 rendered lines at 80 columns, with its `causes` | Every audited folder | Reports |
36
+ | Tables | Six or more body rows whose first column mostly carries a path, command, or link | Every audited folder | Reports |
37
+ | Provenance | A date, change number, or release label. A date after measured, verified, driven, passed, or fired is excluded | `canon/context/` | Reports |
38
38
 
39
39
  The coverage roots come from `roots` in `canon/config/context.toml`, a list of folders or globs such as `packages/*/src`.
40
40
 
@@ -42,7 +42,7 @@ The coverage roots come from `roots` in `canon/config/context.toml`, a list of f
42
42
  - A file that is not valid TOML, or holds no list of strings under `roots`, gates under `--gate`
43
43
  - With no declaration and no `src/`, the audit reports no code root and never gates
44
44
 
45
- A shape break is any of these:
45
+ The shape kinds are `retired-section`, `gotcha-count`, `gotcha-heading`, `gotcha-paragraph`, `layout-heading`, `layout-bullets`, `layout-paragraphs`, and `layout-depth`. A shape break is any of these:
46
46
 
47
47
  - A `## Decisions` H2, or a `Gotchas` section past five bullets or holding a heading or paragraph
48
48
  - A `Layout` H3 titled neither a code-spanned path nor `Other folders`, or a heading below H3 under `Layout`
@@ -56,6 +56,8 @@ The development entry may carry a `Scripts` H3 exempt from both folder caps. `SH
56
56
  | `1` | Refused, with the reason on stderr |
57
57
  | `2` | A gating finding for the mode the run took |
58
58
 
59
+ The exit code follows the mode the run took. The bullets cover where the gate runs, what refuses, and how a seed opts out.
60
+
59
61
  - `bun run check` runs `--gate` against every `tooling/<stack>/seeds/` directory carrying a `.claude/` folder
60
62
  - A root resolving no audited folder refuses with `1` and warns, a root measuring no entry warns, and a seed short a section fails with `2`
61
63
  - A seed omitting a required section on purpose sets `stub: true` in its frontmatter. Only the value `true` counts, and both install paths strip the field.