@erclx/canon 5.61.0 → 5.63.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 (87) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -1
  3. package/claude/.claude-plugin/plugin.json +1 -1
  4. package/claude/skills/canon-cli/SKILL.md +2 -1
  5. package/claude/skills/create-skill/references/skill-practice.md +1 -0
  6. package/claude/skills/design-identity/references/card-route.md +3 -3
  7. package/claude/skills/design-record/references/design.md +1 -1
  8. package/claude/skills/design-taste/REQUIREMENT.md +2 -1
  9. package/claude/skills/design-taste/SKILL.md +6 -5
  10. package/claude/skills/design-taste/references/adopted.md +136 -8
  11. package/claude/skills/design-taste/references/craft.md +1 -1
  12. package/claude/skills/design-taste/references/kinds.md +8 -2
  13. package/claude/skills/design-taste/references/preflight.md +3 -3
  14. package/claude/skills/design-taste/references/tells.md +26 -5
  15. package/claude/skills/plan-feature/SKILL.md +2 -2
  16. package/claude/skills/plan-feature/references/plan.md +24 -3
  17. package/claude/skills/review-craft/SKILL.md +1 -1
  18. package/claude/skills/role-worker/SKILL.md +2 -1
  19. package/claude/skills/target-update/SKILL.md +9 -1
  20. package/claude/skills/ui-checklist/SKILL.md +1 -1
  21. package/claude/skills/ui-craft/REQUIREMENT.md +29 -0
  22. package/claude/skills/ui-craft/SKILL.md +44 -0
  23. package/{governance/rules/ui → claude/skills/ui-craft/references}/a11y.md +2 -10
  24. package/claude/skills/ui-craft/references/adopted.md +27 -0
  25. package/{governance/rules/ui/surface-capture.md → claude/skills/ui-craft/references/capture.md} +5 -15
  26. package/claude/skills/ui-craft/references/controls.md +18 -0
  27. package/claude/skills/ui-craft/references/copy.md +45 -0
  28. package/{governance/rules/ui → claude/skills/ui-craft/references}/forms.md +0 -9
  29. package/{governance/rules/ui → claude/skills/ui-craft/references}/keyboard.md +3 -16
  30. package/{governance/rules/ui → claude/skills/ui-craft/references}/motion.md +0 -10
  31. package/claude/skills/ui-craft/references/pointer.md +13 -0
  32. package/{governance/rules/ui/ux-completeness.md → claude/skills/ui-craft/references/states.md} +2 -20
  33. package/claude/skills/ux-audit/SKILL.md +1 -1
  34. package/claude/skills/write-human/references/adopted.md +4 -1
  35. package/docs/agents/install-and-sync.md +47 -13
  36. package/docs/index.md +1 -1
  37. package/docs/target/migrations.md +6 -8
  38. package/docs/target/sync.md +21 -1
  39. package/docs/workflow/ai-workflow.md +1 -1
  40. package/docs/workflow/index.md +3 -3
  41. package/docs/workflow/skill-map.md +1 -0
  42. package/docs/workflow/visual-design-workflow.md +58 -32
  43. package/governance/detect.toml +1 -37
  44. package/governance/ledger/lib/test-scope.md +1 -1
  45. package/governance/ledger/{ui → skills/ui-craft}/a11y.md +11 -9
  46. package/governance/ledger/{ui/surface-capture.md → skills/ui-craft/capture.md} +15 -15
  47. package/governance/ledger/skills/ui-craft/controls.md +31 -0
  48. package/governance/ledger/skills/ui-craft/copy.md +102 -0
  49. package/governance/ledger/{ui → skills/ui-craft}/forms.md +3 -3
  50. package/governance/ledger/skills/ui-craft/keyboard.md +67 -0
  51. package/governance/ledger/{ui → skills/ui-craft}/motion.md +3 -3
  52. package/governance/ledger/skills/ui-craft/pointer.md +24 -0
  53. package/governance/ledger/{ui/ux-completeness.md → skills/ui-craft/states.md} +14 -26
  54. package/governance/ledger/ui/craft.md +19 -0
  55. package/governance/renames.toml +17 -3
  56. package/governance/rules/lib/test-scope.md +1 -1
  57. package/governance/rules/ui/craft.md +22 -0
  58. package/governance/splits.toml +13 -0
  59. package/package.json +1 -1
  60. package/src/claude/cases/misc.ts +5 -0
  61. package/src/claude/skills-audit.ts +150 -12
  62. package/src/commands/claude.ts +5 -0
  63. package/src/commands/sync.ts +3 -1
  64. package/src/commands/tooling.ts +332 -10
  65. package/src/gate/measures.ts +4 -3
  66. package/src/gov/adapter.ts +53 -4
  67. package/src/gov/audit.ts +6 -1
  68. package/src/gov/splits.ts +36 -0
  69. package/src/inventory/subjects.ts +1 -1
  70. package/src/sync/check.ts +9 -1
  71. package/src/sync/stamp.ts +135 -11
  72. package/src/tooling/disposition.ts +167 -0
  73. package/src/tooling/inject.ts +17 -2
  74. package/src/tooling/package.ts +22 -13
  75. package/src/tooling/scan.ts +86 -7
  76. package/src/tooling/stamp.ts +51 -7
  77. package/tooling/web/reference.md +3 -1
  78. package/governance/ledger/ui/copy.md +0 -49
  79. package/governance/ledger/ui/design-taste.md +0 -19
  80. package/governance/ledger/ui/interface-casing.md +0 -47
  81. package/governance/ledger/ui/keyboard.md +0 -68
  82. package/governance/ledger/ui/link-behavior.md +0 -29
  83. package/governance/rules/ui/copy.md +0 -28
  84. package/governance/rules/ui/design-taste.md +0 -18
  85. package/governance/rules/ui/interface-casing.md +0 -29
  86. package/governance/rules/ui/link-behavior.md +0 -19
  87. /package/tooling/web/{configs → seeds}/e2e/home.spec.ts +0 -0
