@erclx/canon 5.34.0 → 5.35.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 +3 -5
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/REQUIREMENT.md +1 -1
- package/claude/skills/auto-ship/references/draft-mark.md +1 -1
- package/claude/skills/canon-cli/SKILL.md +10 -11
- package/claude/skills/create-skill/SKILL.md +2 -1
- package/claude/skills/create-skill/references/skill-paths.md +12 -15
- package/{standards/standard.md → claude/skills/create-skill/references/skill-reference.md} +50 -45
- package/claude/skills/create-skill/references/skill.md +9 -3
- package/claude/skills/draft-and-pick/SKILL.md +1 -1
- package/claude/skills/git-commit/references/versioning.md +13 -13
- package/claude/skills/git-pr/SKILL.md +1 -1
- package/claude/skills/git-pr/references/publish.md +1 -1
- package/claude/skills/review-address/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/SKILL.md +2 -2
- package/claude/skills/review-pr/SKILL.md +3 -3
- package/claude/skills/review-pr/references/post.md +1 -1
- package/claude/skills/review-ui/REQUIREMENT.md +1 -1
- package/claude/skills/review-ui/SKILL.md +1 -1
- package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -2
- package/claude/skills/role-orchestrator/SKILL.md +11 -12
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +3 -1
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +11 -8
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +10 -4
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +11 -12
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +12 -15
- package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +6 -4
- package/claude/skills/role-orchestrator/scripts/poll.ts +50 -1
- package/claude/skills/role-reviewer/REQUIREMENT.md +17 -7
- package/claude/skills/role-reviewer/SKILL.md +17 -10
- package/claude/skills/role-worker/REQUIREMENT.md +1 -1
- package/claude/skills/role-worker/SKILL.md +6 -6
- package/claude/skills/session-compact/references/handoff-note.md +1 -1
- package/claude/skills/target-setup/SKILL.md +2 -2
- package/claude/skills/target-setup/references/detect.md +3 -3
- package/docs/agents/audits.md +1 -1
- package/docs/agents/commands.md +2 -4
- package/docs/agents/counts.md +5 -6
- package/docs/agents/drift-surfaces.md +15 -19
- package/docs/agents/index.md +2 -3
- package/docs/agents/install-and-sync.md +7 -31
- package/docs/agents/markdown-audit.md +10 -12
- package/docs/agents/migrate.md +1 -1
- package/docs/agents/records-stale.md +1 -1
- package/docs/agents/records-validate.md +11 -23
- package/docs/agents/records.md +1 -1
- package/docs/agents/routing.md +1 -1
- package/docs/agents/rule-citations.md +11 -14
- package/docs/agents/scripting.md +2 -20
- package/docs/agents/state-scoped-risk.md +1 -1
- package/docs/agents/tasks-validate.md +1 -1
- package/docs/agents/teach.md +1 -1
- package/docs/target/index.md +1 -0
- package/docs/target/migrations.md +4 -0
- package/docs/target/projects.md +9 -9
- package/docs/target/scenarios.md +5 -6
- package/docs/target/standards-moved.md +32 -0
- package/docs/target/sync.md +5 -5
- package/docs/workflow/operating-model.md +16 -18
- package/docs/workflow/skill-map.md +1 -1
- package/governance/detect.toml +0 -4
- package/governance/renames.toml +0 -1
- package/governance/stacks/base.toml +15 -8
- package/governance/stacks/go.toml +2 -0
- package/governance/stacks/node.toml +1 -1
- package/governance/stacks/php.toml +2 -0
- package/governance/stacks/python.toml +1 -1
- package/package.json +1 -4
- package/scripts/core/install-check.sh +2 -3
- package/src/audits/catalog.ts +0 -9
- package/src/claude/routing.ts +1 -1
- package/src/claude/skills-reach.ts +4 -6
- package/src/cli/help.ts +3 -4
- package/src/cli.ts +0 -2
- package/src/commands/gov.ts +5 -9
- package/src/commands/init.ts +1 -1
- package/src/commands/labels.ts +4 -44
- package/src/commands/migrate.ts +1 -1
- package/src/commands/records.ts +4 -20
- package/src/commands/tooling.ts +2 -4
- package/src/counts/catalogs.ts +0 -6
- package/src/gate/boundaries.ts +2 -2
- package/src/gate/measures.ts +6 -28
- package/src/gate/sequencer.ts +51 -2
- package/src/gate/stages.ts +0 -18
- package/src/gov/citations.ts +11 -43
- package/src/markdown/bans.ts +1 -1
- package/src/migrate/scratch-evidence.ts +2 -2
- package/src/records/validate.ts +6 -194
- package/src/sandbox/provision.ts +0 -5
- package/src/secrets/shipped.ts +1 -2
- package/src/serve/static.ts +1 -2
- package/src/shipped/references.ts +29 -80
- package/src/sync/check.ts +18 -14
- package/src/tooling/inject.ts +6 -37
- package/src/tooling/read.ts +2 -3
- package/src/tooling/scan.ts +4 -17
- package/src/tooling/subfolder.ts +2 -66
- package/tooling/base/configs/scripts/verify.json +1 -1
- package/tooling/base/configs/scripts/verify.ts +1 -12
- package/tooling/base/manifest.toml +1 -2
- package/tooling/base/reference.md +10 -16
- package/tooling/base/seeds/.github/workflows/verify.yml +0 -3
- package/tooling/base/seeds/.lintstagedrc +1 -2
- package/tooling/base/seeds/canon/context/ci.md +0 -1
- package/tooling/base/seeds/canon/context/development.md +1 -1
- package/tooling/claude/reference.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +13 -1
- package/tooling/go/reference.md +1 -1
- package/tooling/php/reference.md +1 -1
- package/tooling/python/reference.md +2 -2
- package/tooling/web/configs/.github/workflows/verify.yml +0 -3
- package/tooling/web/manifest.toml +0 -1
- package/tooling/web/reference.md +2 -4
- package/docs/agents/standards-audit.md +0 -40
- package/governance/rules/tooling/765-spelling.md +0 -19
- package/governance/stacks/astro.toml +0 -2
- package/governance/stacks/nextjs.toml +0 -2
- package/governance/stacks/node-server.toml +0 -2
- package/governance/stacks/python-fastapi.toml +0 -2
- package/governance/stacks/react.toml +0 -2
- package/src/commands/standards.ts +0 -278
- package/src/labels/spelling.ts +0 -120
- package/src/standards/audit.ts +0 -146
- package/src/standards/list.ts +0 -33
- package/src/standards/read.ts +0 -177
- package/src/standards/scope.ts +0 -56
- package/standards/index.md +0 -10
- package/tooling/base/configs/.vscode/extensions.json +0 -9
- package/tooling/base/configs/.vscode/settings.json +0 -3
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +0 -25
- package/tooling/base/seeds/cspell.json +0 -20
- package/tooling/go/seeds/.cspell/tech-stack.txt +0 -16
- package/tooling/nextjs/seeds/.cspell/tech-stack.txt +0 -3
- package/tooling/php/seeds/.cspell/tech-stack.txt +0 -5
- package/tooling/python/seeds/.cspell/tech-stack.txt +0 -18
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +0 -1
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +0 -2
- package/tooling/web/configs/.vscode/extensions.json +0 -13
- package/tooling/web/configs/.vscode/settings.json +0 -10
- package/tooling/web/seeds/.cspell/tech-stack.txt +0 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: role-reviewer
|
|
3
|
-
description: Asserts the reviewer role for a session dispatched to review one pull request another session built, holding what it may write, what it reads and never reads, the
|
|
3
|
+
description: Asserts the reviewer role for a session dispatched to review one pull request another session built, holding what it may write, what it reads and never reads, the messages it owes the worker and the controller, the lift it runs on a close, and the acts it refuses. Use when asked to "be the reviewer", "you are a reviewer session", at the start of a dispatched or hand-launched review of one pull request, or when a reviewing session needs to know what it may not write or who it answers to. Do NOT use to run the pass itself, which is `review-pr` for the code and `review-ui` for the running app, or to make the cross-branch call across a wave.
|
|
4
4
|
metadata:
|
|
5
5
|
family: parallel
|
|
6
6
|
---
|
|
@@ -25,7 +25,7 @@ from here.
|
|
|
25
25
|
|
|
26
26
|
## Where the session stands
|
|
27
27
|
|
|
28
|
-
- Write the review comment through `review-pr` and the body file it names under `.canon/tmp/pr/review/`, and nothing else. A UI reviewer writes the comment `review-ui` posts, its body file, and the browser's snapshots and frames, all under `.canon/tmp/pr/review-ui/`, and ticks the boxes it passed on the evidence comment through `canon pr tick`. A tracked file, a branch, a worktree, a board file, and a commit all sit outside what this session may touch.
|
|
28
|
+
- Write the review comment through `review-pr` and the body file it names under `.canon/tmp/pr/review/`, and nothing else. A UI reviewer writes the comment `review-ui` posts, its body file, and the browser's snapshots and frames, all under `.canon/tmp/pr/review-ui/`, and ticks the boxes it passed on the evidence comment through `canon pr tick`. Either reviewer writes the draft flag through `canon pr lift` and no other way. 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 and never check the branch out. The pass reads a change, and a checkout is the first step toward editing it.
|
|
30
30
|
- Read a file a finding rests on at the head `review-pr` resolved, through `git show <head>:<path>`. The main worktree holds the trunk, so a finding read off its copy is about a tree the pull request never changed, and it reads as confidently as one that is right.
|
|
31
31
|
- Resolve `.canon/plans/`, `.canon/tasks/`, and `.canon/tmp/` at the main worktree root, and send the body file as a heredoc, the main-root route `session-worktree` states. Report a plan or task that fails to resolve there as unreadable, naming the path, rather than reviewing as though the branch had none.
|
|
@@ -46,16 +46,23 @@ from here.
|
|
|
46
46
|
|
|
47
47
|
## The channel
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
Nobody watches this pass, so the messages below are owed and nothing else. The
|
|
50
|
+
worker and this session answer each other directly, and the controlling session
|
|
51
|
+
hears only what it acts on.
|
|
51
52
|
|
|
52
|
-
-
|
|
53
|
+
- Send the `review-address` dispatch to the worker holding the branch as `review-pr` Step 5 returns an open `## Review`, or as `review-ui` reports an open `## UI review`, carrying the pull request number, the heading, that step's count line verbatim, and this session's own sessionId for the worker's reply. Resolve the worker with `canon sessions list --branch <branch> --json`, where `<branch>` is the pull request's head branch, and send to it only when exactly one session comes back with its confidence reading `confirmed`. Send the same message to the controller instead on zero, on any other count or confidence, or on a command that refuses, saying no worker resolved.
|
|
54
|
+
- Run `canon pr lift <number> --json` after posting `## Review closed` or `## UI review closed`. Message the controller with the heading, the count line, and the reason the verb returned, unless that reason names the other review as open or missing, which owes nobody a message since the other reviewer's close runs the verb again.
|
|
53
55
|
- Send a block out as a message before it becomes an interactive prompt.
|
|
54
56
|
- Send nothing on progress, and send no recommendation to merge as an instruction. `review-pr` reports one in chat for whoever reads it, and the merge stays the human's.
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
Carry the sessionId in the message alone, never in the posted comment. The
|
|
59
|
+
comment is public, and an id there addresses nothing for a reader without the
|
|
60
|
+
roster.
|
|
61
|
+
|
|
62
|
+
Address the controlling session the launch named, which it names as a
|
|
63
|
+
`sessionId` rather than a name. `canon:session-relay` turns that id or the
|
|
64
|
+
worker's branch into an address and carries the send, so invoke it rather than
|
|
65
|
+
resolving a name here.
|
|
59
66
|
|
|
60
67
|
One rung stays here, because it is the rung that differs between roles. A
|
|
61
68
|
reviewer holds no feature branch, so inferring an addressee from the sessions
|
|
@@ -66,13 +73,13 @@ where exactly one does, and say the addressee was inferred.
|
|
|
66
73
|
## Refusing is part of the job
|
|
67
74
|
|
|
68
75
|
- Refuse to fix the defect this pass found, whoever asks. File it in the comment for the worker holding the branch instead. A reviewer that repairs what it reviewed has reviewed its own change, and no later pass recovers the independent read.
|
|
69
|
-
-
|
|
76
|
+
- Lift the draft mark through `canon pr lift` alone, and never ready the pull request directly, whoever asks. The verb reads the reviews, the evidence, the standing, and CI itself, so its lift needs no one to vouch for the request, and a direct ready skips every gate it holds.
|
|
70
77
|
- Refuse to merge, and refuse to approve through the review API in place of the comment `review-pr` posts, since the poll routes on that comment's heading and an approval carries none.
|
|
71
78
|
- Carry the evidence with a refusal. Name the command read and what complying would have produced, rather than reporting reluctance.
|
|
72
79
|
- Withdraw a finding the worker's reply shows wrong, the way `review-pr` states, rather than defending it. A withdrawal naming its cause is part of a pass, not a retreat from one.
|
|
73
80
|
|
|
74
81
|
## Lifetime
|
|
75
82
|
|
|
76
|
-
- The role runs from the launch to the merge of the pull request it reviewed, and covers every pass on that pull request. A re-review comes back to this session while it is live, which keeps the read the first pass paid for.
|
|
83
|
+
- The role runs from the launch to the merge of the pull request it reviewed, and covers every pass on that pull request. A re-review comes back to this session from the worker directly while it is live, which keeps the read the first pass paid for.
|
|
77
84
|
- A session handed a second pull request is a new reviewer under a new launch, since the first one's reading of the change is exactly what the second one must not carry.
|
|
78
85
|
- Treat this body as possibly older than the branch under review. A plugin skill loads from the marketplace cache rather than from the working tree.
|
|
@@ -19,7 +19,7 @@ Finishing is invisible from the other side. A worker that opens a pull request g
|
|
|
19
19
|
|
|
20
20
|
Nothing tells the session that refusing is allowed either. Four occasions across two days had a worker halt correctly with the cost falling on the dispatcher, and the correction that mattered most reached the right place because a worker argued back with evidence rather than complying. A role written only as report-upward suppresses exactly that.
|
|
21
21
|
|
|
22
|
-
The draft mark fails from both ends. On 2026-08-31 four sessions re-drafted a pull request someone had readied, acting on a belief no surface in the tree stated. On 2026-09-07 a controlling session told a worker to lift the mark rather than lifting it itself, and the worker complied and reported against the surface rather than the outcome.
|
|
22
|
+
The draft mark fails from both ends. On 2026-08-31 four sessions re-drafted a pull request someone had readied, acting on a belief no surface in the tree stated. On 2026-09-07 a controlling session told a worker to lift the mark rather than lifting it itself, and the worker complied and reported against the surface rather than the outcome. From 2026-10-12 `canon pr lift` reads the gates itself, so the reviewers run it on a close and the controlling session runs it as the fallback. A worker leaves the verb to them and readies a pull request directly for nobody, since a direct ready skips every gate the verb reads.
|
|
23
23
|
|
|
24
24
|
## Must
|
|
25
25
|
|
|
@@ -32,8 +32,8 @@ which `auto-ship` Step 2 loads.
|
|
|
32
32
|
- Report a plan that fails to resolve as unreadable from here, naming the main-root path. Reporting the task as having no plan is true where this session stands and wrong about the world, and a reader with no second tree to check cannot separate the two.
|
|
33
33
|
- Build the plan the launch named. Do not write a second one when the path fails to resolve, since a row that cites a plan already has one and drafting another produces two plans for one row.
|
|
34
34
|
- Copy a ready folder's files verbatim to the paths its plan's constraints name, when the plan's `**Constraints:**` block names one, and edit only what the gate or the overview's own list requires. A rewrite discards the text the handoff exists to carry.
|
|
35
|
-
- Report a draft flag reading ready once, and leave it cleared. The ship chain marks the pull request a draft and
|
|
36
|
-
-
|
|
35
|
+
- Report a draft flag reading ready once, and leave it cleared. The ship chain marks the pull request a draft, and only `canon pr lift` or the operator un-marks it, so a flag reading ready afterwards passed every gate the verb reads or was readied by a person, which GitHub requires before a merge. Re-drafting fights them, and no surface in the tree states a reason to.
|
|
36
|
+
- Leave the lift to the reviewers, who run `canon pr lift` on posting their close, and to the controlling session as the fallback. Refuse an instruction to ready the pull request directly, whoever sends it, since a direct ready skips every gate the verb reads.
|
|
37
37
|
- Rewrite a plan question's `- Suggested:` line as `overridden at execution to <pick>,` plus the measurement when this build decides against an unanswered one, leaving the `- Answer:` slot blank, and put the same deviation in one line under the open task's `## Findings`, per `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`.
|
|
38
38
|
|
|
39
39
|
## The board is read-only
|
|
@@ -51,13 +51,13 @@ owed and nothing else.
|
|
|
51
51
|
- Announce the pull request as the ship chain's pull request step returns, carrying the number, the branch, and the task it closes. That transition is the one moment only this session knows, and the controller's review poll no longer starts on a dispatch because of it.
|
|
52
52
|
- Carry the reach in that same message: the paths this branch wrote that another live plan or `## Run now` row holds, and who holds each, which `canon tasks plan-reach` reports as `claimed`. Report each as a rebase the controller should order, never as a breach, since sharing a path is not a hold. The gate cleared this branch against a prediction it has since outgrown, so the controller holds a reading of what this branch shares that stopped being true hours ago and nothing else tells it. Say the reach was unread rather than clear when the installed binary carries no such subcommand, and leave the undeclared list to the pull request.
|
|
53
53
|
- Carry a row this build turned up in that same message, with its title, its origin, and the surface it would take. Send it as its own message only when the session will end before a pull request opens, since the row has no other way to reach the controller.
|
|
54
|
-
-
|
|
54
|
+
- Ask for the re-review when an address-review pass finishes, as `review-address` Step 8 returns, carrying what was addressed and the PR's new CI state. Send it to the reviewer whose sessionId the review dispatch carried, resolved from that id at the moment of sending, since a reviewer holds the trunk branch and no branch lookup finds it. Send it to the controller instead when the dispatch named no reviewer or the id resolves to no live session. That transition is the other moment only this session knows, and the message is what starts the re-review rather than a poll for an answer nothing marks as landed.
|
|
55
55
|
- Send a block out as a message before it becomes an interactive prompt.
|
|
56
56
|
- Send nothing on progress. A worker reporting progress rebuilds, on this side of the channel, the poll the announcement retired on the other.
|
|
57
57
|
|
|
58
|
-
Address the session the launch named,
|
|
59
|
-
|
|
60
|
-
send, so invoke it rather than resolving a name here. It reads the roster at the
|
|
58
|
+
Address the session the launch named, and the reviewer by the sessionId its
|
|
59
|
+
dispatch carried, each as a `sessionId` rather than a name.
|
|
60
|
+
`canon:session-relay` turns that id into an address and carries the send, so invoke it rather than resolving a name here. It reads the roster at the
|
|
61
61
|
moment of sending, checks the result against the agent listing, and falls back
|
|
62
62
|
to a copyable block where this session holds no tool to send through. The
|
|
63
63
|
message owed stays in its own bullet above.
|
|
@@ -5,7 +5,7 @@ description: What each section of a compact handoff carries, what stays out, and
|
|
|
5
5
|
|
|
6
6
|
# Handoff note
|
|
7
7
|
|
|
8
|
-
The shape `session-compact` writes. It lives
|
|
8
|
+
The shape `session-compact` writes. It lives in this skill's `references/` because one skill reads it, and a shape nothing else cites has no second reader to correct it.
|
|
9
9
|
|
|
10
10
|
## The test every line passes
|
|
11
11
|
|
|
@@ -99,7 +99,7 @@ Step 2: `canon tooling sync <tooling-stack> --write` installs stack deps, script
|
|
|
99
99
|
CANON_NON_INTERACTIVE=1 canon tooling sync <tooling-stack> <target> --write
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
Monorepo with multiple language roots: run `canon init` once at the repo root so `base` (husky, prettier,
|
|
102
|
+
Monorepo with multiple language roots: run `canon init` once at the repo root so `base` (husky, prettier, commitlint, CI) lands single, then sync each subtree with `--skip base` so the shared layer is not re-dropped. Take the subtree commands from the per-root rows the preview printed rather than picking folders by hand. Detection found each root and its stack, and the two commands below show the shape.
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
105
|
CANON_NON_INTERACTIVE=1 canon tooling sync vite-react ./frontend --skip base --write
|
|
@@ -108,7 +108,7 @@ CANON_NON_INTERACTIVE=1 canon tooling sync python ./backend --skip base --write
|
|
|
108
108
|
|
|
109
109
|
Without `--skip base`, each subtree re-drops husky, and git honors only one `core.hooksPath`, so the extra hook dirs silently break. Each subtree keeps its own framework configs, and its own stack reference reads through `canon tooling reference <stack>`.
|
|
110
110
|
|
|
111
|
-
A subtree sync withholds `.github/`, since GitHub reads workflows only at the repository root, and names each withheld file with the `working-directory` a root CI job needs.
|
|
111
|
+
A subtree sync withholds `.github/`, since GitHub reads workflows only at the repository root, and names each withheld file with the `working-directory` a root CI job needs. A subtree needs its own `bun init` before its scripts and dependencies land. The sync warns and skips them until then.
|
|
112
112
|
|
|
113
113
|
Step 3: post-sync fixups. Golden configs arrive from sync, so no config generation is required. But a few items may need a one-time touch:
|
|
114
114
|
|
|
@@ -77,9 +77,9 @@ already reach every subfolder. Tooling installs per folder. So resolve one
|
|
|
77
77
|
governance stack for the whole repository and one tooling stack per language
|
|
78
78
|
root.
|
|
79
79
|
|
|
80
|
-
- **Stack:** pick the
|
|
80
|
+
- **Stack:** pick the governance stack by matching the repository root's detected language against stack names in the catalog. Governance stacks are per language, so a framework never names one, and its rules arrive as extras. If the root matched nothing, `base` is the stack, including when subfolders matched, since no subfolder owns the repository and picking one by order would state a preference nobody gave. Mark it `fallback` in the preview only when no root matched anywhere.
|
|
81
81
|
- **Tooling stack:** for each language root, pick the closest tooling stack from `canon tooling list --json` (e.g. `vite-react`, `astro`, `nextjs`). Distinct from the governance stack. Fall back to `base` for a root with no framework or language match, and carry that fallback into its preview row.
|
|
82
|
-
- **Next.js:** map `next` in a root's `package.json` dependencies, or a `next.config.ts`/`.js`/`.mjs` file in that root, to the `
|
|
82
|
+
- **Next.js:** map `next` in a root's `package.json` dependencies, or a `next.config.ts`/`.js`/`.mjs` file in that root, to the `node` governance stack and the `nextjs` tooling stack. The dependency name does not match the tooling stack name by itself, and the Next.js rule arrives as an extra.
|
|
83
83
|
- **Extras:** run `canon gov detect <target> --stack <stack> --json` from the target and take its `proposals` array as the candidate extras. Each proposal names a `rule` and the `evidence` that matched it across every language root to depth two. The verb already leaves out every rule the picked stack resolves, so do not dedupe again, and do not match a rule's `description` or `paths` by hand.
|
|
84
84
|
- **Subfolder language rules:** a language root below the repository root whose language the picked stack does not carry contributes its language rule by name, read from `canon gov list --json`. The verb proposes no language rule, since a stack reaches each one.
|
|
85
85
|
- **Subfolder tooling:** a language root below the repository root takes its own `canon tooling sync <stack> <path> --skip base`, since `canon init` already lands `base` once at the root. Leave a root whose stack resolves to `base` out of the commands, since that sync would land nothing. A repository-root `package.json` hosting only formatters and hooks is that case, and it adds no row.
|
|
@@ -111,7 +111,7 @@ toolkit repository, and option 2 hands the project-local file to `create-rule`.
|
|
|
111
111
|
Before executing, output:
|
|
112
112
|
|
|
113
113
|
- **Detected:** each technology with its evidence file, path included, so a subfolder marker reads as one
|
|
114
|
-
- **Stack:** picked governance stack and resolved rule count. Mark it `fallback` when no detected
|
|
114
|
+
- **Stack:** picked governance stack and resolved rule count. Mark it `fallback` when no detected language matched a catalog name.
|
|
115
115
|
- **Tooling stack:** one row per language root, each carrying its path, its picked tooling stack, a `fallback` mark on the same test, and its own command. On the repository root's row, name what `base` lands: configs, seeds, and gitignore entries in every case, plus the JavaScript development dependencies, scripts, and hook activation wherever a `package.json` exists to carry them. A project outside that ecosystem runs none of the second group and keeps the first. Omit these rows entirely on the `gov` phase, which syncs no tooling.
|
|
116
116
|
- **Extras:** each proposal with the evidence the verb returned, plus each subfolder language rule, listed in full as the list the operator confirms. A second matched stack reaches the install only through this list, since `canon init --stack` takes one stack, so a shortened list reads as that stack dropped.
|
|
117
117
|
- **Skip:** any `--skip` entries with reason
|
package/docs/agents/audits.md
CHANGED
|
@@ -85,7 +85,7 @@ It sits under the project root rather than beside the aggregator in `src/`. The
|
|
|
85
85
|
|
|
86
86
|
### What is kept out of it
|
|
87
87
|
|
|
88
|
-
A gitignored record folder holds one machine's session scratch. Its counts describe somebody else's disk, so committing them writes a floor no other clone can reproduce and every contributor reads a regression against a number that was never about their tree. The board and
|
|
88
|
+
A gitignored record folder holds one machine's session scratch. Its counts describe somebody else's disk, so committing them writes a floor no other clone can reproduce and every contributor reads a regression against a number that was never about their tree. The board and every record kind are therefore reported on every run and recorded in none.
|
|
89
89
|
|
|
90
90
|
An audit that did not report is left out rather than written as zero. Zero there records a clean corpus nobody measured, and the next run reads its real numbers as a regression against a floor that was never taken.
|
|
91
91
|
|
package/docs/agents/commands.md
CHANGED
|
@@ -19,7 +19,6 @@ One row per top-level command, in the order `canon --help` prints them. A domain
|
|
|
19
19
|
| `canon migrate <verb>` | Move a project off a retired name or layout, reporting the plan until `--write` |
|
|
20
20
|
| `canon targets <verb>` | Report the projects this toolkit installed into |
|
|
21
21
|
| `canon gov <verb>` | Install and sync governance rules, and audit the tree against them |
|
|
22
|
-
| `canon standards <verb>` | List, audit, or print a standard by name |
|
|
23
22
|
| `canon tooling <verb>` | Sync, diff, and verify tooling stacks |
|
|
24
23
|
| `canon claude <verb>` | Install the Claude workflow and audit both skill corpora |
|
|
25
24
|
| `canon wiki <verb>` | Scaffold the wiki pages |
|
|
@@ -61,7 +60,7 @@ A port already in use is the ordinary case rather than a refusal, so it walks fo
|
|
|
61
60
|
|
|
62
61
|
A request naming a directory is redirected to its trailing-slash form rather than answered in place. A browser resolves a relative asset against the last slash of the URL it is on, so answering `/lesson` directly leaves the page asking for `/course.css` instead of `/lesson/course.css`, and it renders unstyled through the server that exists to prevent exactly that.
|
|
63
62
|
|
|
64
|
-
Containment is tested after symlinks are followed rather than on the path as written, and the test sits immediately before the read rather than beside the request that produced it. Resolving a request lexically clears a link pointing outside the served root, and
|
|
63
|
+
Containment is tested after symlinks are followed rather than on the path as written, and the test sits immediately before the read rather than beside the request that produced it. Resolving a request lexically clears a link pointing outside the served root, and a link out of the served root is the shape it guards against. Position is what makes the property hold: a directory request appends its index after the request path has been checked, so a check placed earlier leaves that index untested. `--index` answers a directory holding no `index.html` with a listing read per request, where the default stays a 404. Every entry the listing names takes the same containment test a request for it would, so a link out of the root is absent rather than greyed, and dotfiles are hidden. With no `--entry` and no root `index.html`, the printed link is `/` and `entryExists` reads true. An `--entry` that escapes the root refuses with `no-entry` before a port is taken, because `url` is the field a caller hands to a reader.
|
|
65
64
|
|
|
66
65
|
`canon demo` is the second browser command and the one that ships, since its purpose is running in a target rather than regenerating what this repository commits. It needs a browser binary the package does not carry, installed once with `bunx playwright install chromium`.
|
|
67
66
|
|
|
@@ -84,7 +83,6 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
|
|
|
84
83
|
- `migrate`, in `migrate.md`: `rename`, `skill-names`, `records`, `surface-roots`, `record-tree`, `rule-layout`, `scratch-evidence`, `record-layout`
|
|
85
84
|
- `targets`, in `targets.md`: `list`, `pulls`
|
|
86
85
|
- `gov`, in `install-and-sync.md`: `list`, `install`, `sync`, `build`, `regen`, `test-order`, `counts`, `superseded`, `citations`, `restated`
|
|
87
|
-
- `standards`, in `standards-audit.md`: `list`, `audit`, `<name>`
|
|
88
86
|
- `tooling`, in `install-and-sync.md`: `list`, `sync`, `diff`, `reference`, `verify`, `inject`, `prune-gitignore`
|
|
89
87
|
- `claude`, in `skills-audit.md`: `init`, `sync`, `setup`, `routing`, `plugin-update`, `seeds list`, `skills list`, `skills audit`, `skills drift`, `skills reach`, `skills rank`
|
|
90
88
|
- `wiki`, in `scripting.md`: `init`
|
|
@@ -130,7 +128,7 @@ Subcommands no other page describes:
|
|
|
130
128
|
- A deck folder's `deck.json` and the faces it embeds, its per-slide `<body>` attributes, transitions and entrances, speaker notes, and charts are described in `slides.md`.
|
|
131
129
|
- `canvas`, with its verbs, content format, and write routes, is described in `canvas.md`.
|
|
132
130
|
- `labels apply <number>` adds the labels this branch earns to its open pull request, refusing a pull request whose head is not the current branch or that is not open, and never creating a label the remote lacks or removing one a person added (`--check` writes nothing and exits 2 when labels are owed, `--base`, `--json`).
|
|
133
|
-
- `labels scan` fails a pull request or a posted review whose title, body, or review comment carries a phase label, a label a code span quotes, a gitignored record path, a session link, a banned character, a body heading outside the closed section list or a missing `## Summary` or `## Key changes`,
|
|
131
|
+
- `labels scan` fails a pull request or a posted review whose title, body, or review comment carries a phase label, a label a code span quotes, a gitignored record path, a session link, a banned character, a body heading outside the closed section list or a missing `## Summary` or `## Key changes`, or a title breaking `claude/skills/git-pr/references/pr.md`'s format, casing, or length rule (`--event`, `--body-file`, `--json`).
|
|
134
132
|
|
|
135
133
|
## Version skew
|
|
136
134
|
|
package/docs/agents/counts.md
CHANGED
|
@@ -22,11 +22,10 @@ Under `--json` the record holds stdout alone and the frame still renders on stde
|
|
|
22
22
|
|
|
23
23
|
## The catalogs it reads
|
|
24
24
|
|
|
25
|
-
A closed set of
|
|
25
|
+
A closed set of four, each with a filesystem reader behind it rather than every list command this CLI ships:
|
|
26
26
|
|
|
27
27
|
- `skills`: shipped plugin skills, a folder per `claude/skills/*/SKILL.md`
|
|
28
28
|
- `rules`: authored governance rules, a file per `governance/rules/**/*.md`
|
|
29
|
-
- `standards`: the authoring corpus at `standards/`
|
|
30
29
|
- `commands`: top-level `canon` commands, read off `src/cli.ts`'s registration imports
|
|
31
30
|
- `audits`: the registered set in `src/audits/catalog.ts`, this entry included
|
|
32
31
|
|
|
@@ -36,7 +35,7 @@ The set is closed rather than derived, so widening it is a deliberate change to
|
|
|
36
35
|
|
|
37
36
|
A sentence has to carry an assertion verb (`loads`, `ships`, `carries`, `holds`, `counts`, `totals`, `documents`, `declares`, `installs`, `lists`, `contains`, `comprises`, `authors`), the quantifier `all`, or an article (`the`, `a`, `an`) immediately ahead of the number, which is immediately ahead of the catalog noun, with one optional qualifying word between the number and the noun (`sixty-one shipped skills`). The number reads either as digits or as a spelled-out cardinal through ninety-nine, since this corpus states a catalog size in words as often as in digits.
|
|
38
37
|
|
|
39
|
-
Nothing stands between the trigger and the number, which is the rule an author writing a new count has to know. It separates `the toolkit authors
|
|
38
|
+
Nothing stands between the trigger and the number, which is the rule an author writing a new count has to know. It separates `the toolkit authors 49 rules` and `took all 49 rules`, both read, from `a domain of 55 skills` and `denominator of sixty-one shipped skills`, neither of them read. A figure meant as a past state takes a date in the same sentence instead, which reads the sentence past whatever its shape.
|
|
40
39
|
|
|
41
40
|
## How the trigger set grew
|
|
42
41
|
|
|
@@ -44,7 +43,7 @@ The verb gate is not the first design tried. A bare number next to a catalog nou
|
|
|
44
43
|
|
|
45
44
|
The article half was added after a first review of the shipped design found a live miss: the development domain's gating-stages entry stated a stale audit total while the tree held 20, and the verb gate never reached it, since that sentence puts its verb after the noun rather than ahead of the number. Widening the trigger set to admit an article ahead of the number closed that gap.
|
|
46
45
|
|
|
47
|
-
The quantifier `all` and the verb `authors` joined on the same evidence, two more live misses failing only the trigger test. Allowing words to stand between the trigger and the number was the other candidate, measured and declined: at widths of one, two, and three it reached 77, 104, and 132 sentences against a baseline of 65, missed `took all
|
|
46
|
+
The quantifier `all` and the verb `authors` joined on the same evidence, two more live misses failing only the trigger test. Allowing words to stand between the trigger and the number was the other candidate, measured and declined: at widths of one, two, and three it reached 77, 104, and 132 sentences against a baseline of 65, missed `took all 49 rules` at every width, and reached `the toolkit authors 49 rules` only at a width admitting the indirect-noun shape below. The two words reach both at 75 sentences and no false positive.
|
|
48
47
|
|
|
49
48
|
## The plausibility filter
|
|
50
49
|
|
|
@@ -52,13 +51,13 @@ The verb gate alone still left four false positives standing: `carries two rules
|
|
|
52
51
|
|
|
53
52
|
A stated figure is read only when it sits within a factor of two of the true count, in either direction. That bound is tuned against the run this sweep was written against rather than reasoned to from first principles, the way `restated.ts` tunes its own document-frequency ceiling, and it is a property of the scale every catalog here sits at (the tens) rather than a universal rule.
|
|
54
53
|
|
|
55
|
-
The article gate is looser than the verb list and carries a real cost. Re-running against the tree once it widened caught the live miss above and also misread a passage in
|
|
54
|
+
The article gate is looser than the verb list and carries a real cost. Re-running against the tree once it widened caught the live miss above and also misread a passage in the standards destinations entry, since retired, naming a real subset, a standard outside the retired bundled fan-out, as a claim about the whole standards catalog. The qualifying adjective there fills the same optional-word slot `sixty-one shipped skills` needs to match at all, and no syntactic rule tells a qualifier that narrows a catalog from one that only restates it. The finding could not be closed by correcting a figure, since the sentence was true when the corpus held it, only unmarked as a past state, which is the class the date exclusion already reads past. Naming the moment, the same way a context entry dates its own figures, closed it with no change to the matcher.
|
|
56
55
|
|
|
57
56
|
## What it does not measure
|
|
58
57
|
|
|
59
58
|
A delta phrased as a transition (`from fourteen to fifteen`), a fraction (`thirteen of sixteen`), and a total reached through an indirect noun (`denominator of sixty-one shipped skills`) are all catalog-size claims this corpus carries, and none matches the trigger shape this reads. Each stays a known gap. The false-positive rate that gated closing them has a measurement behind it now, and what it showed is that the widening these three need is the one that costs a false positive rather than the one that does not.
|
|
60
59
|
|
|
61
|
-
A second figure in a sentence whose first figure already matched is a fourth gap and a structural one, since one match is taken per catalog per sentence. `authors
|
|
60
|
+
A second figure in a sentence whose first figure already matched is a fourth gap and a structural one, since one match is taken per catalog per sentence. `authors 49 rules under governance/rules/ and consumes 31 into .claude/rules/` is read for its 49 alone, which is correct here because the two figures name different populations, and a sentence stating one catalog twice would go unread the same way.
|
|
62
61
|
|
|
63
62
|
A calendar date (`2026-08-21`) or a backticked commit reference in the same sentence reads the whole sentence past, since that is how this corpus already marks a figure as a historical record rather than a live claim. The context entries carry a figure this way deliberately, and every one of them stays correct forever.
|
|
64
63
|
|
|
@@ -50,23 +50,19 @@ seed tree rather than from a fixed set of filenames, so a folder added later is
|
|
|
50
50
|
covered without a code change. Only an exact stem matches, which leaves a
|
|
51
51
|
suffixed variant such as `TASKS-ARCHIVE.md` unreported.
|
|
52
52
|
|
|
53
|
-
No skill splits the file. The
|
|
54
|
-
|
|
55
|
-
its destination shape, so the split is the project's own to make.
|
|
53
|
+
No skill splits the file. The destination's shape lives in the skill that owns
|
|
54
|
+
it, so the split is the project's own to make.
|
|
56
55
|
|
|
57
56
|
`unmigrated` names a domain sitting at the root layout an older toolkit installed
|
|
58
57
|
to, with nothing at the path the current one reads. It carries `rootPath`,
|
|
59
|
-
`installPath`, and a file count. Without it a project holding
|
|
58
|
+
`installPath`, and a file count. Without it a project holding an older layout at its
|
|
60
59
|
root reports zero entries for that domain and reads as clean, which is the most
|
|
61
60
|
misleading state the report can produce.
|
|
62
61
|
|
|
63
|
-
The field currently names no domain.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Nothing proposes moving it, and no command relocates the content. Move it
|
|
68
|
-
yourself. A leftover `snippets/` folder reports under the reverse walk instead,
|
|
69
|
-
where `docs/target/sync.md` says what to do with it.
|
|
62
|
+
The field currently names no domain. Snippets was the one the toolkit ever
|
|
63
|
+
installed at a project root, and it retired outright. A leftover `snippets/`
|
|
64
|
+
folder reports under the reverse walk instead, where `docs/target/sync.md` says
|
|
65
|
+
what to do with it.
|
|
70
66
|
|
|
71
67
|
`unmovedSurfaces` names a tracked surface the target still holds at its `.claude/`
|
|
72
68
|
spelling with nothing at the `canon/` one, such as `.claude/REQUIREMENTS.md` or
|
|
@@ -123,14 +119,14 @@ that is not a full clone as unmeasured rather than clean. This gap does not
|
|
|
123
119
|
reach the chain-based read above, since it consults no anchor at all.
|
|
124
120
|
|
|
125
121
|
In the fallback, entitlement is filtered, because a stack does not receive
|
|
126
|
-
every rule. The base stack
|
|
127
|
-
|
|
128
|
-
list would tell a base consumer about rules it can never receive and
|
|
129
|
-
reader to skip the section.
|
|
130
|
-
|
|
131
|
-
The filter accepts a band on either of two grounds. A folder
|
|
132
|
-
|
|
133
|
-
base later needs no code change. Every other band is read off the folders the
|
|
122
|
+
every rule. The base stack names ten rules, the language stacks add `code` and
|
|
123
|
+
their own language and testing rules, and every other rule is opt-in, so an
|
|
124
|
+
unfiltered list would tell a base consumer about rules it can never receive and
|
|
125
|
+
train the reader to skip the section.
|
|
126
|
+
|
|
127
|
+
The filter accepts a band on either of two grounds. A folder holding a rule the
|
|
128
|
+
base stack resolves to is entitled to every target, read through the stack file so
|
|
129
|
+
a rule added to base later needs no code change. Every other band is read off the folders the
|
|
134
130
|
target already carries, which is the fallback's only evidence of what a target
|
|
135
131
|
was entitled to before it recorded a chain. One band can be reached by more than
|
|
136
132
|
one stack, so the test over-reports inside a folder the target holds, which
|
package/docs/agents/index.md
CHANGED
|
@@ -45,11 +45,11 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
45
45
|
- [The pull request checklist tick](pr-tick.md): How canon pr tick marks the checklist boxes a UI pass drove, the stamp that names the commit each passed at, why a render at a newer head clears a tick, the refusal reasons it names, and why a taste box is never ticked
|
|
46
46
|
- [Records push](records-push.md): Backing the record folders to a private remote and restoring them, which folders the payload carries, the one-time setup, the refusal reasons, and the hook that runs the push
|
|
47
47
|
- [Records stale](records-stale.md): Counting the releases since the requirements record was last reviewed, where the review date is read from, and the exit codes and refusals
|
|
48
|
-
- [Records validate](records-validate.md): Validating the session records
|
|
48
|
+
- [Records validate](records-validate.md): Validating the session records, the per-kind checks, which root they default to, the exit codes, and the refusal reasons
|
|
49
49
|
- [Records](records.md): The two roots a record folder resolves at, claiming the ordinal intake and groundwork share, reading each folder's size and growth, pruning stale scratch, and where validation, the canonical review count, and the private-remote backup are described
|
|
50
50
|
- [Restated instructions](restated.md): Counting the instructions the always-loaded file and every path-scoped rule share with the seed, the skill bodies, and each other, how a match is decided, the three classes, which surface a later edit starts from, and why the sweep reports rather than gates
|
|
51
51
|
- [Routing report](routing.md): Reading per CLAUDE.md section how many bullets name a path, what counts as naming one, when a rule counts as covering it, the two refusals, and why the verb reports rather than gates
|
|
52
|
-
- [Rule citations](rule-citations.md): Resolving every path a governance rule cites and every frontmatter glob the internal corpus declares, the
|
|
52
|
+
- [Rule citations](rule-citations.md): Resolving every path a governance rule cites and every frontmatter glob the internal corpus declares, the two forms a citation is written in, the shapes that look like citations and are not, the two classes where an absent path is correct, why the glob half reads one corpus, and why this one gates
|
|
53
53
|
- [Sandbox](sandbox.md): Scenario routing, the expectation scoring surface, and the coverage census over scenarios and skills
|
|
54
54
|
- [Scripting](scripting.md): The runtime catalogs that replace hardcoded names, what each carries, and a headless invocation per domain
|
|
55
55
|
- [Sessions transfer](sessions-transfer.md): Moving a session to another machine, the export bundle and its manifest, placing it with import, the refusal reasons, and what a resume on the target depends on
|
|
@@ -57,7 +57,6 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
57
57
|
- [Skill audit](skills-audit.md): Measuring both skill corpora against the skill standards, the checks it reads, the requirement gate that is the only failing one, and the drift verb that names bodies rewritten since a ref
|
|
58
58
|
- [Citation reach](skills-reach.md): Reporting the skill bodies that cite a path no target project receives, which corpus the verb reads, the ownership key that decides what counts, the one-word qualifier that marks a citation as decided, and why the verb reports instead of gating
|
|
59
59
|
- [Slides](slides.md): Where a deck folder lives and what it holds, what it declares for the whole deck in deck.json, the faces it embeds, what each slide declares on its own body, transitions and entrances, the master built from the project's tokens, speaker notes, charts, and what each refusal reports
|
|
60
|
-
- [Standard success criteria](standards-audit.md): Reading the corpus against the success-criterion gate, the two headings it accepts, why the check scopes to arrival rather than the whole corpus, and the exit codes it sets
|
|
61
60
|
- [State-scoped risk](state-scoped-risk.md): Reading committed state rather than an arriving change, the shipped-tree corpus the secret scan reads, what it keys on and how a deliberate value is exempted, the advisory check and its network failure mode, and why one gates while the other reports
|
|
62
61
|
- [Superseded values](superseded.md): Reading where the tree still asserts a value a changed convention no longer produces, why the sweep keys on the value rather than the file, the family stem behind a templated citation, the exemption marker, the blind spots it cannot reach, and why it reports rather than gates
|
|
63
62
|
- [Targets](targets.md): The projects this toolkit installed into, the record the install writes against the sweep that backs it, what bounds each answer, and the cross-target pull request read
|
|
@@ -27,15 +27,15 @@ carried, and the sync says so. The sync lists each change by path before it
|
|
|
27
27
|
applies, and the target's git diff is the record afterwards. `canon sync
|
|
28
28
|
--check` lists the same file as `retired` or `renamed` before any sync runs.
|
|
29
29
|
|
|
30
|
-
A rule that only routed a path to a standard
|
|
31
|
-
|
|
32
|
-
`claude/skill.md`. A held copy of each syncs in place, and the
|
|
33
|
-
intake, session, design, readme, and rule copies are deleted as
|
|
34
|
-
markdown rule is hand-written at `writing/markdown.md
|
|
35
|
-
`
|
|
30
|
+
A rule that only routed a path to a standard now names the skill that owns
|
|
31
|
+
the guidance. The tasks, plan, context, and skill rules are hand-written at
|
|
32
|
+
`canon/` and `claude/skill.md`. A held copy of each syncs in place, and the
|
|
33
|
+
groundwork, intake, session, design, readme, and rule copies are deleted as
|
|
34
|
+
retired. The markdown rule is hand-written at `writing/markdown.md` and names
|
|
35
|
+
the `markdown-craft` skill, and `800-prose` retires.
|
|
36
36
|
|
|
37
37
|
A project's own rules belong under `.claude/rules/project/`, where
|
|
38
|
-
`
|
|
38
|
+
the `create-rule` skill's reference reserves `900-999` for them, and a rule placed under
|
|
39
39
|
`canon/` instead is lost on the next sync.
|
|
40
40
|
|
|
41
41
|
A sync never deletes a rule that a newer canon release installed. The stamp
|
|
@@ -86,12 +86,6 @@ from an anchor a later sync could advance past the rule's own commit. A
|
|
|
86
86
|
target whose install predates the recorded chain falls back to the same
|
|
87
87
|
band-inference `newRules` uses in `canon sync --check`.
|
|
88
88
|
|
|
89
|
-
There is no `canon standards sync` and no `canon standards install`. The corpus
|
|
90
|
-
installs into no project, so the domain has nothing in a target to reconcile.
|
|
91
|
-
`canon standards <name>` prints one, resolving `standards/` at the working root
|
|
92
|
-
and then the corpus inside the package, and `canon standards list --json` carries
|
|
93
|
-
the catalog, each entry labeled by the root it was read from.
|
|
94
|
-
|
|
95
89
|
## Tooling diff and sync
|
|
96
90
|
|
|
97
91
|
`canon tooling diff <stack> [target]` is the read-only comparison, and a session asking what differs reaches for it by default. It writes nothing and exits 1 when anything differs and 0 when nothing does, so it gates CI. `--json` adds the scan record on stdout with `ok: true`, and the frame goes to stderr. A refusal such as an unknown stack, an excluded stack, or a toolkit-root target still exits 1 and answers `{ ok: false, reason, message }`, so a caller branches on the record and reads a typo'd stack name as a refusal rather than as drift.
|
|
@@ -129,23 +123,6 @@ Claude Code loads both copies of an edited rule at session start. Run `canon
|
|
|
129
123
|
migrate rule-layout` first to move a target off the flat layout, which reports
|
|
130
124
|
what it would move and applies it under `--write`.
|
|
131
125
|
|
|
132
|
-
## Standards resolution
|
|
133
|
-
|
|
134
|
-
`canon standards <name>` writes the document to stdout and the root it answered
|
|
135
|
-
from to stderr, so a caller capturing with `$(...)` receives the document alone.
|
|
136
|
-
A name resolves with or without its `.md` extension, and one that matches no
|
|
137
|
-
standard exits 1 after listing the catalog on stderr.
|
|
138
|
-
|
|
139
|
-
Two roots answer, in order: `standards/` at the working directory, then the
|
|
140
|
-
corpus inside the package. A project that authors standards of its own uses the
|
|
141
|
-
first, and this repository's own authoring root is the same path. `.claude/standards/`
|
|
142
|
-
is not among them, and no repository writes one any more. A copy an older
|
|
143
|
-
toolkit installed into a target resolves nothing.
|
|
144
|
-
|
|
145
|
-
There is no citation closure to compute, since nothing is copied. A standard
|
|
146
|
-
that hands a concern to a sibling names it in `Does not govern:` and a reader
|
|
147
|
-
runs the verb again for that name.
|
|
148
|
-
|
|
149
126
|
## Governance regen
|
|
150
127
|
|
|
151
128
|
`canon gov regen` is the one governance verb that runs against the toolkit root,
|
|
@@ -258,7 +235,6 @@ still prompts. `--skip` takes `wiki`, `governance`, and `records`, and warns
|
|
|
258
235
|
without aborting on any other value. Records has nothing to run non-interactively,
|
|
259
236
|
since the private backup repository does not exist yet at scaffold time, so its
|
|
260
237
|
step only prints the one-time setup reminder and `--skip records` silences it.
|
|
261
|
-
There is no `--standards`, since no run writes that corpus into the target.
|
|
262
238
|
|
|
263
239
|
## Unguarded tooling primitives
|
|
264
240
|
|
|
@@ -5,14 +5,14 @@ description: Running the audit over any markdown path, where its bans and checkp
|
|
|
5
5
|
|
|
6
6
|
# Markdown audit
|
|
7
7
|
|
|
8
|
-
`canon markdown audit [path...]` reports any markdown file against the
|
|
8
|
+
`canon markdown audit [path...]` reports any markdown file against the `markdown-craft` skill's `markdown.md` reference. That reference governs a file rather than a folder, so this resolves no folder and requires no `index.md`, which is what puts `.claude/rules/` and `governance/` in reach. Folder-shaped findings stay in `canon context audit`, described in `context-audit.md`.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
canon markdown audit
|
|
12
12
|
canon markdown audit --json
|
|
13
13
|
canon markdown audit .claude/rules governance
|
|
14
14
|
canon markdown audit docs/agents/commands.md
|
|
15
|
-
canon markdown audit '
|
|
15
|
+
canon markdown audit 'docs/**/*.md'
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
| Option | Behavior |
|
|
@@ -27,29 +27,27 @@ A bare run measures every markdown file git lists, tracked plus untracked-and-no
|
|
|
27
27
|
|
|
28
28
|
## Where the rules come from
|
|
29
29
|
|
|
30
|
-
The ban set and all ten checkpoints ship with the `canon` package as data, in `src/markdown/bans.ts` and `src/markdown/structure.ts`. Every project is measured against the same set whether or not it installed
|
|
30
|
+
The ban set and all ten checkpoints ship with the `canon` package as data, in `src/markdown/bans.ts` and `src/markdown/structure.ts`. Every project is measured against the same set whether or not it installed the plugin, and no file has to resolve for a run to mean something.
|
|
31
31
|
|
|
32
32
|
Seven of the ten are stated in `markdown.md` and the three cadence numbers are stated in the `write-human` skill. That split is the content boundary rather than an accident: `markdown.md` carries the enforced rules a scan can decide, and the skill carries the rhythm rules a ban list cannot express. A cadence number moved in the skill and left in the code drifts the same way, so move both.
|
|
33
33
|
|
|
34
|
-
Reading them out of the
|
|
34
|
+
Reading them out of the reference per run was the original design. It put a parser contract on a document authored for people, and the reference had to carry a paragraph of its own warning an author that a one-word backticked example in a `- Do not use ` bullet would be lifted into a literal ban set and ban that word everywhere. A rule existing to protect a parser from the prose it parses is the argument for separating them.
|
|
35
35
|
|
|
36
36
|
`markdown.md` still states every ban and every checkpoint, and a reader follows it rather than the code. Nothing compares the two, so a number moved in one place and left in the other drifts silently. Move both in the same change.
|
|
37
37
|
|
|
38
|
-
The set is closed rather than extensible, so a project cannot add a term by editing a file. It holds the two characters alone, since a character is the one class a literal match settles. The set once carried 13 words and 6 British spellings as well. The words moved to the `write-human` skill as guidance, because a word ban catches the token and misses the habit, and `just`, `allows`, and `very` carry honest uses no literal match separates. Spelling
|
|
38
|
+
The set is closed rather than extensible, so a project cannot add a term by editing a file. It holds the two characters alone, since a character is the one class a literal match settles. The set once carried 13 words and 6 British spellings as well. The words moved to the `write-human` skill as guidance, because a word ban catches the token and misses the habit, and `just`, `allows`, and `very` carry honest uses no literal match separates. Spelling is left to the author, with American spelling carried as guidance in `markdown-craft`.
|
|
39
39
|
|
|
40
40
|
A set shipped empty is reported rather than passed. It finds nothing and would exit clean, which reports a corpus nobody checked as a corpus carrying no violation, so the run names the empty set and exits `3`. The set ships with the package, so a defect in the build is the only cause left.
|
|
41
41
|
|
|
42
|
-
`canon standards <name>` still resolves a standard at the authoring root, then the package corpus, and prints it, so the human catalog reads without a project copy on disk.
|
|
43
|
-
|
|
44
42
|
## What each check reports
|
|
45
43
|
|
|
46
44
|
### Bans
|
|
47
45
|
|
|
48
46
|
One closed set reports a hit: the characters `markdown.md` bans under `## Punctuation`.
|
|
49
47
|
|
|
50
|
-
Frontmatter, fenced blocks, inline code spans, and link destinations are excluded. Without the code-span exclusion each
|
|
48
|
+
Frontmatter, fenced blocks, inline code spans, and link destinations are excluded. Without the code-span exclusion each reference would report its own backticked examples, and without the link exclusion a semicolon in a query string would report as prose no rewrite can fix.
|
|
51
49
|
|
|
52
|
-
Word choice stays unmeasured and the report says so on every run. Single words travel in the `write-human` skill as guidance a reader applies. A multi-word ban escapes the harvest by width, whether it carries a placeholder standing in for the rest of the sentence or spells the phrase out in full, and every rule under `## Voice` is a judgment. The bans `## Language` states over what a sentence may claim are patterns of the multi-word kind by construction, since a literal match over a pattern reports the compliant text and reaches none of the violations. A report listing hits without naming those would read as a verdict on the whole
|
|
50
|
+
Word choice stays unmeasured and the report says so on every run. Single words travel in the `write-human` skill as guidance a reader applies. A multi-word ban escapes the harvest by width, whether it carries a placeholder standing in for the rest of the sentence or spells the phrase out in full, and every rule under `## Voice` is a judgment. The bans `## Language` states over what a sentence may claim are patterns of the multi-word kind by construction, since a literal match over a pattern reports the compliant text and reaches none of the violations. A report listing hits without naming those would read as a verdict on the whole reference.
|
|
53
51
|
|
|
54
52
|
### Links
|
|
55
53
|
|
|
@@ -103,14 +101,14 @@ Both hooks answer an absent record as well. A completed run always writes the re
|
|
|
103
101
|
|
|
104
102
|
A machine with neither runner still blocks no edit, and it says so rather than exiting clean. The push stage holds either way. An edit nobody checked and an edit carrying no violation are one silence to a reader, so the enforcement a machine lacks is reported rather than inferred.
|
|
105
103
|
|
|
106
|
-
The stage measures the whole corpus rather than the changed files. A `Do not use` bullet added to a
|
|
104
|
+
The stage measures the whole corpus rather than the changed files. A `Do not use` bullet added to a reference bans a token retroactively, and no file in the push that adds the bullet was edited.
|
|
107
105
|
|
|
108
106
|
## What it does not cover
|
|
109
107
|
|
|
110
|
-
The verb reads the
|
|
108
|
+
The verb reads the `markdown-craft` skill's reference and the `write-human` cadence numbers and nothing else. The references the `git-pr`, `git-branch`, and `git-commit` skills own, `publish.md`, `slug.md`, and `versioning.md`, govern an attribute of other artifacts, and none of them is implemented here.
|
|
111
109
|
|
|
112
110
|
`publish.md` describes a scan applying the same punctuation bans to finished text on its way out. No code implemented that scan before this command, so nothing is duplicated, and a later surface should call this verb rather than build a second one.
|
|
113
111
|
|
|
114
|
-
That
|
|
112
|
+
That reference's cross-reference rule is out of reach rather than merely unimplemented. It resolves by destination, bare where the destination auto-links a pull request or issue number and backticked where it does not, so this verb sees only the half where the backticked form is correct. A check here would report every compliant reference in the tree and reach none of the published text that goes wrong, which is why the rule holds on reading alone.
|
|
115
113
|
|
|
116
114
|
The list-density rule at `claude/skills/markdown-craft/references/markdown.md` is out of scope on purpose, since it carries no number and what a density figure should measure is still open.
|
package/docs/agents/migrate.md
CHANGED
|
@@ -25,7 +25,7 @@ Every citation in scope is reported with its file, its line number, and the line
|
|
|
25
25
|
|
|
26
26
|
`migrate rule-layout` moves a target still on the flat installed-rule layout onto the `canon/`-wrapped one. It classifies each flat file against the target's own recorded stamp: an unchanged hash is clean, a changed one is edited, and a name neither the stamp nor the current rule catalog can vouch for is unclaimed and left in place. Clean and edited files both relocate with their content untouched, since moving a rule is a different decision from re-syncing it. The one renumbered rule reads its destination from a table rather than from its own current name, so it never lands as a second copy under the retired number.
|
|
27
27
|
|
|
28
|
-
`migrate scratch-evidence` moves a folder out of `.tmp/` for good rather than repointing a citation in place. A promoted folder is one a durable record, live or archived, cites as its evidence, and no source file under `claude/`, `scripts/`, `src/`,
|
|
28
|
+
`migrate scratch-evidence` moves a folder out of `.tmp/` for good rather than repointing a citation in place. A promoted folder is one a durable record, live or archived, cites as its evidence, and no source file under `claude/`, `scripts/`, `src/`, or `governance/` names by path, which is what a script still writing into it fails. It walks every `canon records push` folder rather than the live ones alone, since most of what it repoints sits in `tasks/archive/`, `plans/archive/`, and `groundwork/`. A destination already occupied is a refusal, and a second run rewriting nothing is the same idempotence check `migrate record-tree` uses.
|
|
29
29
|
|
|
30
30
|
A destination that already holds the same bytes marks the flat file a duplicate, which `--write` deletes rather than moves. One holding different bytes is a real collision: neither file is touched, it is reported by name, and every other planned move still applies independently. Run this before `canon gov install` or `canon gov sync` against a target still on the flat layout, since neither bootstrap verb detects or clears it on its own.
|
|
31
31
|
|
|
@@ -25,7 +25,7 @@ It reports and never writes, matching `validate` and `size`.
|
|
|
25
25
|
|
|
26
26
|
`canonical` reads `REQUIREMENTS.md` at whichever surface root carries it, `canon/` ahead of `.claude/`, and omits it when the project does not hold one. It is tracked, so `--root` defaults to the worktree the caller stands in rather than the main one, and a stamp a branch just wrote reads back from that branch.
|
|
27
27
|
|
|
28
|
-
The review point is an optional `reviewed: YYYY-MM-DD` frontmatter field, set by whoever finishes a review, per `
|
|
28
|
+
The review point is an optional `reviewed: YYYY-MM-DD` frontmatter field, set by whoever finishes a review, per `claude/skills/draft-doc/references/requirements.md`. It is a date rather than a commit, since a commit written on a feature branch never reaches a trunk that squash-merges. The field is read off the raw frontmatter block rather than a parsed value, since a YAML parser resolves a bare date to a date object on one schema and a string on another. A value that is not a calendar date reads as never reviewed, and the record carries the raw value as `invalidReviewed` so a review can see it rather than the verb throwing over one hand edit.
|
|
29
29
|
|
|
30
30
|
The count is every release tag merged into `HEAD` whose creator date falls after the reviewed day. A release tag ends in a dotted version, bare as `v5.25.0` or behind a component prefix as `canon-v2.1.0`, so an eval, deploy, or snapshot tag on the trunk never inflates it. A lightweight tag's creator date is its commit's date and an annotated tag's is the tagging date, so a project mixing both counts by two clocks.
|
|
31
31
|
|