@erclx/canon 5.43.0 → 5.45.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.
Files changed (245) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/backlog-triage/references/apply.md +6 -6
  4. package/claude/skills/canon-cli/SKILL.md +4 -5
  5. package/claude/skills/canvas-board/REQUIREMENT.md +1 -1
  6. package/claude/skills/canvas-board/SKILL.md +1 -1
  7. package/claude/skills/context-fold/references/context.md +1 -1
  8. package/claude/skills/create-skill/REQUIREMENT.md +1 -1
  9. package/claude/skills/create-skill/SKILL.md +2 -2
  10. package/claude/skills/create-skill/references/skill-requirement.md +68 -9
  11. package/claude/skills/create-skill/references/skill.md +1 -1
  12. package/claude/skills/design-identity/REQUIREMENT.md +40 -0
  13. package/claude/skills/design-identity/SKILL.md +138 -0
  14. package/claude/skills/{draft-identity → design-identity}/references/card-route.md +2 -2
  15. package/claude/skills/design-taste/REQUIREMENT.md +6 -6
  16. package/claude/skills/design-taste/SKILL.md +2 -2
  17. package/claude/skills/design-taste/references/kinds.md +1 -1
  18. package/claude/skills/design-taste/references/preflight.md +1 -1
  19. package/claude/skills/draft-and-pick/REQUIREMENT.md +8 -69
  20. package/claude/skills/draft-and-pick/SKILL.md +3 -153
  21. package/claude/skills/draft-doc/REQUIREMENT.md +9 -30
  22. package/claude/skills/draft-doc/SKILL.md +4 -76
  23. package/claude/skills/draft-figure/REQUIREMENT.md +8 -42
  24. package/claude/skills/draft-figure/SKILL.md +3 -77
  25. package/claude/skills/draft-identity/REQUIREMENT.md +8 -23
  26. package/claude/skills/draft-identity/SKILL.md +3 -130
  27. package/claude/skills/draft-ready/REQUIREMENT.md +8 -37
  28. package/claude/skills/draft-ready/SKILL.md +3 -128
  29. package/claude/skills/draft-screencast/REQUIREMENT.md +8 -23
  30. package/claude/skills/draft-screencast/SKILL.md +3 -62
  31. package/claude/skills/draft-slides/REQUIREMENT.md +8 -27
  32. package/claude/skills/draft-slides/SKILL.md +3 -72
  33. package/claude/skills/draw-figure/REQUIREMENT.md +59 -0
  34. package/claude/skills/draw-figure/SKILL.md +85 -0
  35. package/claude/skills/{draft-figure → draw-figure}/references/architecture-set.md +2 -2
  36. package/claude/skills/{draft-figure → draw-figure}/references/hand-drawn.md +2 -2
  37. package/claude/skills/{draft-figure → draw-figure}/references/mermaid-path.md +2 -2
  38. package/claude/skills/{draft-figure → draw-figure}/references/mermaid.md +1 -1
  39. package/claude/skills/make-deck/REQUIREMENT.md +44 -0
  40. package/claude/skills/make-deck/SKILL.md +80 -0
  41. package/claude/skills/markdown-craft/REQUIREMENT.md +1 -1
  42. package/claude/skills/markdown-craft/SKILL.md +2 -2
  43. package/claude/skills/pick-by-eye/REQUIREMENT.md +36 -0
  44. package/claude/skills/pick-by-eye/SKILL.md +161 -0
  45. package/claude/skills/plan-feature/SKILL.md +2 -1
  46. package/claude/skills/plan-feature/references/plan.md +24 -10
  47. package/claude/skills/plan-groundwork/SKILL.md +1 -1
  48. package/claude/skills/plan-intake/SKILL.md +1 -1
  49. package/claude/skills/plan-ready/REQUIREMENT.md +54 -0
  50. package/claude/skills/plan-ready/SKILL.md +136 -0
  51. package/claude/skills/{draft-ready → plan-ready}/references/assembly.md +1 -1
  52. package/claude/skills/{draft-ready → plan-ready}/references/ready.md +1 -1
  53. package/claude/skills/record-screencast/REQUIREMENT.md +3 -3
  54. package/claude/skills/record-screencast/SKILL.md +2 -2
  55. package/claude/skills/role-orchestrator/REQUIREMENT.md +16 -99
  56. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +5 -2
  57. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
  58. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +18 -13
  59. package/claude/skills/role-planner/REQUIREMENT.md +15 -73
  60. package/claude/skills/role-planner/SKILL.md +2 -1
  61. package/claude/skills/role-worker/REQUIREMENT.md +13 -41
  62. package/claude/skills/role-worker/SKILL.md +9 -0
  63. package/claude/skills/script-screencast/REQUIREMENT.md +40 -0
  64. package/claude/skills/script-screencast/SKILL.md +70 -0
  65. package/claude/skills/{draft-screencast → script-screencast}/references/beats-template.md +2 -2
  66. package/claude/skills/search-craft/REQUIREMENT.md +4 -4
  67. package/claude/skills/search-craft/SKILL.md +1 -1
  68. package/claude/skills/target-setup/SKILL.md +3 -2
  69. package/claude/skills/target-setup/references/detect.md +0 -1
  70. package/claude/skills/target-setup/references/verify.md +2 -2
  71. package/claude/skills/task-board/SKILL.md +11 -9
  72. package/claude/skills/task-board/references/board.md +15 -12
  73. package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
  74. package/claude/skills/teach-workspace/SKILL.md +1 -1
  75. package/claude/skills/teach-workspace/references/lesson-craft.md +2 -2
  76. package/claude/skills/teach-workspace/references/promotion.md +5 -5
  77. package/claude/skills/ui-checklist/SKILL.md +2 -0
  78. package/claude/skills/write-doc/REQUIREMENT.md +46 -0
  79. package/claude/skills/write-doc/SKILL.md +83 -0
  80. package/claude/skills/{draft-doc → write-doc}/references/context.md +2 -2
  81. package/claude/skills/{draft-doc → write-doc}/references/docs.md +2 -2
  82. package/claude/skills/{draft-doc → write-doc}/references/readme.md +2 -2
  83. package/claude/skills/{draft-doc → write-doc}/references/wiki-kind.md +3 -3
  84. package/docs/agents/install-and-sync.md +2 -2
  85. package/docs/agents/markdown-audit.md +4 -2
  86. package/docs/agents/migrate.md +2 -2
  87. package/docs/agents/output-shape.md +1 -2
  88. package/docs/target/migrations.md +35 -4
  89. package/docs/target/projects.md +2 -3
  90. package/docs/target/scenarios.md +4 -1
  91. package/docs/workflow/parallel-features.md +3 -2
  92. package/docs/workflow/skill-map-on-request.md +19 -13
  93. package/docs/workflow/skill-map.md +13 -12
  94. package/docs/workflow/visual-design-workflow.md +2 -2
  95. package/governance/detect.toml +4 -0
  96. package/governance/ledger/framework/astro.md +73 -0
  97. package/governance/ledger/framework/fastapi.md +76 -0
  98. package/governance/ledger/framework/nextjs.md +86 -0
  99. package/governance/ledger/framework/react.md +83 -0
  100. package/governance/ledger/framework/shadcn.md +60 -0
  101. package/governance/ledger/framework/tailwind.md +55 -0
  102. package/governance/ledger/lang/go.md +61 -0
  103. package/governance/ledger/lang/php.md +50 -0
  104. package/governance/ledger/lang/python.md +68 -0
  105. package/governance/ledger/lang/typescript.md +64 -0
  106. package/governance/ledger/lib/database.md +65 -0
  107. package/governance/ledger/lib/e2e-reliability.md +57 -0
  108. package/governance/ledger/lib/pydantic.md +61 -0
  109. package/governance/ledger/lib/security-server.md +62 -0
  110. package/governance/ledger/lib/security-web.md +51 -0
  111. package/governance/ledger/lib/tanstack-query.md +57 -0
  112. package/governance/ledger/lib/test-scope.md +43 -0
  113. package/governance/ledger/lib/testing-go.md +57 -0
  114. package/governance/ledger/lib/testing-php.md +51 -0
  115. package/governance/ledger/lib/testing-py.md +67 -0
  116. package/governance/ledger/lib/testing-ts.md +63 -0
  117. package/governance/ledger/lib/zod.md +47 -0
  118. package/governance/ledger/tooling/ci-workflow.md +33 -0
  119. package/governance/ledger/tooling/code-comments.md +48 -0
  120. package/governance/ledger/tooling/config-comments.md +27 -0
  121. package/governance/ledger/tooling/dependencies.md +38 -0
  122. package/governance/ledger/ui/a11y.md +55 -0
  123. package/governance/ledger/ui/copy.md +49 -0
  124. package/governance/ledger/ui/design-reference.md +42 -0
  125. package/governance/ledger/ui/design-taste.md +19 -0
  126. package/governance/ledger/ui/forms.md +71 -0
  127. package/governance/ledger/ui/interface-casing.md +47 -0
  128. package/governance/ledger/ui/keyboard.md +68 -0
  129. package/governance/ledger/ui/link-behavior.md +29 -0
  130. package/governance/ledger/ui/motion.md +33 -0
  131. package/governance/ledger/ui/surface-capture.md +69 -0
  132. package/governance/ledger/ui/ux-completeness.md +79 -0
  133. package/governance/rules/framework/astro.md +12 -14
  134. package/governance/rules/framework/fastapi.md +20 -24
  135. package/governance/rules/framework/nextjs.md +19 -27
  136. package/governance/rules/framework/react.md +22 -33
  137. package/governance/rules/framework/shadcn.md +11 -15
  138. package/governance/rules/framework/tailwind.md +12 -14
  139. package/governance/rules/lang/go.md +7 -16
  140. package/governance/rules/lang/php.md +3 -3
  141. package/governance/rules/lang/python.md +9 -18
  142. package/governance/rules/lang/typescript.md +9 -19
  143. package/governance/rules/lib/database.md +5 -5
  144. package/governance/rules/lib/e2e-reliability.md +4 -6
  145. package/governance/rules/lib/pydantic.md +14 -16
  146. package/governance/rules/lib/security-server.md +4 -4
  147. package/governance/rules/lib/security-web.md +6 -10
  148. package/governance/rules/lib/tanstack-query.md +10 -12
  149. package/governance/rules/lib/test-scope.md +4 -4
  150. package/governance/rules/lib/testing-go.md +1 -2
  151. package/governance/rules/lib/testing-php.md +4 -5
  152. package/governance/rules/lib/testing-py.md +11 -19
  153. package/governance/rules/lib/testing-ts.md +7 -16
  154. package/governance/rules/lib/zod.md +6 -8
  155. package/governance/rules/tooling/code-comments.md +2 -4
  156. package/governance/rules/tooling/config-comments.md +1 -4
  157. package/governance/rules/tooling/dependencies.md +1 -1
  158. package/governance/rules/ui/a11y.md +16 -45
  159. package/governance/rules/ui/copy.md +6 -9
  160. package/governance/rules/ui/forms.md +13 -19
  161. package/governance/rules/ui/interface-casing.md +5 -7
  162. package/governance/rules/ui/keyboard.md +38 -0
  163. package/governance/rules/ui/link-behavior.md +3 -3
  164. package/governance/rules/ui/motion.md +3 -3
  165. package/governance/rules/ui/surface-capture.md +15 -27
  166. package/governance/rules/ui/ux-completeness.md +16 -39
  167. package/governance/rules/writing/markdown.md +1 -1
  168. package/package.json +1 -1
  169. package/scripts/core/install-check.sh +1 -1
  170. package/src/claude/cases/authoring.ts +15 -3
  171. package/src/claude/cases/misc.ts +12 -0
  172. package/src/claude/cases/workflow.ts +19 -1
  173. package/src/claude/skills-audit.ts +113 -1
  174. package/src/cli/help.ts +0 -1
  175. package/src/cli.ts +0 -2
  176. package/src/commands/claude.ts +34 -11
  177. package/src/commands/demo.ts +1 -1
  178. package/src/commands/gov.ts +4 -0
  179. package/src/commands/init.ts +2 -2
  180. package/src/commands/markdown.ts +1 -1
  181. package/src/commands/migrate.ts +4 -0
  182. package/src/commands/pr.ts +30 -6
  183. package/src/commands/tasks.ts +383 -2
  184. package/src/commands/tooling.ts +18 -5
  185. package/src/context/audit.ts +1 -1
  186. package/src/demo/beats.ts +1 -1
  187. package/src/design/components.ts +1 -1
  188. package/src/gov/audit.ts +25 -4
  189. package/src/init/plan.ts +1 -8
  190. package/src/init/steps.ts +0 -8
  191. package/src/inventory/subjects.ts +1 -1
  192. package/src/markdown/scope.ts +49 -35
  193. package/src/migrate/record-layout.ts +1 -1
  194. package/src/migrate/scratch-evidence.ts +12 -4
  195. package/src/migrate/skill-names.ts +68 -21
  196. package/src/pr/frames.ts +14 -3
  197. package/src/records/backup.ts +3 -3
  198. package/src/records/validate.ts +31 -0
  199. package/src/roots/record.ts +17 -8
  200. package/src/tasks/board.ts +854 -0
  201. package/src/tasks/record.ts +20 -1
  202. package/src/tasks/validate.ts +206 -9
  203. package/src/tooling/inject.ts +26 -7
  204. package/src/tooling/package.ts +32 -0
  205. package/src/tooling/read.ts +46 -3
  206. package/src/tooling/scan.ts +8 -2
  207. package/tooling/astro/configs/card-src/pages/og-card.astro +1 -1
  208. package/tooling/astro/reference.md +64 -93
  209. package/tooling/base/configs/.github/workflows/phase-label-gate.yml +1 -1
  210. package/tooling/base/configs/scripts/verify.ts +1 -1
  211. package/tooling/base/reference.md +1 -9
  212. package/tooling/base/seeds/canon/context/{ci.md → development/ci.md} +1 -1
  213. package/tooling/base/seeds/canon/context/development/index.md +11 -0
  214. package/tooling/base/seeds/canon/context/{development.md → development/setup.md} +8 -12
  215. package/tooling/base/seeds/canon/context/index.md +1 -2
  216. package/tooling/claude/manifest.toml +1 -5
  217. package/tooling/claude/reference.md +36 -59
  218. package/tooling/claude/seeds/.claude/hooks/board-validate.sh +65 -0
  219. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +2 -7
  220. package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +2 -7
  221. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +3 -10
  222. package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +2 -7
  223. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -4
  224. package/tooling/claude/seeds/.claude/settings.json +4 -0
  225. package/tooling/nextjs/reference.md +0 -6
  226. package/tooling/php/reference.md +0 -4
  227. package/tooling/web/configs/.github/workflows/verify.yml +28 -0
  228. package/tooling/web/configs/.oxlintrc.json +7 -0
  229. package/tooling/web/configs/e2e/capture-types.ts +35 -0
  230. package/tooling/web/configs/e2e/screenshot.ts +23 -72
  231. package/tooling/web/manifest.toml +1 -1
  232. package/tooling/web/reference.md +77 -124
  233. package/tooling/web/seeds/e2e/capture/cases.ts +47 -0
  234. package/src/commands/wiki.ts +0 -100
  235. package/src/wiki/init.ts +0 -85
  236. /package/claude/skills/{draft-figure → draw-figure}/references/figures.md +0 -0
  237. /package/claude/skills/{draft-slides → make-deck}/references/deck.md +0 -0
  238. /package/claude/skills/{draft-and-pick → pick-by-eye}/references/live-arms.md +0 -0
  239. /package/claude/skills/{draft-doc → write-doc}/references/readme/agent-facing.md +0 -0
  240. /package/claude/skills/{draft-doc → write-doc}/references/readme/application.md +0 -0
  241. /package/claude/skills/{draft-doc → write-doc}/references/readme/cli.md +0 -0
  242. /package/claude/skills/{draft-doc → write-doc}/references/readme/library.md +0 -0
  243. /package/claude/skills/{draft-doc → write-doc}/references/readme/plugin.md +0 -0
  244. /package/claude/skills/{draft-doc → write-doc}/references/requirements.md +0 -0
  245. /package/claude/skills/{draft-doc → write-doc}/references/wiki.md +0 -0