@@ -48,7 +48,7 @@ The checkbox stays `- [ ]` followed by the action and the result, since the evid
48
48
 
49
49
  ## Boxes no engine reads
50
50
 
51
- The UI review runs axe over every route it reaches, so a box restating what axe checks, such as contrast, a missing name, or a page title, adds a drive and catches nothing. Derive a box instead for each behavior below that the changed surface carries:
51
+ The UI review runs axe over every route it reaches, so a box restating what axe checks, such as contrast, a missing name, or a page title, adds a drive and catches nothing. Derive a box instead from the `ui-craft` references the changed surface reads, for each behavior below that it carries:
52
52
 
53
53
  - **Hover content.** Content shown on hover or focus stays while the pointer moves onto it, and Escape dismisses it, per WCAG 1.4.13.
54
54
  - **Keyboard trap.** Tab and Shift+Tab leave every widget the change added, per WCAG 2.1.2.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: ui-craft
3
+ description: Why the UI behavior practice lives in one skill every role reads by name, and where it stops beside design-taste and design-record
4
+ ---
5
+
6
+ # UI craft requirement
7
+
8
+ ## Gap
9
+
10
+ Without this skill, the UI behavior practice reaches a session only as path rules a target has to sync, so a project holding the plugin without governance builds a component with none of it. A role that plans, builds, or reviews a rendered change has no name to load the practice by, and each one restates the part it remembers.
11
+
12
+ ## Must
13
+
14
+ - Every rule the retired ui practice rules carried sits in a reference, unchanged in wording, with its source row in a ledger beside the reference
15
+ - A rendered change reaches accessibility, keyboard, and state coverage on every read, and the other references by the change that needs them
16
+ - A rendered change that is about to be handed over reaches the capture reference
17
+ - A planning, building, or reviewing role reaches the skill by name, with or without the governance pointer installed
18
+
19
+ ## Must not
20
+
21
+ - Reword a moved rule in the move, since a wording change is a separate change with its own ledger row
22
+ - Restate the look, being layout, type, color, or the layer order
23
+ - Be reached only by an author typing its name, since the `craft` pointer rule and the planning, building, and reviewing skills are its callers
24
+
25
+ ## Out of scope
26
+
27
+ - How a surface looks, which `design-taste` owns
28
+ - The design folder, its references, and the comparison a pull request shows, which `design-record` and the `design-reference` rule own
29
+ - The visual checklist a reviewer reads, which `ui-checklist` owns
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: ui-craft
3
+ description: Carries the behavior practice for rendered UI, being accessibility, keyboard and pointer operation, forms, motion, controls, state coverage, interface copy, and the capture a rendered change owes, routed from the kind of change to the references it reads. Use before building or changing a component, a page, a form, or any rendered surface, when judging one in review, or when asked "is this accessible", "what states does this need", "how should this form validate", "what should the button say", or "what do I capture after this change". Do NOT use for how a surface looks, being layout, type, color, and the layer order, which is `design-taste`, or for the design folder and its references, which is `design-record`.
4
+ metadata:
5
+ family: build
6
+ ---
7
+
8
+ # UI craft
9
+
10
+ A rendered change that skips this practice ships a control a keyboard cannot reach, a list with no empty state, or an error that names the fault and never the fix, and none of it fails a build. The references below carry the rules. This body routes a change to the ones it reads.
11
+
12
+ Load this before building rather than after, since a missing state or a trapped focus is cheaper to design in than to retrofit.
13
+
14
+ ## Read by the change
15
+
16
+ Read every reference on the always row for any rendered change, then each row the change matches.
17
+
18
+ | The change | Read |
19
+ | ------------------------------------------------------------------ | ------------------------------------- |
20
+ | Any rendered change | `a11y.md`, `keyboard.md`, `states.md` |
21
+ | A click, press, drag, gesture, or popover dismissal | `pointer.md` |
22
+ | A form, a field, validation, or a sign-in step | `forms.md` |
23
+ | An animation, transition, autoplay, or carousel | `motion.md` |
24
+ | A destructive action, an edit cancel, or a hover or disabled state | `controls.md` |
25
+ | A rendered string, heading, label, or link | `copy.md` |
26
+ | A rendered surface has changed and is about to be handed over | `capture.md` |
27
+
28
+ Each name sits under `${CLAUDE_SKILL_DIR}/references/`. A row's reference is read whole, since its sections name the cases a change reaches without saying so.
29
+
30
+ ## Hold the floor over taste
31
+
32
+ The references state a floor, and no aesthetic choice trades against it. A contrast ratio, a focus ring, or a state the design leaves out is restored before the look is judged, and `design-taste` decides the look inside that floor.
33
+
34
+ ## Sources
35
+
36
+ Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidance or arguing against a rule in it. It names the authorities the references draw on and where each bullet's source row sits.
37
+
38
+ ## What this delegates
39
+
40
+ - How a surface looks, being the layer order, the coherence locks, and the defaults a model reaches for: `design-taste`
41
+ - The accepted designs under the design folder and how a reference lands there: `design-record`
42
+ - The visual checklist a reviewer reads beside the screenshots: `ui-checklist`
43
+ - Reading source for roughness a rule does not state: `ux-audit`
44
+ - Prose on the surface beyond its interface copy: the `write-human` skill
@@ -1,13 +1,3 @@
1
- ---
2
- description: Semantics, text alternatives, contrast, and reflow for rendered UI
3
- paths:
4
- - '**/*.tsx'
5
- - '**/*.jsx'
6
- - '**/*.astro'
7
- - '**/*.html'
8
- - '**/*.css'
9
- ---
10
-
11
1
  # Accessibility standards
