@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
@@ -8,19 +8,28 @@ const BULLET_RUN_SCOPE = [
8
8
  /^(?:claude|\.claude)\/skills\/[^/]+\/references\/.+\.md$/,
9
9
  ]
10
10
 
11
+ /**
12
+ * The requirement beside each skill. Its findings gate only on a `GATED_PATHS`
13
+ * entry naming the file itself, so the prefix that gates a skill's body never
14
+ * sweeps in a requirement the rewrite has not reached yet.
15
+ */
16
+ const REQUIREMENT_SCOPE =
17
+ /^(?:claude|\.claude)\/skills\/[^/]+\/REQUIREMENT\.md$/
18
+
11
19
  /**
12
20
  * The tracked documents the density limits hold: the context entries, the docs
13
- * pages, the skill bodies and references of both skill trees, the tooling
14
- * seeds and stack references, the wiki, and the two root guides.
21
+ * pages, the skill bodies, references, and requirements of both skill trees,
22
+ * the tooling seeds and stack references, the wiki, and the two root guides.
15
23
  *
16
24
  * Rules stay out, since a rule is one imperative per bullet. So do
17
- * `CLAUDE.md`, the requirement and design records, a seed carrying one of
18
- * those three names, the changelog, the examples, and every `.canon/` record,
19
- * each with a shape and cap of its own. Named here and nowhere else, so the
20
- * audit, the gate stage reading its exit, and their tests read one scope.
25
+ * `CLAUDE.md`, the project requirement and design records, a seed carrying one
26
+ * of those three names, the changelog, the examples, and every `.canon/`
27
+ * record, each with a shape and cap of its own. Named here and nowhere else, so
28
+ * the audit, the gate stage reading its exit, and their tests read one scope.
21
29
  */