package/src/cli/help.ts CHANGED
@@ -29,7 +29,6 @@ export const COMMAND_GROUPS: { title: string; rows: CommandRow[] }[] = [
29
29
  ['gov [cmd]', 'Governance rules'],
30
30
  ['tooling [cmd]', 'Tooling stacks'],
31
31
  ['claude [cmd]', 'Claude workflow'],
32
- ['wiki [cmd]', 'Wiki pages'],
33
32
  ['indexes [cmd]', 'Regenerate index.md files'],
34
33
  ['docs [cmd|topic]', 'Emit toolkit reference docs'],
35
34
  ],
package/src/cli.ts CHANGED
@@ -7,7 +7,6 @@ import { register as sync } from '@/commands/sync'
7
7
  import { register as gov } from '@/commands/gov'
8
8
  import { register as tooling } from '@/commands/tooling'
9
9
  import { register as claude } from '@/commands/claude'
10
- import { register as wiki } from '@/commands/wiki'
11
10
  import { register as indexes } from '@/commands/indexes'
12
11
  import { register as docs } from '@/commands/docs'
13
12
  import { register as design } from '@/commands/design'
@@ -68,7 +67,6 @@ sync(program)
68
67
  gov(program)
69
68
  tooling(program)
70
69
  claude(program)