12
2
 
13
3
  ## Semantics
@@ -16,6 +6,7 @@ paths:
16
6
  - Spell an attribute the way the file's syntax spells it, being `onclick` and `tabindex` in HTML and Astro markup and `onClick` and `tabIndex` in JSX.
17
7
  - Give a custom control the role its pattern names, such as `combobox` or `listbox`, and keep `aria-expanded`, `aria-selected`, and `aria-checked` in step with what it shows.
18
8
  - Give an interactive element with no visible text label a name through `aria-label` or `aria-labelledby`.
9
+ - Put the visible text in the accessible name, first where you can (WCAG 2.5.3).
19
10
 
20
11
  ## Text alternatives
21
12
 
@@ -26,6 +17,7 @@ paths:
26
17
 
27
18
  - Give a control's visual boundary and every graphic that carries meaning at least 3:1 contrast against adjacent colors (WCAG 1.4.11).
28
19
  - Never make color the only carrier of a state, error, or distinction. Pair it with text, an icon, or a pattern (WCAG 1.4.1).
20
+ - Give text 4.5:1 contrast, or 3:1 when large (WCAG 1.4.3).
29
21
 
30
22
  ## Reflow
31
23
 
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Adopted and declined
3
+ description: The authorities the ui-craft references draw on, and where the per-bullet source rows for each reference sit
4
+ ---
5
+
6
+ # Adopted and declined
7
+
8
+ Every bullet in a reference has its own source row in a ledger outside the plugin, so this record names the authorities once and points at the rows. A reader arguing against one bullet opens its ledger, and a session extending a reference adds the row there in the same change.
9
+
10
+ ## Authorities
11
+
12
+ Each field below names the source its references cite, and a house choice covers a threshold or a scope no source states.
13
+
14
+ - **Web accessibility.** The W3C's [WCAG 2.2](https://www.w3.org/TR/WCAG22/) and the [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/) back the accessibility, keyboard, pointer, and motion references.
15
+ - **CSS behavior.** [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) and the CSS specifications back the focus ring, `color-scheme`, and overflow bullets.
16
+ - **Native targets.** Apple's and Android's platform guidelines back the native touch target figures in `pointer.md`.
17
+ - **Forms and copy.** The [GOV.UK Design System](https://design-system.service.gov.uk/) and its style guide back `forms.md` and the copy and casing sections of `copy.md`.
18
+ - **Usability research.** The [Nielsen Norman Group](https://www.nngroup.com/articles/) backs most of `states.md`, part of `controls.md`, and the link sections of `copy.md`.
19
+ - **Capture.** `capture.md` is a house procedure, with its reflow width taken from the WCAG reflow criterion `a11y.md` cites.
20
+
21
+ ## Where the rows sit
22
+
23
+ The rows sit in the toolkit's own repository rather than the plugin, one ledger per reference and one table row per bullet under the H2 the bullet sits under. The toolkit's skill audit fails a reference whose bullets and rows disagree in count under any heading, and a target never carries the rows.
24
+
25
+ ## Declined
26
+
27
+ Each ledger carries its own `## Declined` list, recording the bullets cut or reworded when the source rules were last rewritten. The move into this skill changed no bullet's wording, so it declined nothing.
@@ -1,32 +1,22 @@
1
- ---
2
- description: Require a capture against a running preview after a rendered surface changes
3
- paths:
4
- - '**/routes/**/*.{tsx,jsx,vue,svelte,astro}'
5
- - '**/pages/**/*.{tsx,jsx,vue,svelte,astro}'
6
- - '**/app/**/page.{tsx,jsx}'
7
- - '**/components/**/*.{tsx,jsx,vue,svelte,astro}'
8
- - '**/*.html'
9
- ---
10
-
11
1
  # Surface capture standards
12
2
 
13
3
  ## What a surface is
14
4
 
15
- - Treat anything the project renders for a person as a surface, a generated page as much as a route.
5
+ - Treat anything the project renders for a person as a surface, generated pages included.
16
6
  - Skip a component the production build strips out, such as a dev-only switcher.
17
7
 
18
8
  ## When to capture
19
9
 
20
- - Run the project's capture command against a preview server, never a dev server, after changing a surface. Report it when the project has none.
21
- - Capture every theme the surface ships, and again after fixing a defect a capture found.
10
+ - Run the project's capture command against a preview server, never a dev server, after changing a surface. Report a project with none.
11
+ - Capture every theme the surface ships, and again after fixing a defect found.
12
+ - Read your capture against the `canon:ui-checklist` boxes before opening the pull request, reporting a skill that does not resolve.
22
13
 
23
14
  ## What a capture covers
24
15
 
25
16
  - Capture the full page, never a component in isolation.
26
17
  - Capture a layout case at 320, the reflow floor in `a11y`, plus each breakpoint in the `## Layout` section of `DESIGN.md`, or at 320 alone when there is none.
27
18
  - Capture resizable chrome at its narrowest and widest clamp, at the narrowest width keeping it persistent. Judge the content width beside it.
28
- - Capture a state case at one width rather than the full set.
29
- - Drive a state an initial render cannot reach, such as an open menu or a rail tracking scroll.
19
+ - Capture a state case at one width, driving states a first render cannot reach, such as an open menu.
30
20
  - Add a surface's case with the surface, and remove it with the surface.
31
21
 
32
22
  ## Sharing a capture
@@ -0,0 +1,18 @@
1
+ # UX controls standards
2
+
3
+ ## Destructive actions
4
+
5
+ - Confirm a destructive action, such as a delete, disconnect, or discard, before it runs, unless it can be undone afterward.
6
+ - Restore the value from before an edit when the edit is cancelled. Never discard typed work on Escape or an outside click unasked, but confirm first when the person has typed something.
7
+
8
+ ## Element states
9
+
10
+ - Give every interactive element distinct hover, active, focus, and disabled styles.
11
+ - Never flash an intermediate state, such as a light frame before a dark theme or a layout jump before data arrives. Reserve the space or settle it first.
12
+ - Say why a control is disabled, in text beside it or a tooltip, and keep it focusable through `aria-disabled` when the reason matters.
13
+ - Declare `color-scheme` on `:root` to match each theme, so scrollbars and form controls follow the theme instead of staying light.
14
+
15
+ ## Hover and focus effects
16
+
17
+ - Keep content shown on hover or focus dismissible without moving the pointer, hoverable, and visible until the trigger leaves or the person dismisses it (WCAG 1.4.13).
18
+ - Change no context, such as navigating, submitting, or moving focus, when a control gains focus or changes value, unless the person was told first (WCAG 3.2.1, 3.2.2).
@@ -0,0 +1,45 @@
1
+ # UI copy standards
2
+
3
+ ## Punctuation
4
+
5
+ - Write no em dash (`—`) or semicolon in rendered copy. Use a comma or a period, or restructure the sentence.
6
+ - Add no trailing punctuation to a button label or a short action string.
7
+
8
+ ## Button copy
9
+
10
+ - Label a button with the verb of the action it performs, such as `Save` or `Delete`, never with filler such as `Click to delete`.
11
+
12
+ ## Error messages
13
+
14
+ - Tell the person how to fix the error, such as `Enter an email address` over `Email is invalid`.
15
+ - Keep an error message to one short sentence in plain language, with no technical jargon or error codes.
16
+
17
+ ## Placeholder text
18
+
19
+ - Never use placeholder text as a label, a hint, or an example. Put a format example such as `name@example.com` in hint text under the label.
20
+
21
+ ## Sentence case
22
+
23
+ - Use sentence case for rendered headings, labels, nav items, tab titles, and dialog titles, since title case on every heading reads as a template default.
24
+ - Keep the original casing of a proper noun or product name, such as `GitHub`, `macOS`, or `TypeScript`.
25
+
26
+ ## Uppercase labels
27
+
28
+ - Keep small uppercase labels above headings to `ceil(sections / 3)`, the first screen counting as one. Delete the extra labels, since position already names a section.
29
+
30
+ ## Where it applies
31
+
32
+ - Apply the same casing to interface copy kept outside the globs, such as a locale file, which this rule never fires on.
33
+
34
+ ## Overriding
35
+
36
+ - Depart from sentence case only where the case needs it, such as an acronym, a brand mark, or a set-in-caps identity the design chose on purpose.
37
+
38
+ ## Default target
39
+
40
+ - Open a link in the same tab. Reserve `target="_blank"` for a page the person must consult while finishing a task in the current one.
41
+ - Never add `target="_blank"` as a default for every external link.
42
+
43
+ ## mailto: links
44
+
45
+ - Open a `mailto:` link in the same tab. It hands off to the mail client rather than replacing the page, so a new tab leaves an empty tab behind.
@@ -1,12 +1,3 @@
1
- ---
2
- description: Form validation timing, submission, error placement, and derived state for rendered forms
3
- paths:
4
- - '**/*.tsx'
5
- - '**/*.jsx'
6
- - '**/*.astro'
7
- - '**/*.html'
8
- ---
9
-
10
1
  # Form standards
11
2
 
12
3
  ## Validation timing
@@ -1,13 +1,3 @@
1
- ---
2
- description: Focus styles, keyboard operation, focus management, and pointer targets for rendered UI
3
- paths:
4
- - '**/*.tsx'
5
- - '**/*.jsx'
6
- - '**/*.astro'
7
- - '**/*.html'
8
- - '**/*.css'
9
- ---
10
-
11
1
  # Keyboard and focus standards
12
2
 
13
3
  ## Focus styles
@@ -15,24 +5,21 @@ paths:
15
5
  - Style focus through the project's one focus ring rather than a per-component focus style.
16
6
  - Never set `outline: none` or `outline-none` without a replacement focus indicator in the same rule.
17
7
  - Give the focus ring 3:1 contrast against its background in every theme the project ships.
8
+ - Keep the focus ring whole. Where an ancestor's `overflow` would clip it, inset it with a negative `outline-offset` or pad the edge items of the list.
18
9
 
19
10
  ## Keyboard operation
20
11
 
21
12
  - Close a dialog, popover, menu, or inline confirmation on Escape, and cancel an in-progress edit the same way.
13
+ - Never trap keyboard focus. A person who tabs into a component can leave it by keyboard alone, and a modal dialog leaves on Escape (WCAG 2.1.2).
22
14
  - Bind no single printable character as a shortcut unless a person can turn it off or remap it, or it fires only while its control has focus (WCAG 2.1.4).
23
- - Give every author-defined drag a single-pointer alternative and a keyboard path, such as move buttons or arrow-key reordering (WCAG 2.5.7).
24
15
 
25
16
  ## Composite widgets
26
17
 
27
18
  - Keep one item of a composite widget in the tab sequence, and move between its items with the arrow keys through roving `tabindex` or `aria-activedescendant`.
28
19
  - Open a combobox popup on Down Arrow, accept the focused option on Enter, and close the popup on Escape without changing the value.
20
+ - Give a custom number input the spinbutton keys, Up and Down to step and Home and End for the limits. Take the keys of any other custom widget from its ARIA Authoring Practices Guide pattern.
29
21
 
30
22
  ## Focus management
31
23
 
32
24
  - Move focus into a dialog when it opens, and return it to the element that opened it when it closes.
33
25
  - Never let a sticky header, footer, or overlay fully cover the focused control. Scroll it clear of them (WCAG 2.4.11).
34
-
35
- ## Pointer targets
36
-
37
- - Size a web pointer target at least 24 by 24 CSS pixels, or space it so a 24 pixel circle centered on it touches no other target (WCAG 2.5.8).
38
- - Size a native touch target at the platform figure, 44 points on iOS and 48 dp on Android, and never swap the web and native figures.
@@ -1,13 +1,3 @@
1
- ---
2
- description: Moving content controls and the reduced-motion preference for rendered UI
3
- paths:
4
- - '**/*.tsx'
5
- - '**/*.jsx'
6
- - '**/*.astro'
7
- - '**/*.html'
8
- - '**/*.css'
9
- ---
10
-
11
1
  # Motion standards
12
2
 
13
3
  ## Moving content
@@ -0,0 +1,13 @@
1
+ # Pointer standards
2
+
3
+ ## Pointer actions
4
+
5
+ - Dismiss a popover or menu on a press outside it and when focus leaves it, as well as on Escape.
6
+ - Run a pointer action on release rather than press, so a person can slide off the target to abort it (WCAG 2.5.2).
7
+ - Give a path-based or multipoint gesture, such as a swipe or pinch, a single-pointer alternative with no path (WCAG 2.5.1).
8
+ - Give every author-defined drag a single-pointer alternative and a keyboard path, such as move buttons or arrow-key reordering (WCAG 2.5.7).
9
+
10
+ ## Pointer targets
11
+
12
+ - Size a web pointer target at least 24 by 24 CSS pixels, or space it so a 24 pixel circle centered on it touches no other target (WCAG 2.5.8).
13
+ - Size a native touch target at the platform figure, 44 points on iOS and 48 dp on Android, and never swap the web and native figures.
@@ -1,19 +1,10 @@
1
- ---
2
- description: UX completeness checklist for interactive components and views
3
- paths:
4
- - '**/*.tsx'
5
- - '**/*.jsx'
6
- - '**/*.astro'
7
- - '**/*.html'
8
- - '**/*.css'
9
- ---
10
-
11
1
  # UX completeness standards
12
2
 
13
3
  ## Feedback
14
4
 
15
5
  - Confirm every user-initiated mutation, such as a save, delete, or import, inline on success, and show an inline error when it fails.
16
6
  - Auto-dismiss a success message only when its outcome stays visible elsewhere. Keep a message carrying the only copy of its information until dismissed (WCAG 2.2.1).
7
+ - Pause a timed message while it has pointer hover or keyboard focus, and take no focus for it. A person finishes reading it, and a status message never interrupts typing (WCAG 4.1.3).
17
8
  - Show no optimistic status, such as a green dot or "connected", while unsaved edits are pending.
18
9
 
19
10
  ## Empty states
@@ -26,17 +17,8 @@ paths:
26
17
  - Show a progress indicator for any operation a person waits on for longer than about one second.
27
18
  - Mark previous content as updating while new content loads, rather than showing it unmarked as current.
28
19
 
29
- ## Destructive actions
30
-
31
- - Confirm a destructive action, such as a delete, disconnect, or discard, before it runs, unless it can be undone afterward.
32
-
33
- ## Element states
34
-
35
- - Give every interactive element distinct hover, active, focus, and disabled styles.
36
- - Never flash an intermediate state, such as a light frame before a dark theme or a layout jump before data arrives. Reserve the space or settle it first.
37
-
38
20
  ## Overflow
39
21
 
40
22
  - Truncate long text in a constrained container with an ellipsis rather than letting it overflow.
41
23
  - Expose truncated text through an expand control or full text on focus, never through a `title` tooltip alone.
42
- - Keep focus rings and interactive borders clear of a parent's `overflow` clipping, padding the edge items of a scrollable list.
24
+ - Keep interactive borders clear of a parent's `overflow` clipping, padding the edge items of a scrollable list.
@@ -36,7 +36,7 @@ For each surface, look for:
36
36
  3. **Inconsistencies**: spacing, tone of voice, interaction patterns, icon use, keyboard affordances
37
37
  4. **Roughness in daily use**: friction, redundant steps, unclear affordances, ambiguous labels
38
38
 
39
- Use `canon/DESIGN.md` as ground truth for intent where it exists. Observations only, no implementation suggestions or fixes.
39
+ Use `canon/DESIGN.md` as ground truth for intent where it exists. Observations only, no implementation suggestions or fixes. Take what consistent interaction means from the `ui-craft` skill's references.
40
40
 
41
41
  Where Step 1 found a committed capture for this surface, judge composed output (spacing, overlap, contrast, wrapping) against it rather than inferring layout from markup. Where none exists, judge from source and say so in that surface's findings, since a source read cannot see what only a render shows.
42
42
 
@@ -5,7 +5,10 @@ description: Which external writing patterns this skill adopted, which it declin
5
5
 
6
6
  # Source material
7
7
 
8
- Two external writing skills were read as source material for this one. The first catalogs 31 patterns of machine-sounding prose. The second layers document mode, sentence construction, information density, and ambiguity prevention.
8
+ Two external writing skills were read as source material for this one.
9
+
10
+ - **[humanizer](https://github.com/blader/humanizer)** catalogs 31 patterns of machine-sounding prose
11
+ - **An unidentified second skill** layers document mode, sentence construction, information density, and ambiguity prevention. No record of the read named it, so it carries no link.
9
12
 
10
13
  Neither was imported wholesale, and one measurement settles why. Read this before adding a rule from outside this corpus, and extend the position below rather than deriving a second one.
11
14
 
@@ -32,7 +32,7 @@ A flat installed-rule layout makes `gov sync` report "No governance surfaces fou
32
32
  - A retired `.claude/GOV.md` is removed
33
33
  - A binary older than the stamp holds every rule it has no source for and asks for an upgrade
34
34
 
35
- After a rename the new name shows as `missing` when the stamp records a stack, and `gov install <stack>` adds it.
35
+ After a rename the new name shows as `missing` when the stamp records a stack, and `gov install <stack>` adds it. A partner `governance/splits.toml` names shows as `missing` when the tree holds the split rule and lacks the partner, and `gov install --add <partner>` adds it.
36
36
 
37
37
  `canon gov regen [--root <path>]` runs against the toolkit root alone. It rewrites `.claude/rules/canon/` and `.claude/rules/internal/` from `internal/`, and exits 1 when the record names something that does not resolve.
38
38
 
@@ -62,11 +62,45 @@ After a rename the new name shows as `missing` when the stamp records a stack, a
62
62
 
63
63
  ## Tooling
64
64
 
65
- - `canon tooling diff <stack> [target]` is the read-only comparison, exiting 1 on any difference
65
+ - `canon tooling diff <stack> [target]` is the read-only comparison, exiting 1 on any difference, and it reads a dependency on a later major than the stack pins as `ahead`, which counts as no change
66
66
  - A `--json` refusal answers `{ ok: false, reason, message }`, so branch on the record
67
67
  - `withheld` entries are `{ rel, stack, present }`, hold every `.github/` file below the git root, and count toward no exit
68
68
  - `present` marks a copy an earlier sync left, which is reported and never deleted
69
- - `canon tooling sync <stack> [target]` writes only under `--write`. `--check` reports and exits 0, and a headless run with neither flag exits 1.
69
+ - `canon tooling sync <stack> [target]` writes only under `--write`. `--check` reports and exits 0, and a headless run with neither flag exits 1. It never installs over an `ahead` dependency.
70
+
71
+ ### Drift cause and the write hold
72
+
73
+ A `drifted` entry in `configs` carries a `cause`, read against the golden hash the last write recorded for that path.
74
+
75
+ - `stale`: the target still hashes to the record, so canon moved and the project did not. `--write` replaces it.
76
+ - `edited`: the target no longer hashes to the record. `--write` holds it.
77
+ - `unattributed`: no hash is recorded, as on every target synced before hashes existed. `--write` holds it.
78
+
79
+ A config no stack in the recorded chain ships is a first install and is never held, so a fresh scaffold takes every golden config of a stack new to it, even after `canon init` recorded `base`.
80
+
81
+ A held path stays drifted, so the next headless run still exits 1. Pass `--replace <path>` once per path to take the golden copy, as the command the write prints does. A `--replace` naming no config the chain writes refuses with `unknown-replace`.
82
+
83
+ ### Dispositions
84
+
85
+ `decline <path> [target] [--reason <text>]`, `customize <path> [target]`, and `lift <path> [target]` set or clear one path's disposition, each with `--json`. The path is relative to the target and resolves against the recorded chain, never a stack argument.
86
+
87
+ - A success answers `{ ok: true, action, path, entry? }`, where `entry` is the recorded `{ disposition, base?, reason? }` and is absent after a lift
88
+ - A declined or customized path leaves `configs`, `seeds`, and `withheld` for `dispositions`, as `{ rel, stack, kind, disposition, present, moved? }`
89
+ - `moved` is set on a customized config alone, and counts toward the exit once the golden copy no longer matches `base`
90
+ - Sync and inject never write a path in `dispositions`, and nothing deletes one the project still holds
91
+
92
+ A refusal answers `{ ok: false, reason, message }` with exit 1:
93
+
94
+ | `reason` | Meaning |
95
+ | ----------------------- | --------------------------------------------------------- |
96
+ | `no-chain` | No tooling chain is recorded, so run `tooling sync` first |
97
+ | `bad-path` | The path leaves the target |
98
+ | `not-golden` | No stack in the recorded chain ships the path |
99
+ | `already-held` | The path is already declined or customized, so lift it |
100
+ | `seed-not-customizable` | The path is a seed, which sync never overwrites |
101
+ | `missing-file` | `customize` named a config the target does not hold |
102
+ | `not-held` | `lift` named a path with no disposition |
103
+ | `toolkit-root` | The target is the toolkit checkout, the source of truth |
70
104
 
71
105
  `canon tooling inject` and `prune-gitignore` apply one stack with no scan or prompt, and the latter prints the number removed on stdout. Use `sync` unless scripting provisioning, and pass `--nested` inside an open frame.
72
106
 
@@ -78,16 +112,16 @@ After a rename the new name shows as `missing` when the stamp records a stack, a
78
112
 
79
113
  `canon sync --check` writes nothing and needs no clean tree. `--json` emits the record, `--exit-code` fails CI.
80
114
 
81
- | State | Meaning |
82
- | ------------ | ------------------------------------------------------------------ |
83
- | `stale` | Still matches what the toolkit installed |
84
- | `customized` | The project edited it |
85
- | `stranded` | Sits at a path the toolkit no longer installs to |
86
- | `orphaned` | The project authored it |
87
- | `drifted` | No stamp covers it |
88
- | `missing` | Governance only. The recorded stack lists it and the tree lacks it |
89
- | `retired` | Governance only. The toolkit no longer ships it |
90
- | `renamed` | Governance only. The toolkit ships it under a new name |
115
+ | State | Meaning |
116
+ | ------------ | ----------------------------------------------------------------------- |
117
+ | `stale` | Still matches what the toolkit installed |
118
+ | `customized` | The project edited it |
119
+ | `stranded` | Sits at a path the toolkit no longer installs to |
120
+ | `orphaned` | The project authored it |
121
+ | `drifted` | No stamp covers it |
122
+ | `missing` | Governance only. The recorded stack lists it, or a split rule leaves it |
123
+ | `retired` | Governance only. The toolkit no longer ships it |
124
+ | `renamed` | Governance only. The toolkit ships it under a new name |
91
125
 
92
126
  `retired` and `renamed` count toward `--exit-code`. `orphaned` and `missing` do not.
93
127
 
package/docs/index.md CHANGED
@@ -9,4 +9,4 @@ One-line reference for each doc in this folder.
9
9
 
10
10
  - [Agents](agents/index.md): CLI catalog and invocation rules for agents, split by command domain. Start with overview.
11
11
  - [Target](target/index.md): Scaffold, sync, and migrate a toolkit-managed project, with worked setups for three project shapes.
12
- - [Workflow](workflow/index.md): How a person and their agents run a feature, from the design tier through the parallel-session loop to the shell that launches them.
12
+ - [Workflow](workflow/index.md): How a person and their agents run a feature, from the design loop through the parallel-session loop to the shell that launches them.
@@ -75,7 +75,7 @@ The `memory` record kind left `canon records`, so `canon records validate memory
75
75
  - `canon repo metadata`, `canon autoship`, and the `120-bash` rule are gone, and `canon gov sync` removes the rule <!-- canon-keep-retired -->
76
76
  - `memory-capture`, the `603-memory` rule, and the `memory` standard are gone, so send a lesson to the context entry that owns the fact <!-- canon-keep-retired -->
77
77
 
78
- Two held files run, `.husky/post-merge` and `.claude/hooks/pr-create-log.sh`, and a stale copy calls a missing binary or names a removed skill. Resync what the toolkit owns before sweeping what the project wrote, and run the second line once per stack.
78
+ Two held files run, `.husky/post-merge` and `.claude/hooks/pr-create-log.sh`, and a stale copy calls a missing binary or names a removed skill. Resync what the toolkit owns before sweeping what the project wrote, and run the second line once per stack, naming a held hook with `--replace`.
79
79
 
80
80
  ```bash
81
81
  canon gov sync
@@ -181,20 +181,18 @@ The verb adds `Bash(canon pr merge:*)` and `Bash(gh pr merge:*)` so a session ca
181
181
 
182
182
  ## Move the capture cases out of the harness, once
183
183
 
184
- A web project's `e2e/screenshot.ts` is a config, so sync overwrites it. It now loads `CASES` from a seeded `e2e/capture/cases.ts` that sync copies once and never overwrites. Cases edited in the old harness leave the working tree on the first sync and stay in git history.
184
+ A web project's `e2e/screenshot.ts` is a config. It now loads `CASES` from a seeded `e2e/capture/cases.ts` that sync copies once and never overwrites. A harness you edited is held on `--write`, so the new one lands only once you pass `--replace e2e/screenshot.ts`.
185
185
 
186
- - Copy your cases from the old `e2e/screenshot.ts` into `e2e/capture/cases.ts` before the next sync.
186
+ - Copy your cases from the old `e2e/screenshot.ts` into `e2e/capture/cases.ts`, then sync with `--replace e2e/screenshot.ts`.
187
187
  - Evidence now defaults to `e2e/evidence/`. Set `export const EVIDENCE_ROOT = 'evidence'` in `e2e/capture/cases.ts` to keep a committed baseline at the old path.
188
188
  - A run from a folder with no `e2e/capture/cases.ts` exits 1 and names the file.
189
189
 
190
- ## Add the keyboard rule beside a held a11y rule, once
190
+ ## Fold the ui rules onto one pointer, once
191
191
 
192
- The `a11y` rule split in two. Focus styles, Escape and shortcuts, composite widgets, focus management, and pointer target size moved to a new `keyboard` rule. `canon gov sync` refreshes only the rules a project holds, so it rewrites `a11y.md` without those bullets and never adds `keyboard.md`.
193
-
194
- A project holding `.claude/rules/canon/ui/a11y.md` adds the new rule alone:
192
+ Eleven ui rules moved unchanged into the `ui-craft` skill, being `a11y`, `keyboard`, `pointer`, `forms`, `motion`, `ux-controls`, `ux-completeness`, `surface-capture`, `copy`, `interface-casing`, and `link-behavior`. Update the plugin, then sync, which folds each one you hold and `design-taste.md` onto one `craft.md` pointer without local edits.
195
193
 
196
194
  ```bash
197
- canon gov install --add keyboard --yes .
195
+ canon gov sync .
198
196
  ```
199
197
 
200
198
  ## Group a long paths section in `CLAUDE.md`, once
@@ -44,13 +44,33 @@ Add `--json` for a machine-readable report and `--exit-code` to fail CI when a t
44
44
 
45
45
  - Seed docs such as `CLAUDE.md` and `canon/REQUIREMENTS.md`: merge by hand, keeping the project's customizations
46
46
  - Installed governance rules: `canon gov sync <path>`, which adds no new rules and reports coverage afterward
47
- - Tooling configs and seeds: read differences with `canon tooling diff <stack> <path>`, then `canon tooling sync <stack> <path> --write`, which overwrites golden configs and copies each seed once
47
+ - Tooling configs and seeds: read differences with `canon tooling diff <stack> <path>`, then `canon tooling sync <stack> <path> --write`, which holds an edited config and copies each seed once
48
+ - Tooling dependencies: a dependency on a later major than the stack pins reads as `ahead`, and sync leaves it
48
49
  - Index regeneration: `canon indexes regen`
49
50
 
50
51
  After `canon gov sync` applies, it lists each rule it copied with its globs and how many project files match. A `ui/` rule adds a pointer to `/canon:ux-audit`. `--json` writes `{ "coverage": [{ "rule", "paths", "files", "ui" }] }` to stdout, empty when nothing was copied, with `files` null outside git. The report never changes the exit code.
51
52
 
52
53
  Try a scenario from [sandbox](../../canon/context/development/sandbox.md) before syncing a real project.
53
54
 
55
+ ### Held, declined, and customized golden files
56
+
57
+ `--write` replaces a golden config only when canon changed it and the project did not. A config the project edited, or one no earlier write recorded, is held and listed with a `--replace` command that takes the golden copy. A config from a stack the target never synced is a first install and is never held.
58
+
59
+ A project can also opt out of one golden file without leaving the stack. Each verb below takes the path relative to the target, as `canon tooling diff` lists it.
60
+
61
+ ```bash
62
+ canon tooling decline .github/workflows/readme-screenshot.yml --reason "no screenshots here"
63
+ canon tooling customize e2e/screenshot.ts
64
+ canon tooling lift .github/workflows/readme-screenshot.yml
65
+ ```
66
+
67
+ - `decline` keeps sync and inject from writing the file again, and leaves a copy the project still holds in place
68
+ - `customize` keeps the project's copy of a config through every write, and `diff` exits 1 once the stack ships a newer golden copy
69
+ - A seed cannot be customized, since sync never overwrites one, and the starter `e2e/home.spec.ts` is one
70
+ - `lift` hands the file back, so the next sync writes it
71
+
72
+ These verbs are the only writers of the record in `canon/config/config.json`, so never edit it there by hand.
73
+
54
74
  ## Running sync from an agent session
55
75
 
56
76
  `canon sync .` applies every domain sync, then offers a commit and pull request that needs a terminal. With no terminal on stdin the syncs apply, the git step is refused, and the command exits 0. Commit yourself. Sync refuses a dirty working tree, and `canon sync --check .` does not.
@@ -66,7 +66,7 @@ An independent session invokes `canon:review-pr` once the pull request is open,
66
66
 
67
67
  ### UI-heavy project
68
68
 
69
- Pick a design tier before the first feature session. See [visual design workflow](visual-design-workflow.md).
69
+ A UI feature runs the same plan, build, and review loop at any size. See [visual design workflow](visual-design-workflow.md).
70
70
 
71
71
  ## Skills
72
72
 
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: Workflow
3
- subtitle: How a person and their agents run a feature, from the design tier through the parallel-session loop to the shell that launches them.
3
+ subtitle: How a person and their agents run a feature, from the design loop through the parallel-session loop to the shell that launches them.
4
4
  ---
5
5
 
6
6
  # Workflow
7
7
 
8
- How a person and their agents run a feature, from the design tier through the parallel-session loop to the shell that launches them.
8
+ How a person and their agents run a feature, from the design loop through the parallel-session loop to the shell that launches them.
9
9
 
10
10
  ## Agent surface
11
11
 
@@ -17,5 +17,5 @@ How a person and their agents run a feature, from the design tier through the pa
17
17
  - [Parallel features](parallel-features.md): Run independent features in parallel worktrees, with the records and board every session shares
18
18
  - [Skill map on request](skill-map-on-request.md): When to reach for the plugin skills that serve a request rather than a moment in a project's life
19
19
  - [Skill map](skill-map.md): When to reach for each plugin skill, grouped by the moment a project meets it
20
- - [Visual design workflow](visual-design-workflow.md): Tiered guide for design authoring with Claude Code
20
+ - [Visual design workflow](visual-design-workflow.md): How canon plans, builds, and reviews a UI, from the design reference a plan cites to the browser pass that holds a pull request open
21
21
  - [Zshrc aliases for Claude Code](zshrc-aliases.md): Shell aliases that shorten common Claude Code invocations
@@ -45,6 +45,7 @@ Groups run in the order a project meets them. Every name `canon claude skills li
45
45
  | `canon:search-craft` | Before searching outside the project |
46
46
  | `canon:systematic-debugging` | A test fails or a bug surfaces |
47
47
  | `canon:design-taste` | Drafting or judging an interface |
48
+ | `canon:ui-craft` | Building or judging a component's behavior |
48
49
  | `canon:ui-checklist` | After a UI change, to list what to check |
49
50
 
50
51
  ## Check the work before it leaves the branch