@erclx/canon 5.61.0 → 5.62.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 (39) hide show
  1. package/CHANGELOG.md +9 -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/design-identity/references/card-route.md +3 -3
  6. package/claude/skills/target-update/SKILL.md +9 -1
  7. package/claude/skills/ux-audit/SKILL.md +1 -1
  8. package/docs/agents/install-and-sync.md +45 -11
  9. package/docs/index.md +1 -1
  10. package/docs/target/migrations.md +6 -8
  11. package/docs/target/sync.md +20 -1
  12. package/docs/workflow/ai-workflow.md +1 -1
  13. package/docs/workflow/index.md +3 -3
  14. package/docs/workflow/visual-design-workflow.md +58 -32
  15. package/governance/detect.toml +8 -0
  16. package/governance/ledger/ui/a11y.md +8 -6
  17. package/governance/ledger/ui/keyboard.md +20 -21
  18. package/governance/ledger/ui/pointer.md +24 -0
  19. package/governance/ledger/ui/surface-capture.md +12 -12
  20. package/governance/ledger/ui/ux-completeness.md +11 -23
  21. package/governance/ledger/ui/ux-controls.md +26 -0
  22. package/governance/rules/ui/a11y.md +2 -0
  23. package/governance/rules/ui/keyboard.md +4 -7
  24. package/governance/rules/ui/pointer.md +23 -0
  25. package/governance/rules/ui/surface-capture.md +5 -5
  26. package/governance/rules/ui/ux-completeness.md +2 -10
  27. package/governance/rules/ui/ux-controls.md +25 -0
  28. package/governance/splits.toml +15 -0
  29. package/package.json +1 -1
  30. package/src/commands/sync.ts +3 -1
  31. package/src/commands/tooling.ts +329 -10
  32. package/src/gov/adapter.ts +53 -4
  33. package/src/gov/splits.ts +36 -0
  34. package/src/sync/check.ts +9 -1
  35. package/src/sync/stamp.ts +135 -11
  36. package/src/tooling/disposition.ts +167 -0
  37. package/src/tooling/inject.ts +17 -2
  38. package/src/tooling/scan.ts +86 -7
  39. package/src/tooling/stamp.ts +51 -7
@@ -16,21 +16,21 @@ The rule states canon's own evidence procedure for a rendered change, so most ro
16
16
 
17
17
  ## When to capture
18
18
 
19
- | Bullet | Source | Read |
20
- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
21
- | Preview, not dev server | House choice: a dev server injects overlays and skips the production build's transforms, so its frame differs from what ships | 2026-10-18 |
22
- | Every theme, and again | House choice: a defect in the dark theme passes a light-only capture, and a repair inside a shared stylesheet can cancel a rule written earlier in the same file | 2026-10-18 |
19
+ | Bullet | Source | Read |
20
+ | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
21
+ | Preview, not dev server | House choice: a dev server injects overlays and skips the production build's transforms, so its frame differs from what ships | 2026-10-18 |
22
+ | Every theme, and again | House choice: a defect in the dark theme passes a light-only capture, and a repair inside a shared stylesheet can cancel a rule written earlier in the same file | 2026-10-18 |
23
+ | Read the capture before the pull request | House choice: a defect visible in the worker's own capture, such as a 20px target under the 24px bullet in `pointer.md`, reached review because nobody read the frame against the checklist first, and each review round re-runs both reviews. The skill ships with the plugin, so the bullet carries a report-if-missing clause | 2026-10-23 |
23
24
 
24
25
  ## What a capture covers
25
26
 