22
30
  const DENSITY_SCOPE = [
23
31
  ...BULLET_RUN_SCOPE,
32
+ REQUIREMENT_SCOPE,
24
33
  /^tooling\/[^/]+\/seeds\/(?:.+\/)?(?!(?:CLAUDE|REQUIREMENTS|DESIGN)\.md$)[^/]+\.md$/,
25
34
  /^tooling\/[^/]+\/reference\.md$/,
26
35
  /^wiki\/.+\.md$/,
@@ -105,35 +114,36 @@ export const GATED_PATHS: readonly string[] = [
105
114
  'claude/skills/docs-sync/references/readme.md',
106
115
  'claude/skills/document-health/SKILL.md',
107
116
  'claude/skills/document-health/references/axes.md',
108
- 'claude/skills/draft-and-pick/SKILL.md',
109
- 'claude/skills/draft-and-pick/references/live-arms.md',
110
- 'claude/skills/draft-doc/SKILL.md',
111
- 'claude/skills/draft-doc/references/context.md',
112
- 'claude/skills/draft-doc/references/docs.md',
113
- 'claude/skills/draft-doc/references/readme.md',
114
- 'claude/skills/draft-doc/references/readme/agent-facing.md',
115
- 'claude/skills/draft-doc/references/readme/application.md',
116
- 'claude/skills/draft-doc/references/readme/cli.md',
117
- 'claude/skills/draft-doc/references/readme/library.md',
118
- 'claude/skills/draft-doc/references/readme/plugin.md',
119
- 'claude/skills/draft-doc/references/requirements.md',
120
- 'claude/skills/draft-doc/references/wiki-kind.md',
121
- 'claude/skills/draft-doc/references/wiki.md',
122
- 'claude/skills/draft-figure/SKILL.md',
123
- 'claude/skills/draft-figure/references/architecture-set.md',
124
- 'claude/skills/draft-figure/references/figures.md',
125
- 'claude/skills/draft-figure/references/hand-drawn.md',
126
- 'claude/skills/draft-figure/references/mermaid-path.md',
127
- 'claude/skills/draft-figure/references/mermaid.md',
128
- 'claude/skills/draft-identity/SKILL.md',
129
- 'claude/skills/draft-identity/references/card-route.md',
130
- 'claude/skills/draft-ready/SKILL.md',
131
- 'claude/skills/draft-ready/references/assembly.md',
132
- 'claude/skills/draft-ready/references/ready.md',
133
- 'claude/skills/draft-screencast/SKILL.md',
134
- 'claude/skills/draft-screencast/references/beats-template.md',
135
- 'claude/skills/draft-slides/SKILL.md',
136
- 'claude/skills/draft-slides/references/deck.md',
117
+ 'claude/skills/pick-by-eye/REQUIREMENT.md',
118
+ 'claude/skills/pick-by-eye/SKILL.md',
119
+ 'claude/skills/pick-by-eye/references/live-arms.md',
120
+ 'claude/skills/write-doc/SKILL.md',
121
+ 'claude/skills/write-doc/references/context.md',
122
+ 'claude/skills/write-doc/references/docs.md',
123
+ 'claude/skills/write-doc/references/readme.md',
124
+ 'claude/skills/write-doc/references/readme/agent-facing.md',
125
+ 'claude/skills/write-doc/references/readme/application.md',
126
+ 'claude/skills/write-doc/references/readme/cli.md',
127
+ 'claude/skills/write-doc/references/readme/library.md',
128
+ 'claude/skills/write-doc/references/readme/plugin.md',
129
+ 'claude/skills/write-doc/references/requirements.md',
130
+ 'claude/skills/write-doc/references/wiki-kind.md',
131
+ 'claude/skills/write-doc/references/wiki.md',
132
+ 'claude/skills/draw-figure/SKILL.md',
133
+ 'claude/skills/draw-figure/references/architecture-set.md',
134
+ 'claude/skills/draw-figure/references/figures.md',
135
+ 'claude/skills/draw-figure/references/hand-drawn.md',
136
+ 'claude/skills/draw-figure/references/mermaid-path.md',
137
+ 'claude/skills/draw-figure/references/mermaid.md',
138
+ 'claude/skills/design-identity/SKILL.md',
139
+ 'claude/skills/design-identity/references/card-route.md',
140
+ 'claude/skills/plan-ready/SKILL.md',
141
+ 'claude/skills/plan-ready/references/assembly.md',
142
+ 'claude/skills/plan-ready/references/ready.md',
143
+ 'claude/skills/script-screencast/SKILL.md',
144
+ 'claude/skills/script-screencast/references/beats-template.md',
145
+ 'claude/skills/make-deck/SKILL.md',
146
+ 'claude/skills/make-deck/references/deck.md',
137
147
  'claude/skills/git-branch/SKILL.md',
138
148
  'claude/skills/git-branch/references/branch.md',
139
149
  'claude/skills/git-branch/references/slug.md',
@@ -195,6 +205,7 @@ export const GATED_PATHS: readonly string[] = [
195
205
  'claude/skills/review-ui/references/hosted-preview.md',
196
206
  'claude/skills/review-ui/references/post.md',
197
207
  'claude/skills/review-ui/references/tick.md',
208
+ 'claude/skills/role-orchestrator/REQUIREMENT.md',
198
209
  'claude/skills/role-orchestrator/SKILL.md',
199
210
  'claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md',
200
211
  'claude/skills/role-orchestrator/references/orchestrator-dispatch.md',
@@ -212,8 +223,10 @@ export const GATED_PATHS: readonly string[] = [
212
223
  'claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md',
213
224
  'claude/skills/role-orchestrator/references/orchestrator-sweep.md',
214
225
  'claude/skills/role-orchestrator/references/orchestrator-watch.md',
226
+ 'claude/skills/role-planner/REQUIREMENT.md',
215
227
  'claude/skills/role-planner/SKILL.md',
216
228
  'claude/skills/role-reviewer/SKILL.md',
229
+ 'claude/skills/role-worker/REQUIREMENT.md',
217
230
  'claude/skills/role-worker/SKILL.md',
218
231
  'claude/skills/search-craft/SKILL.md',
219
232
  'claude/skills/search-craft/references/adopted.md',
@@ -301,6 +314,7 @@ export function densityGates(
301
314
  gated: readonly string[] = GATED_PATHS,
302
315
  ): boolean {
303
316
  if (!inDensityScope(rel)) return false
317
+ if (REQUIREMENT_SCOPE.test(rel)) return gated.includes(rel)
304
318
  if (
305
319
  ALWAYS_GATED.includes(kind) &&
306
320
  BULLET_RUN_SCOPE.some((pattern) => pattern.test(rel))
@@ -346,7 +346,7 @@ function entriesOf(dir: string, isDirectory: boolean): string[] {
346
346
  }
347
347
 
348
348
  /**
349
- * What `draft-and-pick` Step 6 writes into the folder it archives a choice to:
349
+ * What `pick-by-eye` Step 6 writes into the folder it archives a choice to:
350
350
  * a capture per canvas frame, named `arm-<id>`. A design handoff marks a pick
351
351
  * folder an earlier skill wrote. A folder carrying neither is evidence.
352
352
  */
@@ -34,7 +34,7 @@ import {
34
34
  slugOf,
35
35
  } from '@/migrate/evidence-ordinal'
36
36
  import { presentFolders } from '@/records/backup'
37
- import { recordDir, SCRATCH } from '@/roots/record'
37
+ import { LEGACY_SCRATCH_REL, recordDir, SCRATCH } from '@/roots/record'
38
38
 
39
39
  /**
40
40
  * Every folder this promotion moves, at the name it carries under scratch.
@@ -64,9 +64,17 @@ export const PROMOTED_FOLDERS: readonly string[] = [
64
64
  'target-survey',
65
65
  ]
66
66
 
67
- /** Where a promoted folder sits before the move. */
67
+ /**
68
+ * Where a promoted folder sits before the move: `.canon/tmp` when it holds the
69
+ * folder, so a target part-way through a move promotes the newer copy, and the
70
+ * retired scratch folder otherwise. The verb is a migration, so it reads an
71
+ * unmigrated target where it is.
72
+ */
68
73
  export function sourcePath(root: string, folder: string): string {
69
- return recordDir(root, SCRATCH, folder)
74
+ const current = recordDir(root, SCRATCH, folder)
75
+ const legacy = join(root, LEGACY_SCRATCH_REL, folder)
76
+
77
+ return !existsSync(current) && existsSync(legacy) ? legacy : current
70
78
  }
71
79
 
72
80
  /** The folder a promoted one lands inside, under whichever root carries it. */
@@ -85,7 +93,7 @@ function escape(value: string): string {
85
93
  * swallowing a sibling folder whose name extends it.
86
94
  */
87
95
  const OLD_PREFIXES = [
88
- '.claude/.tmp/',
96
+ '.claude/.tmp/', // canon-keep-record-root
89
97
  '.canon/tmp/',
90
98
  '../.tmp/',
91
99
  '../tmp/',
@@ -13,13 +13,12 @@ import { defineRenameRules, type RenameRules } from '@/migrate/rename'
13
13
  * session roles together.
14
14
  *
15
15
  * The four `canon-` rows split the same way rather than sharing one
16
- * replacement prefix. `canon-screencast` and `canon-slides-draft` draft a
17
- * document, which is what the `draft-` family already means across its other
18
- * members, so they join it as `draft-screencast` and `draft-slides`.
19
- * `canon-record` and `canon-frames-read` are not drafting anything, so each
20
- * takes a standalone verb-first name, `record-screencast` and `read-frames`,
21
- * reading in sequence with `draft-screencast` as one three-step pipeline with
22
- * no prefix forcing that reading.
16
+ * replacement prefix. `canon-screencast` and `canon-slides-draft` each make
17
+ * an artifact, so each takes the verb-first name of what it makes,
18
+ * `script-screencast` and `make-deck`. `canon-record` and `canon-frames-read`
19
+ * take `record-screencast` and `read-frames`, reading in sequence with
20
+ * `script-screencast` as one three-step pipeline with no prefix forcing that
21
+ * reading.
23
22
  *
24
23
  * Two rows rename a skill rather than retiring a prefix. `ui-test` became
25
24
  * `ui-checklist` when the skill stopped writing tests and shrank to the
@@ -36,15 +35,25 @@ import { defineRenameRules, type RenameRules } from '@/migrate/rename'
36
35
  * Five rows merge skills rather than rename one. `draft-docs`,
37
36
  * `draft-context`, `draft-wireframes`, `draft-readme`, and `draft-wiki` ran
38
37
  * one procedure five times over, differing only in the standard each read and
39
- * the catalog each checked, so they became `draft-doc`, which picks the kind
40
- * from where the document lands. Every retired name lands on the one skill, so
41
- * a target citing any of them resolves after a single sweep.
38
+ * the catalog each checked, so they became one skill, which picks the kind
39
+ * from where the document lands. Every retired name lands on that skill, so a
40
+ * target citing any of them resolves after a single sweep.
42
41
  *
43
- * `draft-diagram` merged into `draft-figure` the same way, its architecture
42
+ * `draft-diagram` merged into the figure skill the same way, its architecture
44
43
  * views becoming one reference the figure skill reads. `claude-diagram` is
45
- * retargeted onto `draft-figure` rather than left on the retired name, for the
44
+ * retargeted onto the figure skill rather than left on a retired name, for the
46
45
  * same reason `claude-ui-test` was.
47
46
  *
47
+ * The `draft-` family then dissolved. Its seven members shared a verb rather
48
+ * than a phase or a role, so the prefix grouped a deck, a figure, a brand
49
+ * identity, a pick loop, and a thin plan under one word that said nothing
50
+ * about which of them a skill makes. Each took a verb-first name for its
51
+ * output instead: `write-doc`, `draw-figure`, `design-identity`, `make-deck`,
52
+ * `pick-by-eye`, `plan-ready`, and `script-screencast`. Every older key that
53
+ * landed on a `draft-` name is retargeted straight onto its new one, so a
54
+ * target on the oldest spelling lands in one pass rather than two.
55
+ * `draft-ready` alone keys on its namespaced forms below rather than here.
56
+ *
48
57
  * Every name takes two words. Ten of these would have landed as a bare single
49
58
  * word under a plain strip, and a bare word such as `review` or `docs` is a
50
59
  * substring of ordinary prose with no token left for a later sweep to find.
@@ -63,7 +72,7 @@ export const SKILL_NAME_MAP: Readonly<Record<string, string>> = {
63
72
  'claude-address-review': 'review-address',
64
73
  'claude-autoship': 'auto-ship',
65
74
  'claude-design-extract': 'design-extract',
66
- 'claude-diagram': 'draft-figure',
75
+ 'claude-diagram': 'draw-figure',
67
76
  'claude-docs': 'context-fold',
68
77
  'docs-fold': 'context-fold',
69
78
  'claude-feature': 'plan-feature',
@@ -87,16 +96,22 @@ export const SKILL_NAME_MAP: Readonly<Record<string, string>> = {
87
96
  'claude-ux-measure': 'ux-measure',
88
97
  'claude-worker': 'role-worker',
89
98
  'claude-worktree': 'session-worktree',
90
- 'canon-screencast': 'draft-screencast',
91
- 'canon-slides-draft': 'draft-slides',
99
+ 'canon-screencast': 'script-screencast',
100
+ 'canon-slides-draft': 'make-deck',
92
101
  'canon-record': 'record-screencast',
93
102
  'canon-frames-read': 'read-frames',
94
- 'draft-docs': 'draft-doc',
95
- 'draft-context': 'draft-doc',
96
- 'draft-wireframes': 'draft-doc',
97
- 'draft-readme': 'draft-doc',
98
- 'draft-wiki': 'draft-doc',
99
- 'draft-diagram': 'draft-figure',
103
+ 'draft-docs': 'write-doc',
104
+ 'draft-context': 'write-doc',
105
+ 'draft-wireframes': 'write-doc',
106
+ 'draft-readme': 'write-doc',
107
+ 'draft-wiki': 'write-doc',
108
+ 'draft-diagram': 'draw-figure',
109
+ 'draft-doc': 'write-doc',
110
+ 'draft-figure': 'draw-figure',
111
+ 'draft-identity': 'design-identity',
112
+ 'draft-slides': 'make-deck',
113
+ 'draft-and-pick': 'pick-by-eye',
114
+ 'draft-screencast': 'script-screencast',
100
115
  }
101
116
 
102
117
  /**
@@ -110,14 +125,42 @@ export const SKILL_NAME_MAP: Readonly<Record<string, string>> = {
110
125
  * guard rejects a following `-`, so a rewritten `canon:canvas-board` is not
111
126
  * matched again.
112
127
  *
128
+ * `draft-ready` became `plan-ready` and takes the same treatment for a
129
+ * different reason. It is two words, but they are ordinary prose for a pull
130
+ * request moving from draft to ready, and the sweep takes no scope in a
131
+ * target, so a bare key would rewrite that sentence in every tracked file a
132
+ * project wrote.
133
+ *
113
134
  * What this leaves behind is a prose mention of the skill by its bare name,
114
135
  * which has no token for a sweep to find and is fixed by hand.
115
136
  */
116
137
  export const SKILL_CITATION_MAP: Readonly<Record<string, string>> = {
117
138
  'canon:canvas': 'canon:canvas-board',
118
139
  'skills/canvas': 'skills/canvas-board',
140
+ 'canon:draft-ready': 'canon:plan-ready',
141
+ 'skills/draft-ready': 'skills/plan-ready',
119
142
  }
120
143
 
144
+ /**
145
+ * The old `draft-` names that still answer as a pointer skill, each naming the
146
+ * skill it became.
147
+ *
148
+ * Each pointer's own files spell the old name on purpose, so the sweep must
149
+ * never reach them. A later run would otherwise move the stub onto the real
150
+ * body at the new name. Their paths join the exclusions only once the sweep
151
+ * that moved the real bodies has run, since excluding them first leaves each
152
+ * body unmoved at its old path.
153
+ */
154
+ export const RENAMED_DRAFT_POINTERS: readonly string[] = [
155
+ 'draft-doc',
156
+ 'draft-figure',
157
+ 'draft-identity',
158
+ 'draft-slides',
159
+ 'draft-and-pick',
160
+ 'draft-ready',
161
+ 'draft-screencast',
162
+ ]
163
+
121
164
  /**
122
165
  * The skill rename.
123
166
  *
@@ -159,5 +202,9 @@ export const SKILL_NAME_RULES: RenameRules = defineRenameRules({
159
202
  'CHANGELOG.md',
160
203
  'src/migrate/skill-names.ts',
161
204
  'src/migrate/skill-names.test.ts',
205
+ ...RENAMED_DRAFT_POINTERS.flatMap((name) => [
206
+ `claude/skills/${name}/SKILL.md`,
207
+ `claude/skills/${name}/REQUIREMENT.md`,
208
+ ]),
162
209
  ],
163
210
  })
package/src/pr/frames.ts CHANGED
@@ -22,6 +22,9 @@ const ADD_ATTEMPTS = 3
22
22
  /** One half of a reference address. It opens on a letter or digit and holds no separator, so `..` and `/` cannot survive it. */
23
23
  const REFERENCE_PART = /^[A-Za-z0-9][A-Za-z0-9._-]*$/
24
24
 
25
+ /** A tracked reference, `canon/design/<surface>/<name>`, whose name may carry its `.png`. The halves are validated as a canvas address's are. */
26
+ const DESIGN_REFERENCE = /^canon\/design\/([^/]+)\/([^/]+?)(?:\.png)?$/
27
+
25
28
  const FOLDER_PATTERN = /^pr-(\d+)$/
26
29
 
27
30
  const DAY_MS = 86_400_000
@@ -163,20 +166,28 @@ export function frameLink(repo: string, path: string): string {
163
166
  }
164
167
 
165
168
  /**
166
- * The file-name slug of a `<page>/<frame>` address, or undefined when the
169
+ * The file-name slug of a `<page>/<frame>` address or a tracked
170
+ * `canon/design/<surface>/<name>` path, or undefined when the
167
171
  * address would not round-trip. Each half must open on a letter or digit and
168
172
  * hold only letters, digits, dots, underscores, and dashes, and neither may
169
173
  * carry `--`, so the joined slug reads back as the same two names and a path
170
174
  * never gains a directory or escapes the pass folder.
171
175
  */
172
176
  export function referenceSlug(address: string): string | undefined {
173
- const parts = address.split('/')
177
+ const tracked = DESIGN_REFERENCE.exec(address)
178
+ const parts = tracked ? [tracked[1], tracked[2]] : address.split('/')
174
179
  if (parts.length !== 2) return undefined
175
180
  const [page, frame] = parts as [string, string]
176
181
  const valid = [page, frame].every(
177
182
  (part) => REFERENCE_PART.test(part) && !part.includes('--'),
178
183
  )
179
- return valid ? `${page}--${frame}` : undefined
184
+ if (!valid) return undefined
185
+ return tracked ? `design--${page}--${frame}` : `${page}--${frame}`
186
+ }
187
+
188
+ /** Whether a reference names a tracked `canon/design/<surface>/<name>` file rather than a `<page>/<frame>` address. */
189
+ export function isDesignReference(address: string): boolean {
190
+ return DESIGN_REFERENCE.test(address)
180
191
  }
181
192
 
182
193
  /**
@@ -107,9 +107,9 @@ export const EXCLUDED_ENTRIES = [
107
107
  /**
108
108
  * Whether a top-level name stays out of every push, at either root.
109
109
  *
110
- * `SCRATCH` is the legacy `.tmp` spelling, which a records index opened before
111
- * the move can still carry and which `EXCLUDED_ENTRIES` names at its `.canon`
112
- * spelling only.
110
+ * `SCRATCH` is the retired `.tmp` spelling. It is a guard rather than a lookup,
111
+ * keeping a stray `.tmp` out of a push, and `EXCLUDED_ENTRIES` names the
112
+ * `.canon` spelling only.
113
113
  */
114
114
  function isExcluded(name: string): boolean {
115
115
  return (
@@ -208,6 +208,7 @@ const PLAN_SECTIONS = [
208
208
  'Summary',
209
209
  'Constraints',
210
210
  'Files to touch',
211
+ 'Design references',
211
212
  'Verification',
212
213
  'Risks',
213
214
  'Review focus',
@@ -226,6 +227,22 @@ const PLAN_REQUIRED: readonly PlanSection[] = [
226
227
  'Questions',
227
228
  ]
228
229
 
230
+ /**
231
+ * The files whose edit changes what a person sees, the set the `ui/a11y` and
232
+ * `ui/keyboard` rules glob plus the other markup and style extensions a plan
233
+ * names. A plan touching one owes a `Design references` section, so a set too wide forces it on every
234
+ * plan and one too narrow lets a UI plan skip it.
235
+ */
236
+ const RENDERED_SURFACE = /\.(?:tsx|jsx|astro|vue|svelte|html|css|scss)$/
237
+
238
+ export function touchesRenderedSurface(entries: readonly string[]): boolean {
239
+ return entries.some((entry) =>
240
+ [...entry.matchAll(/`([^`]+)`/g)].some((span) =>
241
+ RENDERED_SURFACE.test(span[1]),
242
+ ),
243
+ )
244
+ }
245
+
229
246
  /**
230
247
  * A line standing alone as a bold label or an H2, whatever it names. A plan is
231
248
  * free to carry a section of its own, so the split has to see one to close the
@@ -450,6 +467,20 @@ export function checkPlan(name: string, text: string): Finding[] {
450
467
  }
451
468
  }
452
469
 
470
+ if (
471
+ !sections.has('Design references') &&
472
+ touchesRenderedSurface(sections.get('Files to touch') ?? [])
473
+ ) {
474
+ findings.push(
475
+ finding(
476
+ 'section-missing',
477
+ name,
478
+ preferredMarker('Design references'),
479
+ 'is required when Files to touch names a rendered-surface file. Write None identified. when no reference folder governs it.',
480
+ ),
481
+ )
482
+ }
483
+
453
484
  for (const line of sections.get('Files to touch') ?? []) {
454
485
  const trimmed = line.trim()
455
486
  if (!trimmed.startsWith('- ') || trimmed === `- ${NONE_IDENTIFIED}`)
@@ -29,17 +29,22 @@ export type RecordRoot = (typeof RECORD_ROOTS)[number]
29
29
  export const CREATION_ROOT: RecordRoot = '.canon'
30
30
 
31
31
  /**
32
- * The deletable scratch folder, named at the spelling `.claude/` gives it.
32
+ * The deletable scratch folder, named at the spelling `.claude/` gave it.
33
33
  *
34
- * It is the one folder whose name differs by root, and callers name it at the
35
- * old spelling because `spell` is the only place the variant is decided. Inside
36
- * a dotted root the leading dot hides nothing already hidden and costs a bare
37
- * `ls` that omits the folder, so the move dropped it. Every other record folder
38
- * keeps its name, `.records.git` included, where the dot marks the mechanism
39
- * apart from a payload rather than hiding it.
34
+ * Scratch resolves at `.canon/tmp` only. The `.claude/.tmp` spelling is a
35
+ * migration source, named through `LEGACY_SCRATCH_REL` by the verbs that move
36
+ * it, and no lookup falls back to it. Callers still name the folder at this
37
+ * spelling because `spell` is the only place the variant is decided. Inside a
38
+ * dotted root the leading dot hides nothing already hidden and costs a bare
39
+ * `ls` that omits the folder, so the move dropped it. Every other record
40
+ * folder keeps its name, `.records.git` included, where the dot marks the
41
+ * mechanism apart from a payload rather than hiding it.
40
42
  */
41
43
  export const SCRATCH = '.tmp'
42
44
 
45
+ /** The retired scratch location, read only as the source of a migration. */
46
+ export const LEGACY_SCRATCH_REL = '.claude/.tmp' // canon-keep-record-root
47
+
43
48
  /** The scratch folder's name under `.canon/`. */
44
49
  const CANON_SCRATCH = 'tmp'
45
50
 
@@ -109,6 +114,8 @@ export function spell(root: RecordRoot, folder: string): string {
109
114
  * records it belongs to rather than at the creation default.
110
115
  */
111
116
  function rootOf(root: string, folder: string): RecordRoot {
117
+ if (folder === SCRATCH) return CREATION_ROOT
118
+
112
119
  return (
113
120
  RECORD_ROOTS.find((candidate) =>
114
121
  existsSync(join(root, candidate, spell(candidate, folder))),
@@ -147,7 +154,9 @@ export function recordDirs(
147
154
  folder: string,
148
155
  ...rest: string[]
149
156
  ): string[] {
150
- return RECORD_ROOTS.map((candidate) =>
157
+ const candidates = folder === SCRATCH ? [CREATION_ROOT] : RECORD_ROOTS
158
+
159
+ return candidates.map((candidate) =>
151
160
  join(root, candidate, spell(candidate, folder), ...rest),
152
161
  )
153
162
  }