@erclx/canon 4.0.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/LICENSE +21 -0
- package/README.md +129 -0
- package/claude/.claude-plugin/plugin.json +19 -0
- package/claude/skills/bash-cli-script/REQUIREMENT.md +42 -0
- package/claude/skills/bash-cli-script/SKILL.md +48 -0
- package/claude/skills/bash-cli-script/references/template.md +43 -0
- package/claude/skills/bash-script/REQUIREMENT.md +36 -0
- package/claude/skills/bash-script/SKILL.md +100 -0
- package/claude/skills/bash-script/references/patterns.md +349 -0
- package/claude/skills/canon-cli/REQUIREMENT.md +41 -0
- package/claude/skills/canon-cli/SKILL.md +103 -0
- package/claude/skills/canon-feedback-file/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-file/SKILL.md +80 -0
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-triage/SKILL.md +63 -0
- package/claude/skills/canon-operator/REQUIREMENT.md +61 -0
- package/claude/skills/canon-operator/SKILL.md +108 -0
- package/claude/skills/canon-rollout/REQUIREMENT.md +59 -0
- package/claude/skills/canon-rollout/SKILL.md +147 -0
- package/claude/skills/canon-screencast/REQUIREMENT.md +39 -0
- package/claude/skills/canon-screencast/SKILL.md +167 -0
- package/claude/skills/canon-slides-draft/REQUIREMENT.md +39 -0
- package/claude/skills/canon-slides-draft/SKILL.md +62 -0
- package/claude/skills/ci-workflow/REQUIREMENT.md +40 -0
- package/claude/skills/ci-workflow/SKILL.md +65 -0
- package/claude/skills/ci-workflow/references/workflows.md +98 -0
- package/claude/skills/claude-address-review/REQUIREMENT.md +57 -0
- package/claude/skills/claude-address-review/SKILL.md +212 -0
- package/claude/skills/claude-address-review/references/rebase-conflicts.md +39 -0
- package/claude/skills/claude-autoship/REQUIREMENT.md +50 -0
- package/claude/skills/claude-autoship/SKILL.md +207 -0
- package/claude/skills/claude-design-extract/REQUIREMENT.md +42 -0
- package/claude/skills/claude-design-extract/SKILL.md +102 -0
- package/claude/skills/claude-diagram/REQUIREMENT.md +45 -0
- package/claude/skills/claude-diagram/SKILL.md +177 -0
- package/claude/skills/claude-docs/REQUIREMENT.md +60 -0
- package/claude/skills/claude-docs/SKILL.md +287 -0
- package/claude/skills/claude-docs/references/anchor-sweep.md +58 -0
- package/claude/skills/claude-docs/references/wireframe-sweep.md +45 -0
- package/claude/skills/claude-feature/REQUIREMENT.md +36 -0
- package/claude/skills/claude-feature/SKILL.md +115 -0
- package/claude/skills/claude-groundwork/REQUIREMENT.md +48 -0
- package/claude/skills/claude-groundwork/SKILL.md +142 -0
- package/claude/skills/claude-intake/REQUIREMENT.md +49 -0
- package/claude/skills/claude-intake/SKILL.md +114 -0
- package/claude/skills/claude-intake-answer/REQUIREMENT.md +48 -0
- package/claude/skills/claude-intake-answer/SKILL.md +90 -0
- package/claude/skills/claude-markdown-propose/REQUIREMENT.md +48 -0
- package/claude/skills/claude-markdown-propose/SKILL.md +118 -0
- package/claude/skills/claude-markdown-propose/references/format.md +107 -0
- package/claude/skills/claude-memory-capture/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-capture/SKILL.md +101 -0
- package/claude/skills/claude-memory-review/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-review/SKILL.md +210 -0
- package/claude/skills/claude-memory-review/references/receipt-format.md +48 -0
- package/claude/skills/claude-orchestrate/REQUIREMENT.md +121 -0
- package/claude/skills/claude-orchestrate/SKILL.md +241 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +132 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +32 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +72 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +87 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +30 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-sweep.md +21 -0
- package/claude/skills/claude-orchestrate/scripts/poll.sh +373 -0
- package/claude/skills/claude-orchestrate/scripts/watch.sh +181 -0
- package/claude/skills/claude-pr-review/REQUIREMENT.md +47 -0
- package/claude/skills/claude-pr-review/SKILL.md +295 -0
- package/claude/skills/claude-review/REQUIREMENT.md +39 -0
- package/claude/skills/claude-review/SKILL.md +142 -0
- package/claude/skills/claude-seed-sync/REQUIREMENT.md +45 -0
- package/claude/skills/claude-seed-sync/SKILL.md +156 -0
- package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
- package/claude/skills/claude-standards-audit/SKILL.md +99 -0
- package/claude/skills/claude-tasks/REQUIREMENT.md +43 -0
- package/claude/skills/claude-tasks/SKILL.md +161 -0
- package/claude/skills/claude-teach/REQUIREMENT.md +56 -0
- package/claude/skills/claude-teach/SKILL.md +196 -0
- package/claude/skills/claude-teach/references/lesson-craft.md +59 -0
- package/claude/skills/claude-teach/references/pedagogy.md +67 -0
- package/claude/skills/claude-teach/references/promotion.md +54 -0
- package/claude/skills/claude-ui-test/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ui-test/SKILL.md +77 -0
- package/claude/skills/claude-ux-audit/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ux-audit/SKILL.md +79 -0
- package/claude/skills/claude-ux-measure/REQUIREMENT.md +48 -0
- package/claude/skills/claude-ux-measure/SKILL.md +122 -0
- package/claude/skills/claude-worker/REQUIREMENT.md +54 -0
- package/claude/skills/claude-worker/SKILL.md +96 -0
- package/claude/skills/claude-worktree/REQUIREMENT.md +58 -0
- package/claude/skills/claude-worktree/SKILL.md +136 -0
- package/claude/skills/create-rule/REQUIREMENT.md +45 -0
- package/claude/skills/create-rule/SKILL.md +68 -0
- package/claude/skills/create-skill/REQUIREMENT.md +38 -0
- package/claude/skills/create-skill/SKILL.md +32 -0
- package/claude/skills/create-snippet/REQUIREMENT.md +39 -0
- package/claude/skills/create-snippet/SKILL.md +30 -0
- package/claude/skills/create-standard/REQUIREMENT.md +35 -0
- package/claude/skills/create-standard/SKILL.md +29 -0
- package/claude/skills/decision-escalate/REQUIREMENT.md +45 -0
- package/claude/skills/decision-escalate/SKILL.md +79 -0
- package/claude/skills/docs-sync/REQUIREMENT.md +41 -0
- package/claude/skills/docs-sync/SKILL.md +95 -0
- package/claude/skills/git-branch/REQUIREMENT.md +38 -0
- package/claude/skills/git-branch/SKILL.md +60 -0
- package/claude/skills/git-commit/REQUIREMENT.md +36 -0
- package/claude/skills/git-commit/SKILL.md +49 -0
- package/claude/skills/git-followup/REQUIREMENT.md +43 -0
- package/claude/skills/git-followup/SKILL.md +48 -0
- package/claude/skills/git-issue/REQUIREMENT.md +38 -0
- package/claude/skills/git-issue/SKILL.md +65 -0
- package/claude/skills/git-pr/REQUIREMENT.md +50 -0
- package/claude/skills/git-pr/SKILL.md +164 -0
- package/claude/skills/git-pr/references/labels.md +95 -0
- package/claude/skills/git-ship/REQUIREMENT.md +42 -0
- package/claude/skills/git-ship/SKILL.md +55 -0
- package/claude/skills/git-split/REQUIREMENT.md +39 -0
- package/claude/skills/git-split/SKILL.md +162 -0
- package/claude/skills/git-stage/REQUIREMENT.md +39 -0
- package/claude/skills/git-stage/SKILL.md +73 -0
- package/claude/skills/git-worktree/REQUIREMENT.md +38 -0
- package/claude/skills/git-worktree/SKILL.md +130 -0
- package/claude/skills/migration-claude-md/REQUIREMENT.md +40 -0
- package/claude/skills/migration-claude-md/SKILL.md +76 -0
- package/claude/skills/migration-context/REQUIREMENT.md +36 -0
- package/claude/skills/migration-context/SKILL.md +95 -0
- package/claude/skills/migration-standards-drop/REQUIREMENT.md +55 -0
- package/claude/skills/migration-standards-drop/SKILL.md +113 -0
- package/claude/skills/migration-superseded/REQUIREMENT.md +44 -0
- package/claude/skills/migration-superseded/SKILL.md +115 -0
- package/claude/skills/project-commands/REQUIREMENT.md +42 -0
- package/claude/skills/project-commands/SKILL.md +85 -0
- package/claude/skills/restate-plainly/REQUIREMENT.md +41 -0
- package/claude/skills/restate-plainly/SKILL.md +39 -0
- package/claude/skills/session-map/REQUIREMENT.md +57 -0
- package/claude/skills/session-map/SKILL.md +70 -0
- package/claude/skills/session-resume/REQUIREMENT.md +49 -0
- package/claude/skills/session-resume/SKILL.md +51 -0
- package/claude/skills/setup-gov/REQUIREMENT.md +37 -0
- package/claude/skills/setup-gov/SKILL.md +77 -0
- package/claude/skills/setup-indexes/REQUIREMENT.md +45 -0
- package/claude/skills/setup-indexes/SKILL.md +153 -0
- package/claude/skills/setup-init/REQUIREMENT.md +45 -0
- package/claude/skills/setup-init/SKILL.md +127 -0
- package/claude/skills/setup-plugins/REQUIREMENT.md +42 -0
- package/claude/skills/setup-plugins/SKILL.md +81 -0
- package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
- package/claude/skills/setup-verify/REQUIREMENT.md +39 -0
- package/claude/skills/setup-verify/SKILL.md +51 -0
- package/claude/skills/systematic-debugging/REQUIREMENT.md +41 -0
- package/claude/skills/systematic-debugging/SKILL.md +70 -0
- package/claude/skills/write-human/REQUIREMENT.md +46 -0
- package/claude/skills/write-human/SKILL.md +68 -0
- package/claude/skills/write-human/references/density.md +38 -0
- package/claude/skills/write-human/references/machine-tells.md +107 -0
- package/claude/skills/write-human/references/source-material.md +37 -0
- package/claude/skills/youtube-transcripts/REQUIREMENT.md +38 -0
- package/claude/skills/youtube-transcripts/SKILL.md +34 -0
- package/docs/agents/audits.md +98 -0
- package/docs/agents/capture.md +37 -0
- package/docs/agents/census.md +23 -0
- package/docs/agents/commands.md +146 -0
- package/docs/agents/comments.md +34 -0
- package/docs/agents/context-audit-checks.md +120 -0
- package/docs/agents/context-audit.md +83 -0
- package/docs/agents/counts.md +76 -0
- package/docs/agents/demo.md +86 -0
- package/docs/agents/docs.md +17 -0
- package/docs/agents/gate.md +84 -0
- package/docs/agents/index.md +47 -0
- package/docs/agents/indexes.md +35 -0
- package/docs/agents/install-and-sync.md +385 -0
- package/docs/agents/intake.md +81 -0
- package/docs/agents/key-changes.md +103 -0
- package/docs/agents/label-coverage.md +73 -0
- package/docs/agents/markdown-audit.md +197 -0
- package/docs/agents/output-shape.md +70 -0
- package/docs/agents/overview.md +26 -0
- package/docs/agents/records.md +170 -0
- package/docs/agents/restated.md +81 -0
- package/docs/agents/review-classification.md +77 -0
- package/docs/agents/routing.md +61 -0
- package/docs/agents/rule-citations.md +98 -0
- package/docs/agents/sandbox.md +71 -0
- package/docs/agents/scripting.md +149 -0
- package/docs/agents/sessions.md +120 -0
- package/docs/agents/skills-audit.md +94 -0
- package/docs/agents/skills-reach.md +64 -0
- package/docs/agents/standards-audit.md +38 -0
- package/docs/agents/state-scoped-risk.md +105 -0
- package/docs/agents/superseded.md +85 -0
- package/docs/agents/targets.md +83 -0
- package/docs/agents/tasks.md +200 -0
- package/docs/agents/teach.md +158 -0
- package/docs/agents/test-order.md +56 -0
- package/docs/agents/worktrees.md +62 -0
- package/docs/ai-workflow.md +317 -0
- package/docs/index.md +23 -0
- package/docs/operating-model.md +223 -0
- package/docs/target-projects.md +258 -0
- package/docs/visual-design-workflow.md +151 -0
- package/docs/zshrc-aliases.md +65 -0
- package/governance/rules/ci/700-ci-workflow.md +44 -0
- package/governance/rules/claude/500-prose.md +15 -0
- package/governance/rules/claude/501-markdown.md +14 -0
- package/governance/rules/claude/510-context.md +28 -0
- package/governance/rules/claude/511-indexes.md +14 -0
- package/governance/rules/claude/520-wireframes.md +12 -0
- package/governance/rules/claude/530-requirements.md +11 -0
- package/governance/rules/claude/540-architecture.md +11 -0
- package/governance/rules/claude/550-design.md +11 -0
- package/governance/rules/claude/555-tasks.md +12 -0
- package/governance/rules/claude/556-groundwork.md +11 -0
- package/governance/rules/claude/557-intake.md +11 -0
- package/governance/rules/claude/558-plan.md +22 -0
- package/governance/rules/claude/559-memory.md +11 -0
- package/governance/rules/claude/560-diagrams.md +18 -0
- package/governance/rules/claude/561-teach.md +13 -0
- package/governance/rules/claude/562-session.md +15 -0
- package/governance/rules/claude/570-skill.md +24 -0
- package/governance/rules/claude/575-hooks.md +17 -0
- package/governance/rules/claude/576-settings.md +14 -0
- package/governance/rules/claude/580-readme.md +11 -0
- package/governance/rules/claude/590-rule-authoring.md +12 -0
- package/governance/rules/claude/591-standard-authoring.md +12 -0
- package/governance/rules/claude/592-claude-md.md +19 -0
- package/governance/rules/core/000-constitution.md +30 -0
- package/governance/rules/core/005-behavior.md +27 -0
- package/governance/rules/core/010-testing.md +35 -0
- package/governance/rules/core/015-output.md +20 -0
- package/governance/rules/core/020-concurrency.md +22 -0
- package/governance/rules/core/025-indexes.md +9 -0
- package/governance/rules/core/030-error-handling.md +31 -0
- package/governance/rules/core/035-tasks.md +13 -0
- package/governance/rules/core/040-performance.md +20 -0
- package/governance/rules/core/045-memory.md +12 -0
- package/governance/rules/core/050-logging.md +20 -0
- package/governance/rules/core/055-scratch.md +9 -0
- package/governance/rules/core/060-naming.md +19 -0
- package/governance/rules/core/065-spelling.md +19 -0
- package/governance/rules/core/070-planning.md +18 -0
- package/governance/rules/core/075-dependencies.md +25 -0
- package/governance/rules/core/080-config-comments.md +22 -0
- package/governance/rules/core/085-worktrees.md +17 -0
- package/governance/rules/core/087-git.md +11 -0
- package/governance/rules/core/090-code-comments.md +39 -0
- package/governance/rules/framework/200-react.md +51 -0
- package/governance/rules/framework/210-astro.md +41 -0
- package/governance/rules/framework/220-fastapi.md +43 -0
- package/governance/rules/framework/230-nextjs.md +48 -0
- package/governance/rules/framework/250-tailwind.md +32 -0
- package/governance/rules/framework/260-shadcn.md +34 -0
- package/governance/rules/lang/100-typescript.md +40 -0
- package/governance/rules/lang/110-python.md +42 -0
- package/governance/rules/lang/120-bash.md +19 -0
- package/governance/rules/lib/300-testing-ts.md +39 -0
- package/governance/rules/lib/305-e2e-reliability.md +34 -0
- package/governance/rules/lib/306-test-scope.md +25 -0
- package/governance/rules/lib/310-zod.md +25 -0
- package/governance/rules/lib/320-tanstack-query.md +32 -0
- package/governance/rules/lib/330-testing-py.md +44 -0
- package/governance/rules/lib/340-pydantic.md +38 -0
- package/governance/rules/lib/350-security-web.md +32 -0
- package/governance/rules/lib/360-security-server.md +39 -0
- package/governance/rules/lib/370-database.md +35 -0
- package/governance/rules/snippets/505-at-references.md +9 -0
- package/governance/rules/ui/400-ui.md +36 -0
- package/governance/rules/ui/410-a11y.md +48 -0
- package/governance/rules/ui/420-forms.md +36 -0
- package/governance/rules/ui/430-ux-completeness.md +65 -0
- package/governance/rules/ui/440-surface-capture.md +34 -0
- package/governance/rules/ui/450-link-behavior.md +19 -0
- package/governance/stacks/astro.toml +2 -0
- package/governance/stacks/base.toml +8 -0
- package/governance/stacks/node-server.toml +2 -0
- package/governance/stacks/node.toml +2 -0
- package/governance/stacks/python-fastapi.toml +2 -0
- package/governance/stacks/python.toml +2 -0
- package/governance/stacks/react.toml +2 -0
- package/package.json +69 -0
- package/scripts/config.sh +11 -0
- package/scripts/core/bootstrap.sh +81 -0
- package/scripts/core/check-color-source.sh +41 -0
- package/scripts/core/check-ignore-parity.sh +162 -0
- package/scripts/core/check-plugin-boundary.sh +45 -0
- package/scripts/core/check-seed-independence.sh +59 -0
- package/scripts/core/check-skill-paths.sh +24 -0
- package/scripts/core/clean.sh +36 -0
- package/scripts/core/install-check.sh +101 -0
- package/scripts/core/list-seed-roots.sh +18 -0
- package/scripts/core/regen-claude-copies.sh +10 -0
- package/scripts/core/regen-hero.sh +217 -0
- package/scripts/core/regen-indexes.sh +10 -0
- package/scripts/core/regen-tooling-paths.sh +61 -0
- package/scripts/core/repair-bare-flag.sh +19 -0
- package/scripts/core/snapshot.sh +134 -0
- package/scripts/core/update.sh +35 -0
- package/scripts/docs/list.sh +165 -0
- package/scripts/lib/frontmatter.sh +30 -0
- package/scripts/lib/gov.sh +14 -0
- package/scripts/lib/sandbox-fixtures.sh +191 -0
- package/scripts/lib/sandbox-git.sh +125 -0
- package/scripts/lib/sandbox-path.sh +206 -0
- package/scripts/lib/tooling.sh +35 -0
- package/scripts/lib/ui.sh +266 -0
- package/scripts/lib/worktree.sh +20 -0
- package/scripts/manage-sandbox.sh +466 -0
- package/scripts/snippets/create.sh +156 -0
- package/scripts/standards/list.sh +115 -0
- package/scripts/tooling/create.sh +109 -0
- package/scripts/tooling/verify.sh +179 -0
- package/snippets/align.md +12 -0
- package/snippets/claude/decision-memo.md +39 -0
- package/snippets/claude/feature-recap.md +19 -0
- package/snippets/claude/figma-steps.md +24 -0
- package/snippets/compact-summary.md +5 -0
- package/snippets/decision-help.md +6 -0
- package/snippets/meta-prompt.md +14 -0
- package/snippets/research-prompt.md +7 -0
- package/snippets/session-notes.md +11 -0
- package/snippets/snippets.toml +5 -0
- package/snippets/step-by-step.md +10 -0
- package/snippets/web-research.md +21 -0
- package/src/audits/baseline.ts +201 -0
- package/src/audits/catalog.ts +876 -0
- package/src/audits/run.ts +204 -0
- package/src/autoship/classify.ts +75 -0
- package/src/autoship/paths.ts +51 -0
- package/src/binary.ts +16 -0
- package/src/browser/engine.ts +40 -0
- package/src/census/count.ts +113 -0
- package/src/claude/cases/all.ts +24 -0
- package/src/claude/cases/authoring.ts +53 -0
- package/src/claude/cases/claude-workflow.ts +158 -0
- package/src/claude/cases/git.ts +44 -0
- package/src/claude/cases/misc.ts +27 -0
- package/src/claude/cases/setup.ts +94 -0
- package/src/claude/gitignore.ts +51 -0
- package/src/claude/routing.ts +283 -0
- package/src/claude/seeds-list.ts +47 -0
- package/src/claude/seeds.ts +150 -0
- package/src/claude/settings.ts +151 -0
- package/src/claude/skills-audit.ts +228 -0
- package/src/claude/skills-drift.ts +156 -0
- package/src/claude/skills-list.ts +99 -0
- package/src/claude/skills-rank.ts +320 -0
- package/src/claude/skills-reach.ts +227 -0
- package/src/cli-run.ts +43 -0
- package/src/cli.ts +200 -0
- package/src/commands/audits.ts +350 -0
- package/src/commands/autoship.ts +129 -0
- package/src/commands/capture.ts +133 -0
- package/src/commands/census.ts +105 -0
- package/src/commands/claude.ts +1286 -0
- package/src/commands/comments.ts +240 -0
- package/src/commands/context.ts +857 -0
- package/src/commands/demo.ts +389 -0
- package/src/commands/deps.ts +173 -0
- package/src/commands/design.ts +36 -0
- package/src/commands/docs.ts +60 -0
- package/src/commands/feedback-format.ts +23 -0
- package/src/commands/feedback.ts +112 -0
- package/src/commands/gate.ts +189 -0
- package/src/commands/gov.ts +1265 -0
- package/src/commands/indexes.ts +184 -0
- package/src/commands/init.ts +113 -0
- package/src/commands/intake.ts +406 -0
- package/src/commands/inventory.ts +256 -0
- package/src/commands/labels.ts +361 -0
- package/src/commands/markdown.ts +544 -0
- package/src/commands/migrate.ts +175 -0
- package/src/commands/pass-through.ts +39 -0
- package/src/commands/pr.ts +411 -0
- package/src/commands/records.ts +728 -0
- package/src/commands/sandbox.ts +468 -0
- package/src/commands/secrets.ts +132 -0
- package/src/commands/serve.ts +159 -0
- package/src/commands/sessions.ts +408 -0
- package/src/commands/slides.ts +126 -0
- package/src/commands/snippets.ts +84 -0
- package/src/commands/standards.ts +247 -0
- package/src/commands/sync.ts +428 -0
- package/src/commands/targets.ts +319 -0
- package/src/commands/tasks.ts +743 -0
- package/src/commands/teach.ts +786 -0
- package/src/commands/tooling.ts +573 -0
- package/src/commands/transcripts.ts +44 -0
- package/src/commands/upgrade.ts +231 -0
- package/src/commands/wiki.ts +100 -0
- package/src/commands/worktrees.ts +191 -0
- package/src/comments/scan.ts +338 -0
- package/src/comments/trend.ts +207 -0
- package/src/comments/vocabulary.ts +85 -0
- package/src/context/architecture.ts +364 -0
- package/src/context/audit.ts +790 -0
- package/src/context/citations.ts +196 -0
- package/src/context/folders.ts +186 -0
- package/src/context/gate.ts +57 -0
- package/src/context/index-drift.ts +64 -0
- package/src/context/narration.ts +99 -0
- package/src/copy.ts +30 -0
- package/src/counts/catalogs.ts +96 -0
- package/src/counts/numbers.ts +79 -0
- package/src/counts/scan.ts +314 -0
- package/src/demo/beats.ts +135 -0
- package/src/demo/compile.ts +326 -0
- package/src/demo/container.ts +63 -0
- package/src/demo/cursors.ts +55 -0
- package/src/demo/drive.ts +357 -0
- package/src/demo/pointer.ts +178 -0
- package/src/demo/theme.ts +112 -0
- package/src/deps/audit.ts +153 -0
- package/src/design/parse.ts +116 -0
- package/src/design/render.ts +249 -0
- package/src/docs/read.ts +77 -0
- package/src/exec.ts +16 -0
- package/src/exempt-marker.ts +43 -0
- package/src/frontmatter.ts +13 -0
- package/src/gate/measures.ts +682 -0
- package/src/gate/sequencer.ts +386 -0
- package/src/gate/stages.ts +412 -0
- package/src/git-env.ts +36 -0
- package/src/git-files.ts +105 -0
- package/src/git-ignore.ts +46 -0
- package/src/github-format.ts +13 -0
- package/src/github.ts +24 -0
- package/src/gov/adapter.ts +103 -0
- package/src/gov/citations.ts +514 -0
- package/src/gov/consumed.ts +129 -0
- package/src/gov/install.ts +132 -0
- package/src/gov/list.ts +106 -0
- package/src/gov/payload.ts +39 -0
- package/src/gov/restated.ts +814 -0
- package/src/gov/stacks.ts +205 -0
- package/src/gov/superseded.ts +415 -0
- package/src/gov/test-order.ts +407 -0
- package/src/indexes/frontmatter.ts +46 -0
- package/src/indexes/regen.ts +84 -0
- package/src/indexes/render.ts +201 -0
- package/src/indexes/walk.ts +83 -0
- package/src/init/flags.ts +60 -0
- package/src/init/plan.ts +114 -0
- package/src/init/run.ts +46 -0
- package/src/init/steps.ts +77 -0
- package/src/intake/folder.ts +320 -0
- package/src/intake/items.ts +174 -0
- package/src/inventory/config.ts +117 -0
- package/src/inventory/group.ts +76 -0
- package/src/inventory/subjects.ts +114 -0
- package/src/inventory/walk.ts +129 -0
- package/src/labels/audit.ts +82 -0
- package/src/labels/coverage.ts +79 -0
- package/src/labels/map.ts +101 -0
- package/src/labels/phase.ts +95 -0
- package/src/markdown/bans.ts +94 -0
- package/src/markdown/files.ts +102 -0
- package/src/markdown/gate.ts +28 -0
- package/src/markdown/scan.ts +295 -0
- package/src/markdown/structure.ts +730 -0
- package/src/migrate/apply.ts +115 -0
- package/src/migrate/plan.ts +103 -0
- package/src/migrate/rename.ts +183 -0
- package/src/pr/bijection.ts +145 -0
- package/src/pr/paths.ts +335 -0
- package/src/process/harness.ts +167 -0
- package/src/project-root.ts +19 -0
- package/src/records/backup.ts +455 -0
- package/src/records/migrate.ts +78 -0
- package/src/records/size.ts +260 -0
- package/src/records/validate.ts +1162 -0
- package/src/sandbox/census.ts +228 -0
- package/src/sandbox/coverage.ts +115 -0
- package/src/sandbox/expect.ts +629 -0
- package/src/sandbox/tree.ts +47 -0
- package/src/secrets/marker.ts +30 -0
- package/src/secrets/patterns.ts +142 -0
- package/src/secrets/scan.ts +123 -0
- package/src/secrets/shipped.ts +111 -0
- package/src/seed-marker.ts +74 -0
- package/src/serve/static.ts +322 -0
- package/src/sessions/claim.ts +85 -0
- package/src/sessions/live.ts +79 -0
- package/src/sessions/registry.ts +137 -0
- package/src/sessions/resolve.ts +333 -0
- package/src/slides/layouts.ts +391 -0
- package/src/slides/open.ts +18 -0
- package/src/slides/parse.ts +84 -0
- package/src/slides/render.ts +88 -0
- package/src/slides/styles.ts +44 -0
- package/src/snippets/categories.ts +66 -0
- package/src/snippets/list.ts +32 -0
- package/src/snippets/presets.ts +50 -0
- package/src/standards/audit.ts +132 -0
- package/src/standards/read.ts +100 -0
- package/src/sync/check.ts +692 -0
- package/src/sync/engine.ts +576 -0
- package/src/sync/git.ts +225 -0
- package/src/sync/history.ts +123 -0
- package/src/sync/layout.ts +140 -0
- package/src/sync/reverse.ts +268 -0
- package/src/sync/seeds-report.ts +126 -0
- package/src/sync/stamp.ts +358 -0
- package/src/sync/target.ts +70 -0
- package/src/sync/workflow.ts +200 -0
- package/src/target.ts +43 -0
- package/src/targets/pulls.ts +250 -0
- package/src/targets/registry.ts +203 -0
- package/src/targets/resolve.ts +145 -0
- package/src/targets/sweep.ts +246 -0
- package/src/tasks/archive.ts +506 -0
- package/src/tasks/record.ts +311 -0
- package/src/tasks/trunk.ts +89 -0
- package/src/tasks/validate.ts +1001 -0
- package/src/teach/lesson.ts +180 -0
- package/src/teach/workspace.ts +842 -0
- package/src/tooling/gitignore.ts +122 -0
- package/src/tooling/inject.ts +193 -0
- package/src/tooling/list.ts +39 -0
- package/src/tooling/manifest.ts +176 -0
- package/src/tooling/package.ts +166 -0
- package/src/tooling/read.ts +65 -0
- package/src/tooling/scan.ts +147 -0
- package/src/tooling/stamp.ts +44 -0
- package/src/transcripts/fetch.ts +156 -0
- package/src/transcripts/metadata.ts +54 -0
- package/src/transcripts/vtt.ts +114 -0
- package/src/ui.ts +266 -0
- package/src/version/compare.ts +53 -0
- package/src/version/installed.ts +40 -0
- package/src/version/manager.ts +67 -0
- package/src/version/skew.ts +192 -0
- package/src/wiki/init.ts +85 -0
- package/src/worktree.ts +143 -0
- package/src/worktrees/reclaim.ts +306 -0
- package/standards/architecture.md +72 -0
- package/standards/branch.md +59 -0
- package/standards/commit.md +72 -0
- package/standards/context.md +151 -0
- package/standards/design.md +93 -0
- package/standards/diagrams.md +152 -0
- package/standards/glossary.md +75 -0
- package/standards/groundwork.md +211 -0
- package/standards/index.md +36 -0
- package/standards/intake.md +192 -0
- package/standards/issue.md +94 -0
- package/standards/markdown.md +137 -0
- package/standards/memory.md +144 -0
- package/standards/plan.md +172 -0
- package/standards/pr.md +139 -0
- package/standards/publish.md +51 -0
- package/standards/readme.md +208 -0
- package/standards/requirements.md +70 -0
- package/standards/rule.md +118 -0
- package/standards/session.md +109 -0
- package/standards/skill.md +300 -0
- package/standards/slug.md +39 -0
- package/standards/snippets.md +76 -0
- package/standards/standard.md +170 -0
- package/standards/tasks.md +254 -0
- package/standards/teach.md +153 -0
- package/standards/versioning.md +71 -0
- package/standards/wireframes.md +113 -0
- package/tooling/astro/configs/astro.config.mjs +31 -0
- package/tooling/astro/configs/eslint.config.js +79 -0
- package/tooling/astro/configs/playwright.config.ts +26 -0
- package/tooling/astro/configs/tsconfig.json +12 -0
- package/tooling/astro/configs/vitest.config.ts +22 -0
- package/tooling/astro/manifest.toml +34 -0
- package/tooling/astro/reference.md +60 -0
- package/tooling/base/configs/.editorconfig +5 -0
- package/tooling/base/configs/.github/pull_request_template.md +18 -0
- package/tooling/base/configs/.github/workflows/verify.yml +35 -0
- package/tooling/base/configs/.husky/commit-msg +1 -0
- package/tooling/base/configs/.husky/post-merge +61 -0
- package/tooling/base/configs/.husky/post-rewrite +21 -0
- package/tooling/base/configs/.husky/pre-commit +1 -0
- package/tooling/base/configs/.husky/pre-push +1 -0
- package/tooling/base/configs/.prettierrc +12 -0
- package/tooling/base/configs/.shellcheckrc +1 -0
- package/tooling/base/configs/.vscode/extensions.json +9 -0
- package/tooling/base/configs/.vscode/settings.json +3 -0
- package/tooling/base/configs/commitlint.config.js +11 -0
- package/tooling/base/configs/scripts/verify.sh +64 -0
- package/tooling/base/manifest.toml +30 -0
- package/tooling/base/reference.md +98 -0
- package/tooling/base/seeds/.claude/context/ci.md +33 -0
- package/tooling/base/seeds/.claude/context/development.md +37 -0
- package/tooling/base/seeds/.claude/context/index.md +11 -0
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/base/seeds/.lintstagedrc +8 -0
- package/tooling/base/seeds/.prettierignore +0 -0
- package/tooling/base/seeds/cspell.json +20 -0
- package/tooling/claude/manifest.toml +14 -0
- package/tooling/claude/reference.md +79 -0
- package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
- package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
- package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
- package/tooling/claude/seeds/.claude/diagrams/index.md +8 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +50 -0
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +68 -0
- package/tooling/claude/seeds/.claude/hooks/path-form.sh +57 -0
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +52 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +86 -0
- package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +71 -0
- package/tooling/claude/seeds/.claude/memory/index.md +8 -0
- package/tooling/claude/seeds/.claude/settings.json +47 -0
- package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
- package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
- package/tooling/claude/seeds/CLAUDE.md +29 -0
- package/tooling/claude/user/settings.template.json +10 -0
- package/tooling/claude/user/statusline-command.sh +53 -0
- package/tooling/python/configs/.coveragerc +14 -0
- package/tooling/python/configs/.python-version +1 -0
- package/tooling/python/configs/mypy.ini +6 -0
- package/tooling/python/configs/pytest.ini +4 -0
- package/tooling/python/configs/ruff.toml +15 -0
- package/tooling/python/configs/scripts/verify.sh +77 -0
- package/tooling/python/manifest.toml +16 -0
- package/tooling/python/reference.md +66 -0
- package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/python/seeds/tests/test_smoke.py +2 -0
- package/tooling/vite-react/configs/playwright.config.ts +26 -0
- package/tooling/vite-react/configs/tsconfig.json +35 -0
- package/tooling/vite-react/configs/vite.config.ts +24 -0
- package/tooling/vite-react/configs/vitest.config.ts +26 -0
- package/tooling/vite-react/manifest.toml +23 -0
- package/tooling/vite-react/reference.md +55 -0
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
- package/tooling/web/configs/.github/workflows/verify.yml +134 -0
- package/tooling/web/configs/.vscode/extensions.json +13 -0
- package/tooling/web/configs/.vscode/settings.json +10 -0
- package/tooling/web/configs/e2e/home.spec.ts +6 -0
- package/tooling/web/configs/e2e/screenshot.ts +53 -0
- package/tooling/web/configs/eslint.config.js +82 -0
- package/tooling/web/configs/scripts/screenshot.sh +28 -0
- package/tooling/web/configs/scripts/verify.sh +80 -0
- package/tooling/web/configs/scripts/worktree-port.sh +74 -0
- package/tooling/web/configs/src/test/setup.ts +8 -0
- package/tooling/web/manifest.toml +58 -0
- package/tooling/web/reference.md +115 -0
- package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Install and sync
|
|
3
|
+
description: What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Install and sync
|
|
7
|
+
|
|
8
|
+
The behavior notes behind the verbs listed in `commands.md`. Each one records what the verb writes, what it refuses, and what it deliberately leaves alone.
|
|
9
|
+
|
|
10
|
+
## Domain sync
|
|
11
|
+
|
|
12
|
+
`canon gov sync` updates only rules already present under `.claude/rules/` and
|
|
13
|
+
never adds new ones. A rule the toolkit does not ship is left alone, which is
|
|
14
|
+
how project-authored rules survive, and one under `.claude/rules/project/`
|
|
15
|
+
is left alone regardless of its name, since that subfolder is project-authored
|
|
16
|
+
by location. It also removes a stale `.claude/GOV.md`
|
|
17
|
+
from the retired build. Use `canon gov install` to add rules.
|
|
18
|
+
|
|
19
|
+
A rule the toolkit finds no source for, sitting in a shared subdirectory rather
|
|
20
|
+
than under `.claude/rules/project/`, is reported with the path under that
|
|
21
|
+
subfolder it would take. The offer is conditional on the project having written
|
|
22
|
+
the rule, since a rule the toolkit shipped and later renamed reaches the same
|
|
23
|
+
line, and moving one there would mark it the project's for good. Nothing is
|
|
24
|
+
moved either way, because a rule's installed path is one the project's own
|
|
25
|
+
rules, skills, and docs may cite. `canon standards rule` carries the reserved
|
|
26
|
+
number bands behind that placement, where `900-999` is the range a
|
|
27
|
+
project-authored rule takes and everything below it belongs to the toolkit.
|
|
28
|
+
|
|
29
|
+
`canon sync --check` does not report an orphaned entry. It skips every one, so
|
|
30
|
+
the destination reaches `canon gov sync` alone, the one domain sync verb left.
|
|
31
|
+
|
|
32
|
+
When the target's install recorded a stack, `canon gov sync` also reports a
|
|
33
|
+
rule that stack lists and `.claude/rules/` does not hold, as a `missing` entry
|
|
34
|
+
carrying no change. This is what makes a target whose recorded sync point
|
|
35
|
+
postdates a rule joining its stack still see that rule: the report reads the
|
|
36
|
+
target's current entitlement against its current tree rather than diffing
|
|
37
|
+
from an anchor a later sync could advance past the rule's own commit. A
|
|
38
|
+
target whose install predates the recorded chain falls back to the same
|
|
39
|
+
band-inference `newRules` uses in `canon sync --check`.
|
|
40
|
+
|
|
41
|
+
There is no `canon standards sync` and no `canon standards install`. The corpus
|
|
42
|
+
installs into no project, so the domain has nothing in a target to reconcile.
|
|
43
|
+
`canon standards <name>` prints one, resolving `standards/` at the working root
|
|
44
|
+
and then the corpus inside the package, and `canon standards list --json` carries
|
|
45
|
+
the catalog.
|
|
46
|
+
|
|
47
|
+
There is no `canon snippets sync` and no `canon snippets install` either, on the
|
|
48
|
+
same ground: `claude/snippets` in the plugin cache symlinks live to the
|
|
49
|
+
toolkit's own `snippets/`, so a session reaches one at its `@` reference with
|
|
50
|
+
no copy to reconcile. `canon snippets list --json` carries the catalog and
|
|
51
|
+
`canon snippets create` is the one verb left that still writes a file.
|
|
52
|
+
|
|
53
|
+
## Install guards
|
|
54
|
+
|
|
55
|
+
`canon gov install` requires its first argument under
|
|
56
|
+
`CANON_NON_INTERACTIVE=1`. It used to fall back to an interactive picker that
|
|
57
|
+
resolved to its first option headlessly, so a call with no stack installed
|
|
58
|
+
whichever stack sorted first. It now reports the valid names on stderr and
|
|
59
|
+
exits 1.
|
|
60
|
+
|
|
61
|
+
Every documented agent path already passes the argument, including
|
|
62
|
+
`canon init`. The confirm-then-apply prompt after it still resolves to `Yes`
|
|
63
|
+
headlessly, so a call that names its stack is unchanged.
|
|
64
|
+
|
|
65
|
+
`canon gov install` also refuses the toolkit root as a target. It resolves the
|
|
66
|
+
target before anything else, so a path that does not exist fails rather than
|
|
67
|
+
being scaffolded.
|
|
68
|
+
|
|
69
|
+
## Standards resolution
|
|
70
|
+
|
|
71
|
+
`canon standards <name>` writes the document to stdout and the root it answered
|
|
72
|
+
from to stderr, so a caller capturing with `$(...)` receives the document alone.
|
|
73
|
+
A name resolves with or without its `.md` extension, and one that matches no
|
|
74
|
+
standard exits 1 after listing the catalog on stderr.
|
|
75
|
+
|
|
76
|
+
Two roots answer, in order: `standards/` at the working directory, then the
|
|
77
|
+
corpus inside the package. A project that authors standards of its own uses the
|
|
78
|
+
first, and this repository's own authoring root is the same path. `.claude/standards/`
|
|
79
|
+
is not among them, and no repository writes one any more. A copy an older
|
|
80
|
+
toolkit installed into a target resolves nothing.
|
|
81
|
+
|
|
82
|
+
There is no citation closure to compute, since nothing is copied. A standard
|
|
83
|
+
that hands a concern to a sibling names it in `Does not govern:` and a reader
|
|
84
|
+
runs the verb again for that name.
|
|
85
|
+
|
|
86
|
+
## Governance regen
|
|
87
|
+
|
|
88
|
+
`canon gov regen` is the one governance verb that runs against the toolkit root,
|
|
89
|
+
because the `.claude/rules/` it writes there is produced output rather than an
|
|
90
|
+
operator's working copy. It reads the stack recorded in `internal/governance.toml`,
|
|
91
|
+
installs it alongside anything under `internal/rules/`, and clears the
|
|
92
|
+
destination first so a rule the record stopped naming disappears.
|
|
93
|
+
|
|
94
|
+
It takes `--root <path>` and defaults to the toolkit root, prints nothing on success, and
|
|
95
|
+
reports the reason on stderr with exit 1 when the record names a stack or rule
|
|
96
|
+
that does not resolve. `scripts/core/regen-claude-copies.sh` calls it, and the
|
|
97
|
+
Consumed copies stage of `bun run check` asserts the result is committed.
|
|
98
|
+
|
|
99
|
+
## Whole-project sync
|
|
100
|
+
|
|
101
|
+
`canon sync` runs every installed domain sync, then offers to commit the result
|
|
102
|
+
and open a pull request. Under `CANON_NON_INTERACTIVE=1` it applies the domain
|
|
103
|
+
syncs and then refuses the git workflow, reporting the branch and commit it
|
|
104
|
+
would have created and exiting 0. Nothing is staged, committed, or pushed
|
|
105
|
+
headlessly.
|
|
106
|
+
|
|
107
|
+
Run it interactively to reach the commit and pull request options.
|
|
108
|
+
It also refuses a target whose working tree is dirty, so commit or stash first.
|
|
109
|
+
|
|
110
|
+
## Drift reporting
|
|
111
|
+
|
|
112
|
+
`canon sync --check` reports drift and writes nothing, so it needs no clean tree
|
|
113
|
+
and is safe to run at any time. Each file is classified as `stale` when it still
|
|
114
|
+
matches what the toolkit installed, `customized` when the project edited it,
|
|
115
|
+
`stranded` when it sits at a path the toolkit no longer installs to, `orphaned`
|
|
116
|
+
when the project authored it, or `drifted` when no stamp covers it. Governance
|
|
117
|
+
also reports `missing`, for a rule the target's recorded stack lists that its
|
|
118
|
+
tree does not hold at all.
|
|
119
|
+
|
|
120
|
+
Use `--json` for the machine-readable report and `--exit-code` to fail a CI job. Orphaned
|
|
121
|
+
and missing files are both excluded from that exit code: a project-authored
|
|
122
|
+
rule never converges, and a sync that added a missing one silently changes
|
|
123
|
+
what the project is governed by, which stays a separate command an operator
|
|
124
|
+
chooses to run. Attribution reads `.claude/canon/config.json`, which every
|
|
125
|
+
install and sync writes.
|
|
126
|
+
|
|
127
|
+
A target installed before stamping shipped has no such file, and neither does
|
|
128
|
+
that fallback do anything to migrate it. A target stamped before the file
|
|
129
|
+
moved into `.claude/canon/` still carries it at the retired
|
|
130
|
+
`.claude/canon.json`, and `canon sync --check` reads that path when the current
|
|
131
|
+
one is absent, reporting it rather than moving it. Only a target carrying
|
|
132
|
+
neither path falls back to the toolkit's own git history.
|
|
133
|
+
Installed content matching any
|
|
134
|
+
version that history ever published proves the file is untouched, so it reports
|
|
135
|
+
`stale` naming the commit it came from, and content matching no published
|
|
136
|
+
version stays `drifted`. A toolkit reached outside a git clone, which is what a
|
|
137
|
+
registry install is, cannot run that fallback and reports
|
|
138
|
+
`historyUnavailable` alongside the unattributed files.
|
|
139
|
+
|
|
140
|
+
Each domain carries its own toolkit anchor in that file, so syncing one domain
|
|
141
|
+
never advances the revision another measures from, and each reports the upstream
|
|
142
|
+
commits touching its own source path. The `covers` field names the domains a
|
|
143
|
+
target has actually stamped, so a domain that was never stamped is legible
|
|
144
|
+
rather than reading as a clean one.
|
|
145
|
+
|
|
146
|
+
### Tooling
|
|
147
|
+
|
|
148
|
+
Tooling records the stack chain an install resolved rather than per-file hashes,
|
|
149
|
+
since `src/tooling/` runs its own inject machinery and has no walk to attribute.
|
|
150
|
+
The chain is ordered nearest stack first, which is what a `--skip` run needs:
|
|
151
|
+
recording the leaf alone would send the next report measuring against a layer the
|
|
152
|
+
target deliberately does not carry. The report loads exactly those stacks, scans
|
|
153
|
+
them the way `canon tooling sync` would, and counts what differs per category
|
|
154
|
+
under `tooling.counts`.
|
|
155
|
+
|
|
156
|
+
`measured` is the field the section exists for. A target carrying no chain
|
|
157
|
+
reports `measured: false`, which separates tooling nobody has ever looked at from
|
|
158
|
+
tooling that is current. Both produce zero changes otherwise. Every target
|
|
159
|
+
installed before the record shipped starts unmeasured and leaves on its next
|
|
160
|
+
`canon tooling sync`, since backfilling would mean inferring the chain from
|
|
161
|
+
installed files, which is the guess the record replaces.
|
|
162
|
+
|
|
163
|
+
A workspace root records nothing, because each package resolves its own chain and
|
|
164
|
+
one written at the root would be that same guess. Run the check against a package
|
|
165
|
+
to measure it. Tooling never counts toward `--exit-code`, on the grounds seeds
|
|
166
|
+
are already excluded on, since it reports golden configs a project is expected to
|
|
167
|
+
edit and a job counting those stays red with no remedy.
|
|
168
|
+
|
|
169
|
+
### Surfaces reported beside the domains
|
|
170
|
+
|
|
171
|
+
Six sections sit outside the per-domain scan, because each names something
|
|
172
|
+
that walk cannot see: `seeds`, `superseded`, `unmigrated`, `newSkills`,
|
|
173
|
+
`newRules`, and `reverse`. None of them produces a change, and no sync command
|
|
174
|
+
applies any of them. The headings below group the first three together and give
|
|
175
|
+
`newSkills` its description under `newRules`, which answers the same question
|
|
176
|
+
about a different corpus.
|
|
177
|
+
|
|
178
|
+
All six report only against a toolkit-managed target, which is one carrying a
|
|
179
|
+
`.claude/` directory, a `CLAUDE.md`, or a domain still at the root layout. The
|
|
180
|
+
report says so through `managed` in the JSON and routes an unmanaged directory to
|
|
181
|
+
`canon init`. Seeds are why the gate exists, since they enumerate from the toolkit
|
|
182
|
+
source rather than from what a target installed, so an unmanaged directory would
|
|
183
|
+
otherwise report every seed as `missing`.
|
|
184
|
+
|
|
185
|
+
A root-layout domain counts as a marker on its own, because the detection fires
|
|
186
|
+
only on root files the toolkit ships and a project in the old layout is one the
|
|
187
|
+
toolkit installed. When `managed` is false every section comes back empty rather
|
|
188
|
+
than the render alone going quiet, so a consumer reading `--json` never acts on a
|
|
189
|
+
finding the rendered half withheld.
|
|
190
|
+
|
|
191
|
+
#### Seeds, superseded artifacts, and unmigrated domains
|
|
192
|
+
|
|
193
|
+
`seeds` classifies every seed the toolkit ships against the target's copy, as
|
|
194
|
+
`matching`, `stale`, `drifted`, or `missing`. `missing` has no per-domain
|
|
195
|
+
equivalent, since the domain walk lists what a target installed and cannot see a
|
|
196
|
+
file that never arrived. There is no `customized` verdict here, because that one
|
|
197
|
+
needs a stamp and seeds carry none, so a file history cannot attribute stays
|
|
198
|
+
`drifted`. Reconcile the section with `claude-seed-sync`, which merges one
|
|
199
|
+
section at a time rather than replacing a file the project edits.
|
|
200
|
+
|
|
201
|
+
A markdown seed installs rewritten rather than copied, since the `stub: true`
|
|
202
|
+
marker the toolkit's own seed gate reads is stripped on the way in. The
|
|
203
|
+
comparison above runs against what the install would write, so a marked seed a
|
|
204
|
+
target never touched still reports `matching`. Every other seed copies byte for
|
|
205
|
+
byte.
|
|
206
|
+
|
|
207
|
+
`superseded` names a file a newer seed folder replaced, such as `.claude/TASKS.md`
|
|
208
|
+
against the `.claude/tasks/` that now ships. The entry carries `replacedBy` and
|
|
209
|
+
nothing else, and the file is never deleted, since the content belongs to the
|
|
210
|
+
project and only its author can decide where it moves. The list derives from the
|
|
211
|
+
seed tree rather than from a fixed set of filenames, so a folder added later is
|
|
212
|
+
covered without a code change. Only an exact stem matches, which leaves a
|
|
213
|
+
suffixed variant such as `TASKS-ARCHIVE.md` unreported.
|
|
214
|
+
|
|
215
|
+
Route it to `migration-superseded`. That skill resolves the standard governing
|
|
216
|
+
`replacedBy` from the `appliesTo` the standards catalog declares, reads the
|
|
217
|
+
destination shape with `canon standards <name>`, and proposes the split without
|
|
218
|
+
writing. Where a folder has no governing standard, the entry earns a named
|
|
219
|
+
refusal rather than a shape nobody stated.
|
|
220
|
+
|
|
221
|
+
`unmigrated` names a domain sitting at the root layout an older toolkit installed
|
|
222
|
+
to, with nothing at the path the current one reads. It carries `rootPath`,
|
|
223
|
+
`installPath`, and a file count. Without it a project holding `standards/` at its
|
|
224
|
+
root reports zero entries for that domain and reads as clean, which is the most
|
|
225
|
+
misleading state the report can produce.
|
|
226
|
+
|
|
227
|
+
The field currently names no domain. Standards and snippets are the two the
|
|
228
|
+
toolkit ever installed at a project root, and both closed their install channel,
|
|
229
|
+
so a project still holding a root `standards/` or `snippets/` folder is carrying
|
|
230
|
+
its own authoring surface rather than an unfinished install. Nothing proposes
|
|
231
|
+
moving either, and no command relocates the content. Move it yourself.
|
|
232
|
+
|
|
233
|
+
#### Rules the target never received
|
|
234
|
+
|
|
235
|
+
`newRules` names a rule the target could receive and its tree does not hold. A
|
|
236
|
+
sync refreshes the files a target already holds and adds none, so without this
|
|
237
|
+
section a project's rule set freezes at its install date while every file it
|
|
238
|
+
does hold reports as current. That is the report's most confident wrong
|
|
239
|
+
answer, since a clean result reads as a target holding everything the toolkit
|
|
240
|
+
publishes.
|
|
241
|
+
|
|
242
|
+
The list rides beside `newSkills`, which asks the same question about the plugin
|
|
243
|
+
catalog. Both are names rather than paths, and neither queues a change, because
|
|
244
|
+
the two remedies differ: a skill loads live from the plugin directory and needs
|
|
245
|
+
nothing run, while a rule reaches a target only when someone runs
|
|
246
|
+
`canon gov install`.
|
|
247
|
+
|
|
248
|
+
Read a clean section as reporting rather than as delivering. Nothing here
|
|
249
|
+
installs, nothing counts toward `--exit-code`, and a target can read the list and
|
|
250
|
+
act on none of it. The value stops at an operator reading it, which is the same
|
|
251
|
+
contract the skills list already sets.
|
|
252
|
+
|
|
253
|
+
Since `canon gov install` records the stack it resolved, a target carrying that
|
|
254
|
+
record answers this by comparing its current entitlement against its current
|
|
255
|
+
tree, with no anchor and no git diff involved. That is what lets the section
|
|
256
|
+
name a rule that shipped before the target's last sync: the anchor a sync
|
|
257
|
+
advances plays no part in the read, where an anchor-bound diff can never see a
|
|
258
|
+
rule on the far side of a window a later sync moved past it. The per-file
|
|
259
|
+
`missing` state `canon gov sync` reports comes from the same comparison, so a
|
|
260
|
+
rule the chain lists reaches both surfaces the same way.
|
|
261
|
+
|
|
262
|
+
A target stamped before governance recorded a chain falls back to the older
|
|
263
|
+
band-inference read below. The measurement there anchors on governance's own
|
|
264
|
+
stamp rather than on the oldest anchor across domains, since rules are
|
|
265
|
+
domain-scoped and a shared anchor would let another domain's sync move the
|
|
266
|
+
revision rules are measured from. A target carrying no chain and no governance anchor
|
|
267
|
+
reports nothing at all: it has no date to measure against, and diffing from the
|
|
268
|
+
start of history would read the whole catalog as new.
|
|
269
|
+
|
|
270
|
+
An anchor this toolkit cannot resolve reports nothing by the same route, and that
|
|
271
|
+
one is not visible. A stamp naming a revision the running clone has never seen,
|
|
272
|
+
which is what a registry install without history or a shallow clone produces,
|
|
273
|
+
fails the read and yields an empty list rather than a stated absence. It looks
|
|
274
|
+
identical to a target holding every rule the toolkit publishes. `newSkills`
|
|
275
|
+
behaves the same way, and neither carries the `historyUnavailable` flag the
|
|
276
|
+
per-domain scan uses to separate the two. Treat an empty section on a toolkit
|
|
277
|
+
that is not a full clone as unmeasured rather than clean. This gap does not
|
|
278
|
+
reach the chain-based read above, since it consults no anchor at all.
|
|
279
|
+
|
|
280
|
+
In the fallback, entitlement is filtered, because a stack does not receive
|
|
281
|
+
every rule. The base stack takes the `core` and `claude` folders whole and
|
|
282
|
+
every other stack extends it with individually named rules, so an unfiltered
|
|
283
|
+
list would tell a base consumer about rules it can never receive and train the
|
|
284
|
+
reader to skip the section.
|
|
285
|
+
|
|
286
|
+
The filter accepts a band on either of two grounds. A folder the base stack takes
|
|
287
|
+
whole is entitled to every target, read from the stack file so a folder added to
|
|
288
|
+
base later needs no code change. Every other band is read off the folders the
|
|
289
|
+
target already carries, which is the fallback's only evidence of what a target
|
|
290
|
+
was entitled to before it recorded a chain. One band can be reached by more than
|
|
291
|
+
one stack, so the test over-reports inside a folder the target holds, which
|
|
292
|
+
costs a line where under-reporting would cost the section its point.
|
|
293
|
+
|
|
294
|
+
A rule the target already holds is dropped by name. That is what keeps a rule the
|
|
295
|
+
toolkit moved between band folders out of the list, since a rename reaches this
|
|
296
|
+
read as an addition and only the name tells the two apart.
|
|
297
|
+
|
|
298
|
+
This closes the dangling-citation case as a side effect rather than checking for
|
|
299
|
+
one. The live instance is a rule citing a sibling authored after the target's
|
|
300
|
+
install, and the section names the sibling as new rather than naming the citation
|
|
301
|
+
as broken. That is enough for an operator to act on, and it is not a citation
|
|
302
|
+
check.
|
|
303
|
+
|
|
304
|
+
#### The reverse walk
|
|
305
|
+
|
|
306
|
+
`reverse` is the one section built by walking the target rather than the
|
|
307
|
+
catalog. Every other surface enumerates toolkit-owned keys and asks whether the
|
|
308
|
+
target matches, so a folder the toolkit deleted appears in none of them. It
|
|
309
|
+
carries `unclaimed`, `migrations`, and `historyUnavailable`.
|
|
310
|
+
|
|
311
|
+
`unclaimed` names a folder the target holds at a top-level path the toolkit once
|
|
312
|
+
shipped and has since deleted. The candidate roots come from the toolkit's own
|
|
313
|
+
history rather than from a list, so a root dropped later is covered without a
|
|
314
|
+
code change. Scoping to those roots is what keeps the walk useful: walking the
|
|
315
|
+
whole tree reports every project folder as unclaimed, which is true and says
|
|
316
|
+
nothing.
|
|
317
|
+
|
|
318
|
+
The managed gate above applies here too, and it is the one place it surprises.
|
|
319
|
+
A directory holding a dropped folder and nothing else reports an empty `reverse`
|
|
320
|
+
rather than the folder, because it carries none of the three markers. Read an
|
|
321
|
+
empty section on an unmanaged target as a walk that never ran rather than as a
|
|
322
|
+
clean result.
|
|
323
|
+
|
|
324
|
+
Each entry carries `rel`, a file count, and an `attribution` of `dropped`,
|
|
325
|
+
`project`, or `unattributed`. A dropped folder and one the project wrote are the
|
|
326
|
+
same bytes at the same path, so the verdict is traced from history rather than
|
|
327
|
+
guessed from the filesystem.
|
|
328
|
+
|
|
329
|
+
Content matching a version the toolkit published reads as `dropped` and carries
|
|
330
|
+
the `since` commit that published it. Names the toolkit shipped holding content
|
|
331
|
+
it never published read as `unattributed`, which is a state in its own right
|
|
332
|
+
rather than a soft yes. No overlap at all reads as `project`, and the render
|
|
333
|
+
drops those while the JSON keeps them.
|
|
334
|
+
|
|
335
|
+
Only files whose path the toolkit once held are hashed, so a project folder
|
|
336
|
+
colliding on a retired name costs the walk no reads. The cost is that a file the
|
|
337
|
+
toolkit shipped and the target renamed goes unmatched, the same limit the
|
|
338
|
+
`unmigrated` count carries.
|
|
339
|
+
|
|
340
|
+
`migrations` names a proposal-only skill with a live case in this target. It
|
|
341
|
+
fires on a `CLAUDE.md` past 250 lines for `migration-claude-md`, and on a `docs/` folder
|
|
342
|
+
holding markdown with no populated `.claude/context/` for `migration-context`.
|
|
343
|
+
Each entry carries the skill name and the measurement behind it, so a consumer
|
|
344
|
+
can check the proposal before running it. Without the field both skills are
|
|
345
|
+
documented and unreachable from any report.
|
|
346
|
+
|
|
347
|
+
#### What counts toward the gate
|
|
348
|
+
|
|
349
|
+
`unmigrated` counts toward `--exit-code`, since running the relocation closes it.
|
|
350
|
+
`superseded` and every seed state are excluded, for the reason `orphaned` already
|
|
351
|
+
is: only the user can move content they wrote, so failing a job on it leaves the
|
|
352
|
+
job red with no mechanical remedy.
|
|
353
|
+
|
|
354
|
+
`newRules` is excluded on a different ground, since a command does close it. What
|
|
355
|
+
excludes it is that installing a rule changes what a project is governed by, so
|
|
356
|
+
gating on the count would pressure a target into adopting rules nobody chose.
|
|
357
|
+
`newSkills` is excluded because it needs no command at all.
|
|
358
|
+
|
|
359
|
+
The whole `reverse` section is excluded on the same grounds, and more strongly.
|
|
360
|
+
Every entry in it is a judgment about a file the project may own, and one of its
|
|
361
|
+
three verdicts is a labelled unknown by design. The unmigrated detection shipped
|
|
362
|
+
that exact false positive once, failing a push with no action that cleared it,
|
|
363
|
+
so this section reports and gates nothing.
|
|
364
|
+
|
|
365
|
+
## Bootstrap
|
|
366
|
+
|
|
367
|
+
`canon init` installs up to four core domains and reports each one independently. A
|
|
368
|
+
domain that fails does not abort the run, so the command finishes the rest and
|
|
369
|
+
exits 1 naming the failures. Passing any flag skips the confirmation prompt,
|
|
370
|
+
which is what makes it scriptable.
|
|
371
|
+
|
|
372
|
+
`--stack` defaults to `base`, and the default
|
|
373
|
+
does not read as a passed flag, so a bare `canon init` installs governance and
|
|
374
|
+
still prompts. `--skip` takes `wiki` and `governance`, and warns
|
|
375
|
+
without aborting on any other value. There is no `--standards` and no
|
|
376
|
+
`--snippets`, since no run writes either corpus into the target.
|
|
377
|
+
|
|
378
|
+
## Unguarded tooling primitives
|
|
379
|
+
|
|
380
|
+
`canon tooling inject` and `canon tooling prune-gitignore` are the unguarded
|
|
381
|
+
primitives beneath `sync`. They apply one stack with no scan and no prompt, and
|
|
382
|
+
they deliberately skip the check that rejects `claude`, which is how `canon
|
|
383
|
+
claude` drives its own stack through them. Use `sync` unless you are scripting
|
|
384
|
+
provisioning. Both frame their own output, so pass `--nested` when calling from
|
|
385
|
+
inside an already-open frame.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Intake
|
|
3
|
+
description: Reading intake folder counts and items, the three read states an item can be in, landing a batch of selections in one cluster, the refusal reasons, and why a call is scoped to one file
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Intake
|
|
7
|
+
|
|
8
|
+
## List
|
|
9
|
+
|
|
10
|
+
`canon intake list` reports the intake folders under `.claude/intake/`, or the items one folder holds. It reads and never writes, because an answer belongs to the operator and a verb that filled one would decide what the folder exists to ask.
|
|
11
|
+
|
|
12
|
+
A folder carries a two-digit ordinal ahead of its slug, as in `21-toolkit-overview`, so a listing sorts by when each opened. A bare slug still resolves: passing `toolkit-overview` matches the one folder whose name is an ordinal ahead of it, and the folder's real name is what every command reports back.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
canon intake list
|
|
16
|
+
canon intake list toolkit-overview --unread --json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Option | Behavior |
|
|
20
|
+
| --------------- | ------------------------------------------------------------------------- |
|
|
21
|
+
| `--unread` | Keep only what is unread: folders carrying one, or a folder's empty slots |
|
|
22
|
+
| `--json` | Emit a machine-readable record on stdout |
|
|
23
|
+
| `--root <path>` | Intake root, defaulting to the main worktree |
|
|
24
|
+
|
|
25
|
+
With no slug it reports per-folder counts. With one it reports every item grouped by the cluster file holding it, each carrying its label, title, open question, suggestion, and answer.
|
|
26
|
+
|
|
27
|
+
An item sits in one of three read states, and the counts keep them apart:
|
|
28
|
+
|
|
29
|
+
| State | What it means |
|
|
30
|
+
| --------- | ------------------------------------------------------- |
|
|
31
|
+
| unread | The slot is present and empty, so nobody has reached it |
|
|
32
|
+
| answered | The slot carries text, which is a decision already made |
|
|
33
|
+
| malformed | The item carries no slot, so no verb here can answer it |
|
|
34
|
+
|
|
35
|
+
The third is counted apart from both rather than folded into either. Counted as answered it hides a file that needs fixing behind a folder reading as fully worked through, and counted as unread it joins a list whose every entry `answer` then refuses.
|
|
36
|
+
|
|
37
|
+
The index is skipped, since it points at items and answers nothing itself. So is any item a file displays inside a fence, which is how a folder copying the item format into its own overview is read as the sample it is rather than as an item offering a slot no reader owns.
|
|
38
|
+
|
|
39
|
+
## Answer
|
|
40
|
+
|
|
41
|
+
`canon intake answer` writes selections into the answer slots of one cluster file.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
canon intake answer toolkit-overview --cluster 05-coverage.md --set 3=ok
|
|
45
|
+
canon intake answer toolkit-overview --cluster 11-intake-skill.md --set 3d=ok --set 9="not worth it" --json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
| Option | Behavior |
|
|
49
|
+
| --------------------- | ----------------------------------------------------- |
|
|
50
|
+
| `--cluster <file>` | Cluster file the items live in, with or without `.md` |
|
|
51
|
+
| `--set <item=answer>` | Answer to land on an item, repeatable |
|
|
52
|
+
| `--json` | Emit a machine-readable record on stdout |
|
|
53
|
+
| `--root <path>` | Intake root, defaulting to the main worktree |
|
|
54
|
+
|
|
55
|
+
Items are labeled per cluster file, so a selection names the cluster and the label together. A label alone names an item in every cluster at once.
|
|
56
|
+
|
|
57
|
+
A label may carry a letter suffix, as in `3a` beside `3`, which is how a pass records a finding split after the fact rather than renumbering every item below it. Pass it exactly as the heading spells it.
|
|
58
|
+
|
|
59
|
+
One call writes one cluster. A call per selection is the alternative, and several of those against the same file read it before any of them writes, so every answer but the last is lost with nothing reporting it. The selections split on the first `=`, so an answer carrying its own survives intact.
|
|
60
|
+
|
|
61
|
+
An item already carrying an answer refuses rather than being overwritten, and one filled item refuses the whole batch, so a partly applied write never lands. Drop the named item and send the rest.
|
|
62
|
+
|
|
63
|
+
Exit codes: `0` every named item now carries its answer, `1` refused. The `reason` field carries `no-intake`, `no-folder`, `ambiguous-slug`, `no-cluster`, `no-item`, `answered`, or `bad-input`. A bare slug matching more than one ordinal-prefixed folder refuses as `ambiguous-slug` rather than `no-folder`, naming every match in `detail`.
|
|
64
|
+
|
|
65
|
+
An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the record's `reason` rather than the exit when a skill consumes this, which matters most here because the verb writes.
|
|
66
|
+
|
|
67
|
+
`bad-input` covers a malformed command line: no cluster, no selection, a selection that parses to no label and answer, an empty answer, an answer carrying a line break, or two answers for one item. It is separate from the reasons describing the folder, so a caller that mistyped a flag is not sent to repair a file that is fine.
|
|
68
|
+
|
|
69
|
+
An empty answer refuses rather than writing an empty slot. The slot means unread while it is empty, so writing one back would report an item as answered that nobody decided.
|
|
70
|
+
|
|
71
|
+
An answer occupies one line, and one carrying a line break refuses before anything is read. Writing it splices a bare continuation into the item that matches none of the patterns the reader tests, so the slot reads back as the text before the break while the item counts as answered, and the refusal on an already-answered item then leaves hand-editing the file as the only correction. The whole batch refuses, so a good selection beside a broken one never lands half applied.
|
|
72
|
+
|
|
73
|
+
The folder is shared scratch at the main worktree root, so `--root` defaults to the first entry of `git worktree list` rather than the working directory. The write is an edit inside a file that already exists, which `Edit` and `Write` refuse from a linked worktree and a shell stream editor may not do, so the verb resolves the root in-process and rewrites whole lines.
|
|
74
|
+
|
|
75
|
+
Skills branch on the reason rather than on the exit code:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
canon intake list toolkit-overview --unread --json | jq -r '.clusters[] | .cluster'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For the folder layout, the item format, the answer contract, and retrieval, see `standards/intake.md`.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Key Changes bijection
|
|
3
|
+
description: Comparing the files a pull request body's Key Changes names against its own diff, the two directions and why they are graded apart, the span rules the extractor was measured into, and the three refusals that separate a clean pass from a read that produced nothing
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Key Changes bijection
|
|
7
|
+
|
|
8
|
+
`canon pr key-changes` reads the `## Key Changes` section of a pull request body, lifts the paths its bullets claim, and compares that set against the files the pull request actually changed. This repository squash-merges, so the body becomes the commit message and the record on the trunk once the branch is gone.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
canon pr key-changes
|
|
12
|
+
canon pr key-changes 1265 --json
|
|
13
|
+
canon pr key-changes --body .claude/.tmp/pr/body.md --base origin/main
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The positional is the pull request to read, defaulting to the one open on this branch.
|
|
17
|
+
|
|
18
|
+
| Option | Behavior |
|
|
19
|
+
| --------------- | ------------------------------------------------------------------ |
|
|
20
|
+
| `--body <path>` | Read the body from a file, taking the changed set from git instead |
|
|
21
|
+
| `--base <ref>` | Far side of the range when `--body` supplies the body |
|
|
22
|
+
| `--root <path>` | Repository to read, defaulting to the cwd |
|
|
23
|
+
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
24
|
+
|
|
25
|
+
`--body` decides where both halves come from, so a number passed beside it is never read. The body comes off disk and the changed set from the local range, which is the shape a fixture and a body still being drafted both need.
|
|
26
|
+
|
|
27
|
+
Without `--body` the body, the file list, and the head commit come back from one `gh pr view` call, because the three have to describe the same commit and reading them apart leaves a window where a push between them compares a body against another head's files.
|
|
28
|
+
|
|
29
|
+
That view caps its file list at 100 rows and says nothing about having done so, which was measured against `#1250`: the pull request carries 101 files and the view reports 100. A pull request at the cap therefore takes a second read through the paginated endpoint, and a failure there refuses with `gh-truncated` rather than comparing against a set known to be short. A set silently one file short is the worst input this takes, since the missing file is exactly what a correct bullet would then be accused of inventing.
|
|
30
|
+
|
|
31
|
+
## The two directions
|
|
32
|
+
|
|
33
|
+
They are reported apart because they want different tolerances.
|
|
34
|
+
|
|
35
|
+
- **`unmet`** is a whole path the body claims and the diff does not carry. This is the graded direction and it sets the exit code. A bullet naming an untouched file is wrong more often than not, and it corrupts the record that reaches the trunk.
|
|
36
|
+
- **`unnamed`** is a changed file no bullet reached. Reported with no grade, since the class covers a real omission and equally a lockfile, a generated asset, or a regenerated index that earns no bullet. Grading it would fire on nearly every branch.
|
|
37
|
+
- **`unresolved`** is a path written partially, such as `claude-worker/SKILL.md` for a file under `claude/skills/`. It is judged in neither direction.
|
|
38
|
+
|
|
39
|
+
A partial path can credit a changed file and can never accuse one. Nothing separates a path written short from a path written wrong, so the asymmetry keeps the accusing direction to spans the tree can anchor.
|
|
40
|
+
|
|
41
|
+
## What counts as a claim
|
|
42
|
+
|
|
43
|
+
Only `## Key Changes` is read. `## Technical Context` legitimately names files a branch never touched, such as an install stamp inside a target, so widening the read manufactures a finding out of every argument an author made for the change.
|
|
44
|
+
|
|
45
|
+
Inside the section, the claim region of a bullet ends at its first comma outside a backticked span. That one lever was chosen by measurement. Over the 23 merged pull requests in this repository carrying the section, reading whole bullets reported 16 paths as claimed-but-untouched and every one was a file the body named for context. Cutting at the comma left 110 claims of the original 149 and took the false reports to 2. A list of sixteen clause-opening words tried beside it removed nothing the comma had not already removed, because this corpus punctuates every one of them.
|
|
46
|
+
|
|
47
|
+
A span inside the claim region has to survive all of these:
|
|
48
|
+
|
|
49
|
+
| Rule | What it keeps out |
|
|
50
|
+
| ------------------------------------------------- | ------------------------------------------------------ |
|
|
51
|
+
| No whitespace, `<`, `>`, `$`, `*`, `\|`, `?`, `^` | A backticked command, a placeholder, a glob, a pattern |
|
|
52
|
+
| No `://` and no leading `/`, `~`, `@`, `#`, `!` | A URL, an absolute path, a module alias |
|
|
53
|
+
| Contains `/` | A bare filename with no folder around it |
|
|
54
|
+
| Extension starts with a letter, or ends with `/` | A dotted number such as an address |
|
|
55
|
+
| Not a single top-level folder | `src/`, which nobody claims to have rewritten whole |
|
|
56
|
+
| A `file:line` span leads its bullet | A citation into a file the bullet is describing |
|
|
57
|
+
| The region carries no no-change marker | A bullet recording a file it deliberately left alone |
|
|
58
|
+
|
|
59
|
+
The last three rows earn their place from the corpus rather than from a rule. Every body that spelled a lone top-level folder was naming where something lives, and a line citation that follows another claim in the same bullet points into the file being described rather than naming a second one. A line citation leading its bullet stays a claim, which is how a body names the exact line it rewrote.
|
|
60
|
+
|
|
61
|
+
The no-change marker is the one rule the region cut cannot substitute for. A body writes "Leave `x` untouched, since the decision keeps it" to record a change it declined, and the path sits ahead of the first comma, so a stricter cut would not reach it and a looser one would find more. Since `keep` and `leave` each open a real claim often enough, the marker decides it rather than the leading verb. Three words carry the set: `untouched`, `unchanged`, and `as written`. `in place` was measured and dropped, because rewriting a file in place is an ordinary claim, and `no other line` was dropped because a correct bullet writes "as one insertion that touches no other line" about a change it did make. `alone` shipped in the set too, until review found every corpus occurrence sitting past the first comma, where the cut already excludes it, so the word voided no true claim there. Restrictive use is the more common one in this repository's own prose, and a comma-free bullet exposed it: "Move the threshold read into `src/gate/stages.ts` alone" asserts an edit, and the marker voided it while the word was still in the set. Over the 40-pull-request corpus the rule still voids no true claim.
|
|
62
|
+
|
|
63
|
+
A folder claim covers every changed file beneath it. A bare filename drops outright: resolved as a sibling of a path earlier in its bullet it produced seven wrong paths across this corpus against two right ones, because a compound bullet names a sibling folder as often as a sibling file.
|
|
64
|
+
|
|
65
|
+
## Anchoring
|
|
66
|
+
|
|
67
|
+
A claim is anchored when its first segment names a folder the tree holds. The roots come from the tracked file list joined with the first segment of every changed path, and the second half is what admits a folder the branch created. Reading the tree alone would mark every claim under a new top-level directory unanchored, and an unanchored claim never accuses, so the first branch to open one would lose the graded direction with nothing reporting it.
|
|
68
|
+
|
|
69
|
+
## Exit codes and refusals
|
|
70
|
+
|
|
71
|
+
| Code | Meaning |
|
|
72
|
+
| ---- | ------------------------------------------------- |
|
|
73
|
+
| `0` | every claimed path is in the diff |
|
|
74
|
+
| `1` | refused, with `reason` naming the cause |
|
|
75
|
+
| `2` | at least one claimed path is absent from the diff |
|
|
76
|
+
|
|
77
|
+
Branch on the record rather than on the exit code. A shell function wrapping `canon` takes its status from whatever it runs last, so every non-zero exit can reach a caller as zero.
|
|
78
|
+
|
|
79
|
+
Three refusals separate a clean pass from a read that produced nothing:
|
|
80
|
+
|
|
81
|
+
- `no-section`. The body carries no such heading, so it claims nothing.
|
|
82
|
+
- `no-claims`. The heading is there and no span resolved, which is the extractor failing over prose rather than the body being wrong. Nothing is raised.
|
|
83
|
+
- `no-changes`. The pull request changed no files, so no claim has anything to answer.
|
|
84
|
+
|
|
85
|
+
An empty extraction read as a clean pass is the failure shape this repository has recorded twice, which is why the middle one is its own reason rather than a zero count.
|
|
86
|
+
|
|
87
|
+
`gh-missing`, `gh-failed`, `gh-truncated`, `unreadable-body`, `unreadable-tree`, `no-base`, `bad-base`, and `unreadable-changes` cover the reads that never reached a comparison.
|
|
88
|
+
|
|
89
|
+
## What it was measured against
|
|
90
|
+
|
|
91
|
+
Driven over the 40 most recent merged pull requests in this repository, 23 of which carry the section, the shipped verb reported zero unmet paths and one `no-claims` refusal. The naive extractor it replaced reported 16.
|
|
92
|
+
|
|
93
|
+
The first body written after that corpus closed produced two, which is what the no-change marker and the open class above come from. One was the disclaiming bullet and the rule now covers it at no cost to the corpus. The other is the definition-site class, left open with the report naming it.
|
|
94
|
+
|
|
95
|
+
The bound is that the corpus is one repository writing to one house style. A project that punctuates differently loses claims to the comma cut rather than gaining false ones, since every rule above drops rather than invents, so the check degrades toward silence rather than toward noise.
|
|
96
|
+
|
|
97
|
+
What it cannot see is a bullet claiming a change to a file the branch did touch for another reason, a path written without backticks, and a claim in a second coordinated clause after the comma. The last of those falls to the ungraded direction rather than out of the reading.
|
|
98
|
+
|
|
99
|
+
One class stays open and is named rather than closed. A bullet can cite where something is defined while claiming an edit somewhere else, as `#1274` does with "Name the slug transform in `standards/slug.md` inline in the same step". The path is a definition site, the edit target is the step, and separating the two needs the sentence parsed rather than cut. A finding on such a bullet is this class rather than a stale claim, and a reader weighing an `unmet` path checks whether the bullet's real target is a locative the path does not name.
|
|
100
|
+
|
|
101
|
+
## Where it runs
|
|
102
|
+
|
|
103
|
+
`claude-pr-review` Step 3 calls it and files an `unmet` path as a `should-fix` finding under the `**PR body**` block the stale ticked box already takes, since what both corrupt is the merge record rather than a file in the diff. A body is edited between pushes, so a finding names the head the comparison ran at.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Label coverage
|
|
3
|
+
description: Reading a changed set against the pull request label map, the two tables it matches, how a gap is separated from a decision, and why an absent map is an answer
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Label coverage
|
|
7
|
+
|
|
8
|
+
`canon labels audit` resolves the paths a branch changed against the label map a project declares, reports the labels the set earns, and names every path no row reaches. It closes a gap the map's own comment had predicted since the map shipped: nothing detected a surface added after the rows were written, so such a branch merged carrying no label and nobody heard about it.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
canon labels audit
|
|
12
|
+
canon labels audit --json
|
|
13
|
+
canon labels audit --base origin/main
|
|
14
|
+
canon labels audit src/cli.ts docs/index.md --json
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
| Option | Behavior |
|
|
18
|
+
| --------------- | ----------------------------------------------------------------- |
|
|
19
|
+
| `--base <ref>` | Far side of the range, defaulting to the merge base against trunk |
|
|
20
|
+
| `--root <path>` | Repository to read, defaulting to the current directory |
|
|
21
|
+
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
22
|
+
|
|
23
|
+
Positional paths replace the range entirely. A caller holding a changed set already passes it rather than paying for a second git read, and the record then omits `base` to say the range was never resolved.
|
|
24
|
+
|
|
25
|
+
Under `--json` the record holds stdout alone and the frame still renders on stderr, refusals included, which is the split `output-shape.md` fixes for every mode.
|
|
26
|
+
|
|
27
|
+
## The map it reads
|
|
28
|
+
|
|
29
|
+
The map sits at `.claude/canon/pr-labels.toml` and carries two tables. `[domains]` keys a label name to the path prefixes that earn it, and `[declined]` keys a reason to the prefixes that earn no label on purpose.
|
|
30
|
+
|
|
31
|
+
```toml
|
|
32
|
+
[domains]
|
|
33
|
+
api = ["services/api/"]
|
|
34
|
+
web = ["apps/web/", "packages/ui/"]
|
|
35
|
+
|
|
36
|
+
[declined]
|
|
37
|
+
release-managed = ["CHANGELOG.md", "package.json"]
|
|
38
|
+
generated = ["build/manifest.json"]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Matching is prefix-anchored, so a row written for an authoring root reaches nothing under the copy a project consumes. A path claimed by rows in both tables takes the label, since it already has a subject and reporting it as deliberately unlabelled would contradict the label the same run applies.
|
|
42
|
+
|
|
43
|
+
## A gap and a decision are different findings
|
|
44
|
+
|
|
45
|
+
The verb sorts every changed path into three buckets and keeps two of them apart:
|
|
46
|
+
|
|
47
|
+
- **Labelled.** At least one `[domains]` row reaches the path. It contributes its label and nothing else.
|
|
48
|
+
- **Declined.** A `[declined]` row reaches it. Somebody already decided the path earns no label, so the run names it and moves no exit code.
|
|
49
|
+
- **Uncovered.** Neither table reaches it. This is the finding, and it wants either a prefix on the row that owns its subject or a `[declined]` row carrying the reason.
|
|
50
|
+
|
|
51
|
+
Folding the last two together was the shape this replaced. A report that cannot tell a surface nobody has gotten to from one somebody refused is useful about neither, which is why the declined half moved out of the map's trailing comment and became data the command reads.
|
|
52
|
+
|
|
53
|
+
## The range it reads
|
|
54
|
+
|
|
55
|
+
The default range is the branch against the trunk, resolved as the merge base against `origin/main` and then local `main`. The changed set is that base diffed against the working tree, plus untracked files git does not ignore, rather than against `HEAD`.
|
|
56
|
+
|
|
57
|
+
Reading the working tree is what lets the check run before the branch commits, which is the moment a session adds the surface nobody covered. The set is a superset of `base..HEAD`, so a caller running after the commits still sees the whole branch.
|
|
58
|
+
|
|
59
|
+
## Exit codes and refusals
|
|
60
|
+
|
|
61
|
+
| Code | Meaning |
|
|
62
|
+
| ---- | ---------------------------------------------- |
|
|
63
|
+
| `0` | every changed path is labelled or declined |
|
|
64
|
+
| `1` | refused, with `reason` naming the cause |
|
|
65
|
+
| `2` | at least one changed path is reached by no row |
|
|
66
|
+
|
|
67
|
+
It reports and never gates. Whether an uncovered surface deserves a label is a judgment only whoever owns that surface can make, and a push failing on one teaches a contributor to route around the check while nothing about the surface has changed.
|
|
68
|
+
|
|
69
|
+
A project declaring no map refuses with `no-map`, which is an answer rather than a fault. Such a project is labelled silently by design, and treating the absence as a break would make the map mandatory for every target. `canon audits run` reads that one reason as an expected absence and every other refusal as a measure that did not run.
|
|
70
|
+
|
|
71
|
+
## What it does not measure
|
|
72
|
+
|
|
73
|
+
A prefix reaching no path is invisible here. A row left behind by a deleted folder stays in the map forever, and this verb has nothing to say about it. That is the map going stale from the other side and a second measure rather than this one.
|