26
- | Bullet | Source | Read |
27
- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
28
- | Full page | House choice: a component captured alone shows none of the spacing, overflow, or stacking its page imposes on it | 2026-10-18 |
29
- | 320 plus breakpoints | [Understanding Reflow](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html): the criterion tests "a width equivalent to 320 CSS pixels". A 320 frame proves a frame was taken there, never that the page reflows, which `a11y.md` states. | 2026-10-18, WCAG 2.2 |
30
- | Chrome at both clamps | House choice: a sidebar widened to its clamp leaves the content under the floor at a window width the criterion passes, and a frame where the chrome turned into an overlay shows none of the width it takes | 2026-10-18 |
31
- | State case at one width | House choice: a case driving a menu open tests the state, and repeating it at every layout width multiplies the evidence with no layout to compare | 2026-10-18 |
32
- | Drive unreachable states | House choice: an initial render reports nothing about a menu that opens, an answer that is chosen, or a rail that tracks scrolling | 2026-10-18 |
33
- | Case lives with the surface | House choice: a surface with no case ships uncaptured, and a case left after its surface goes fails every later capture run | 2026-10-18 |
27
+ | Bullet | Source | Read |
28
+ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
29
+ | Full page | House choice: a component captured alone shows none of the spacing, overflow, or stacking its page imposes on it | 2026-10-18 |
30
+ | 320 plus breakpoints | [Understanding Reflow](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html): the criterion tests "a width equivalent to 320 CSS pixels". A 320 frame proves a frame was taken there, never that the page reflows, which `a11y.md` states. | 2026-10-18, WCAG 2.2 |
31
+ | Chrome at both clamps | House choice: a sidebar widened to its clamp leaves the content under the floor at a window width the criterion passes, and a frame where the chrome turned into an overlay shows none of the width it takes | 2026-10-18 |
32
+ | State case at one width, driven | House choice: a case driving a menu open tests the state, and repeating it at every layout width multiplies the evidence with no layout to compare, and an initial render reports nothing about a menu that opens, an answer that is chosen, or a rail that tracks scrolling | 2026-10-18 |
33
+ | Case lives with the surface | House choice: a surface with no case ships uncaptured, and a case left after its surface goes fails every later capture run | 2026-10-18 |
34
34
 
35
35
  ## Sharing a capture
36
36
 
@@ -9,11 +9,12 @@ The field is interaction design, and the authorities are the Nielsen Norman Grou
9
9
 
10
10
  ## Feedback
11
11
 
