@erclx/canon 5.39.0 → 5.40.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.
- package/README.md +5 -5
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/canvas-board/SKILL.md +1 -1
- package/claude/skills/draft-slides/SKILL.md +2 -3
- package/claude/skills/draft-slides/references/deck.md +183 -0
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-pr/references/final-command.md +1 -1
- package/claude/skills/git-pr/references/labels.md +1 -1
- package/claude/skills/git-pr/references/publish.md +1 -1
- package/claude/skills/review-ui/SKILL.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
- package/claude/skills/task-board/references/board.md +1 -1
- package/claude/skills/task-board/references/tasks.md +1 -1
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/docs/agents/audits.md +61 -60
- package/docs/agents/context-audit.md +40 -58
- package/docs/agents/index.md +5 -51
- package/docs/agents/install-and-sync.md +1 -0
- package/docs/agents/markdown-audit.md +53 -99
- package/docs/agents/records.md +37 -79
- package/docs/agents/sessions-transfer.md +26 -70
- package/docs/target/index.md +0 -1
- package/docs/target/migrations.md +57 -66
- package/docs/target/projects.md +36 -78
- package/docs/target/scenarios.md +9 -19
- package/docs/target/sync.md +27 -68
- package/docs/workflow/ai-workflow.md +22 -68
- package/docs/workflow/operating-model.md +32 -186
- package/docs/workflow/parallel-features.md +29 -66
- package/docs/workflow/skill-map-on-request.md +22 -24
- package/docs/workflow/skill-map.md +72 -76
- package/docs/workflow/visual-design-workflow.md +25 -118
- package/docs/workflow/zshrc-aliases.md +18 -37
- package/package.json +1 -1
- package/src/canvas/client/inspector/fields.css +4 -0
- package/src/canvas/index.html +6 -0
- package/src/claude/skills-reach.ts +2 -2
- package/src/cli/ui.ts +3 -1
- package/src/commands/canvas.ts +23 -0
- package/src/commands/capture.ts +14 -0
- package/src/commands/claude.ts +13 -0
- package/src/commands/demo.ts +22 -0
- package/src/commands/deps.ts +6 -0
- package/src/commands/driver.ts +28 -2
- package/src/commands/gov.ts +52 -18
- package/src/commands/intake.ts +17 -0
- package/src/commands/labels.ts +38 -5
- package/src/commands/pr.ts +160 -43
- package/src/commands/records.ts +8 -0
- package/src/commands/secrets.ts +6 -0
- package/src/commands/sessions.ts +8 -0
- package/src/commands/tasks.ts +52 -0
- package/src/commands/teach.ts +13 -0
- package/src/commands/upstream.ts +25 -1
- package/src/commands/worktrees.ts +5 -0
- package/src/context/audit.ts +22 -4
- package/src/context/folders.ts +1 -1
- package/src/context/shape-gated.ts +4 -2
- package/src/counts/scan.ts +1 -1
- package/src/design/components.ts +1 -1
- package/src/design/document.ts +1 -1
- package/src/design/tokens.ts +1 -1
- package/src/gate/boundaries.ts +4 -1
- package/src/gate/measures.ts +1 -1
- package/src/gate/stages.ts +7 -7
- package/src/git/env.ts +6 -0
- package/src/markdown/scope.ts +5 -17
- package/src/pr/lift.ts +153 -19
- package/src/pr/painted.ts +87 -0
- package/src/roots/record.ts +18 -1
- package/src/sandbox/census.ts +1 -1
- package/src/sandbox/headless/run.ts +3 -2
- package/src/sandbox/headless/watch.ts +3 -4
- package/src/slides/convert/master.ts +3 -0
- package/src/sync/format.ts +46 -0
- package/src/sync/stamp.ts +6 -0
- package/tooling/astro/reference.md +2 -2
- package/tooling/base/reference.md +1 -1
- package/tooling/go/reference.md +1 -1
- package/tooling/nextjs/reference.md +1 -1
- package/tooling/php/reference.md +1 -1
- package/tooling/python/reference.md +1 -1
- package/tooling/vite-react/reference.md +1 -1
- package/tooling/web/reference.md +1 -1
- package/docs/agents/canvas.md +0 -86
- package/docs/agents/capture.md +0 -65
- package/docs/agents/census.md +0 -23
- package/docs/agents/comments.md +0 -34
- package/docs/agents/context-audit-checks.md +0 -108
- package/docs/agents/context-classify.md +0 -101
- package/docs/agents/counts.md +0 -74
- package/docs/agents/demo.md +0 -140
- package/docs/agents/driver.md +0 -103
- package/docs/agents/gate.md +0 -90
- package/docs/agents/hooks.md +0 -78
- package/docs/agents/intake.md +0 -81
- package/docs/agents/key-changes.md +0 -116
- package/docs/agents/label-coverage.md +0 -86
- package/docs/agents/markdown-audit-density.md +0 -39
- package/docs/agents/markdown-audit-weight.md +0 -83
- package/docs/agents/pr-evidence-layout.md +0 -70
- package/docs/agents/pr-evidence.md +0 -273
- package/docs/agents/pr-frames.md +0 -131
- package/docs/agents/pr-lift.md +0 -132
- package/docs/agents/pr-local.md +0 -111
- package/docs/agents/pr-preview.md +0 -155
- package/docs/agents/pr-reads.md +0 -111
- package/docs/agents/pr-tick.md +0 -72
- package/docs/agents/records-push.md +0 -61
- package/docs/agents/records-stale.md +0 -40
- package/docs/agents/records-validate.md +0 -57
- package/docs/agents/restated.md +0 -83
- package/docs/agents/routing.md +0 -61
- package/docs/agents/rule-citations.md +0 -90
- package/docs/agents/sandbox.md +0 -126
- package/docs/agents/sessions.md +0 -128
- package/docs/agents/skills-audit.md +0 -120
- package/docs/agents/skills-reach.md +0 -64
- package/docs/agents/slides.md +0 -176
- package/docs/agents/state-scoped-risk.md +0 -105
- package/docs/agents/superseded.md +0 -85
- package/docs/agents/tasks-archive.md +0 -83
- package/docs/agents/tasks-plans.md +0 -152
- package/docs/agents/tasks-validate.md +0 -133
- package/docs/agents/tasks.md +0 -123
- package/docs/agents/teach-authoring.md +0 -118
- package/docs/agents/teach.md +0 -157
- package/docs/agents/test-order.md +0 -58
- package/docs/agents/upstream.md +0 -94
- package/docs/agents/worktrees.md +0 -118
- package/docs/target/standards-moved.md +0 -34
package/README.md
CHANGED
|
@@ -161,13 +161,13 @@ For the full journey from scaffold through adding a domain later to syncing upst
|
|
|
161
161
|
|
|
162
162
|
Each domain carries an entry written for someone maintaining the toolkit rather than installing it. These paths resolve in a clone only. The published package ships `docs` and not `.claude`, so an installed copy does not carry them.
|
|
163
163
|
|
|
164
|
-
- [Claude Code plugin](canon/context/
|
|
165
|
-
- [Governance rules](canon/context/governance
|
|
166
|
-
- [Tooling stacks](canon/context/tooling
|
|
167
|
-
- [Design system](canon/context/design.md)
|
|
164
|
+
- [Claude Code plugin](canon/context/surfaces/plugin.md)
|
|
165
|
+
- [Governance rules](canon/context/surfaces/governance.md)
|
|
166
|
+
- [Tooling stacks](canon/context/surfaces/tooling.md)
|
|
167
|
+
- [Design system](canon/context/features/design.md)
|
|
168
168
|
- [Slides](canon/context/features/slides.md)
|
|
169
169
|
- [Transcripts](canon/context/features/transcripts.md)
|
|
170
|
-
- [Sandbox](canon/context/sandbox
|
|
170
|
+
- [Sandbox](canon/context/development/sandbox.md)
|
|
171
171
|
|
|
172
172
|
## Contributing
|
|
173
173
|
|
|
@@ -9,7 +9,7 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
Drive the canvas the operator is looking at. A page is a folder of HTML frames and a frame is one file, so a session draws by writing files and the operator sees each write land in the browser. The content format is fixed by `${CLAUDE_SKILL_DIR}/references/canvas.md`. Read it before writing a frame.
|
|
11
11
|
|
|
12
|
-
Every verb below is `canon canvas`. Run `canon
|
|
12
|
+
Every verb below is `canon canvas`. Run `canon canvas --help` for the verbs and their refusals, and read `${CLAUDE_SKILL_DIR}/references/canvas.md` for the content format.
|
|
13
13
|
|
|
14
14
|
## Guards
|
|
15
15
|
|
|
@@ -11,16 +11,15 @@ Draw each slide as an HTML file in a deck folder, then shell out to `canon slide
|
|
|
11
11
|
|
|
12
12
|
## Read the decks and the format
|
|
13
13
|
|
|
14
|
-
Run
|
|
14
|
+
Run the list first, then read the format. Never hardcode a deck name, an attribute, or a chart type.
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
canon slides list --json 2>/dev/null
|
|
18
|
-
canon docs slides
|
|
19
18
|
```
|
|
20
19
|
|
|
21
20
|
The list returns one row per deck, carrying its `name`, `title`, slide count, and `path`. When the request names a deck the list holds, edit that folder. Otherwise pick a new kebab-case name no row carries.
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
Read `${CLAUDE_SKILL_DIR}/references/deck.md`. It states what `deck.json` holds, what each slide declares on its `<body>`, the motion attributes, speaker notes, and charts. Each refusal prints as a `✗` line from the render.
|
|
24
23
|
|
|
25
24
|
## Draw the deck
|
|
26
25
|
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Deck reference
|
|
3
|
+
description: The deck folder, the deck.json fields, the attributes a slide sets on its body, motion, the master's token roles, speaker notes, and charts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deck reference
|
|
7
|
+
|
|
8
|
+
Applies to the slides under `.canon/slides/<deck>/`, which `canon slides render <deck>` turns into an editable PowerPoint file. Each slide describes its own shapes. What belongs to the whole deck sits in `deck.json`.
|
|
9
|
+
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [The deck folder](#the-deck-folder)
|
|
13
|
+
- [The deck file](#the-deck-file)
|
|
14
|
+
- [What each slide declares](#what-each-slide-declares)
|
|
15
|
+
- [Motion](#motion)
|
|
16
|
+
- [The master](#the-master)
|
|
17
|
+
- [Speaker notes](#speaker-notes)
|
|
18
|
+
- [Charts](#charts)
|
|
19
|
+
|
|
20
|
+
## The deck folder
|
|
21
|
+
|
|
22
|
+
| Path | Holds |
|
|
23
|
+
| -------------------------------- | ---------------------------------------------------- |
|
|
24
|
+
| `.canon/slides/<deck>/*.html` | the slides, rendered in filename order |
|
|
25
|
+
| `.canon/slides/<deck>/deck.json` | what belongs to the whole deck |
|
|
26
|
+
| `.canon/slides/<deck>/assets/` | images the slides reference by a relative path |
|
|
27
|
+
| `.canon/slides/layouts/` | the project's shared layouts, never listed as a deck |
|
|
28
|
+
|
|
29
|
+
A folder holding no `.html` file is not a deck. `render` with no name takes the only deck, and refuses with the list when there are several. It also takes a folder path outside `.canon/slides/`.
|
|
30
|
+
|
|
31
|
+
## The deck file
|
|
32
|
+
|
|
33
|
+
`deck.json` is optional. Without it the deck takes the defaults below.
|
|
34
|
+
|
|
35
|
+
| Field | Default | What it sets |
|
|
36
|
+
| -------------- | ------------------------------ | ------------------------------------------------- |
|
|
37
|
+
| `title` | the folder name | the file's title and the default footer text |
|
|
38
|
+
| `header` | off | a band at the top, with `left`, `center`, `right` |
|
|
39
|
+
| `footer` | on, with the title on the left | a band at the bottom, with the same three slots |
|
|
40
|
+
| `slideNumbers` | `true` | the number at the right of the footer |
|
|
41
|
+
| `mark` | none | an image path, relative to the folder, top right |
|
|
42
|
+
| `fonts` | none | faces to embed in the file |
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"title": "Q3 review",
|
|
47
|
+
"header": { "left": "Acme" },
|
|
48
|
+
"footer": { "center": "Internal" },
|
|
49
|
+
"mark": "assets/mark.png",
|
|
50
|
+
"fonts": [
|
|
51
|
+
{ "family": "Inter", "path": "fonts/Inter-Regular.ttf" },
|
|
52
|
+
{ "family": "Inter", "weight": 700, "path": "fonts/Inter-Bold.ttf" }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Bands and the mark
|
|
58
|
+
|
|
59
|
+
A band takes `show` and the three slots. A declared band merges over its default, so `"footer": { "center": "Internal" }` keeps the title on the left. Declaring any slot turns a band on unless it also says `"show": false`. Set a slot to `""` to empty it.
|
|
60
|
+
|
|
61
|
+
- Slide numbers hold the footer's right slot and show only where the footer does. Set `slideNumbers` to `false` to use `footer.right`.
|
|
62
|
+
- Prefer a raster mark, since an SVG mark lands as a vector with a broken fallback.
|
|
63
|
+
|
|
64
|
+
### Embedded faces
|
|
65
|
+
|
|
66
|
+
Each `fonts` entry names one TrueType or OpenType file inside the deck folder:
|
|
67
|
+
|
|
68
|
+
| Key | Default | Rule |
|
|
69
|
+
| -------- | -------- | ------------------------------------------------------------------- |
|
|
70
|
+
| `family` | required | match the family the slides set |
|
|
71
|
+
| `weight` | `400` | `600` and above fills the bold slot, anything lighter fills regular |
|
|
72
|
+
| `style` | `normal` | `normal` or `italic` |
|
|
73
|
+
| `path` | required | relative to the folder, and has to stay inside it |
|
|
74
|
+
|
|
75
|
+
A face is left out, and the deck still written, when its license forbids embedding, when it is a variable font or a `woff` or `woff2` file, or when a second face lands in a filled slot. Supply static instances, one per weight, and the TrueType or OpenType file a `woff2` was compressed from.
|
|
76
|
+
|
|
77
|
+
## What each slide declares
|
|
78
|
+
|
|
79
|
+
A slide sets its place in the deck through attributes on `<body>`.
|
|
80
|
+
|
|
81
|
+
| Attribute | Effect |
|
|
82
|
+
| --------------------------------------- | --------------------------------------------- |
|
|
83
|
+
| `data-section="Results"` | opens a section the slides after it stay in |
|
|
84
|
+
| `data-hidden` | hides the slide in the show |
|
|
85
|
+
| `data-header="off"` | drops the header on this slide |
|
|
86
|
+
| `data-footer="off"` | drops the footer and its number on this slide |
|
|
87
|
+
| `data-footer-left`, `-center`, `-right` | replaces that footer slot on this slide alone |
|
|
88
|
+
| `data-header-left`, `-center`, `-right` | replaces that header slot on this slide alone |
|
|
89
|
+
|
|
90
|
+
Once any slide opens a section, slides ahead of the first sit in a section named after the deck. A title the deck returns to after another section opens a new section numbered `Intro (2)`.
|
|
91
|
+
|
|
92
|
+
A slide dropping one band keeps the other from the master. A slide replacing a slot draws its band as its own text, so a later edit in the master view skips it.
|
|
93
|
+
|
|
94
|
+
## Motion
|
|
95
|
+
|
|
96
|
+
| Attribute | Takes | Effect |
|
|
97
|
+
| -------------------------- | ------------------------------- | -------------------------------------- |
|
|
98
|
+
| `data-transition` | `fade`, `push`, `wipe`, `cover` | the transition into this slide |
|
|
99
|
+
| `data-transition-duration` | `500`, `500ms`, or `0.5s` | rounded to 0.5, 0.75, or 1 second |
|
|
100
|
+
| `data-enter` | `fade`, `fly`, `wipe`, `zoom` | an entrance played on a click |
|
|
101
|
+
| `data-enter-order` | a number | the click it plays on, lowest first |
|
|
102
|
+
| `data-enter-duration` | `500`, `500ms`, or `0.5s` | the entrance length, 500 ms by default |
|
|
103
|
+
|
|
104
|
+
`data-transition` and `data-transition-duration` go on `<body>`. The `data-enter` family goes on the element.
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<body data-transition="fade">
|
|
108
|
+
<h1>Results</h1>
|
|
109
|
+
<div class="card" data-enter="fly" data-enter-order="1">…</div>
|
|
110
|
+
<div class="card" data-enter="fly" data-enter-order="2">…</div>
|
|
111
|
+
</body>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- Each entrance is its own click, and entrances without an order play after the ordered ones, in page order.
|
|
115
|
+
- An entrance brings in every shape drawn from its element and the elements inside it, so a card's box and text arrive together.
|
|
116
|
+
- An inner element with its own `data-enter` waits for its own click.
|
|
117
|
+
- Fly comes in from the bottom and wipe from the left.
|
|
118
|
+
|
|
119
|
+
## The master
|
|
120
|
+
|
|
121
|
+
The master takes its colors from the `<html>` element of the first slide, laid out with the project's token stylesheet injected:
|
|
122
|
+
|
|
123
|
+
| Source | Used for |
|
|
124
|
+
| -------------------------------------------- | ---------------- |
|
|
125
|
+
| `--color-background` | the slide ground |
|
|
126
|
+
| `--color-text` | the header text |
|
|
127
|
+
| `--color-muted` | the footer text |
|
|
128
|
+
| `--color-accent` | the slide number |
|
|
129
|
+
| `<body>` font family, ` Variable` suffix cut | the theme face |
|
|
130
|
+
|
|
131
|
+
A role the project declares no token for falls back to the slide body's own color and prints one `✗` line naming it. It never falls back to the toolkit's palette.
|
|
132
|
+
|
|
133
|
+
A slide whose `<body>` background differs from the master's keeps its own. A slide whose `<body>` computes a `--color-text` apart from the master's prints a `✗` line, since its bands keep the master's colors and may not read against its ground.
|
|
134
|
+
|
|
135
|
+
## Speaker notes
|
|
136
|
+
|
|
137
|
+
`<aside class="notes">` becomes the slide's notes and is never drawn. Each paragraph or list item becomes its own line, and markup is dropped.
|
|
138
|
+
|
|
139
|
+
## Charts
|
|
140
|
+
|
|
141
|
+
A `<figure data-chart="...">` holding a `<table>` becomes a native, editable chart where the figure was laid out. The table is not drawn as well.
|
|
142
|
+
|
|
143
|
+
```html
|
|
144
|
+
<figure data-chart="bar" data-labels>
|
|
145
|
+
<figcaption>Revenue by region</figcaption>
|
|
146
|
+
<table>
|
|
147
|
+
<tr>
|
|
148
|
+
<th>Region</th>
|
|
149
|
+
<th>Q1</th>
|
|
150
|
+
<th>Q2</th>
|
|
151
|
+
</tr>
|
|
152
|
+
<tr>
|
|
153
|
+
<td>North</td>
|
|
154
|
+
<td>12</td>
|
|
155
|
+
<td>16</td>
|
|
156
|
+
</tr>
|
|
157
|
+
<tr>
|
|
158
|
+
<td>South</td>
|
|
159
|
+
<td></td>
|
|
160
|
+
<td>11</td>
|
|
161
|
+
</tr>
|
|
162
|
+
</table>
|
|
163
|
+
</figure>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
- `data-chart` takes `bar`, `line`, `area`, `pie`, or `doughnut`.
|
|
167
|
+
- The header row names the series and the first column names the categories.
|
|
168
|
+
- An empty cell is a gap, not a zero. A comma is a thousands separator only where it groups in threes, as in `12,345.5`, so a comma-decimal `3,5` refuses.
|
|
169
|
+
- `data-labels` shows each value, and a `<figcaption>` becomes the chart title.
|
|
170
|
+
- Series take the accent first, then every other declared `--color-*` role in sheet order except the background and surface, repeating past the last.
|
|
171
|
+
|
|
172
|
+
A refused chart, effect, or face is left out and the rest of the deck is written. Each prints a `✗` line, and the exit depends on the case:
|
|
173
|
+
|
|
174
|
+
| Case | Exit |
|
|
175
|
+
| ----------------------------------------------------------------------- | ---- |
|
|
176
|
+
| malformed or unknown `deck.json` field | 1 |
|
|
177
|
+
| `mark` path missing | 1 |
|
|
178
|
+
| `fonts` path missing or outside the folder | 1 |
|
|
179
|
+
| face that cannot embed | 0 |
|
|
180
|
+
| unknown transition or entrance name | 0 |
|
|
181
|
+
| entrance on an element that draws nothing | 0 |
|
|
182
|
+
| chart cell that is not a number, or `data-chart` off-list | 0 |
|
|
183
|
+
| token role not declared, or a slide body setting its own `--color-text` | 0 |
|
|
@@ -31,7 +31,7 @@ A reviewer on the operator's machine can open the branch's running dev server, w
|
|
|
31
31
|
canon pr local --json
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
The verb reads the listening sockets on this machine, keeps those whose process runs inside this worktree, and reports the lowest port serving an HTML page. A server in another worktree or in the main checkout is never reported, since it shows a different branch. `canon
|
|
34
|
+
The verb reads the listening sockets on this machine, keeps those whose process runs inside this worktree, and reports the lowest port serving an HTML page. A server in another worktree or in the main checkout is never reported, since it shows a different branch. `canon pr local --help` states the contract. Read `reason` on the record rather than the exit code.
|
|
35
35
|
|
|
36
36
|
- `ok`: hold the record's `url` for the evidence step below.
|
|
37
37
|
- `no-server` or `no-listener-reader`: hold the reason for the closing report, pass no link, and move on. Do not start a server here, since one started inside the ship chain has no owner to stop it.
|
|
@@ -110,7 +110,7 @@ The evidence comment is already posted, so the reviewer has the screenshots whil
|
|
|
110
110
|
canon pr preview <number> --json
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
The verb dispatches the project's Pages deploy on the pull request's branch and waits on the run for up to 15 minutes. It refuses before dispatching anything when the deploy command passes no `--branch`, since that deploy would publish the branch to production, and when the workflow's own push path filter matches no path the pull request changed, since a dispatch ignores that filter and the site it published would show none of the change. `canon
|
|
113
|
+
The verb dispatches the project's Pages deploy on the pull request's branch and waits on the run for up to 15 minutes. It refuses before dispatching anything when the deploy command passes no `--branch`, since that deploy would publish the branch to production, and when the workflow's own push path filter matches no path the pull request changed, since a dispatch ignores that filter and the site it published would show none of the change. `canon pr preview --help` states the contract. Read `reason` on the record rather than the exit code.
|
|
114
114
|
|
|
115
115
|
- `ok`: re-render the evidence body with the address on the line under `## Evidence`, then post or update it exactly as the evidence step does, through the same tmp file and the `commentId` the record carries:
|
|
116
116
|
|
|
@@ -54,7 +54,7 @@ case "$links" in
|
|
|
54
54
|
printf 'Removed %s session link(s) from the live body of #%s.\n' "$links" "$pr_number" >&2
|
|
55
55
|
;;
|
|
56
56
|
esac
|
|
57
|
-
record=$(canon labels apply "$pr_number" --
|
|
57
|
+
record=$(canon labels apply "$pr_number" --json 2>/dev/null | tail -n 1)
|
|
58
58
|
if printf '%s' "$record" | jq -e 'has("earned")' >/dev/null 2>&1; then
|
|
59
59
|
owed=$(printf '%s' "$record" | jq -r '.owed | join(",")')
|
|
60
60
|
missing=$(printf '%s' "$record" | jq -r '.missingOnRemote | join(",")')
|
|
@@ -82,7 +82,7 @@ What it leaves unmeasured is a prefix reaching no path, so a row left behind by
|
|
|
82
82
|
|
|
83
83
|
Apply labels after the pull request resolves, never as a field on the create. A create carrying a label the remote lacks either fails whole or creates the label, depending on the surface, and neither is the map's call. One step against a pull request that already exists covers the create and the edit path alike. It runs over REST, so it works where GraphQL is blocked, and the REST endpoint creates any label it is handed that the remote lacks, so the step reads each name off the remote first and warns on a missing one rather than adding it.
|
|
84
84
|
|
|
85
|
-
`canon labels apply <number>` is that step. It resolves the earned set the
|
|
85
|
+
`canon labels apply <number>` is that step. It resolves the earned set from the pull request's own files listing, or from the git range when `--base` is passed, binds to the pull request only when its head is the current branch and it is open, and adds each earned label the pull request lacks. `--check` reports what is owed and writes nothing. The record carries `number`, `earned`, `present`, `added`, `owed`, `missingOnRemote`, and `uncovered`.
|
|
86
86
|
|
|
87
87
|
A pull request opened outside this skill, such as by `gh pr create`, takes the same command, since nothing else labels it.
|
|
88
88
|
|
|
@@ -44,7 +44,7 @@ A phase label is one way text names the board, and a path under a record root is
|
|
|
44
44
|
|
|
45
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.
|
|
46
46
|
|
|
47
|
-
Under the tracked `canon/` and `.claude/` folders there is no hit, since `canon/context/governance
|
|
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.
|
|
48
48
|
|
|
49
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.
|
|
50
50
|
|
|
@@ -26,6 +26,7 @@ A pass stops rather than repeat a verdict that already covers the head.
|
|
|
26
26
|
- An open verdict at the head stops the same way, unless a `## Review response` or `## Post-review findings` comment is newer than it or the launch names an address
|
|
27
27
|
- The hosted preview was not built from the head: stop and post nothing, naming `built`, `tip`, and `canon pr preview <number> --json` for the dispatcher
|
|
28
28
|
- Post, then run `canon pr lift <number>` on a close. Never merge or ready the PR by hand, and edit the evidence comment only through `canon pr tick`.
|
|
29
|
+
- A push after a close owes a re-drive only when it changed a painted path, since the lift carries the close across the rest.
|
|
29
30
|
|
|
30
31
|
## Step 1: resolve the pull request
|
|
31
32
|
|
|
@@ -11,7 +11,7 @@ Read this at loop step 6, once the poll reports a branch stale or conflicted, or
|
|
|
11
11
|
- Resolve the target at the moment of sending with `canon sessions list --branch`, never from a mapping written down earlier, since names rotate as sessions end and one recorded earlier in a session has failed inside the hour. `orchestrator-poll.md` routes on the count and the confidence it answers with
|
|
12
12
|
- Open the message with the worktree and branch the sender believes the reader holds, asking to be corrected, whenever that mapping is inferred rather than confirmed
|
|
13
13
|
- Name the skill for the reader to run rather than writing an invocation, which arrives as text
|
|
14
|
-
- Read the pull request's own draft flag rather than the state a worker reports, and report what the read returned and when rather than the state alone. `canon
|
|
14
|
+
- Read the pull request's own draft flag rather than the state a worker reports, and report what the read returned and when rather than the state alone. `canon pr head --help` states why a reported field can lag and say nothing about it. The flag settles the question only once the worker's chain has run its undo, and nothing marks that moment, so a read taken between the pull request opening and that call sees a genuinely ready pull request about to become a draft and has told an operator the opposite of what the worker had said.
|
|
15
15
|
|
|
16
16
|
## The rebase handback
|
|
17
17
|
|
|
@@ -144,4 +144,4 @@ Add no fourth readiness group in place of this file. The three group names are t
|
|
|
144
144
|
|
|
145
145
|
## Validation
|
|
146
146
|
|
|
147
|
-
`canon tasks validate` reads the board against the tree, and what it checks, what it refuses on, and what it reports are at `canon
|
|
147
|
+
`canon tasks validate` reads the board against the tree, and what it checks, what it refuses on, and what it reports are at `canon tasks validate --help`. Run it when the readiness claim is made rather than on a schedule, since the board is gitignored per-machine scratch and no shared moment exists to hang it on.
|
|
@@ -171,7 +171,7 @@ The line is what lets a merge close its own task. `canon tasks archive --pull-re
|
|
|
171
171
|
|
|
172
172
|
## Archiving
|
|
173
173
|
|
|
174
|
-
Never delete a task file. A shipped task moves to `.canon/tasks/archive/` under its own name, and the live index regenerates without it. `canon tasks archive` owns that move, and what it does and what it refuses on are at `canon
|
|
174
|
+
Never delete a task file. A shipped task moves to `.canon/tasks/archive/` under its own name, and the live index regenerates without it. `canon tasks archive` owns that move, and what it does and what it refuses on are at `canon tasks archive --help`.
|
|
175
175
|
|
|
176
176
|
The archive nests inside `.canon/tasks/` rather than sitting beside it as a flat `.claude/task-archive/`, which is what a binary predating this convention still writes. Meeting the flat sibling names an older checkout rather than a second archive to reconcile.
|
|
177
177
|
|
|
@@ -20,7 +20,7 @@ Report numbers. A sentence about what the source looks like is what this exists
|
|
|
20
20
|
Read these in parallel from the project root, skipping any that do not exist:
|
|
21
21
|
|
|
22
22
|
- `package.json`: the `scripts` block naming a dev, preview, or start command
|
|
23
|
-
- `canon/context/development
|
|
23
|
+
- `canon/context/development/local-loop.md`: the documented run commands and the port each serves
|
|
24
24
|
- `CLAUDE.md`: project type and conventions
|
|
25
25
|
|
|
26
26
|
Prefer a production-shaped build (`preview`, `start`) over the dev server, since a dev server ships unminified modules and reports a cost no user pays.
|
package/docs/agents/audits.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Audits
|
|
3
|
-
description: Running every health check as one set,
|
|
3
|
+
description: Running every health check as one set, the verdict and exit codes, the corpus states, the retained baseline and its delta, and a catalog of every audit verb with whether a finding gates
|
|
4
|
+
kind: reference
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# Audits
|
|
7
8
|
|
|
8
|
-
`canon audits run` runs every audit this repository owns, reports each
|
|
9
|
+
`canon audits run` runs every audit this repository owns, reports each under one verdict, and compares each count to the baseline the last recorded run left. Every number comes from a verb in the catalog below.
|
|
9
10
|
|
|
10
11
|
```bash
|
|
11
12
|
canon audits run
|
|
@@ -15,36 +16,11 @@ canon audits run --corpus tracked --corpus per-machine
|
|
|
15
16
|
canon audits list --json
|
|
16
17
|
```
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
| ----------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
20
|
-
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
21
|
-
| `--root <path>` | Measure this tree instead of the current worktree |
|
|
22
|
-
| `--record` | Write this run's tracked counts to `canon/config/baseline.json` |
|
|
23
|
-
| `--corpus <name>` | Limit the run to one corpus (`tracked`, `per-machine`, `upstream`), repeatable, defaulting to every corpus |
|
|
19
|
+
`--record` writes the tracked counts to `canon/config/baseline.json`. `--corpus` limits the run to `tracked`, `per-machine`, or `upstream` and repeats. `--root <path>` measures another tree. `canon audits list` prints the catalog the run reads.
|
|
24
20
|
|
|
25
|
-
##
|
|
21
|
+
## Output
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
The verbs walk separate trees and share no state, so they run together. Measured on the authoring machine at twelve verbs, a run finished in 0.8 seconds of wall clock against 4.4 seconds of processor, which is under every other stage in `bun run check`. `canon deps audit` is the one that changes that reading, since it reaches a network rather than a tree and its latency is the index's rather than this machine's: three clean runs measured 44.7, 77.6, and 62.9 seconds, and a stalled lookup runs to an explicit 120-second timeout rather than to bun's own 299-second ceiling. `--corpus` is what keeps a caller from paying that cost when it wants only the corpora on this disk.
|
|
30
|
-
|
|
31
|
-
Eighteen of the twenty-one read a tree on this disk, the one added by `restated.md` and the one added by `census.md` among them, since the first reads four such trees against each other and the second counts every file in one. The two added by `state-scoped-risk.md` read committed state rather than an arriving change, which is the gap every review surface here leaves by construction, and the one added by `label-coverage.md` reads a branch range against a map the project declares.
|
|
32
|
-
|
|
33
|
-
The placement entry runs `canon context classify sweep` pinned to `--backend off`, so it reads the regex layer alone whatever classifier setting the project resolves. A count that moves with whichever model a machine runs is not comparable across clones, and the model layer turned a sub-second read into one measured at about 17 minutes over this repository's context sections on the authoring machine. It retains one tally per verdict, `keep`, `rewrite`, and `move`, and gates on nothing, since each verdict is a judgment. `document-health` is the surface that reads the same sections with the model.
|
|
34
|
-
|
|
35
|
-
Each is invoked as the CLI the caller is running rather than as a global `canon`. A globally installed binary resolves to the main checkout no matter which worktree is executing, so the aggregate would measure a tree the branch never touched and report a pass over it.
|
|
36
|
-
|
|
37
|
-
## What gates and what reports
|
|
38
|
-
|
|
39
|
-
Five findings fail the run: an unresolved context citation, a banned character, a relative link resolving to nothing on disk, a skill folder carrying no `REQUIREMENT.md`, and a credential-shaped value in the tree the package ships. Each is a fact with no false-positive class behind it.
|
|
40
|
-
|
|
41
|
-
Four of the five are the ones `canon gate run` already fails a push on. The secret scan is the one entry gating without a stage behind it, added on that same fact-or-judgment test rather than as a side effect of registering a measure, and the toolkit already ranks content leaving the repository above content that stays.
|
|
42
|
-
|
|
43
|
-
Everything else reports. A heavy bullet, a long entry, a board row nothing resolves, a degradation term in a comment, and an implementation reaching history ahead of its test are judgments a reader settles. A push failing on one of those teaches contributors to route around the stage, which is the split recorded across every audit here and the one this command inherits rather than moves.
|
|
44
|
-
|
|
45
|
-
Growth against the baseline reports too. The standards behind the largest measures set no hard cap, so a count that rose is a fact about the corpus and a judgment about whether it matters.
|
|
46
|
-
|
|
47
|
-
## Exit codes
|
|
23
|
+
`summary.verdict` is `clean`, `reported`, `findings`, or `incomplete`. Every run also states how many corpora it measured against how many it skipped.
|
|
48
24
|
|
|
49
25
|
| Code | Meaning |
|
|
50
26
|
| ---- | -------------------------------------------------------------------- |
|
|
@@ -53,52 +29,77 @@ Growth against the baseline reports too. The standards behind the largest measur
|
|
|
53
29
|
| `2` | An audit carries a finding that is a fact |
|
|
54
30
|
| `3` | An audit did not report, so the run measured less than the whole set |
|
|
55
31
|
|
|
56
|
-
`3`
|
|
57
|
-
|
|
58
|
-
The verdict is published as a field as well as an exit code. A reader branching on `summary.verdict` gets `clean`, `reported`, `findings`, or `incomplete` without inferring the difference between a quiet corpus and one nobody finished measuring.
|
|
59
|
-
|
|
60
|
-
### An absent corpus is not an unmeasured one
|
|
61
|
-
|
|
62
|
-
A per-machine folder that is not on this disk reports as `absent` and moves neither the verdict nor the exit code. Every one of those folders is gitignored, so a fresh clone and every CI run carry none of them, and counting six expected absences as failures pins the verdict at `incomplete` forever. A signal that never changes is one nobody reads after the second time they see it.
|
|
63
|
-
|
|
64
|
-
Which refusals count as an absence is declared per audit rather than inferred from the corpus alone. A per-machine corpus counts a missing folder. An upstream corpus counts every reason the advisory verb publishes, since each of the three means there is nothing resolved to measure. Several tracked audits override that default too, wherever the corpus not being there is the ordinary state of a target rather than a broken checkout: the secret scan for a project that publishes nothing, the skill corpora, the citation reach check, and the routing measure for a project holding no skills tree, and the context audit for a project that adopted none of the folders it measures.
|
|
65
|
-
|
|
66
|
-
Everything else stays `unmeasured`. That covers a tree git cannot list, which is a broken checkout, and a package declaring no `files` field, where a publish would pack the whole tree and the scan read none of it. Both are a corpus that exists and went unread, so softening either would report a pass over a shipped tree nobody measured.
|
|
32
|
+
Code `3` marks a defect in the run rather than in the tree. An unparseable record, a verb that could not start, and an undocumented exit all land there.
|
|
67
33
|
|
|
68
|
-
|
|
34
|
+
Four findings gate, being an unresolved context citation, a banned character, a skill folder with no `REQUIREMENT.md`, and a credential-shaped value in the shipped tree. Everything else reports, and growth against the baseline reports too.
|
|
69
35
|
|
|
70
|
-
|
|
36
|
+
**Corpus states.**
|
|
71
37
|
|
|
72
|
-
|
|
38
|
+
An audit that finds no corpus reports `absent`, which moves neither the verdict nor the exit code. Anything unread that should exist is `unmeasured`, which sets `incomplete` and exit `3`.
|
|
73
39
|
|
|
74
|
-
|
|
40
|
+
- A per-machine folder missing from this disk is `absent`
|
|
41
|
+
- `upstream` is `absent` offline, and stays out of the baseline
|
|
42
|
+
- The secret scan reports `no-manifest`, `no-publish`, and `no-shipped-files` as `absent`, and `no-files-field` and `no-git` as `unmeasured`
|
|
43
|
+
- The skill audits, the citation reach check, and the routing measure report `absent` for a project with no skills tree
|
|
44
|
+
- The context audit reports `absent` for a project that adopted none of its folders, and a tree git cannot list is `unmeasured`
|
|
75
45
|
|
|
76
|
-
|
|
46
|
+
**Baseline.**
|
|
77
47
|
|
|
78
|
-
|
|
48
|
+
`canon/config/baseline.json` holds the counts from the last `--record`, with the day and the commit. It falls back to `.claude/canon/baseline.json` for a project that has not moved. Each run reports which counts moved and by how much.
|
|
79
49
|
|
|
80
|
-
|
|
50
|
+
- A run with no baseline says so rather than showing a delta of zero
|
|
51
|
+
- A key on one side only is named as new or gone
|
|
52
|
+
- A per-machine record and the task board are reported every run and never recorded
|
|
53
|
+
- An audit that did not report is left out, never written as zero
|
|
54
|
+
- A baseline that does not parse refuses the run
|
|
81
55
|
|
|
82
|
-
|
|
56
|
+
`gov test-order` reads zero in a shallow clone, so read its delta only from a clone carrying the history.
|
|
83
57
|
|
|
84
|
-
|
|
58
|
+
**In `bun run check`.**
|
|
85
59
|
|
|
86
|
-
|
|
60
|
+
`bun run check` runs `--corpus tracked --corpus per-machine` as a reporting stage after the gating stages, and never fails on it. `summary` is a flat object of unique scalar keys that a shell stage greps without a JSON parser. `deps` runs weekly instead.
|
|
87
61
|
|
|
88
|
-
|
|
62
|
+
The placement entry runs pinned to `--backend off`, so its tally stays comparable across machines. Each audit runs as the CLI the caller is running, never a global `canon`.
|
|
89
63
|
|
|
90
|
-
|
|
64
|
+
**Catalog.**
|
|
91
65
|
|
|
92
|
-
|
|
66
|
+
`canon audits list` reports the first 19 rows. The rows marked `outside` run by hand or from a skill and sit beside the aggregate.
|
|
93
67
|
|
|
94
|
-
|
|
68
|
+
| Id | Verb | Measures | Finding |
|
|
69
|
+
| -------------------- | ----------------------------------- | ---------------------------------------------------------------------------------- | -------------- |
|
|
70
|
+
| `context` | `canon context audit` | Context folder structure, citations, and the requirements record's word cap | Gates |
|
|
71
|
+
| `placement` | `canon context classify sweep` | Keep, rewrite, and move tally per context section, regex layer only | Reports |
|
|
72
|
+
| `markdown` | `canon markdown audit` | Bans, dead links, density, and reference shape | Gates |
|
|
73
|
+
| `skills` | `canon claude skills audit` | Both skill corpora against the skill standards | Gates |
|
|
74
|
+
| `skills-reach` | `canon claude skills reach` | Skill bodies citing a path no target receives | Reports |
|
|
75
|
+
| `skills-rank` | `canon claude skills rank` | Whether skill descriptions separate against a routing case corpus | Reports |
|
|
76
|
+
| `tasks` | `canon tasks validate` | Board rows nothing resolves | Reports |
|
|
77
|
+
| `records-plans` | `canon records validate plans` | Plan records against their shape | Reports |
|
|
78
|
+
| `records-groundwork` | `canon records validate groundwork` | Groundwork folders against their shape | Reports |
|
|
79
|
+
| `records-intake` | `canon records validate intake` | Intake folders against their shape | Reports |
|
|
80
|
+
| `records-teach` | `canon records validate teach` | Teach records against their shape | Reports |
|
|
81
|
+
| `comments` | `canon comments scan` | Comment density by language and kind, and `TODO`, `FIXME`, `HACK`, `XXX` | Reports |
|
|
82
|
+
| `test-order` | `canon gov test-order` | Implementations that reached branch history before their test | Reports |
|
|
83
|
+
| `secrets` | `canon secrets scan` | Credential-shaped values in the shipped tree | Gates |
|
|
84
|
+
| `labels` | `canon labels audit` | Changed paths no row of the label map reaches | Reports |
|
|
85
|
+
| `restated` | `canon gov restated` | Instructions `CLAUDE.md` states that a second surface states too | Reports |
|
|
86
|
+
| `counts` | `canon gov counts` | Sentences stating a closed catalog's size that disagree with the tree | Reports |
|
|
87
|
+
| `census` | `canon census` | File count, extension breakdown, and line total | Reports |
|
|
88
|
+
| `deps` | `canon deps audit` | Advisories against the resolved dependencies | Reports |
|
|
89
|
+
| `outside` | `canon gov citations` | Rule citations and internal frontmatter globs reaching nothing | Gates in check |
|
|
90
|
+
| `outside` | `canon gov superseded <old> <new>` | Where the tree still asserts a value a changed convention no longer produces | Reports |
|
|
91
|
+
| `outside` | `canon claude skills drift <ref>` | Shipped skill bodies rewritten since a ref | Reports |
|
|
92
|
+
| `outside` | `canon claude routing` | Per `CLAUDE.md` section, how many bullets name a path and whether a rule covers it | Reports |
|
|
93
|
+
| `outside` | `canon context classify diff` | Classification of the chunks a git range changed | Reports |
|
|
95
94
|
|
|
96
|
-
A
|
|
95
|
+
A deliberate secret takes a `canon-allow-secret: <reason>` marker. A deliberate citation takes `canon-allow-citation: <reason>` and a deliberate superseded value takes `canon-allow-superseded: <reason>`, each on its own line or the one above. Run any verb with `--help` for its flags and refusal reasons.
|
|
97
96
|
|
|
98
|
-
##
|
|
97
|
+
## Refusals
|
|
99
98
|
|
|
100
|
-
|
|
99
|
+
- A baseline that does not parse
|
|
100
|
+
- A `--root` that is not a tree git can list
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
## See also
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
- `markdown-audit.md`: the markdown audit
|
|
105
|
+
- `context-audit.md`: the context audit
|