@erclx/canon 5.25.0 → 5.26.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 +2 -1
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/canvas/SKILL.md +1 -1
- package/claude/skills/context-fold/REQUIREMENT.md +6 -2
- package/claude/skills/context-fold/SKILL.md +8 -6
- package/claude/skills/context-fold/references/anchor-sweep.md +2 -2
- package/claude/skills/design-taste/REQUIREMENT.md +1 -1
- package/claude/skills/design-taste/SKILL.md +4 -2
- package/claude/skills/design-taste/references/adopted.md +40 -0
- package/claude/skills/design-taste/references/kinds.md +1 -1
- package/claude/skills/design-taste/references/systems.md +1 -7
- package/claude/skills/design-taste/references/tells.md +2 -24
- package/claude/skills/docs-sync/REQUIREMENT.md +2 -1
- package/claude/skills/document-health/REQUIREMENT.md +2 -0
- package/claude/skills/document-health/SKILL.md +21 -0
- package/claude/skills/document-health/references/axes.md +12 -0
- package/claude/skills/draft-and-pick/SKILL.md +1 -1
- package/claude/skills/draft-identity/SKILL.md +1 -1
- package/claude/skills/draft-screencast/SKILL.md +9 -7
- package/claude/skills/draft-slides/REQUIREMENT.md +17 -12
- package/claude/skills/draft-slides/SKILL.md +31 -20
- package/claude/skills/git-issue/references/issue.md +10 -0
- package/claude/skills/git-pr/references/evidence.md +8 -0
- package/claude/skills/git-pr/references/labels.md +12 -0
- package/claude/skills/git-split/SKILL.md +19 -8
- package/claude/skills/markdown-propose/references/format.md +9 -0
- package/claude/skills/memory-review/references/later-phases.md +7 -0
- package/claude/skills/review-ui/references/post.md +4 -2
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +8 -0
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +13 -0
- package/claude/skills/search-craft/REQUIREMENT.md +1 -1
- package/claude/skills/search-craft/SKILL.md +3 -1
- package/claude/skills/search-craft/references/adopted.md +30 -0
- package/claude/skills/target-setup/references/detect.md +8 -0
- package/claude/skills/target-setup/references/indexes.md +13 -0
- package/claude/skills/target-setup/references/verify.md +8 -0
- package/claude/skills/test-first/SKILL.md +2 -0
- package/claude/skills/test-first/references/adopted.md +36 -0
- package/claude/skills/write-human/SKILL.md +1 -1
- package/claude/skills/write-human/references/machine-tells.md +13 -0
- package/docs/agents/canvas.md +3 -1
- package/docs/agents/capture.md +1 -1
- package/docs/agents/commands.md +3 -3
- package/docs/agents/index.md +2 -2
- package/docs/agents/records-stale.md +22 -9
- package/docs/agents/records.md +1 -1
- package/docs/agents/sandbox.md +1 -1
- package/docs/agents/skills-audit.md +10 -3
- package/docs/agents/slides.md +15 -3
- package/docs/workflow/ai-workflow.md +1 -1
- package/docs/workflow/index.md +1 -0
- package/docs/workflow/parallel-features.md +1 -1
- package/docs/workflow/skill-map-on-request.md +42 -0
- package/docs/workflow/skill-map.md +1 -34
- package/package.json +1 -1
- package/scripts/lib/sandbox-dispatch.sh +1 -1
- package/scripts/lib/sandbox-git.sh +1 -9
- package/scripts/lib/sandbox-path.sh +1 -1
- package/scripts/sandbox-hook.sh +99 -0
- package/src/canvas/capture.ts +1 -9
- package/src/canvas/client/inspector/color-field.tsx +368 -0
- package/src/canvas/client/inspector/fields.css +163 -22
- package/src/canvas/client/inspector/values.ts +123 -0
- package/src/canvas/client/inspector.tsx +46 -69
- package/src/capture/render.ts +45 -7
- package/src/capture/sources.ts +43 -0
- package/src/census/count.ts +1 -1
- package/src/claude/cases/workflow.ts +5 -0
- package/src/claude/seeds.ts +1 -1
- package/src/claude/skills-audit.ts +68 -14
- package/src/client-commands.ts +1 -1
- package/src/commands/claude.ts +27 -2
- package/src/commands/feedback.ts +3 -3
- package/src/commands/records.ts +88 -6
- package/src/commands/sandbox.ts +50 -10
- package/src/commands/slides.ts +31 -77
- package/src/context/audit.ts +1 -1
- package/src/design/tokens.ts +2 -18
- package/src/docs/read.ts +1 -1
- package/src/{github.ts → feedback/github.ts} +1 -1
- package/src/gate/measures.ts +6 -4
- package/src/gov/citations.ts +1 -1
- package/src/gov/payload.ts +1 -1
- package/src/gov/superseded.ts +2 -2
- package/src/markdown/ceiling.ts +1 -1
- package/src/record-root.ts +1 -0
- package/src/records/backup.ts +1 -0
- package/src/records/push-guard.ts +1 -1
- package/src/records/stale-canonical.ts +146 -0
- package/src/records/stale.ts +1 -1
- package/src/sandbox/hooks.ts +128 -0
- package/src/sandbox/provision.ts +596 -0
- package/src/sandbox/tree.ts +103 -4
- package/src/secrets/marker.ts +2 -2
- package/src/secrets/scan.ts +1 -1
- package/src/shipped/references.ts +2 -2
- package/src/slides/convert/export.ts +2 -16
- package/src/slides/decks.ts +110 -0
- package/src/standards/read.ts +1 -1
- package/src/sync/seeds-report.ts +1 -1
- package/src/tasks/answers.ts +1 -1
- package/src/tasks/archive.ts +1 -1
- package/src/teach/nav.ts +1 -1
- package/src/tooling/inject.ts +1 -1
- package/src/web/readme-citations.ts +1 -1
- package/standards/architecture.md +1 -0
- package/standards/canvas.md +1 -1
- package/standards/requirements.md +2 -0
- package/standards/skill-practice.md +2 -1
- package/standards/skill.md +1 -0
- package/scripts/manage-sandbox.sh +0 -472
- package/src/slides/layouts.ts +0 -478
- package/src/slides/parse.ts +0 -84
- package/src/slides/render.ts +0 -110
- package/src/slides/styles.ts +0 -96
- /package/claude/skills/write-human/references/{source-material.md → adopted.md} +0 -0
- /package/src/{commands/feedback-format.ts → feedback/body.ts} +0 -0
- /package/src/{github-format.ts → feedback/github-format.ts} +0 -0
- /package/src/{frontmatter.ts → markdown/frontmatter.ts} +0 -0
- /package/src/{binary.ts → sweep/binary.ts} +0 -0
- /package/src/{exempt-marker.ts → sweep/exempt-marker.ts} +0 -0
- /package/src/{paths.ts → tasks/paths.ts} +0 -0
- /package/src/{seed-marker.ts → tooling/seed-marker.ts} +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Issue reference
|
|
2
2
|
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Scope](#scope)
|
|
6
|
+
- [Title](#title)
|
|
7
|
+
- [Labels](#labels)
|
|
8
|
+
- [Content](#content)
|
|
9
|
+
- [Sections](#sections)
|
|
10
|
+
- [Formatting](#formatting)
|
|
11
|
+
- [Examples](#examples)
|
|
12
|
+
|
|
3
13
|
## Scope
|
|
4
14
|
|
|
5
15
|
Governs a tracker issue: its title, its labels, and the sections its body carries.
|
|
@@ -7,6 +7,14 @@ description: How git-pr finds the UI checklist and the local server, posts the e
|
|
|
7
7
|
|
|
8
8
|
The rendered-surface step of `git-pr`, reached after the final command printed the pull request number. The step runs on every pull request, with no test on the diff ahead of it. `no-evidence` is the silent branch, so a pull request that changes no rendered surface posts nothing.
|
|
9
9
|
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [Find the UI checklist](#find-the-ui-checklist)
|
|
13
|
+
- [Find the local server](#find-the-local-server)
|
|
14
|
+
- [Post the evidence comparison](#post-the-evidence-comparison)
|
|
15
|
+
- [Post the UI checklist alone](#post-the-ui-checklist-alone)
|
|
16
|
+
- [Post the preview address](#post-the-preview-address)
|
|
17
|
+
|
|
10
18
|
## Find the UI checklist
|
|
11
19
|
|
|
12
20
|
`ui-checklist` writes a visual checklist to `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root when a change needs visual verification, with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. This skill is the file's sole consumer. Resolve the main root the way `session-worktree` does (`git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`) and check for the file there. A missing file means no checklist was produced, and the two steps below each skip their checklist half.
|
|
@@ -5,6 +5,18 @@ description: Path-to-label map format, prefix matching against the changed set,
|
|
|
5
5
|
|
|
6
6
|
# Label reference
|
|
7
7
|
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Scope](#scope)
|
|
11
|
+
- [Map format](#map-format)
|
|
12
|
+
- [Paths a map declines to label](#paths-a-map-declines-to-label)
|
|
13
|
+
- [Reporting a surface no row reaches](#reporting-a-surface-no-row-reaches)
|
|
14
|
+
- [Matching](#matching)
|
|
15
|
+
- [Applying](#applying)
|
|
16
|
+
- [A label the remote does not carry](#a-label-the-remote-does-not-carry)
|
|
17
|
+
- [Release pull requests](#release-pull-requests)
|
|
18
|
+
- [Labels at run time](#labels-at-run-time)
|
|
19
|
+
|
|
8
20
|
## Scope
|
|
9
21
|
|
|
10
22
|
Governs the labels a pull request carries: the map a project declares, how a changed path resolves to a label, and what a label missing from the remote costs.
|
|
@@ -86,7 +86,8 @@ git switch -c <branch> main && git cherry-pick <sha> <sha> \
|
|
|
86
86
|
&& (cat <<'BODY' > .canon/tmp/pr/split/<branch>.md
|
|
87
87
|
<body following pr.md template, written from the cherry-picked commits>
|
|
88
88
|
BODY
|
|
89
|
-
) && gh
|
|
89
|
+
) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<branch> -f base=main -F body=@.canon/tmp/pr/split/<branch>.md --jq .html_url \
|
|
90
|
+
&& printf 'opened=true\n' \
|
|
90
91
|
&& rm .canon/tmp/pr/split/<branch>.md
|
|
91
92
|
|
|
92
93
|
# Return to primary branch, push, and open its PR
|
|
@@ -94,13 +95,18 @@ git checkout <new_name> && git push -u origin <new_name> \
|
|
|
94
95
|
&& (cat <<'BODY' > .canon/tmp/pr/split/<new_name>.md
|
|
95
96
|
<body following pr.md template, written from the primary's commits>
|
|
96
97
|
BODY
|
|
97
|
-
) && gh
|
|
98
|
+
) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<new_name> -f base=main -F body=@.canon/tmp/pr/split/<new_name>.md --jq .html_url \
|
|
99
|
+
&& printf 'opened=true\n' \
|
|
98
100
|
&& rm .canon/tmp/pr/split/<new_name>.md
|
|
99
101
|
|
|
100
102
|
# Clean up the body-file dir if all PRs succeeded (no-op when non-empty)
|
|
101
103
|
rmdir .canon/tmp/pr/split 2>/dev/null || true
|
|
102
104
|
```
|
|
103
105
|
|
|
106
|
+
Every pull request opens through the REST pulls endpoint rather than the `gh pr` create subcommand, which runs on GraphQL and fails where a cloud session's GitHub proxy refuses it. The endpoint requires `base`, so each call names the branch its layer sits on. `-F` reads the body file, where `-f` would post the path itself.
|
|
107
|
+
|
|
108
|
+
A create the endpoint refuses, such as one for a head that already has an open pull request, exits non-zero and stops the chain before `opened=true` prints and before the body file is removed. The `opened=true` line is what a pull request creation log reads to count the opening, since the REST call prints a URL and never names itself.
|
|
109
|
+
|
|
104
110
|
For stacked mode, base each branch on the previous and cherry-pick only that group's commits:
|
|
105
111
|
|
|
106
112
|
```bash
|
|
@@ -115,7 +121,8 @@ git switch -c <branch-1> main && git cherry-pick <g1-sha> <g1-sha> \
|
|
|
115
121
|
&& (cat <<'BODY' > .canon/tmp/pr/split/<branch-1>.md
|
|
116
122
|
<body following pr.md template, written from the cherry-picked commits>
|
|
117
123
|
BODY
|
|
118
|
-
) && gh
|
|
124
|
+
) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<branch-1> -f base=main -F body=@.canon/tmp/pr/split/<branch-1>.md --jq .html_url \
|
|
125
|
+
&& printf 'opened=true\n' \
|
|
119
126
|
&& rm .canon/tmp/pr/split/<branch-1>.md
|
|
120
127
|
|
|
121
128
|
# Group 2: based on <branch-1>, this group's commits only
|
|
@@ -124,15 +131,17 @@ git checkout -b <branch-2> && git cherry-pick <g2-sha> <g2-sha> \
|
|
|
124
131
|
&& (cat <<'BODY' > .canon/tmp/pr/split/<branch-2>.md
|
|
125
132
|
<body following pr.md template, written from the cherry-picked commits>
|
|
126
133
|
BODY
|
|
127
|
-
) && gh
|
|
134
|
+
) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<branch-2> -f base=<branch-1> -F body=@.canon/tmp/pr/split/<branch-2>.md --jq .html_url \
|
|
135
|
+
&& printf 'opened=true\n' \
|
|
128
136
|
&& rm .canon/tmp/pr/split/<branch-2>.md
|
|
129
137
|
|
|
130
|
-
# Return to primary branch, push, and open its PR
|
|
138
|
+
# Return to primary branch, push, and open its PR on the last group's branch
|
|
131
139
|
git checkout <new_name> && git push -u origin <new_name> \
|
|
132
140
|
&& (cat <<'BODY' > .canon/tmp/pr/split/<new_name>.md
|
|
133
141
|
<body following pr.md template, written from the primary's commits>
|
|
134
142
|
BODY
|
|
135
|
-
) && gh
|
|
143
|
+
) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<new_name> -f base=<branch-2> -F body=@.canon/tmp/pr/split/<new_name>.md --jq .html_url \
|
|
144
|
+
&& printf 'opened=true\n' \
|
|
136
145
|
&& rm .canon/tmp/pr/split/<new_name>.md
|
|
137
146
|
|
|
138
147
|
# Clean up the body-file dir if all PRs succeeded (no-op when non-empty)
|
|
@@ -145,6 +154,8 @@ Respond with exactly one line:
|
|
|
145
154
|
|
|
146
155
|
`✅ Renamed: <old> → <new> | PRs: <primary-url>, <url1>, <url2>`
|
|
147
156
|
|
|
157
|
+
Read each URL off the line its create printed through `--jq .html_url`.
|
|
158
|
+
|
|
148
159
|
Do not add any other text.
|
|
149
160
|
|
|
150
161
|
## Stacked merge loop
|
|
@@ -153,10 +164,10 @@ When the user signals the previous stacked PR has merged, restack the next one.
|
|
|
153
164
|
|
|
154
165
|
1. Rebase and push. The own-commit-count comes from the original split table.
|
|
155
166
|
`git fetch origin main && git checkout <branch> && git rebase --onto origin/main HEAD~<own-commit-count> && git push --force-with-lease`
|
|
156
|
-
2. Verify the PR's base auto-retargeted to main with `gh api repos/{owner}/{repo}/pulls/<num> --jq .base.ref`, a REST read a cloud session's GitHub proxy serves where it refuses GraphQL. If not, `gh
|
|
167
|
+
2. Verify the PR's base auto-retargeted to main with `gh api repos/{owner}/{repo}/pulls/<num> --jq .base.ref`, a REST read a cloud session's GitHub proxy serves where it refuses GraphQL. If not, retarget it with `gh api -X PATCH repos/{owner}/{repo}/pulls/<num> -f base=main --silent`.
|
|
157
168
|
3. Reply: `✅ <branch> rebased onto main. Ready for squash-merge.`
|
|
158
169
|
|
|
159
170
|
Edge cases:
|
|
160
171
|
|
|
161
172
|
- If this branch's commits modify a file added by an unmerged upstream PR, wait for that PR to merge before rebasing.
|
|
162
|
-
- If the PR was orphaned by base-branch deletion, recreate it with
|
|
173
|
+
- If the PR was orphaned by base-branch deletion, recreate it with the same create the final commands run, passing `-f head=<branch> -f base=main` and a regenerated body, and print `opened=true` after it.
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Governs the proposal `markdown-propose` writes before it edits anything. The concern being screened is an input and does not change the format.
|
|
4
4
|
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- [Folder](#folder)
|
|
8
|
+
- [Change format](#change-format)
|
|
9
|
+
- [The answer contract](#the-answer-contract)
|
|
10
|
+
- [Applying](#applying)
|
|
11
|
+
- [After](#after)
|
|
12
|
+
- [Retrieval](#retrieval)
|
|
13
|
+
|
|
5
14
|
## Folder
|
|
6
15
|
|
|
7
16
|
- One folder per screening pass at `.canon/proposals/<nn>-<slug>/`, where the slug names the subject rather than the activity
|
|
@@ -7,6 +7,13 @@ description: The Challenge, Discuss, Apply, and Cleanup phases of memory-review,
|
|
|
7
7
|
|
|
8
8
|
The phases of `memory-review` after Propose. The session reads this file when the phase table in the skill picks Challenge, Discuss, Apply, or Cleanup, and reads only the section for that phase. The skill's Guards still hold for every phase here.
|
|
9
9
|
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [Challenge phase](#challenge-phase)
|
|
13
|
+
- [Discuss phase](#discuss-phase)
|
|
14
|
+
- [Apply phase](#apply-phase)
|
|
15
|
+
- [Cleanup phase](#cleanup-phase)
|
|
16
|
+
|
|
10
17
|
## Challenge phase
|
|
11
18
|
|
|
12
19
|
Trigger: user says "challenge the promotes", "challenge before apply", or asks for a high-bar pass. Run before Apply. No mutations to memory files or promotion targets. Review file only.
|
|
@@ -68,7 +68,9 @@ Record the instant just before the post, in UTC, as `<posted-at>`. Step 8 keeps
|
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
70
|
date -u +%Y-%m-%dT%H:%M:%SZ
|
|
71
|
-
gh
|
|
71
|
+
gh api -X POST 'repos/{owner}/{repo}/pulls/<number>/reviews' -f event=COMMENT -F body=@.canon/tmp/pr/review-ui/body-<number>-<short-sha>.md --jq .html_url
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
The post goes through the REST reviews endpoint rather than the `gh pr` review subcommand, which runs on GraphQL and fails where a cloud session's GitHub proxy refuses it. `-F` reads the file into the body, where `-f` would post the path itself.
|
|
75
|
+
|
|
76
|
+
Never pass `event=APPROVE` or `event=REQUEST_CHANGES`, which carry a state the poll does not read and a weight this pass has not earned.
|
|
@@ -9,6 +9,14 @@ Run this once `orchestrator-dispatch.md` has cleared a row and picked cloud for
|
|
|
9
9
|
|
|
10
10
|
The shape needs a `SessionStart` hook in the repository that, on the VM alone, copies the plugin skills into `.claude/skills/` and puts `canon` on the path. A repository without one cannot take this shape, so fall back to a local worker there. Where the hook exists, the launch prompt calls `/auto-ship` with no `canon:` prefix, since the copied skills list as project skills.
|
|
11
11
|
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
- [Check the row is unclaimed](#check-the-row-is-unclaimed)
|
|
15
|
+
- [The prompt](#the-prompt)
|
|
16
|
+
- [The create](#the-create)
|
|
17
|
+
- [Recognize the pull request](#recognize-the-pull-request)
|
|
18
|
+
- [Dispatch a review to a cloud reviewer](#dispatch-a-review-to-a-cloud-reviewer)
|
|
19
|
+
|
|
12
20
|
## Check the row is unclaimed
|
|
13
21
|
|
|
14
22
|
A cloud worker never appears in `canon sessions list` and never pushes the derived branch, since the cloud assigns it a `claude/` branch of its own. So the roster and the refs read clear on a row a cloud worker is already building. Run the local check in `orchestrator-dispatch.md` anyway, since a local worker on the same row still collides, then read the two places a cloud worker does show:
|
|
@@ -5,6 +5,19 @@ description: The plan-answer gate, the collision check before a self-dispatch, t
|
|
|
5
5
|
|
|
6
6
|
Run this at loop step 4, for a `## Run now` row whose plan is verified, in place of handing the worktree to a human. The disjointness gate below is where that row's file set is tested against every track in flight.
|
|
7
7
|
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Derive the candidate](#derive-the-candidate)
|
|
11
|
+
- [Check the plan waits on nobody](#check-the-plan-waits-on-nobody)
|
|
12
|
+
- [Check the branch is unclaimed](#check-the-branch-is-unclaimed)
|
|
13
|
+
- [Hold what this pass already launched](#hold-what-this-pass-already-launched)
|
|
14
|
+
- [Check the file sets are disjoint](#check-the-file-sets-are-disjoint)
|
|
15
|
+
- [Pick the model](#pick-the-model)
|
|
16
|
+
- [Pick local or cloud](#pick-local-or-cloud)
|
|
17
|
+
- [Dispatch](#dispatch)
|
|
18
|
+
- [Fall back to the human](#fall-back-to-the-human)
|
|
19
|
+
- [Stop the loop](#stop-the-loop)
|
|
20
|
+
|
|
8
21
|
## Derive the candidate
|
|
9
22
|
|
|
10
23
|
Run `canon tasks plan-branch <plan> --json` against the row's plan file and read `branch`, `type`, `slug`, and `conforms` off the record.
|
|
@@ -18,7 +18,7 @@ The miss is measured. On 2026-10-02 two queries ran twice each with identical te
|
|
|
18
18
|
|
|
19
19
|
The authorities in both pairs were named by the session unprompted once it was asked to, which is the argument for a method over a list. Two queries at one run each show the effect exists and do not size it.
|
|
20
20
|
|
|
21
|
-
Access is a second gap a session cannot derive. Probed on 2026-10-02, Reddit refused its JSON search with a 403 and refused `WebFetch`, while its RSS feed answered 200. X redirected `curl` to a login page and returned 402 to `WebFetch`, so no free route reaches it.
|
|
21
|
+
Access is a second gap a session cannot derive. Probed on 2026-10-02, Reddit refused its JSON search with a 403 and refused `WebFetch`, while its RSS feed answered 200. X redirected `curl` to a login page and returned 402 to `WebFetch`, so no free route reaches it. Re-probed on 2026-10-04, Reddit's RSS feed, its search feed, and its JSON listing and search all answered 403, so the feed that answered two days earlier no longer does.
|
|
22
22
|
|
|
23
23
|
## Must
|
|
24
24
|
|
|
@@ -44,10 +44,12 @@ The procedure that loaded this skill owns what the result is for and where it is
|
|
|
44
44
|
|
|
45
45
|
Each line is a claim measured once, and `${CLAUDE_SKILL_DIR}/REQUIREMENT.md` records the date under its Gap. Sites change their blocking without notice, so re-check a line before relying on it. Add a line only for a failure a session actually hit, and record the date it hit in the requirement beside it.
|
|
46
46
|
|
|
47
|
-
- Reddit
|
|
47
|
+
- Reddit refuses its RSS feed and its JSON search alike with a 403. `WebFetch` is refused for the site, so no keyless route reaches it.
|
|
48
48
|
- X answers nothing without paying or a login. `curl` redirects to a login page and `WebFetch` returns 402.
|
|
49
49
|
- Stop and ask the operator before any route that pays, logs in, or works around a refusal. Never suggest scraping behind a login.
|
|
50
50
|
|
|
51
|
+
Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidance or arguing against a rule in it. It records which comparable skills were read, what was adopted and declined, and why.
|
|
52
|
+
|
|
51
53
|
## Excuses and rebuttals
|
|
52
54
|
|
|
53
55
|
| Excuse | Rebuttal |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Adopted and declined
|
|
3
|
+
description: Which comparable research skills this skill was read against, what it took from them, what it declined, and which of its rules rest on measurement rather than a source
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adopted and declined
|
|
7
|
+
|
|
8
|
+
Three third-party research skills were read before this one was written. None of them was imported, and most of the body rests on paired searches measured in this skill's `REQUIREMENT.md` rather than on any of them. A later session extending the skill adds to this file rather than re-arguing an item settled here.
|
|
9
|
+
|
|
10
|
+
## Adopted
|
|
11
|
+
|
|
12
|
+
**Recording each route's failure.** [aghori3004/claude-research-stack](https://github.com/aghori3004/claude-research-stack) keeps one `research-sources` skill that orders sources cheapest first and writes down how each one fails. Adopted as the access note, which records a refusal a session hit rather than leaving the next session to learn it by failing.
|
|
13
|
+
|
|
14
|
+
**Calling the tools directly.** The same skill ships no wrapper scripts, so it calls the command-line tools and servers it names. Adopted as the rule to reach a keyless API with a plain request rather than writing a wrapper for one search.
|
|
15
|
+
|
|
16
|
+
**Treating a paid route as the operator's call.** [rohunvora/x-research-skill](https://github.com/rohunvora/x-research-skill) reaches X through the official API at a cost per search page. Adopted as the stop before any route that pays or logs in, since that cost is one the operator decides rather than one a session discovers.
|
|
17
|
+
|
|
18
|
+
## Declined
|
|
19
|
+
|
|
20
|
+
**A directory of sites per category.** None of the three is one, and each earns its keep on access and cost instead. A site list also rots with nobody noticing, so the body derives a field's authorities per question rather than reading them off a list.
|
|
21
|
+
|
|
22
|
+
**Reaching walled sites through a logged-in browser.** `claude-research-stack` reaches Reddit and X through a desktop Chrome session holding the operator's login. Declined because the body never suggests working around a login.
|
|
23
|
+
|
|
24
|
+
**A bundled engine.** [mvanhorn/last30days-skill](https://github.com/mvanhorn/last30days-skill) is a Python engine with its own test suite and paid aggregators behind it. Declined because a skill here ships no code, and access a session needs repeatedly becomes a `canon` verb.
|
|
25
|
+
|
|
26
|
+
## Stated by no source
|
|
27
|
+
|
|
28
|
+
**Naming the field and deriving its authorities.** No comparable skill takes a thinking step before searching. The step rests on the paired open and scoped searches recorded in `REQUIREMENT.md` under `Gap`, where the scoped run returned primary sources and caught a wrong version number the open run carried.
|
|
29
|
+
|
|
30
|
+
**Preferring a public API over a fetched page.** It rests on the same probes, where the scholarly and reference APIs returned the dates, authors, and identifiers a citation needs and a fetched page returned a summary.
|
|
@@ -9,6 +9,14 @@ What the `install` and `gov` phases both do before they write anything. Stated
|
|
|
9
9
|
once here rather than twice in the body, since the two phases differ in what
|
|
10
10
|
they install rather than in how they read the project.
|
|
11
11
|
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
- [Read the catalogs](#read-the-catalogs)
|
|
15
|
+
- [Detect](#detect)
|
|
16
|
+
- [Resolve arguments](#resolve-arguments)
|
|
17
|
+
- [Gap handling](#gap-handling)
|
|
18
|
+
- [Preview](#preview)
|
|
19
|
+
|
|
12
20
|
## Read the catalogs
|
|
13
21
|
|
|
14
22
|
Run in parallel. Never hardcode stack, rule, or standards names. The
|
|
@@ -12,6 +12,19 @@ user, and writes. The CLI handles validation and regeneration only.
|
|
|
12
12
|
Read `canon docs indexes` from the toolkit if context on the system is needed
|
|
13
13
|
before scanning.
|
|
14
14
|
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- [Scope](#scope)
|
|
18
|
+
- [Scan](#scan)
|
|
19
|
+
- [Present candidates](#present-candidates)
|
|
20
|
+
- [Draft frontmatter](#draft-frontmatter)
|
|
21
|
+
- [Scaffold the folder index](#scaffold-the-folder-index)
|
|
22
|
+
- [Inject](#inject)
|
|
23
|
+
- [Validate](#validate)
|
|
24
|
+
- [Offer the convention seed](#offer-the-convention-seed)
|
|
25
|
+
- [Closeout](#closeout)
|
|
26
|
+
- [Reference](#reference)
|
|
27
|
+
|
|
15
28
|
## Scope
|
|
16
29
|
|
|
17
30
|
- Bootstrap un-indexed folders only. Skip folders that already contain an `index.md`.
|
|
@@ -12,6 +12,14 @@ Two depths over one contract. Both read the `scripts` block from the project's
|
|
|
12
12
|
own `package.json` and run what is declared there, so neither hardcodes a script
|
|
13
13
|
name and a stack exposing a different set is covered without an edit here.
|
|
14
14
|
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- [Guards](#guards)
|
|
18
|
+
- [Step 1: read scripts](#step-1-read-scripts)
|
|
19
|
+
- [Step 2: run the chain](#step-2-run-the-chain)
|
|
20
|
+
- [Step 3: report](#step-3-report)
|
|
21
|
+
- [Out of scope](#out-of-scope)
|
|
22
|
+
|
|
15
23
|
## Guards
|
|
16
24
|
|
|
17
25
|
A monorepo syncs each language root into its own subfolder, so the project root
|
|
@@ -19,6 +19,8 @@ description: Write the failing test for a behavior before writing the code that
|
|
|
19
19
|
- Changing what a function already does starts with changing what its test asserts. Run that changed test once before touching the implementation, and confirm it fails against the code as it stands today.
|
|
20
20
|
- A test that already passes before any code changes proves nothing about the new behavior. Widen the assertion or add a case until the suite fails against the current implementation.
|
|
21
21
|
|
|
22
|
+
Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidance or arguing against a rule in it. It records which external sources the loop matches, which parts were declined, and which rules no source states.
|
|
23
|
+
|
|
22
24
|
## What this skill does not cover
|
|
23
25
|
|
|
24
26
|
- Which layer a test belongs at and what makes it a good one. `canon:test-craft` owns that judgment, and step 1 loads it.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Adopted and declined
|
|
3
|
+
description: Which external sources the test-first loop draws on, which parts it declined, and which of its rules no source states, so a later session extends the position instead of re-deriving it
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adopted and declined
|
|
7
|
+
|
|
8
|
+
The loop predates this ledger, so this file records the sources it matches rather than the ones it was drafted from. Each was opened before it was cited. A later session extending the skill adds to this file rather than re-arguing an item settled here.
|
|
9
|
+
|
|
10
|
+
## Adopted
|
|
11
|
+
|
|
12
|
+
**The loop itself.** Kent Beck's [Canon TDD](https://newsletter.kentbeck.com/p/canon-tdd) states it as turning one item into "an actual, concrete, runnable test", changing the code "to make the test (& all previous tests) pass", then refactoring. Adopted as steps 2, 4, 5, and 6, with the whole suite run after the pass rather than the new test alone.
|
|
13
|
+
|
|
14
|
+
**Making it pass without designing.** The same post warns against "mixing refactoring into making the test pass", and keeps implementation design decisions for the refactor. Adopted as step 4's smallest change and step 6's cleanup of the shortcuts that change left.
|
|
15
|
+
|
|
16
|
+
**Never faking the pass.** The same post lists deleting assertions "so the test pretends to pass" and "copying actual, computed values & pasting them into the expected values" as mistakes. Adopted as step 5's rule that a pass must be the one the test was written to prove.
|
|
17
|
+
|
|
18
|
+
**Refactoring is a step, not an option.** Martin Fowler's [TestDrivenDevelopment](https://martinfowler.com/bliki/TestDrivenDevelopment.html) names "neglecting the third step" as the most common way to get the practice wrong. Adopted as step 6 being mandatory where Canon TDD writes "optionally refactor".
|
|
19
|
+
|
|
20
|
+
## Declined
|
|
21
|
+
|
|
22
|
+
**The test list.** Canon TDD opens by listing every expected variant of the new behavior before writing a test. Declined because a plan already names the behaviors a build covers, and `canon:build-in-slices` owns the order they land in, so a second list here would hold a second copy of the scope.
|
|
23
|
+
|
|
24
|
+
**Refactoring only as far as the session needs.** Canon TDD warns against refactoring further than necessary and calls duplication "a hint, not a command". Declined as a separate rule, since `canon:code-craft` owns when an abstraction earns its place and step 6 already limits refactoring to what step 4 left.
|
|
25
|
+
|
|
26
|
+
## Checked and not a source
|
|
27
|
+
|
|
28
|
+
**Software Engineering at Google, [Testing Overview](https://abseil.io/resources/swe-book/html/ch11.html).** The default shelf's testing chapter covers why tests matter and how a suite is structured, and never addresses writing a test before its code or watching it fail. It informs `canon:test-craft`, which step 1 loads, rather than this loop.
|
|
29
|
+
|
|
30
|
+
**Kent Beck's _Test-Driven Development: By Example_.** The book is the loop's origin, and no openable copy was available to cite a version from. Canon TDD is Beck's own later restatement and stands in for it here.
|
|
31
|
+
|
|
32
|
+
## Stated by no source
|
|
33
|
+
|
|
34
|
+
**Confirming the failure is the right one.** Step 3's rule, that a test failing for a typo or a wrong signature is a defect in the test, comes from the failure recorded in this skill's `REQUIREMENT.md` under `Gap` rather than from any source above.
|
|
35
|
+
|
|
36
|
+
**Extending existing behavior.** The rule that a changed assertion must fail against the code as it stands today is the same failure applied to an edit, and carries no external source.
|
|
@@ -67,4 +67,4 @@ Report each file written or updated by its full path from the project root.
|
|
|
67
67
|
|
|
68
68
|
## Source material
|
|
69
69
|
|
|
70
|
-
The position on external writing guidance sits in `${CLAUDE_SKILL_DIR}/references/
|
|
70
|
+
The position on external writing guidance sits in `${CLAUDE_SKILL_DIR}/references/adopted.md`, which states what this skill adopted, what it declined, and the measurement behind each. Read it before importing a rule from outside this corpus. Do not re-derive that position, since a second answer will disagree with the recorded one.
|
|
@@ -9,6 +9,19 @@ Each pattern below is a shape rather than a token, so no closed word set matches
|
|
|
9
9
|
|
|
10
10
|
Work top down. The first three account for most of what a reader calls machine-written.
|
|
11
11
|
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
- [Rule of three](#rule-of-three)
|
|
15
|
+
- [Synonym cycling](#synonym-cycling)
|
|
16
|
+
- [False ranges](#false-ranges)
|
|
17
|
+
- [Inline-header lists](#inline-header-lists)
|
|
18
|
+
- [Adverb propping](#adverb-propping)
|
|
19
|
+
- [Passive voice with an unnamed actor](#passive-voice-with-an-unnamed-actor)
|
|
20
|
+
- [Closing restatement](#closing-restatement)
|
|
21
|
+
- [Question as transition](#question-as-transition)
|
|
22
|
+
- [Escalating parallel clauses](#escalating-parallel-clauses)
|
|
23
|
+
- [Empty superlative frames](#empty-superlative-frames)
|
|
24
|
+
|
|
12
25
|
## Rule of three
|
|
13
26
|
|
|
14
27
|
A triad wherever a list appears, whatever the subject actually holds. Three adjectives, three clauses, three examples, over and over, until the count is the only thing a reader can predict.
|
package/docs/agents/canvas.md
CHANGED
|
@@ -39,7 +39,9 @@ A pick is refused as `address-mismatch` when the browser builds elements the fil
|
|
|
39
39
|
|
|
40
40
|
`text` replaces the text of an element holding text alone and refuses one holding other elements as `not-text-only`. Every byte outside the element stays as it was. `--json` emits the page, frame, file, path, and the file's new `hash`.
|
|
41
41
|
|
|
42
|
-
The operator edits the same set from the inspector, which posts to the same writer with the hash the frame was served with. An edit made against a version of the file Claude has since rewritten is refused as `stale-address` and the shell reloads the frame, so nothing lands on a shifted element.
|
|
42
|
+
The operator edits the same set from the inspector, which posts to the same writer with the hash the frame was served with. An edit made against a version of the file Claude has since rewritten is refused as `stale-address` and the shell reloads the frame, so nothing lands on a shifted element. Both writers take the frame file's lock, and an edit that keeps the selected element where it was keeps the selection fresh.
|
|
43
|
+
|
|
44
|
+
A color picked from the project's tokens is written as `var(--<name>)`, and below full opacity as a `color-mix()` of that `var()` with `transparent` at the opacity percent, so it keeps following the theme. A browser older than 2023 drops a `color-mix()` value, which leaves the property unset there. A hex is written as six digits, or eight below full opacity.
|
|
43
45
|
|
|
44
46
|
Inline style beats a class, so an operator's edit masks a class change Claude makes later. Read a frame's inline styles before restyling it, and remove one the change should replace. The inspector marks a color or background set inline with the word `raw` when its value names no `var()` and is not `currentColor` or a CSS-wide keyword, since that value stays fixed when the theme changes. A property outside the set, or a value carrying `;`, `{`, `}`, `<`, `>`, or a line break, is refused as `invalid-edit`.
|
|
45
47
|
|
package/docs/agents/capture.md
CHANGED
|
@@ -44,7 +44,7 @@ Neither digest is ever written by hand. A digest is what the gate compares, so a
|
|
|
44
44
|
|
|
45
45
|
Each source renders at `deviceScaleFactor` 2 with a transparent background, and the success line reports the pixel dimensions the element wrapped to. Size is reported and never asserted. The height of a terminal frame is whatever its text wrapped to at a fixed width, so pinning that number would harden an accident.
|
|
46
46
|
|
|
47
|
-
What is asserted is the font. The command reads the first family the captured element
|
|
47
|
+
What is asserted is the font. The command reads the first family of each rendered element holding text inside the captured element, and fails when the browser did not resolve one of them, because a fallback face rewraps the block and silently changes the output. A generic keyword as the first family, such as `monospace` or `system-ui`, also fails with its own reason, since it resolves to a different font on each machine, though a quoted `"monospace"` is a family name and goes through the probe. An element holding no text skips the check, since there is nothing to rewrap. Sources therefore name a real font rather than relying on `monospace`. A source that cannot render reports its own line and exits 1 without dropping the rest of the batch.
|
|
48
48
|
|
|
49
49
|
A run refuses before it reads anything else when `--selector` is absent, naming the flag and pointing at `--help`. Ordering it first is what keeps the message about the invocation: the source defaults to `assets`, so checking that first would answer `assets not found` from whatever directory the caller happened to be in and say nothing about the flag that was actually missing. That source default is a deliberate choice rather than one inherited from some general convention: a missing folder still refuses loud, naming the argument, once the flag check passes, where the selector's dropped default cropped the wrong region in silence.
|
|
50
50
|
|
package/docs/agents/commands.md
CHANGED
|
@@ -26,7 +26,7 @@ One row per top-level command, in the order `canon --help` prints them. A domain
|
|
|
26
26
|
| `canon indexes <verb>` | Regenerate `index.md` files from sibling frontmatter, or flatten them |
|
|
27
27
|
| `canon docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
|
|
28
28
|
| `canon design <verb>` | Render or regenerate `canon/DESIGN.md` tokens, emit their CSS, install the base stylesheet |
|
|
29
|
-
| `canon slides <verb>` | Render a
|
|
29
|
+
| `canon slides <verb>` | Render a deck folder of HTML slides, or list the decks |
|
|
30
30
|
| `canon capture [source]` | Render HTML or a URL to PNG and prove each declared font resolved |
|
|
31
31
|
| `canon serve [dir]` | Serve a directory on loopback and print the link that opens it |
|
|
32
32
|
| `canon demo <verb>` | Compile and record a running app |
|
|
@@ -128,8 +128,8 @@ Subcommands no other page describes:
|
|
|
128
128
|
- `claude plugin-update` matches the installed marketplace plugin against `claude/.claude-plugin/plugin.json`'s own name and runs `claude plugin update` on it, reading the version back off `claude plugin list --json`, since the update call reports none of its own (`--json`).
|
|
129
129
|
- `claude skills rank` scores either skill corpus's descriptions against a case corpus by TF-IDF cosine similarity, reporting rank-one and top-three (`--cases <path>`).
|
|
130
130
|
- `design regen` rewrites this repository's `canon/DESIGN.md` from `src/design/tokens.ts` and `src/design/base.css` from `src/design/neutral.ts`. `design css` emits the tokens and components as CSS on stdout, with `--no-components` for properties alone, and `design render` declares each vendored face the typography table names under `--embed-fonts`.
|
|
131
|
-
- `slides
|
|
132
|
-
- `slides render
|
|
131
|
+
- `slides list --json` emits one row per deck under `.canon/slides/`, carrying `name`, `title`, `slides`, and `path`.
|
|
132
|
+
- `slides render [deck]` takes a deck name or a folder, defaulting to the only deck, and lays out each `.html` file in filename order in Chromium at 1280 by 720 and rebuilds it as editable shapes. Each element drawn as a picture prints one `✗` line on stderr naming the slide, the selector, and the properties that forced it. A link left out, being a `#slide-N` past the deck's end or any target that is neither that nor an absolute URL, prints one too, and the exit stays 0.
|
|
133
133
|
- 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`.
|
|
134
134
|
- `canvas`, with its verbs, content format, and write routes, is described in `canvas.md`.
|
|
135
135
|
- `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 title word no dictionary holds, or a title breaking `standards/pr.md`'s format, casing, or length rule (`--event`, `--body-file`, `--json`).
|
package/docs/agents/index.md
CHANGED
|
@@ -41,7 +41,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
41
41
|
- [The pull request preview deploy](pr-preview.md): How canon pr preview finds a fenced Cloudflare Pages deploy, 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
|
|
42
42
|
- [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
|
|
43
43
|
- [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
|
|
44
|
-
- [Records stale](records-stale.md): Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, and the exit codes and refusals
|
|
44
|
+
- [Records stale](records-stale.md): Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, counting the releases since the requirements and architecture records were last reviewed, and the exit codes and refusals
|
|
45
45
|
- [Records validate](records-validate.md): Validating the session records and the standards corpus, the per-kind checks, which root each kind defaults to, the exit codes, and the refusal reasons
|
|
46
46
|
- [Records](records.md): The two roots a record folder resolves at, migrating a record a frontmatter change orphaned, claiming the ordinal intake and groundwork share, reading each folder's size and growth, pruning stale scratch, and where validation, the memory review queue, and the private-remote backup are described
|
|
47
47
|
- [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
|
|
@@ -54,7 +54,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
54
54
|
- [Sessions](sessions.md): Resolving live peer sessions to the worktree and branch each holds, reading which row is the caller, the liveness confidence field, what each session surface can see, and where moving a session to another machine is described
|
|
55
55
|
- [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
|
|
56
56
|
- [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
|
|
57
|
-
- [Slides](slides.md):
|
|
57
|
+
- [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
|
|
58
58
|
- [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
|
|
59
59
|
- [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
|
|
60
60
|
- [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
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Records stale
|
|
3
|
-
description: Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, and the exit codes and refusals
|
|
3
|
+
description: Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, counting the releases since the requirements and architecture records were last reviewed, and the exit codes and refusals
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Records stale
|
|
7
7
|
|
|
8
|
-
`canon records stale memory` reports each memory entry's review state and every backticked path it cites that the project no longer holds. It answers what a review of the pen should read next, so a skill takes the queue from the verb rather than re-deriving it by grep.
|
|
8
|
+
`canon records stale memory` reports each memory entry's review state and every backticked path it cites that the project no longer holds. It answers what a review of the pen should read next, so a skill takes the queue from the verb rather than re-deriving it by grep. `canon records stale canonical` reports when the requirements and architecture records were last reviewed and how many releases have shipped since.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
canon records stale memory
|
|
12
12
|
canon records stale memory --json
|
|
13
13
|
canon records stale memory --days 60 --json
|
|
14
|
+
canon records stale canonical --json
|
|
14
15
|
```
|
|
15
16
|
|
|
16
|
-
| Option | Behavior
|
|
17
|
-
| --------------- |
|
|
18
|
-
| `--json` | Add a machine-readable record on stdout
|
|
19
|
-
| `--days <n>` | Days after a review before
|
|
20
|
-
| `--root <path>` | Project root, defaulting to the main worktree
|
|
17
|
+
| Option | Behavior |
|
|
18
|
+
| --------------- | --------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `--json` | Add a machine-readable record on stdout |
|
|
20
|
+
| `--days <n>` | Days after a review before a memory entry is due again (default 30) |
|
|
21
|
+
| `--root <path>` | Project root, defaulting to the main worktree for `memory` and the current worktree for `canonical` |
|
|
21
22
|
|
|
22
|
-
`memory`
|
|
23
|
+
`memory` and `canonical` are the two kinds it reads, since each is a record carrying a review date. Any other argument refuses as `unknown-kind`.
|
|
23
24
|
|
|
24
25
|
It reports and never writes. It moves, archives, and rewrites no entry, matching `validate` and `size`.
|
|
25
26
|
|
|
@@ -53,10 +54,22 @@ canon records stale memory --json | jq -r '[.entries[] | select(.due)][0:20][] |
|
|
|
53
54
|
|
|
54
55
|
The record carries `total`, `due`, `days`, the `folder` read relative to the root, and one `entries` row per entry with `name`, `category`, `reviewed`, `due`, and `unresolved`.
|
|
55
56
|
|
|
57
|
+
## Canonical records
|
|
58
|
+
|
|
59
|
+
`canonical` reads `REQUIREMENTS.md` and `ARCHITECTURE.md` at whichever surface root carries each, `canon/` ahead of `.claude/`, and omits one the project does not hold. Both are 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.
|
|
60
|
+
|
|
61
|
+
Each doc's review point is an optional `reviewed: YYYY-MM-DD` frontmatter field, set by whoever finishes a review, per `canon standards requirements` and `canon standards architecture`. 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 the way the memory field is, so a value that is not a calendar date comes back as `invalidReviewed`.
|
|
62
|
+
|
|
63
|
+
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.
|
|
64
|
+
|
|
65
|
+
The record carries `tagged`, false when `HEAD` has merged no release tag or the repository has no commit yet, and one `docs` row per doc with `path`, `reviewed`, `releasesSince`, and `latestRelease`. `releasesSince` is null on a doc never reviewed and `0` on one reviewed after every tag. With no tags it is also `0`, which is why `tagged` travels beside it.
|
|
66
|
+
|
|
67
|
+
It gates nothing, and no hook, gate stage, or workflow runs it. `canon:document-health` reads it when asked to review the two records.
|
|
68
|
+
|
|
56
69
|
## Exit codes and refusals
|
|
57
70
|
|
|
58
71
|
Exit codes: `0` the reading completed, whatever it found, and `1` refused. A due entry is a queue position rather than a failure, so nothing here gates.
|
|
59
72
|
|
|
60
|
-
A `reason` field carries which gate fired: `no-folder` when the project holds no memory folder at either record root, `unknown-kind` for any kind but `memory
|
|
73
|
+
A `reason` field carries which gate fired: `no-folder` when the project holds no memory folder at either record root, `unknown-kind` for any kind but `memory` or `canonical`, `bad-days` when `--days` is not a positive whole number or is passed to `canonical`, and `unreadable-tags` when `canonical` cannot read the tags. An empty pen is not a refusal. It reports an empty list and exits `0`.
|
|
61
74
|
|
|
62
75
|
The pen is shared scratch at the main worktree root, so `--root` defaults there, the same default `validate memory` takes. A pen at the legacy `.claude/memory/` root resolves the way every record verb resolves it, per `records.md`. <!-- canon-keep-record-root -->
|
package/docs/agents/records.md
CHANGED
|
@@ -118,7 +118,7 @@ Exit codes: `0` nothing to prune, or `--write` deleted every candidate. `1` refu
|
|
|
118
118
|
|
|
119
119
|
## Stale
|
|
120
120
|
|
|
121
|
-
`canon records stale memory` reports which memory entries are due for review and which cite a path the tree no longer holds, ordered so a review takes the first N as a batch. What makes an entry due, how a cited path resolves, and the refusals are in `records-stale.md`.
|
|
121
|
+
`canon records stale memory` reports which memory entries are due for review and which cite a path the tree no longer holds, ordered so a review takes the first N as a batch. `canon records stale canonical` reports when the requirements and architecture records were last reviewed and how many releases have shipped since. What makes an entry due, how a cited path resolves, how the release count is taken, and the refusals are in `records-stale.md`.
|
|
122
122
|
|
|
123
123
|
## Push and pull
|
|
124
124
|
|
package/docs/agents/sandbox.md
CHANGED
|
@@ -9,7 +9,7 @@ description: Scenario routing, the expectation scoring surface, and the coverage
|
|
|
9
9
|
|
|
10
10
|
## Scenarios
|
|
11
11
|
|
|
12
|
-
Scenarios live under `sandbox/`, one folder per category. `sandbox/fixtures/` is the exception, holding file content that scenarios stage rather than scenarios of its own, so both
|
|
12
|
+
Scenarios live under `sandbox/`, one folder per category. `sandbox/fixtures/` is the exception, holding file content that scenarios stage rather than scenarios of its own, so the picker and the coverage report both filter it out. That tree sits outside `files` in `package.json`, so an installed `canon` carries the command, reports it as toolkit-only on one line, and exits 1 rather than failing on the missing directory. Route non-interactively with `SANDBOX_SCENARIO`:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
SANDBOX_SCENARIO=sync canon sandbox infra:tooling
|