12
- | Bullet | Source | Read |
13
- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
14
- | Confirm success and failure | [Visibility of system status](https://www.nngroup.com/articles/visibility-system-status/): "Whenever users interact with a system, they need to know whether the interaction was successful" | 2026-10-18 |
15
- | Auto-dismiss only a redundant message | [Understanding Timing Adjustable](https://www.w3.org/WAI/WCAG22/Understanding/timing-adjustable.html): "If the user has no other means of discovering the same information (or performing the same function), then each message would need to meet this success criterion" | 2026-10-18, WCAG 2.2 |
16
- | No optimistic status | House choice: a "connected" dot shown over unsaved edits reports a state the system has not reached, and the person leaves believing their change took | 2026-10-18 |
12
+ | Bullet | Source | Read |
13
+ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
14
+ | Confirm success and failure | [Visibility of system status](https://www.nngroup.com/articles/visibility-system-status/): "Whenever users interact with a system, they need to know whether the interaction was successful" | 2026-10-18 |
15
+ | Auto-dismiss only a redundant message | [Understanding Timing Adjustable](https://www.w3.org/WAI/WCAG22/Understanding/timing-adjustable.html): "If the user has no other means of discovering the same information (or performing the same function), then each message would need to meet this success criterion" | 2026-10-18, WCAG 2.2 |
16
+ | Timed messages pause and take no focus | [Fluent 2, Toast usage](https://fluent2.microsoft.design/components/web/react/core/toast/usage): a toast with no action times out "after seven seconds", and mouse users "can pause the timer by hovering". [Understanding Status Messages](https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html): status messages are presented "without receiving focus". The pause leaves the redundant-message bullet's rule for when a message may leave unchanged | 2026-10-23 |
17
+ | No optimistic status | House choice: a "connected" dot shown over unsaved edits reports a state the system has not reached, and the person leaves believing their change took | 2026-10-18 |
17
18
 
18
19
  ## Empty states
19
20
 
@@ -29,26 +30,13 @@ The field is interaction design, and the authorities are the Nielsen Norman Grou
29
30
  | Indicator past one second | [Progress indicators](https://www.nngroup.com/articles/progress-indicators/): "Use a progress indicator for any action that takes longer than about 1.0 second" | 2026-10-18 |
30
31
  | Mark stale content as updating | [Progress indicators](https://www.nngroup.com/articles/progress-indicators/): "Without any visual change from the system, most users will assume the action was not registered and they will try again" | 2026-10-18 |
31
32
 
32
- ## Destructive actions
33
-
34
- | Bullet | Source | Read |
35
- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
36
- | Confirm unless undoable | [Confirmation dialogs](https://www.nngroup.com/articles/confirmation-dialog/): "consider a confirmation dialog before actions that cannot be undone", and "do try your best to offer undo" | 2026-10-18 |
37
-
38
- ## Element states
39
-
40
- | Bullet | Source | Read |
41
- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
42
- | Distinct interaction states | [Visibility of system status](https://www.nngroup.com/articles/visibility-system-status/): "Did the system actually catch that button press", and an element with no pressed or hover response leaves the person unable to tell | 2026-10-18 |
43
- | No intermediate flash | [Cumulative Layout Shift](https://web.dev/articles/cls): "Unexpected layout shifts can disrupt the user experience", caused by content "dynamically added to the page before existing content" | 2026-10-18 |
44
-
45
33
  ## Overflow
46
34
 
47
- | Bullet | Source | Read |
48
- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
49
- | Ellipsis over overflow | [text-overflow](https://developer.mozilla.org/en-US/docs/Web/CSS/text-overflow): `text-overflow: ellipsis` with `overflow: hidden` and `white-space: nowrap` clips text at the box with a visible marker | 2026-10-18 |
50
- | Never `title` alone | [The title attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/title): "Use of the title attribute is highly problematic for" people using touch-only devices, keyboards, and assistive technology | 2026-10-18 |
51
- | Focus rings clear of clipping | House choice: a ring cut off by a parent's `overflow` shows on the middle items of a list and vanishes on the first and last, so the focus indicator fails exactly where the list ends | 2026-10-18 |
35
+ | Bullet | Source | Read |
36
+ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
37
+ | Ellipsis over overflow | [text-overflow](https://developer.mozilla.org/en-US/docs/Web/CSS/text-overflow): `text-overflow: ellipsis` with `overflow: hidden` and `white-space: nowrap` clips text at the box with a visible marker | 2026-10-18 |
38
+ | Never `title` alone | [The title attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/title): "Use of the title attribute is highly problematic for" people using touch-only devices, keyboards, and assistive technology | 2026-10-18 |
39
+ | Borders clear of clipping | House choice: a ring cut off by a parent's `overflow` shows on the middle items of a list and vanishes on the first and last, so the focus indicator fails exactly where the list ends | 2026-10-18 |
52
40
 
53
41
  ## Declined
54
42
 
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: UX controls rule ledger
3
+ description: Sources for governance/rules/ui/ux-controls.md, one row per bullet
4
+ ---
5
+
6
+ # UX controls rule ledger
7
+
8
+ The field is interaction design, and the authorities are the Nielsen Norman Group, WCAG 2.2, Primer, Cloudscape, MDN, and web.dev. These bullets were split from `ux-completeness.md`.
9
+
10
+ ## Destructive actions
11
+
12
+ | Bullet | Source | Read |
13
+ | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
+ | Confirm unless undoable | [Confirmation dialogs](https://www.nngroup.com/articles/confirmation-dialog/): "consider a confirmation dialog before actions that cannot be undone", and "do try your best to offer undo" | 2026-10-18 |
15
+ | Cancelled edit restores, never discards unasked | [Primer, Edit pattern](https://primer.style/product/scenario-patterns/edit): "Put the content back to the value it had before the edit when someone cancels", and "Confirm before discarding an edit someone has put work into". The anti-pattern is to "Discard a half-written edit because someone pressed Escape or clicked outside the editor" | 2026-10-23 |
16
+
17
+ ## Element states
18
+
19
+ | Bullet | Source | Read |
20
+ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
21
+ | Distinct interaction states | [Visibility of system status](https://www.nngroup.com/articles/visibility-system-status/): "Did the system actually catch that button press", and an element with no pressed or hover response leaves the person unable to tell | 2026-10-18 |
22
+ | Say why a control is disabled | [Cloudscape, Disabled and read-only states](https://cloudscape.design/patterns/general/disabled-and-read-only-states/): "Use disabled reasons where adequate context is not provided through disabled button or label text", and `aria-disabled="true"` is used "so that it will remain focusable" | 2026-10-23 |
23
+ | Declare `color-scheme` | [MDN, color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/color-scheme): the user agent adapts "The default colors of scrollbars and other interaction UI" and "The default colors of form controls", and the page opts in by declaring it on the `:root` element | 2026-10-23 |
24
+ | Hover and focus content | [Understanding Content on Hover or Focus](https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html): additional content is "Dismissible" without moving hover or focus, "Hoverable" so the pointer can move over it, and "Persistent" until "the hover or focus trigger is removed, the user dismisses it, or its information is no longer valid" | 2026-10-23, WCAG 2.2 |
25
+ | No change of context on focus or input | [Understanding On Focus](https://www.w3.org/WAI/WCAG22/Understanding/on-focus.html): "When any user interface component receives focus, it does not initiate a change of context". [Understanding On Input](https://www.w3.org/WAI/WCAG22/Understanding/on-input.html): changing a setting does not cause one "unless the user has been advised of the behavior before using the component" | 2026-10-23, WCAG 2.2 |
26
+ | No intermediate flash | [Cumulative Layout Shift](https://web.dev/articles/cls): "Unexpected layout shifts can disrupt the user experience", caused by content "dynamically added to the page before existing content" | 2026-10-18 |
@@ -16,6 +16,7 @@ paths:
16
16
  - 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
17
  - 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
18
  - Give an interactive element with no visible text label a name through `aria-label` or `aria-labelledby`.
19
+ - Put the visible text in the accessible name, first where you can (WCAG 2.5.3).
19
20
 
20
21
  ## Text alternatives
21
22
 
@@ -26,6 +27,7 @@ paths:
26
27
 
27
28
  - 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
29
  - 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).
30
+ - Give text 4.5:1 contrast, or 3:1 when large (WCAG 1.4.3).
29
31
 
30
32
  ## Reflow
31
33
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Focus styles, keyboard operation, focus management, and pointer targets for rendered UI
2
+ description: Focus styles, keyboard operation, composite widgets, and focus management for rendered UI
3
3
  paths:
4
4
  - '**/*.tsx'
5
5
  - '**/*.jsx'
@@ -15,24 +15,21 @@ paths:
15
15
  - Style focus through the project's one focus ring rather than a per-component focus style.
16
16
  - Never set `outline: none` or `outline-none` without a replacement focus indicator in the same rule.
17
17
  - Give the focus ring 3:1 contrast against its background in every theme the project ships.
18
+ - 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
19
 
19
20
  ## Keyboard operation
20
21
 
21
22
  - Close a dialog, popover, menu, or inline confirmation on Escape, and cancel an in-progress edit the same way.
23
+ - 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
24
  - 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
25
 
25
26
  ## Composite widgets
26
27
 
27
28
  - 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
29
  - Open a combobox popup on Down Arrow, accept the focused option on Enter, and close the popup on Escape without changing the value.
30
+ - 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
31
 
30
32
  ## Focus management
31
33
 
32
34
  - Move focus into a dialog when it opens, and return it to the element that opened it when it closes.
33
35
  - 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.
@@ -0,0 +1,23 @@
1
+ ---
2
+ description: Pointer actions, gestures, outside-press dismissal, and target size for rendered UI
3
+ paths:
4
+ - '**/*.tsx'
5
+ - '**/*.jsx'
6
+ - '**/*.astro'
7
+ - '**/*.html'
8
+ - '**/*.css'
9
+ ---
10
+
11
+ # Pointer standards
12
+
13
+ ## Pointer actions
14
+
15
+ - Dismiss a popover or menu on a press outside it and when focus leaves it, as well as on Escape.
16
+ - Run a pointer action on release rather than press, so a person can slide off the target to abort it (WCAG 2.5.2).
17
+ - Give a path-based or multipoint gesture, such as a swipe or pinch, a single-pointer alternative with no path (WCAG 2.5.1).
18
+ - 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).
19
+
20
+ ## Pointer targets
21
+
22
+ - 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).
23
+ - 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.
@@ -12,21 +12,21 @@ paths:
12
12
 
13
13
  ## What a surface is
14
14
 
15
- - Treat anything the project renders for a person as a surface, a generated page as much as a route.
15
+ - Treat anything the project renders for a person as a surface, generated pages included.
16
16
  - Skip a component the production build strips out, such as a dev-only switcher.
17
17
 
18
18
  ## When to capture
19
19
 
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.
20
+ - Run the project's capture command against a preview server, never a dev server, after changing a surface. Report a project with none.
21
+ - Capture every theme the surface ships, and again after fixing a defect found.
22
+ - Read your capture against the `canon:ui-checklist` boxes before opening the pull request, reporting a skill that does not resolve.
22
23
 
23
24
  ## What a capture covers
24
25
 
25
26
  - Capture the full page, never a component in isolation.
26
27
  - 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
28
  - 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.
29
+ - Capture a state case at one width, driving states a first render cannot reach, such as an open menu.
30
30
  - Add a surface's case with the surface, and remove it with the surface.
31
31
 
32
32
  ## Sharing a capture
@@ -14,6 +14,7 @@ paths:
14
14
 
15
15
  - Confirm every user-initiated mutation, such as a save, delete, or import, inline on success, and show an inline error when it fails.
16
16
  - 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).
17
+ - 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
18
  - Show no optimistic status, such as a green dot or "connected", while unsaved edits are pending.
18
19
 
19
20
  ## Empty states
@@ -26,17 +27,8 @@ paths:
26
27
  - Show a progress indicator for any operation a person waits on for longer than about one second.
27
28
  - Mark previous content as updating while new content loads, rather than showing it unmarked as current.
28
29
 
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
30
  ## Overflow
39
31
 
40
32
  - Truncate long text in a constrained container with an ellipsis rather than letting it overflow.
41
33
  - 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.
34
+ - Keep interactive borders clear of a parent's `overflow` clipping, padding the edge items of a scrollable list.
@@ -0,0 +1,25 @@
1
+ ---
2
+ description: Destructive actions, edit cancel, and element states for interactive controls
3
+ paths:
4
+ - '**/*.tsx'
5
+ - '**/*.jsx'
6
+ - '**/*.astro'
7
+ - '**/*.html'
8
+ - '**/*.css'
9
+ ---
10
+
11
+ # UX controls standards
12
+
13
+ ## Destructive actions
14
+
15
+ - Confirm a destructive action, such as a delete, disconnect, or discard, before it runs, unless it can be undone afterward.
16
+ - 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.
17
+
18
+ ## Element states
19
+
20
+ - Give every interactive element distinct hover, active, focus, and disabled styles.
21
+ - 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.
22
+ - Say why a control is disabled, in text beside it or a tooltip, and keep it focusable through `aria-disabled` when the reason matters.
23
+ - Declare `color-scheme` on `:root` to match each theme, so scrollbars and form controls follow the theme instead of staying light.
24
+ - 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).
25
+ - 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,15 @@
1
+ # Rule splits a sync tells a target about. Each key under [split] is the
2
+ # basename of a rule that shed bullets into others, and its value lists the
3
+ # basenames those bullets moved to. `canon gov sync` adds no rule, so a target
4
+ # holding the key and not a partner reads a notice naming the partner and the
5
+ # `canon gov install --add` command that installs it.
6
+ #
7
+ # This ledger is not the rename ledger. A rename entry resolves to a successor
8
+ # the sync installs, and a split key is a live rule the target keeps. Add the
9
+ # entry in the same change as the split. The notice is stateless, so a target
10
+ # installed after the split reads it too until it adds the partner. Prune an
11
+ # entry only once its key or partner is retired, which the live-rule check in
12
+ # `src/gov/splits.test.ts` forces.
13
+ [split]
14
+ keyboard = ["pointer"]
15
+ ux-completeness = ["ux-controls"]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/canon",
3
3
  "type": "module",
4
- "version": "5.61.0",
4
+ "version": "5.62.0",
5
5
  "description": "Runs your agent's work and keeps its code good, on one setup for every repo.",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -285,7 +285,9 @@ function renderTooling(report: CheckReport): void {
285
285
  if (count > 0) logWarn(`${count} ${category}`)
286
286
  }
287
287
  logInfo(
288
- 'Run `canon tooling sync --check` to see which files, `--write` to apply.',
288
+ tooling.changes === tooling.counts.customized
289
+ ? 'A customized config moved upstream, and no write touches it. Run `canon tooling diff` to see which, and `canon tooling lift <path>` to take it.'
290
+ : 'Run `canon tooling sync --check` to see which files, `--write` to apply.',
289
291
  )
290
292
  }
291
293