@erclx/canon 5.33.0 → 5.34.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/REQUIREMENT.md +1 -2
- package/claude/skills/api-design/SKILL.md +2 -3
- package/claude/skills/api-design/references/adopted.md +1 -1
- package/claude/skills/canon-feedback/REQUIREMENT.md +1 -0
- package/claude/skills/canon-feedback/SKILL.md +10 -28
- package/claude/skills/canon-feedback/references/template.md +53 -0
- package/claude/skills/canvas-board/SKILL.md +4 -1
- package/claude/skills/canvas-board/references/canvas.md +26 -3
- package/claude/skills/code-craft/REQUIREMENT.md +1 -1
- package/claude/skills/code-craft/SKILL.md +0 -1
- package/claude/skills/create-rule/SKILL.md +1 -1
- package/claude/skills/create-rule/references/rule.md +3 -1
- package/claude/skills/create-skill/references/skill.md +1 -1
- package/claude/skills/git-issue/references/issue.md +4 -1
- package/claude/skills/review-craft/references/ui.md +1 -1
- package/claude/skills/review-ui/SKILL.md +7 -5
- package/claude/skills/review-ui/references/driving.md +8 -8
- package/claude/skills/review-ui/references/post.md +52 -16
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +9 -0
- package/claude/skills/target-setup/SKILL.md +10 -4
- package/claude/skills/target-setup/references/detect.md +19 -2
- package/claude/skills/test-craft/REQUIREMENT.md +2 -3
- package/claude/skills/test-craft/SKILL.md +15 -3
- package/docs/agents/canvas.md +5 -1
- package/docs/agents/commands.md +1 -1
- package/docs/agents/gov-detect.md +47 -0
- package/docs/agents/index.md +4 -1
- package/docs/agents/install-and-sync.md +4 -0
- package/docs/agents/pr-evidence-layout.md +70 -0
- package/docs/agents/pr-evidence.md +8 -9
- package/docs/agents/pr-frames.md +7 -2
- package/docs/agents/pr-lift.md +132 -0
- package/docs/agents/scripting.md +2 -1
- package/docs/target/projects.md +3 -3
- package/governance/detect.toml +201 -0
- package/governance/rules/code/000-code.md +1 -13
- package/governance/rules/code/010-testing.md +2 -30
- package/governance/rules/ui/400-ui.md +1 -1
- package/governance/rules/ui/480-canvas.md +13 -0
- package/package.json +1 -1
- package/scripts/core/regen-hero.ts +0 -6
- package/scripts/lib/ui.sh +0 -9
- package/src/canvas/arrange.ts +66 -0
- package/src/canvas/capture.ts +20 -6
- package/src/canvas/content.ts +39 -0
- package/src/canvas/fit.ts +238 -0
- package/src/canvas/tokens.ts +28 -10
- package/src/capture/frame-values.ts +2 -32
- package/src/commands/canvas.ts +179 -1
- package/src/commands/gov.ts +144 -1
- package/src/commands/pr.ts +376 -1
- package/src/feedback/body.ts +26 -5
- package/src/gate/measures.ts +58 -44
- package/src/gate/stages.ts +3 -4
- package/src/gov/detect.ts +301 -0
- package/src/gov/list.ts +23 -2
- package/src/gov/stacks.ts +9 -0
- package/src/pr/evidence.ts +218 -45
- package/src/pr/frames.ts +23 -3
- package/src/pr/lift.ts +418 -0
- package/src/pr/rest.ts +3 -0
- package/src/pr/review-scope.ts +76 -0
- package/src/sandbox/equivalence.ts +14 -7
|
@@ -80,7 +80,8 @@ root.
|
|
|
80
80
|
- **Stack:** pick the closest governance stack by matching the repository root's detected runtime or framework against stack names in the catalog. 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
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 `nextjs` governance stack and the `nextjs` tooling stack. The dependency name does not match either stack name by itself.
|
|
83
|
-
- **Extras:**
|
|
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
|
+
- **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.
|
|
84
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.
|
|
85
86
|
- **Skip (`--skip`):** `wiki` installs by default. Add `--skip wiki` only when the user explicitly wants it left out.
|
|
86
87
|
|
|
@@ -112,7 +113,7 @@ Before executing, output:
|
|
|
112
113
|
- **Detected:** each technology with its evidence file, path included, so a subfolder marker reads as one
|
|
113
114
|
- **Stack:** picked governance stack and resolved rule count. Mark it `fallback` when no detected runtime or framework matched a catalog name.
|
|
114
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.
|
|
115
|
-
- **Extras:** each
|
|
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.
|
|
116
117
|
- **Skip:** any `--skip` entries with reason
|
|
117
118
|
- **Target:** resolved target path
|
|
118
119
|
- **Commands:** the full chain that will run
|
|
@@ -120,3 +121,19 @@ Before executing, output:
|
|
|
120
121
|
A resolved name and a fallback read alike once written, so mark the fallback
|
|
121
122
|
here rather than in the report. The preview is the last point before the first
|
|
122
123
|
write, and the report runs after the files have landed.
|
|
124
|
+
|
|
125
|
+
### Confirm the extras
|
|
126
|
+
|
|
127
|
+
The extras are the one part of the preview the operator confirms before the
|
|
128
|
+
install runs, since a proposal is evidence that a project might want a rule
|
|
129
|
+
rather than proof that it does. Put the list through the structured question
|
|
130
|
+
surface with three options: take every proposal, which is the recommended
|
|
131
|
+
first option, take none, or name a subset, which the operator types as a
|
|
132
|
+
comma-separated list. Pass what they kept to `--add` and drop the flag when
|
|
133
|
+
they kept nothing.
|
|
134
|
+
|
|
135
|
+
An `--extras` argument answers ahead of time and skips the question.
|
|
136
|
+
`--extras <a>,<b>` takes the named rules, and `--extras none` takes none. With
|
|
137
|
+
neither and no one to answer, take every proposal and list each in the report,
|
|
138
|
+
since a proposed rule costs one file to delete and stopping would break every
|
|
139
|
+
headless setup.
|
|
@@ -15,7 +15,7 @@ The failure is measured on a real target. A single-page portfolio site carried 2
|
|
|
15
15
|
|
|
16
16
|
A stated rule is also one a session can talk itself out of. Each test in that suite sat where it did for a reason that sounded fine at the time, such as the end to end spec already being open or a pause quieting a run that flaked under load, and nothing in front of the session answered the reason.
|
|
17
17
|
|
|
18
|
-
Moving the guidance into a path-scoped rule does not reach the session that needs it. A path-scoped rule loads when a session reads a matching file and
|
|
18
|
+
Moving the guidance into a path-scoped rule does not reach the session that needs it. A path-scoped rule loads when a session reads or writes a matching file, and it is absent from the write that creates the first one, measured in three headless runs, so a rule scoped to test files is silent on the first test of every feature.
|
|
19
19
|
|
|
20
20
|
## Must
|
|
21
21
|
|
|
@@ -23,6 +23,7 @@ Moving the guidance into a path-scoped rule does not reach the session that need
|
|
|
23
23
|
- Open every test with the question of which production change makes it fail and whether that change is a bug or a decision, since a test with no answer proves nothing
|
|
24
24
|
- State the end to end budget in words: journeys and what only a real browser renders, never a state a component test reaches
|
|
25
25
|
- Carry a final filter the session runs over its own tests, each item a shape it can check: mirror assertion, change detector, assertion on a mock, framework behavior, fixed pause, and the mutation check
|
|
26
|
+
- Own the structure floors every test carries, being arrange, act, assert, one behavior per test, no branching or loops in a body, no testing of private functions or internal state, no coverage targets, nesting at most two levels deep, independent tests that clean up, factories for test data, every async call awaited, and no snapshot verification. The testing rule only points here, so a later trim keeps them.
|
|
26
27
|
- Hold in the body what every test decision pays for, and defer each layer's specifics to a reference loaded only when a test at that layer is being written
|
|
27
28
|
- Promise a middle layer for behavior a simulated DOM cannot render, naming the real-browser component runners, so a static site is not left choosing between a simulated DOM that computes no layout and a whole-site run
|
|
28
29
|
- Repeat in the end to end reference the two floors a session writing its first spec never loads through the path-scoped rule, being the `scrollend` settle and motion reduced by default
|
|
@@ -34,7 +35,6 @@ Moving the guidance into a path-scoped rule does not reach the session that need
|
|
|
34
35
|
|
|
35
36
|
- Name a framework or runner in the body. Runner specifics live in the references and in the language testing rules, so the body holds across stacks.
|
|
36
37
|
- Carry a numeric mix across layers. A codebase-wide ratio is a target a session writing one test cannot act on.
|
|
37
|
-
- Restate the structure floors the testing rule already carries, such as arrange, act, assert, one behavior per test, isolation, and no snapshots
|
|
38
38
|
- Restate the settle, guard, and run-scope rules the end to end rules carry, beyond the two floors named above
|
|
39
39
|
- Run the red, green, refactor procedure or decide its order, which `test-first` owns
|
|
40
40
|
- Import an external skill's tone, such as a law stated as absolute, or an excuse row rebutting an objection no session has raised
|
|
@@ -49,7 +49,6 @@ Moving the guidance into a path-scoped rule does not reach the session that need
|
|
|
49
49
|
|
|
50
50
|
- The red, green, refactor loop and the order it runs in: `test-first`, which loads this skill at its first step
|
|
51
51
|
- Reproducing a failure with no known cause: `systematic-debugging`
|
|
52
|
-
- Structure floors for every test: the core testing rule
|
|
53
52
|
- Runner choice, file suffix, placement, and query conventions: the TypeScript and Python testing rules
|
|
54
53
|
- Settle, guard, and run-scope rules inside an end to end file: the end to end reliability and test scope rules
|
|
55
54
|
- Writing a UI change's visual checklist, and naming the behaviors it ships untested for this skill to place: `ui-checklist`
|
|
@@ -45,10 +45,23 @@ Size a test by what it touches rather than by what it covers. Pick the first row
|
|
|
45
45
|
|
|
46
46
|
## Keep test code readable over clever
|
|
47
47
|
|
|
48
|
-
- Prefer a descriptive, repeated arrange over a shared helper a reader has to open. A test is read when it fails, by someone who did not write it.
|
|
49
|
-
- Assert through the public surface a caller uses. A test reaching into internals breaks on every refactor and catches nothing a caller sees.
|
|
48
|
+
- Prefer a descriptive, repeated arrange over a shared helper a reader has to open. A test is read when it fails, by someone who did not write it. Build test data through a factory or builder rather than an inline object literal repeated across tests.
|
|
49
|
+
- Assert through the public surface a caller uses, never on a private function or internal state directly. A test reaching into internals breaks on every refactor and catches nothing a caller sees.
|
|
50
50
|
- Prefer a real collaborator, then a fake, then a stub, and a mock last. A mock asserts how the code is built rather than what it does.
|
|
51
51
|
|
|
52
|
+
## Hold the structure floors
|
|
53
|
+
|
|
54
|
+
Every test carries these, at any layer and in any runner:
|
|
55
|
+
|
|
56
|
+
- Structure each test as arrange, act, assert.
|
|
57
|
+
- Verify one behavior per test.
|
|
58
|
+
- Keep conditional logic and loops out of a test body. A table of cases is one test per row, never a branch inside one.
|
|
59
|
+
- Set no coverage percentage as a target. Cover the behaviors and their edges.
|
|
60
|
+
- Group related tests with the framework's nesting mechanism, and keep it to two levels deep.
|
|
61
|
+
- Keep tests independent with no shared side effects. Clean up and restore state after each one.
|
|
62
|
+
- Await every async operation. Never leave a promise fire-and-forget in a test.
|
|
63
|
+
- Verify with assertions, never with a snapshot.
|
|
64
|
+
|
|
52
65
|
## Read the reference for the layer
|
|
53
66
|
|
|
54
67
|
Read the one reference matching the layer the table picked, before writing the first test at it. Skip the other two.
|
|
@@ -92,6 +105,5 @@ Run the final filter over every test written this session, checking each line. A
|
|
|
92
105
|
|
|
93
106
|
- The red, green, refactor procedure and its order: `test-first`, which loads this skill at its first step
|
|
94
107
|
- Reproducing a failure with no known cause: `systematic-debugging`
|
|
95
|
-
- Test structure floors such as arrange, act, assert, one behavior per test, isolation, and no snapshots: `010-testing`
|
|
96
108
|
- Runner, file suffix, placement, and query conventions per language: `300-testing-ts`, `330-testing-py`, `335-testing-go`, and `336-testing-php`
|
|
97
109
|
- Settle, guard, and run-scope rules inside an end to end file: `305-e2e-reliability` and `306-test-scope`
|
package/docs/agents/canvas.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Canvas
|
|
3
|
-
description: The canvas server, its content format, and the verbs that list, arrange, select, edit, mark, and capture frames
|
|
3
|
+
description: The canvas server, its content format, and the verbs that list, arrange, fit, select, edit, mark, and capture frames
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Canvas
|
|
@@ -29,6 +29,10 @@ The write routes the shell posts to also refuse a request carrying an `Origin` o
|
|
|
29
29
|
|
|
30
30
|
`frame resize <page> <name> --width <px> --height <px>` rewrites one frame's whole box in one write, and `--x` and `--y` move it at the same time. An omitted flag keeps the frame's current value. It refuses a width or height that is not a positive number as `invalid-size`, a position that is not a number as `invalid-position`, and a missing frame, a missing page, or a layout that does not parse as `frame move` does.
|
|
31
31
|
|
|
32
|
+
`canvas arrange <page>` re-lays a page's frames. It keeps the rows they already sit in, where boxes whose vertical spans overlap share a row, orders each row left to right by `x`, places the boxes on the 80px frame gap from the page's leftmost edge, and stacks the rows on their tallest box plus the gap from the page's top edge. It also drops every layout entry whose frame file is gone. `--check` writes nothing. `--json` emits `{ ok, page, written, moved, dropped }`, where `moved` lists each frame with its `from` and `to` position and `dropped` lists the entries with no file. Sizes never change. Under `--check` it exits 2 when a frame would move or an entry would drop, and it refuses a missing page as `no-page` and a layout that does not parse as `malformed-layout`.
|
|
33
|
+
|
|
34
|
+
`canvas fit <page>/<frame>` and `canvas fit <page>` set each frame's height to its content. The content is measured in the capture browser at the frame's box width, through the served address, after fonts and the load event settle, and the height is that measure rounded up with no margin. The write goes through the same writer as `frame resize`. `--check` writes nothing. `--json` emits `{ ok, written, frames }`, one row per frame carrying `height`, `fitted`, `wide`, `font`, `viewport`, `family`, and `owed`. `wide` is true when the content is wider than the box, which fit reports and never widens, since the width is the frame's declared render width. `font` is true when the first family of the body text is not one the served sheet declares a face for, being the toolkit faces `Geist Variable`, `Noto Sans Mono`, and the hand-drawn pair, plus any face the project declares, because a height fitted against a machine family may not hold in another browser. `viewport` is true when the frame's height depends on the viewport, as a height in `vh` does. The lowest element edge is read with the viewport at the box height and at twice it, and an edge that moved means the content measure is not the height a viewer draws, so its height is kept and nothing is written for it. Under `--check` it exits 2 when any row is owed, and it refuses as `no-page`, `no-frame`, `no-server`, or `capture-failed` the way `canvas capture` does. Rows below a frame that grew do not move, so run `canvas arrange` after a fit.
|
|
35
|
+
|
|
32
36
|
The shell writes through the same writer when the operator drags a frame or one of its corner handles. Both take a lock file beside the layout, read it, merge their change, and replace it, so a drag released while a verb writes loses neither position. A writer that cannot get the lock within two seconds refuses with reason `busy`.
|
|
33
37
|
|
|
34
38
|
`canvas selection --json` emits `{ ok, selection }` with the page, frame, file, box, and path of the frame the operator selected, or `selection: null` when nothing is selected or the selected frame has since been removed. Read it when the operator says "this one".
|
package/docs/agents/commands.md
CHANGED
|
@@ -103,7 +103,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
|
|
|
103
103
|
- `sessions`, in `sessions.md`: `list`, `export`, `import`
|
|
104
104
|
- `worktrees`, in `worktrees.md`: `list`, `reclaim`
|
|
105
105
|
- `hooks`, in `hooks.md`: `post-merge`
|
|
106
|
-
- `pr`, in `pr-reads.md`: `key-changes`, `head`, `checks`, `review-state`, `evidence`, `preview`, `local`, `frames`
|
|
106
|
+
- `pr`, in `pr-reads.md`: `key-changes`, `head`, `checks`, `review-state`, `evidence`, `preview`, `local`, `frames`, `lift` (in `pr-lift.md`)
|
|
107
107
|
- `audits`, in `audits.md`: `run`, `list`
|
|
108
108
|
- `gate`, in `gate.md`: `run`
|
|
109
109
|
- `secrets`, in `state-scoped-risk.md`: `scan`
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Rule detection
|
|
3
|
+
description: Proposing opt-in governance rules from a target's dependencies and paths, the evidence file the verb reads, the record it emits, and its exit codes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rule detection
|
|
7
|
+
|
|
8
|
+
`canon gov detect` proposes the opt-in governance rules a target's evidence points at, and writes nothing. A rule no stack names reaches a project only through this verb, which `canon:target-setup` calls before it previews an install.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
canon gov detect
|
|
12
|
+
canon gov detect ../my-app --stack node --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
| Option | Behavior |
|
|
16
|
+
| ----------------- | ------------------------------------------------ |
|
|
17
|
+
| `--stack <stack>` | Leave out every rule this stack already resolves |
|
|
18
|
+
| `--json` | Emit the record on stdout instead of the frame |
|
|
19
|
+
|
|
20
|
+
## Evidence
|
|
21
|
+
|
|
22
|
+
Each opt-in rule keeps a table in the toolkit's `governance/detect.toml`, keyed by rule basename. Its `deps` are package names, read from `package.json` (`dependencies` and `devDependencies`), `pyproject.toml`, `go.mod`, and `composer.json`. Its `files` are globs matched against the target's git-listed paths and against each folder on those paths, so `.github/workflows` matches a folder holding a workflow. A glob with no wildcard is also tested on disk, which is how `.canon/canvas` matches in a target that gitignores `.canon/`.
|
|
23
|
+
|
|
24
|
+
Both reads stop at depth two, which reaches a service folder and a workspace package under `packages/<name>/`. Outside git the verb walks the directory to the same depth and skips `.git`, `node_modules`, `vendor`, and `.venv`. A manifest that does not parse contributes nothing.
|
|
25
|
+
|
|
26
|
+
## Record
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"target": "/abs/path/my-app",
|
|
31
|
+
"stack": "node",
|
|
32
|
+
"proposals": [
|
|
33
|
+
{
|
|
34
|
+
"rule": "200-react",
|
|
35
|
+
"evidence": [{ "kind": "dep", "match": "react", "path": "package.json" }]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`kind` is `dep` for a dependency, with `path` naming the manifest that declares it, or `file` for a glob, with `path` naming what it matched. `stack` is null when no `--stack` was passed.
|
|
42
|
+
|
|
43
|
+
## Exit codes
|
|
44
|
+
|
|
45
|
+
The verb exits 0 on every readable target, including one with no evidence, which returns an empty `proposals` array. A target that does not exist and a `--stack` that does not resolve each exit 1 with the reason on stderr.
|
|
46
|
+
|
|
47
|
+
Install what the operator kept with `canon gov install --add <rules> <target>`, which needs no stack.
|
package/docs/agents/index.md
CHANGED
|
@@ -9,7 +9,7 @@ category: Agent surface
|
|
|
9
9
|
CLI catalog and invocation rules for agents, split by command domain. Start with overview.
|
|
10
10
|
|
|
11
11
|
- [Audits](audits.md): Running every health check as one set, what the single verdict means, the exit code each outcome takes, the retained baseline and the delta it reports, and which corpora are kept out of the record
|
|
12
|
-
- [Canvas](canvas.md): The canvas server, its content format, and the verbs that list, arrange, select, edit, mark, and capture frames
|
|
12
|
+
- [Canvas](canvas.md): The canvas server, its content format, and the verbs that list, arrange, fit, select, edit, mark, and capture frames
|
|
13
13
|
- [Capture](capture.md): Rendering HTML sources to PNG, what the command asserts about fonts, and why the selector has no default
|
|
14
14
|
- [Census](census.md): Tracked-plus-untracked file count, a breakdown by extension, and a line total that skips whatever reads as binary
|
|
15
15
|
- [Command catalog](commands.md): Every top-level command with its purpose, each domain's subcommands and the page describing them, the browser commands, and the version skew report
|
|
@@ -23,6 +23,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
23
23
|
- [Drift surfaces](drift-surfaces.md): The seven sections canon sync --check reports beside the per-domain scan, being seeds, superseded artifacts, unmigrated domains, surfaces at the old root, new rules and skills, and the reverse walk, with the managed-target gate and what counts toward the exit code
|
|
24
24
|
- [Driver](driver.md): Walking a page through named interactions, the probe catalog and the false finding each one carries, why viewport heights are never defaulted, and what each refusal reports
|
|
25
25
|
- [Merge gate](gate.md): Running the gate this repository verifies a branch with, what the stage table holds and what stays a script, how the changed set scopes three stages, and why a stage that cannot read its input reports rather than passing
|
|
26
|
+
- [Rule detection](gov-detect.md): Proposing opt-in governance rules from a target's dependencies and paths, the evidence file the verb reads, the record it emits, and its exit codes
|
|
26
27
|
- [Hooks](hooks.md): Running the post-merge steps through one verb, the order and the child call behind each, the root and working directory each step reads, the skip switches, and the line each record maps to
|
|
27
28
|
- [Indexes](indexes.md): Flags, exit codes, and JSON shape for canon indexes regen and canon indexes list, plus when regen auto-stages what it rewrote
|
|
28
29
|
- [Install and sync](install-and-sync.md): What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
|
|
@@ -34,8 +35,10 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
34
35
|
- [Migrate](migrate.md): What each canon migrate verb moves and rewrites, what it refuses, the markers that keep an old spelling, and the idempotence check a second run gives
|
|
35
36
|
- [Output shape](output-shape.md): Two framed shapes every command renders into, how JSON and --names modes keep stdout clean, and the exit discipline that lets piped output drain
|
|
36
37
|
- [Overview](overview.md): What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
|
|
38
|
+
- [The pull request evidence layout](pr-evidence-layout.md): How canon pr evidence groups screenshots into one block per view with a row per width and a column per theme, when a base column appears, where a name outside the form lands, how the commit line links, and when the blocks open
|
|
37
39
|
- [The pull request evidence comparison](pr-evidence.md): What canon pr evidence compares, the marker that lets it edit its own comment rather than duplicate it, the refusal reasons it names, what the --check read reports as owed, and why the comparison anchors at the merge base rather than the previous push
|
|
38
40
|
- [The pull request frame store](pr-frames.md): How canon pr frames pushes a UI review frame to a never-merged branch through the GitHub API and returns a branch-path link, which ref it writes, the pass segment that keeps an earlier image fixed, the refusal reasons it names, and how --drop and --prune rewrite the branch so a dropped frame leaves history
|
|
41
|
+
- [The pull request draft lift](pr-lift.md): How canon pr lift removes the draft mark once the reviews, evidence, standing, and CI all read clear at the head, the gate order and what each reads, the wait on a pending run, the re-read before the write, the refusal reasons it names, and what --check reports
|
|
39
42
|
- [The pull request local preview](pr-local.md): How canon pr local finds the server a worktree is running, why a server in another worktree is never reported, the refusal reasons it names, and how a close workflow drops the address line with --remove
|
|
40
43
|
- [The pull request preview deploy](pr-preview.md): How canon pr preview finds a fenced Cloudflare Pages deploy, refuses a branch its push filter does not serve, dispatches it on a pull request's branch, reads the alias the run prints, the refusal reasons it names, and why an unfenced deploy is refused before anything runs
|
|
41
44
|
- [Head-sensitive pull request reads](pr-reads.md): Resolving a branch tip from the remote rather than from the pull request object, reading what a review pass covered off its own marker rather than off GitHub's submission stamps, why an empty run list is not a pass, the refusal reasons each verb names, and what the remote read costs
|
|
@@ -112,6 +112,10 @@ Every documented agent path already passes the argument, including
|
|
|
112
112
|
`canon init`. The confirm-then-apply prompt after it still resolves to `Yes`
|
|
113
113
|
headlessly, so a call that names its stack is unchanged.
|
|
114
114
|
|
|
115
|
+
`--add` with no stack installs the named rules into the one positional, or the
|
|
116
|
+
current directory, and keeps the recorded chain. Pass `./node` to force a target
|
|
117
|
+
named like a stack. [Rule detection](gov-detect.md) proposes the names.
|
|
118
|
+
|
|
115
119
|
`canon gov install` also refuses the toolkit root as a target. It resolves the
|
|
116
120
|
target before anything else, so a path that does not exist fails rather than
|
|
117
121
|
being scaffolded.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: The pull request evidence layout
|
|
3
|
+
description: How canon pr evidence groups screenshots into one block per view with a row per width and a column per theme, when a base column appears, where a name outside the form lands, how the commit line links, and when the blocks open
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# The pull request evidence layout
|
|
7
|
+
|
|
8
|
+
`canon pr evidence` renders the screenshots of a pull request as blocks a
|
|
9
|
+
reviewer reads by view. The record behind them, and the reasons a run can
|
|
10
|
+
refuse, are in `canon docs pr-evidence`.
|
|
11
|
+
|
|
12
|
+
## One block per view
|
|
13
|
+
|
|
14
|
+
A case name that ends in `-dark-<width>` or `-light-<width>` belongs to the
|
|
15
|
+
view named by everything before that suffix, so `menu-open-light-1440` is the
|
|
16
|
+
`menu-open` view. The name is split from the right because a view may carry
|
|
17
|
+
hyphens of its own.
|
|
18
|
+
|
|
19
|
+
Each view is one `<details>` block. Its summary carries the view and its case
|
|
20
|
+
count, a row holds one width in ascending number order, and a column holds one
|
|
21
|
+
theme:
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
| Width | Dark | Light |
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
A view with any case already at the base takes a base and a head column per
|
|
28
|
+
theme, and a case the pull request added shows `*(new)*` in its base cell:
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
| Width | Dark base | Dark head | Light base | Light head |
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
A cell with no case in it stays empty. A theme no case of the view carries has
|
|
35
|
+
no column. A state under a named directory titles its blocks
|
|
36
|
+
`<state> / <view>`, so two states holding one view never repeat a name.
|
|
37
|
+
|
|
38
|
+
## Names outside the form
|
|
39
|
+
|
|
40
|
+
A case name that does not split into a view, a theme, and a width lands in a
|
|
41
|
+
flat `Case | Base | Head` block for its state, or `Case | Head` when every case
|
|
42
|
+
in it is new. Nothing is dropped, so `board.png` or a name with no width still
|
|
43
|
+
shows.
|
|
44
|
+
|
|
45
|
+
## The commit line
|
|
46
|
+
|
|
47
|
+
Under `## Evidence`, the Base and Head line names each commit as a short sha
|
|
48
|
+
that links to the full commit:
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
**Base:** [`<base>`](https://github.com/<repo>/commit/<base-sha>) · **Head:** [`<head>`](https://github.com/<repo>/commit/<head-sha>)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A reader opens what the screenshots were taken against in one click. The base
|
|
55
|
+
is the merge base the compare endpoint returns, not trunk's tip.
|
|
56
|
+
|
|
57
|
+
## When the blocks open
|
|
58
|
+
|
|
59
|
+
Every block opens while the comment carries six images or fewer, counting one
|
|
60
|
+
per case for the head plus one per case that is not new. Past that every block
|
|
61
|
+
closes, so the whole comment is open or closed together.
|
|
62
|
+
|
|
63
|
+
## What reads the body back
|
|
64
|
+
|
|
65
|
+
The case count that `would-empty` compares is the number of head images in the
|
|
66
|
+
body. It holds for the grouped rows, where one row carries up to two cases, and
|
|
67
|
+
for every layout posted before, so a comment rendered under an older shape
|
|
68
|
+
still counts. The bold `**Base:**` label and the `<details>` blocks are
|
|
69
|
+
unchanged, which keeps the address reader and the review skills working on both
|
|
70
|
+
layouts. An older comment keeps its shape until the next run edits it in place.
|
|
@@ -41,8 +41,9 @@ The record groups every evidence path by state, the remainder of its
|
|
|
41
41
|
directory under the `evidence/` segment, and within a state by filename stem,
|
|
42
42
|
so a `before/hero.png` and an `after/hero.png` naming the same case group as
|
|
43
43
|
one entry, not two files. Each entry carries whether it existed at the base
|
|
44
|
-
commit, so the comment shows a base image or marks it new.
|
|
45
|
-
|
|
44
|
+
commit, so the comment shows a base image or marks it new. Each `<img>` takes
|
|
45
|
+
its PNG width, at most 1000. `canon docs pr-evidence-layout` covers how the body
|
|
46
|
+
groups those entries by view.
|
|
46
47
|
|
|
47
48
|
`reason` on the record is what a caller branches on, not the exit code:
|
|
48
49
|
|
|
@@ -152,7 +153,7 @@ whichever previews apply, joined by a middle dot:
|
|
|
152
153
|
|
|
153
154
|
**Preview:** <url> · **Local preview:** <url>
|
|
154
155
|
|
|
155
|
-
**Base:** `<base>` · **Head:** `<head>`
|
|
156
|
+
**Base:** [`<base>`](<base-commit-url>) · **Head:** [`<head>`](<head-commit-url>)
|
|
156
157
|
```
|
|
157
158
|
|
|
158
159
|
The Base and Head line follows only when the comment carries screenshots.
|
|
@@ -258,12 +259,10 @@ the caller, and lifts only on `settled`, so a refusal holds it the same as
|
|
|
258
259
|
|
|
259
260
|
## When the comment opens
|
|
260
261
|
|
|
261
|
-
The comment opens every
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
reader whether the images match the latest push. The base is the merge base the
|
|
266
|
-
compare endpoint returns, not trunk's tip.
|
|
262
|
+
The comment opens every block while it carries six images or fewer and closes
|
|
263
|
+
every block past that. A line under `## Evidence` names the compared base and
|
|
264
|
+
head as linked short shas, which tells a reader whether the images match the
|
|
265
|
+
latest push. `canon docs pr-evidence-layout` covers the count and the blocks.
|
|
267
266
|
|
|
268
267
|
## What the comment still leaves to GitHub
|
|
269
268
|
|
package/docs/agents/pr-frames.md
CHANGED
|
@@ -12,6 +12,7 @@ the `canon-frames` branch and returns a link to its path there.
|
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
canon pr frames 1341 --add frames/3.png --box 3 --head <sha> --pass 20261002T154450Z --json
|
|
15
|
+
canon pr frames 1341 --add frames/3-dark.png --box 3 --theme dark --head <sha> --pass 20261002T154450Z --json
|
|
15
16
|
canon pr frames 1341 --drop --json
|
|
16
17
|
canon pr frames --prune 30 --json
|
|
17
18
|
```
|
|
@@ -23,7 +24,10 @@ through the GitHub git data API, being blobs, trees, commits, and that one ref,
|
|
|
23
24
|
so nothing is checked out, no worktree is entered, and neither `main` nor any
|
|
24
25
|
branch a pull request holds is touched. The branch never merges.
|
|
25
26
|
|
|
26
|
-
A frame lands at `pr-<number>/<short-head>/<pass>/box-<n>.png
|
|
27
|
+
A frame lands at `pr-<number>/<short-head>/<pass>/box-<n>.png`, or at
|
|
28
|
+
`box-<n>-<theme>.png` when `--theme` names `dark` or `light`, so two shots of
|
|
29
|
+
one box in one pass never take the same path. A frame without `--theme` keeps
|
|
30
|
+
the plain form. `--head` names
|
|
27
31
|
the commit the pass drove, 7 to 40 lowercase hex characters, and defaults to
|
|
28
32
|
the head the pull request object reports. `--pass` is the instant the pass
|
|
29
33
|
started, in compact UTC as `date -u +%Y%m%dT%H%M%SZ` prints it, which
|
|
@@ -59,6 +63,7 @@ be published with it.
|
|
|
59
63
|
| `bad-box` | `--add` carried no positive `--box`. |
|
|
60
64
|
| `bad-head` | `--head`, or the head the pull request reported, is not a 7 to 40 character sha. |
|
|
61
65
|
| `bad-pass` | `--add` carried no `--pass` stamp in compact UTC. |
|
|
66
|
+
| `bad-theme` | `--theme` is neither `dark` nor `light`, or came without `--add`. |
|
|
62
67
|
| `bad-days` | `--prune` carried no positive number of days. |
|
|
63
68
|
| `unreadable-frame` | The `--add` file is missing, empty, or not a PNG. Nothing is called. |
|
|
64
69
|
| `read-only` | GitHub refused a write with 403 or 404, which is what a fork's token gets. |
|
|
@@ -69,7 +74,7 @@ be published with it.
|
|
|
69
74
|
| `gh-missing` | `gh` is not on the path. |
|
|
70
75
|
| `gh-failed` | `gh` could not name the repository or read the pull request. |
|
|
71
76
|
|
|
72
|
-
An add's `ok` record carries `link`, `commit`, `path`, `box`, `head`, `pass`,
|
|
77
|
+
An add's `ok` record carries `link`, `commit`, `path`, `box`, `theme` when one was passed, `head`, `pass`,
|
|
73
78
|
and `created`, which is true when the add made the branch. A drop's carries
|
|
74
79
|
`removed`, the pull requests whose folders went, plus `commit` for the rewrite
|
|
75
80
|
or `deleted` when it emptied the branch. A prune adds `kept` and `unread`.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: The pull request draft lift
|
|
3
|
+
description: How canon pr lift removes the draft mark once the reviews, evidence, standing, and CI all read clear at the head, the gate order and what each reads, the wait on a pending run, the re-read before the write, the refusal reasons it names, and what --check reports
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# The pull request draft lift
|
|
7
|
+
|
|
8
|
+
`canon pr lift` takes a pull request out of draft. It reads the gate itself, so
|
|
9
|
+
any session that closes a review can run it, and nobody has to judge whether a
|
|
10
|
+
message asking for the lift came from someone entitled to ask.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
canon pr lift 1341 --json
|
|
14
|
+
canon pr lift 1341 --check --json
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
With no number it resolves the one open pull request on the checked-out branch.
|
|
18
|
+
The ship chain marks every pull request a draft, and this is the verb that
|
|
19
|
+
undoes it.
|
|
20
|
+
|
|
21
|
+
## What it reads
|
|
22
|
+
|
|
23
|
+
Five gates, read in this order. The first four need no wait, so they all run
|
|
24
|
+
before the check runs are read.
|
|
25
|
+
|
|
26
|
+
| Gate | Clear when |
|
|
27
|
+
| ---------- | --------------------------------------------------------------------------------------------- |
|
|
28
|
+
| `review` | The newest `## Review` pass is closed, and its marker names the head. |
|
|
29
|
+
| `ui` | The newest `## UI review` verdict is closed at the head. Binds only where a checklist exists. |
|
|
30
|
+
| `evidence` | `canon pr evidence --check` reads `settled`, meaning no post-pull-request step is owed. |
|
|
31
|
+
| `standing` | The head merges into the freshly fetched base, and the base moved no path the branch writes. |
|
|
32
|
+
| `ci` | Every check run on the branch tip concluded and none failed. |
|
|
33
|
+
|
|
34
|
+
The head is the branch tip read from the remote, not the pull request object's
|
|
35
|
+
head, which trails a push by up to a minute. A review marker names the commit
|
|
36
|
+
the reviewer read, and it covers the head when it is that commit or a prefix of
|
|
37
|
+
it.
|
|
38
|
+
|
|
39
|
+
The UI gate binds only when `canon pr evidence --check --json` carries a
|
|
40
|
+
`checklist` field. The verb branches on that field and not on the exit, so a
|
|
41
|
+
branch with no rendered surface owes no UI review.
|
|
42
|
+
|
|
43
|
+
A review pass with no read-time marker refuses as `review-unmarked`. Its covered
|
|
44
|
+
commit would be the stamp GitHub wrote at submission, which the marker exists to
|
|
45
|
+
replace, and lifting on it reintroduces the defect `canon pr review-state`
|
|
46
|
+
documents.
|
|
47
|
+
|
|
48
|
+
## The wait
|
|
49
|
+
|
|
50
|
+
A pending CI run is waited on rather than refused. `--wait <seconds>` bounds it,
|
|
51
|
+
defaulting to 1200, and the check runs are read every 30 seconds until one of
|
|
52
|
+
four things happens:
|
|
53
|
+
|
|
54
|
+
- every run passed, and the verb goes on to the write
|
|
55
|
+
- a run failed, which refuses `ci-failing` at once
|
|
56
|
+
- the branch conflicts with its base, which refuses `ci-conflicted` at once,
|
|
57
|
+
since no run starts for a conflicted branch and the wait could not end
|
|
58
|
+
- the deadline passed, which refuses `ci-timeout`
|
|
59
|
+
|
|
60
|
+
A refusal on any of the first four gates comes before the wait starts. A code
|
|
61
|
+
reviewer whose UI partner is still driving refuses `ui-open` immediately
|
|
62
|
+
instead of holding a turn through a CI run.
|
|
63
|
+
|
|
64
|
+
## The re-read
|
|
65
|
+
|
|
66
|
+
A push during the wait moves the head off the commit every earlier gate
|
|
67
|
+
cleared. After the wait, and immediately before the write, the verb reads the
|
|
68
|
+
pull request, the branch tip, and the reviews again. A tip that moved refuses
|
|
69
|
+
`head-moved`, and a review that opened refuses with its own reason. The
|
|
70
|
+
standing is read again as well, so a sibling merging during the wait refuses
|
|
71
|
+
`standing-stale` instead of lifting a branch that read fresh before it. A pull
|
|
72
|
+
request already out of draft by then reports `already-ready`.
|
|
73
|
+
|
|
74
|
+
Two reviewers closing within seconds of each other can each read the other's
|
|
75
|
+
review as still open and both refuse. The re-read narrows that window and does
|
|
76
|
+
not close it, so a draft whose reviews both read closed is the controlling
|
|
77
|
+
session's to lift.
|
|
78
|
+
|
|
79
|
+
## The write
|
|
80
|
+
|
|
81
|
+
The lift is the `markPullRequestReadyForReview` GraphQL mutation, because the
|
|
82
|
+
REST pull request update carries no draft field. It is the one GraphQL call the
|
|
83
|
+
verb makes, and every read stays on REST. The verb reads `isDraft` back from the
|
|
84
|
+
mutation's answer, and a response that does not say `false` refuses `gh-failed`
|
|
85
|
+
rather than reporting a lift.
|
|
86
|
+
|
|
87
|
+
A cloud session's proxy refuses GraphQL, so a reviewer running there reaches
|
|
88
|
+
`gh-failed` on the write and hands the lift to the controlling session.
|
|
89
|
+
|
|
90
|
+
## What it reports
|
|
91
|
+
|
|
92
|
+
`reason` on the record is what a caller branches on. Exit 0 covers `lifted` and
|
|
93
|
+
`already-ready`, so the second of two reviewers to close owes nobody a message.
|
|
94
|
+
Every other reason exits 1.
|
|
95
|
+
|
|
96
|
+
| Reason | What it means |
|
|
97
|
+
| ------------------- | ---------------------------------------------------------------------- |
|
|
98
|
+
| `lifted` | The mark came off. |
|
|
99
|
+
| `already-ready` | The pull request was not a draft. Nothing is written. |
|
|
100
|
+
| `clear` | Under `--check`, every gate reads clear. |
|
|
101
|
+
| `pull-closed` | The pull request is closed. |
|
|
102
|
+
| `review-missing` | The thread carries no code review. |
|
|
103
|
+
| `review-open` | The newest code review is open. |
|
|
104
|
+
| `review-unmarked` | The newest code review carries no marker. |
|
|
105
|
+
| `review-behind` | The newest code review closed on an earlier commit than the head. |
|
|
106
|
+
| `ui-missing` | A checklist exists and no UI review has been posted. |
|
|
107
|
+
| `ui-open` | The newest UI review is open. |
|
|
108
|
+
| `ui-unmarked` | The newest UI review carries no head marker. |
|
|
109
|
+
| `ui-behind` | The newest UI review closed on an earlier commit than the head. |
|
|
110
|
+
| `evidence-owed` | The evidence check reads `owed`. |
|
|
111
|
+
| `standing-stale` | The base moved under a path the branch writes. |
|
|
112
|
+
| `standing-conflict` | The head does not merge cleanly into the base. |
|
|
113
|
+
| `standing-unknown` | The head or base did not resolve, which a fork or deleted head leaves. |
|
|
114
|
+
| `ci-pending` | Under `--check`, a run has yet to conclude. |
|
|
115
|
+
| `ci-failing` | A check run failed. |
|
|
116
|
+
| `ci-conflicted` | The branch conflicts, so no run will start. |
|
|
117
|
+
| `ci-timeout` | A run was still pending when `--wait` ran out. |
|
|
118
|
+
| `head-moved` | A push landed during the wait. |
|
|
119
|
+
| `gh-failed` | A read or the write was refused, so nothing is reported as lifted. |
|
|
120
|
+
|
|
121
|
+
`standing-unknown` waits on a person, matching the orchestrator poll's own rule
|
|
122
|
+
for a head it cannot resolve.
|
|
123
|
+
|
|
124
|
+
## `--check`
|
|
125
|
+
|
|
126
|
+
`--check` reports every gate and writes nothing. It reads the check runs once
|
|
127
|
+
and does not wait, so a pending run reports `ci-pending`. The record carries a
|
|
128
|
+
`gates` array with each gate's name, whether it is clear, and its reason, so a
|
|
129
|
+
caller sees every gate that blocks and not the first alone.
|
|
130
|
+
|
|
131
|
+
The orchestrator's poll and a session deciding whether to run the verb read the
|
|
132
|
+
same answer this way, rather than each restating the gate.
|
package/docs/agents/scripting.md
CHANGED
|
@@ -15,7 +15,8 @@ Use these to discover what's available instead of hardcoding names.
|
|
|
15
15
|
| --------------------------------- | ---------------------------------------------------------------- |
|
|
16
16
|
| `canon tooling list --json` | Stacks, extends chain, dep and script counts |
|
|
17
17
|
| `canon standards list --json` | Standards docs and the paths each governs |
|
|
18
|
-
| `canon gov list --json` | Governance stacks, rule sets, and unreferenced rules
|
|
18
|
+
| `canon gov list --json` | Governance stacks, rule sets, evidence, and unreferenced rules |
|
|
19
|
+
| `canon gov detect --json` | Opt-in rules a target's dependencies and paths propose |
|
|
19
20
|
| `canon claude seeds list --json` | Seed doc sources with content |
|
|
20
21
|
| `canon claude skills list --json` | Plugin skills, descriptions, requirement flag, family vocabulary |
|
|
21
22
|
| `canon docs list --json` | Consumer docs plus per-domain context |
|
package/docs/target/projects.md
CHANGED
|
@@ -51,7 +51,7 @@ claude --plugin-dir <toolkit>/claude
|
|
|
51
51
|
Two steps, in order:
|
|
52
52
|
|
|
53
53
|
1. Run the framework's own scaffold if the project needs one, such as `bun init`, `npm create vite`, or `npm create astro`. The toolkit does not wrap framework scaffolding.
|
|
54
|
-
2. Invoke `canon:target-setup` in Claude Code. The skill detects the stack,
|
|
54
|
+
2. Invoke `canon:target-setup` in Claude Code. The skill detects the stack, asks `canon gov detect` which opt-in rules the project's evidence proposes, previews the full chain with those proposals for you to confirm, and runs it end-to-end.
|
|
55
55
|
|
|
56
56
|
The chain is:
|
|
57
57
|
|
|
@@ -88,7 +88,7 @@ Escalate only for real web apps. The `target-setup` skill reads `package.json` a
|
|
|
88
88
|
|
|
89
89
|
In a monorepo the skill reads each folder holding a `package.json`, `pyproject.toml`, `go.mod`, `composer.json`, or `Cargo.toml` to depth two, skipping what git ignores. Each of those folders gets its own tooling stack and a `canon tooling sync <stack> <folder> --skip base` in the preview. Governance still installs once at the root, since a rule's `paths:` globs reach every subfolder, so a subfolder's language rules join the root install through `--add`.
|
|
90
90
|
|
|
91
|
-
`node-server` is named rather than detected. It carries the server-side security and persistence rules for a project writing request handlers or a persistence layer in TypeScript, and the detect step matches a runtime or a framework against stack names, so
|
|
91
|
+
`node-server` is named rather than detected. It carries the server-side security and persistence rules for a project writing request handlers or a persistence layer in TypeScript, and the detect step matches a runtime or a framework against stack names, so the stack never resolves on its own. `canon gov detect` proposes its two rules from a server framework or database client in the manifest, which you confirm in the preview. Pass the stack deliberately with `canon init --stack node-server` or `canon gov install node-server <target>`.
|
|
92
92
|
|
|
93
93
|
Markdown-heavy projects, CLI tools, docs sites, research notebooks, and scripting repos stay on `base`. Escalation is a ceiling move, not a default.
|
|
94
94
|
|
|
@@ -113,7 +113,7 @@ The plugin corpus carries runtime behavior rather than reference prose alone, be
|
|
|
113
113
|
|
|
114
114
|
When a new need appears after scaffold, install the one domain without re-running `canon init`.
|
|
115
115
|
|
|
116
|
-
- Governance rule for a newly adopted library:
|
|
116
|
+
- Governance rule for a newly adopted library: run `canon gov detect <path> --json` to see what the project's evidence proposes, then `canon gov install --add <rule> <path>`, which installs the rule with no stack
|
|
117
117
|
- Project-specific rule the toolkit does not ship: invoke `canon:create-rule`. It scaffolds a rule into `.claude/rules/project/` with a non-colliding number, and `canon gov sync` leaves it untouched. A rule placed under `.claude/rules/canon/` instead is deleted on the next sync, since that folder belongs to the toolkit.
|
|
118
118
|
- Index.md system for a markdown-heavy folder that emerged: invoke `canon:target-setup indexes`
|
|
119
119
|
|