71
- wiki(program)
72
70
  indexes(program)
73
71
  docs(program)
74
72
  design(program)
@@ -32,7 +32,9 @@ import {
32
32
  PRACTICE_LEDGER,
33
33
  PRACTICE_SECTIONS,
34
34
  PRACTICE_SKILLS,
35
+ REQUIREMENT_LIMITS,
35
36
  REQUIREMENT_SECTIONS,
37
+ RETIRED_REQUIREMENT_SECTION,
36
38
  SHIPPED_CORPUS,
37
39
  type SkillFinding,
38
40
  type SkillsAudit,
@@ -441,7 +443,7 @@ export function register(program: Command): void {
441
443
  'Refuses when neither claude/skills/ nor .claude/skills/ resolves.',
442
444
  '',
443
445
  'Only a missing REQUIREMENT.md sets a failing exit code. Name, description,',
444
- 'folder, and requirement-section findings are advisory.',
446
+ 'folder, and requirement shape and limit findings are advisory.',
445
447
  '',
446
448
  'Examples:',
447
449
  ' canon claude skills audit',
@@ -1503,6 +1505,7 @@ async function runSkillsAudit(
1503
1505
  readme: report.readme,
1504
1506
  folderName: report.folderName,
1505
1507
  requirementSections: report.requirementSections,
1508
+ requirementLimits: report.requirementLimits,
1506
1509
  datedProvenance: report.datedProvenance,
1507
1510
  practiceShape: report.practiceShape,
1508
1511
  referenceContents: report.referenceContents,
@@ -1511,6 +1514,7 @@ async function runSkillsAudit(
1511
1514
  checkpoints: {
1512
1515
  descriptionLimit: DESCRIPTION_LIMIT,
1513
1516
  requirementSections: REQUIREMENT_SECTIONS,
1517
+ requirementLimits: REQUIREMENT_LIMITS,
1514
1518
  corpora: CORPORA,
1515
1519
  practiceSkills: PRACTICE_SKILLS,
1516
1520
  ledgerSkills: LEDGER_SKILLS,
@@ -1671,21 +1675,40 @@ function reportRequirementShape(report: SkillsAudit): void {
1671
1675
  'A folder carrying no requirement is reported above rather than counted twice here.',
1672
1676
  )
1673
1677
 
1674
- if (report.requirementSections.length === 0) {
1675
- logInfo('Every requirement declares both.')
1678
+ logInfo(
1679
+ `Each list holds at most ${REQUIREMENT_LIMITS.bullets} top-level bullets, the body at most ${REQUIREMENT_LIMITS.words} words, and Gap no date or issue number outside a code span.`,
1680
+ )
1681
+ logInfo(
1682
+ `A ## ${RETIRED_REQUIREMENT_SECTION} section is retired into Must not. These limits report and never fail the run.`,
1683
+ )
1684
+
1685
+ if (
1686
+ report.requirementSections.length === 0 &&
1687
+ report.requirementLimits.length === 0
1688
+ ) {
1689
+ logInfo('Every requirement declares both and holds to the limits.')
1676
1690
  return
1677
1691
  }
1678
1692
 
1679
- logWarn(
1680
- `${plural(report.requirementSections.length, 'requirement')} short a declared section`,
1681
- )
1682
- reportFindings(report.requirementSections)
1693
+ if (report.requirementSections.length > 0) {
1694
+ logWarn(
1695
+ `${plural(report.requirementSections.length, 'requirement')} short a declared section`,
1696
+ )
1697
+ reportFindings(report.requirementSections)
1698
+ }
1699
+
1700
+ if (report.requirementLimits.length > 0) {
1701
+ logWarn(
1702
+ `${plural(report.requirementLimits.length, 'finding')} past a requirement limit`,
1703
+ )
1704
+ reportFindings(report.requirementLimits)
1705
+ }
1683
1706
  }
1684
1707
 
1685
1708
  /**
1686
- * Names where the date belongs, since the finding is a date to move rather
1687
- * than one to delete, and reports without failing the run for the same reason
1688
- * the frontmatter measures do.
1709
+ * Names where the date belongs, since a reader deleting it should know git
1710
+ * still holds it, and reports without failing the run for the same reason the
1711
+ * frontmatter measures do.
1689
1712
  */
1690
1713
  function reportProvenance(report: SkillsAudit): void {
1691
1714
  logStep('Provenance')
@@ -1693,7 +1716,7 @@ function reportProvenance(report: SkillsAudit): void {
1693
1716
  'A SKILL.md and its references state the current rule, with no ISO date outside a fence or code span.',
1694
1717
  )
1695
1718
  logInfo(
1696
- 'The incident and date that earned a rule go in REQUIREMENT.md under Gap, or stay in git.',
1719
+ 'The incident and date that earned a rule stay in git, where the log of the file finds them.',
1697
1720
  )
1698
1721
 
1699
1722
  if (report.datedProvenance.length === 0) {
@@ -62,7 +62,7 @@ export function register(program: Command): void {
62
62
  demo
63
63
  .command('compile')
64
64
  .description('Turn a screencast draft into a plan a run can drive')
65
- .argument('<draft>', 'Screencast draft written by draft-screencast')
65
+ .argument('<draft>', 'Screencast draft written by script-screencast')
66
66
  .helpOption('-h, --help', 'Show this help message')
67
67
  .option('-o, --out <dir>', 'Directory the plan is written to', DEFAULT_OUT)
68
68
  .option('-s, --slug <slug>', 'Plan name, defaulting to the draft filename')
@@ -37,6 +37,7 @@ import {
37
37
  hasFinding,
38
38
  PRACTICE_FOLDERS,
39
39
  readRuleAudit,
40
+ RULE_GATE_EXEMPT,
40
41
  RULE_GATED_FOLDERS,
41
42
  RULE_LIMITS,
42
43
  type RuleAuditReport,
@@ -631,6 +632,7 @@ export function register(program: Command): void {
631
632
  ' inside it.',
632
633
  '',
633
634
  `Gated folders: ${RULE_GATED_FOLDERS.length === 0 ? 'none yet' : RULE_GATED_FOLDERS.join(', ')}`,
635
+ `Exempt from the gate: ${RULE_GATE_EXEMPT.length === 0 ? 'none' : RULE_GATE_EXEMPT.join(', ')}`,
634
636
  '',
635
637
  'Exit codes:',
636
638
  ' 0 no finding, or under --gate no finding in a gated folder',
@@ -691,6 +693,7 @@ async function runAudit(
691
693
  root,
692
694
  limits: RULE_LIMITS,
693
695
  gated: RULE_GATED_FOLDERS,
696
+ exempt: RULE_GATE_EXEMPT,
694
697
  ...report,
695
698
  })}\n`,
696
699
  )
@@ -699,6 +702,7 @@ async function runAudit(
699
702
  return auditExit(report, {
700
703
  gate: opts.gate ?? false,
701
704
  gated: RULE_GATED_FOLDERS,
705
+ exempt: RULE_GATE_EXEMPT,
702
706
  })
703
707
  }
704
708
 
@@ -39,8 +39,8 @@ export function register(program: Command): void {
39
39
  '',
40
40
  'Runs `canon tooling sync base --write` first, which replaces every',
41
41
  'base golden config the target holds, then `canon claude init`,',
42
- '`canon gov install`, and `canon wiki init`. Refuses a target that is',
43
- 'not a directory or is the toolkit root.',
42
+ 'and `canon gov install`. Refuses a target that is not a directory or is',
43
+ 'the toolkit root.',
44
44
  '',
45
45
  'Exit codes:',
46
46
  ' 0 every domain installed, or the prompt was cancelled',
@@ -486,7 +486,7 @@ function reportDensity(reports: readonly FileReport[], gates: boolean): void {
486
486
  `Paragraphs past ${CHECKPOINTS.paragraph} characters, more than 2 paragraphs in a row, bullets past ${CHECKPOINTS.bullet} characters, more than 5 plain bullets in a row, a heading past H3, and an H3 opening with neither a paragraph nor a table.`,
487
487
  )
488
488
  logInfo(
489
- 'Measured on context entries, docs, skill bodies and references, tooling seeds and stack references, the wiki, README.md, and CONTRIBUTING.md. Every other path takes no density finding.',
489
+ 'Measured on context entries, docs, skill bodies, references, and requirements, tooling seeds and stack references, the wiki, README.md, and CONTRIBUTING.md. Every other path takes no density finding.',
490
490
  )
491
491
  logInfo(
492
492
  gates
@@ -1335,6 +1335,10 @@ export function register(program: Command): void {
1335
1335
  '',
1336
1336
  `Rewrites ${Object.keys(SKILL_NAME_MAP).length} skill names and moves the folders that carry them.`,
1337
1337
  `It also carries ${Object.keys(SKILL_CITATION_MAP).length} namespaced-only rows for a skill renamed from a single word.`,
1338
+ 'The seven draft- skills move onto verb-first names, such as',
1339
+ // The old spellings below are the rename itself. canon-keep-retired
1340
+ 'draft-doc to write-doc and draft-and-pick to pick-by-eye, and a',
1341
+ 'pointer left under each old name is never moved.',
1338
1342
  'It takes no scope. The skill folders it moves are authored in the',
1339
1343
  'toolkit and no target holds a copy of that catalog, so in a target it',
1340
1344
  'rewrites citations of a renamed skill and moves nothing.',
@@ -1,4 +1,4 @@
1
- import { existsSync } from 'node:fs'
1
+ import { existsSync, statSync } from 'node:fs'
2
2
  import { readFile, realpath } from 'node:fs/promises'
3
3
  import { basename, join, resolve } from 'node:path'
4
4
  import { $ } from 'bun'
@@ -57,6 +57,7 @@ import {
57
57
  pruneFramesWithLegacy,
58
58
  pushFrame,
59
59
  readFrame,
60
+ isDesignReference,
60
61
  referenceSlug,
61
62
  type TreeEntry,
62
63
  } from '@/pr/frames'
@@ -222,9 +223,9 @@ const FRAMES_REFUSALS: Record<FramesCommandRefusal, string> = {
222
223
  'no-number':
223
224
  '--add and --drop write for one pull request, so name its number.',
224
225
  'bad-box':
225
- '--add takes --box <n>, a positive whole number naming the checklist box, or --reference <page>/<frame>, never both.',
226
+ '--add takes --box <n>, a positive whole number naming the checklist box, or --reference, as <page>/<frame> or a tracked canon/design/<surface>/<name> path, never both.',
226
227
  'bad-reference':
227
- '--reference takes <page>/<frame>, each half opening on a letter or digit and holding only letters, digits, dots, underscores, and dashes, with no `--` in either, so the capture files under a name that reads back as the frame.',
228
+ '--reference takes <page>/<frame> or a tracked canon/design/<surface>/<name> path, each half opening on a letter or digit and holding only letters, digits, dots, underscores, and dashes, with no `--` in either, so the capture files under a name that reads back as the frame.',
228
229
  'bad-head':
229
230
  '--head takes a commit sha, 7 to 40 lowercase hex characters. A branch name or a path would file the frame under a folder that names no commit.',
230
231
  'bad-pass':
@@ -1060,7 +1061,7 @@ export function register(program: Command): void {
1060
1061
  .option('--box <n>', 'The checklist box the frame shows, with --add')
1061
1062
  .option(
1062
1063
  '--reference <address>',
1063
- 'The design reference the capture shows, as <page>/<frame>, with --add in place of --box',
1064
+ 'The design reference the capture shows, as <page>/<frame> or a tracked canon/design/<surface>/<name> path, with --add in place of --box',
1064
1065
  )
1065
1066
  .option(
1066
1067
  '--head <sha>',
@@ -1087,7 +1088,9 @@ export function register(program: Command): void {
1087
1088
  'so nothing is checked out and no other branch is touched. A frame lands',
1088
1089
  'at pr-<number>/<short-head>/<pass>/box-<n>.png, or box-<n>-<theme>.png',
1089
1090
  'with --theme, or ref-<page>--<frame>.png for a design reference capture',
1090
- 'passed as --reference <page>/<frame> in place of --box, and `link` names that',
1091
+ 'passed as --reference <page>/<frame> in place of --box, or',
1092
+ 'ref-design--<surface>--<name>.png for a tracked canon/design/<surface>/<name>',
1093
+ 'reference, whose --add must name that same file, and `link` names that',
1091
1094
  `path on ${FRAMES_BRANCH}, so it survives a rewrite that drops other pull`,
1092
1095
  'requests and resolves until its own pull request is dropped. The pass',
1093
1096
  'segment keeps a second pass at one head and box from replacing an image',
@@ -1109,7 +1112,7 @@ export function register(program: Command): void {
1109
1112
  ' bad-mode not exactly one of --add, --drop, --prune',
1110
1113
  ' no-number --add or --drop named no pull request',
1111
1114
  ' bad-box --add with both --box and --reference, or neither',
1112
- ' bad-reference --reference is not <page>/<frame> in the safe name form',
1115
+ ' bad-reference --reference is not <page>/<frame> or canon/design/<surface>/<name> in the safe name form, or the tracked path is no file',
1113
1116
  ' bad-head --head is not 7 to 40 lowercase hex characters',
1114
1117
  ' bad-pass --add without a compact UTC --pass stamp',
1115
1118
  ' bad-theme --theme is not dark or light, or no --add, or rides a --reference',
@@ -3192,6 +3195,27 @@ async function runFrames(
3192
3195
  const invalid = framesArgumentRefusal(number, opts)
3193
3196
  if (invalid !== undefined) return refuseFrames(invalid)
3194
3197
 
3198
+ if (opts.reference !== undefined && isDesignReference(opts.reference)) {
3199
+ const tracked = resolve(
3200
+ root,
3201
+ opts.reference.endsWith('.png')
3202
+ ? opts.reference
3203
+ : `${opts.reference}.png`,
3204
+ )
3205
+ const refuseTracked = (message: string) =>
3206
+ refuseWith('bad-reference', message, emitJson, root)
3207
+ if (!statSync(tracked, { throwIfNoEntry: false })?.isFile()) {
3208
+ return refuseTracked(
3209
+ `${opts.reference} is not a file under the repository, so no tracked reference can be filed from it.`,
3210
+ )
3211
+ }
3212
+ if (opts.add === undefined || resolve(opts.add) !== tracked) {
3213
+ return refuseTracked(
3214
+ `--add must name ${tracked}, since a tracked reference files its own image and a different one would disagree with its label.`,
3215
+ )
3216
+ }
3217
+ }
3218
+
3195
3219
  const bytes =
3196
3220
  opts.add === undefined ? undefined : await readFrame(resolve(opts.add))
3197
3221
  if (opts.add !== undefined && bytes === undefined) {