@erclx/canon 5.44.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 (126) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/canon-cli/SKILL.md +0 -1
  4. package/claude/skills/design-taste/REQUIREMENT.md +2 -2
  5. package/claude/skills/pick-by-eye/REQUIREMENT.md +17 -67
  6. package/claude/skills/role-orchestrator/REQUIREMENT.md +16 -99
  7. package/claude/skills/role-planner/REQUIREMENT.md +15 -73
  8. package/claude/skills/role-worker/REQUIREMENT.md +13 -41
  9. package/claude/skills/target-setup/SKILL.md +2 -2
  10. package/claude/skills/target-setup/references/detect.md +0 -1
  11. package/claude/skills/target-setup/references/verify.md +2 -2
  12. package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
  13. package/claude/skills/teach-workspace/references/promotion.md +5 -5
  14. package/docs/agents/install-and-sync.md +2 -2
  15. package/docs/agents/output-shape.md +1 -2
  16. package/docs/target/migrations.md +18 -0
  17. package/docs/target/projects.md +1 -2
  18. package/docs/target/scenarios.md +4 -1
  19. package/docs/workflow/skill-map-on-request.md +1 -1
  20. package/governance/detect.toml +4 -0
  21. package/governance/ledger/lang/go.md +61 -0
  22. package/governance/ledger/lang/php.md +50 -0
  23. package/governance/ledger/lang/python.md +68 -0
  24. package/governance/ledger/lang/typescript.md +64 -0
  25. package/governance/ledger/lib/database.md +65 -0
  26. package/governance/ledger/lib/e2e-reliability.md +57 -0
  27. package/governance/ledger/lib/pydantic.md +61 -0
  28. package/governance/ledger/lib/security-server.md +62 -0
  29. package/governance/ledger/lib/security-web.md +51 -0
  30. package/governance/ledger/lib/tanstack-query.md +57 -0
  31. package/governance/ledger/lib/test-scope.md +43 -0
  32. package/governance/ledger/lib/testing-go.md +57 -0
  33. package/governance/ledger/lib/testing-php.md +51 -0
  34. package/governance/ledger/lib/testing-py.md +67 -0
  35. package/governance/ledger/lib/testing-ts.md +63 -0
  36. package/governance/ledger/lib/zod.md +47 -0
  37. package/governance/ledger/tooling/ci-workflow.md +33 -0
  38. package/governance/ledger/tooling/code-comments.md +48 -0
  39. package/governance/ledger/tooling/config-comments.md +27 -0
  40. package/governance/ledger/tooling/dependencies.md +38 -0
  41. package/governance/ledger/ui/a11y.md +55 -0
  42. package/governance/ledger/ui/copy.md +49 -0
  43. package/governance/ledger/ui/design-reference.md +42 -0
  44. package/governance/ledger/ui/design-taste.md +19 -0
  45. package/governance/ledger/ui/forms.md +71 -0
  46. package/governance/ledger/ui/interface-casing.md +47 -0
  47. package/governance/ledger/ui/keyboard.md +68 -0
  48. package/governance/ledger/ui/link-behavior.md +29 -0
  49. package/governance/ledger/ui/motion.md +33 -0
  50. package/governance/ledger/ui/surface-capture.md +69 -0
  51. package/governance/ledger/ui/ux-completeness.md +79 -0
  52. package/governance/rules/lang/go.md +7 -16
  53. package/governance/rules/lang/php.md +3 -3
  54. package/governance/rules/lang/python.md +9 -18
  55. package/governance/rules/lang/typescript.md +9 -19
  56. package/governance/rules/lib/database.md +5 -5
  57. package/governance/rules/lib/e2e-reliability.md +4 -6
  58. package/governance/rules/lib/pydantic.md +14 -16
  59. package/governance/rules/lib/security-server.md +4 -4
  60. package/governance/rules/lib/security-web.md +6 -10
  61. package/governance/rules/lib/tanstack-query.md +10 -12
  62. package/governance/rules/lib/test-scope.md +4 -4
  63. package/governance/rules/lib/testing-go.md +1 -2
  64. package/governance/rules/lib/testing-php.md +4 -5
  65. package/governance/rules/lib/testing-py.md +11 -19
  66. package/governance/rules/lib/testing-ts.md +7 -16
  67. package/governance/rules/lib/zod.md +6 -8
  68. package/governance/rules/tooling/code-comments.md +2 -4
  69. package/governance/rules/tooling/config-comments.md +1 -4
  70. package/governance/rules/tooling/dependencies.md +1 -1
  71. package/governance/rules/ui/a11y.md +16 -45
  72. package/governance/rules/ui/copy.md +6 -9
  73. package/governance/rules/ui/forms.md +13 -19
  74. package/governance/rules/ui/interface-casing.md +5 -7
  75. package/governance/rules/ui/keyboard.md +38 -0
  76. package/governance/rules/ui/link-behavior.md +3 -3
  77. package/governance/rules/ui/motion.md +3 -3
  78. package/governance/rules/ui/surface-capture.md +15 -27
  79. package/governance/rules/ui/ux-completeness.md +16 -39
  80. package/package.json +1 -1
  81. package/scripts/core/install-check.sh +1 -1
  82. package/src/cli/help.ts +0 -1
  83. package/src/cli.ts +0 -2
  84. package/src/commands/gov.ts +4 -0
  85. package/src/commands/init.ts +2 -2
  86. package/src/commands/tooling.ts +18 -5
  87. package/src/design/components.ts +1 -1
  88. package/src/gov/audit.ts +22 -2
  89. package/src/init/plan.ts +1 -8
  90. package/src/init/steps.ts +0 -8
  91. package/src/inventory/subjects.ts +1 -1
  92. package/src/markdown/scope.ts +4 -0
  93. package/src/migrate/scratch-evidence.ts +12 -4
  94. package/src/records/backup.ts +3 -3
  95. package/src/records/validate.ts +3 -3
  96. package/src/roots/record.ts +17 -8
  97. package/src/tooling/inject.ts +26 -7
  98. package/src/tooling/package.ts +32 -0
  99. package/src/tooling/read.ts +46 -3
  100. package/src/tooling/scan.ts +8 -2
  101. package/tooling/astro/reference.md +64 -93
  102. package/tooling/base/configs/.github/workflows/phase-label-gate.yml +1 -1
  103. package/tooling/base/configs/scripts/verify.ts +1 -1
  104. package/tooling/base/reference.md +1 -9
  105. package/tooling/base/seeds/canon/context/{ci.md → development/ci.md} +1 -1
  106. package/tooling/base/seeds/canon/context/development/index.md +11 -0
  107. package/tooling/base/seeds/canon/context/{development.md → development/setup.md} +8 -12
  108. package/tooling/base/seeds/canon/context/index.md +1 -2
  109. package/tooling/claude/manifest.toml +1 -5
  110. package/tooling/claude/reference.md +36 -59
  111. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +2 -7
  112. package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +2 -7
  113. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +3 -10
  114. package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +2 -7
  115. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -4
  116. package/tooling/nextjs/reference.md +0 -6
  117. package/tooling/php/reference.md +0 -4
  118. package/tooling/web/configs/.github/workflows/verify.yml +28 -0
  119. package/tooling/web/configs/.oxlintrc.json +7 -0
  120. package/tooling/web/configs/e2e/capture-types.ts +35 -0
  121. package/tooling/web/configs/e2e/screenshot.ts +23 -72
  122. package/tooling/web/manifest.toml +1 -1
  123. package/tooling/web/reference.md +77 -124
  124. package/tooling/web/seeds/e2e/capture/cases.ts +47 -0
  125. package/src/commands/wiki.ts +0 -100
  126. package/src/wiki/init.ts +0 -85
@@ -10,35 +10,27 @@ paths:
10
10
 
11
11
  ## Framework
12
12
 
13
- - Use `pytest` for all tests. Do not use `unittest.TestCase`.
14
- - Place tests under `tests/`, mirroring the `src/` package layout.
15
- - Name files `test_*.py` and test functions `test_*`.
13
+ - Write tests as plain `pytest` functions, never `unittest.TestCase` subclasses, which lose fixtures and parametrization.
16
14
 
17
15
  ## Fixtures
18
16
 
19
- - Use `@pytest.fixture` over setup and teardown methods.
20
- - Place shared fixtures in `conftest.py` at the narrowest scope that needs them.
21
- - Set `scope=` (`"session"`, `"module"`, `"function"`) explicitly when reuse matters.
22
- - Use `tmp_path` and `monkeypatch` over hand-rolled temp directories or env stashes.
17
+ - Write setup and teardown as a `@pytest.fixture` that yields, over setup and teardown methods.
18
+ - Place a shared fixture in the `conftest.py` of the narrowest directory whose tests need it.
19
+ - Widen a fixture's `scope=` past the `function` default only for state no test mutates.
20
+ - Use `tmp_path` and `monkeypatch` over hand-rolled temp directories or environment stashes, since both undo themselves.
23
21
 
24
22
  ## Parametrize
25
23
 
26
24
  - Use `@pytest.mark.parametrize` for table-driven cases over per-case test functions.
27
- - Use `ids=` to label parametrized cases when their repr is unclear.
28
25
 
29
26
  ## Async
30
27
 
31
- - Mark async tests with `@pytest.mark.asyncio` or configure `asyncio_mode = "auto"`.
32
- - Do not start a fresh event loop inside tests.
28
+ - Mark each async test `@pytest.mark.asyncio`, or set `asyncio_mode = "auto"`, since strict mode runs only marked tests.
29
+ - Run on the event loop `pytest-asyncio` provides. Never call `asyncio.run()` or create a loop inside a test.
33
30
 
34
31
  ## Assertions and mocks
35
32
 
36
- - Use plain `assert` over `self.assertEqual`. Pytest rewrites assertions for readable diffs.
37
- - Use `pytest.raises(...)` over `try/except` for expected exceptions.
38
- - Use `monkeypatch.setattr` or `unittest.mock.patch` over ad hoc module rewrites.
39
- - Do not make real network calls. Use `responses`, `httpx_mock`, or fakes.
40
-
41
- ## Conventions
42
-
43
- - Arrange, act, assert per test, with one logical assertion group.
44
- - Use descriptive `test_*` names that read as the assertion. Do not prefix with `should_`.
33
+ - Use plain `assert`, which pytest rewrites to report the values, over `self.assertEqual`.
34
+ - Use `pytest.raises(...)` over `try` and `except` for an expected exception.
35
+ - Patch with `monkeypatch.setattr` or `unittest.mock.patch`, never by assigning a module attribute by hand.
36
+ - Do not make real network calls. Use `responses`, `pytest-httpx`, or a fake.
@@ -12,29 +12,20 @@ paths:
12
12
  ## Unit and integration
13
13
 
14
14
  - Use Vitest for unit and integration tests.
15
- - Co-locate unit tests with their respective components.
16
- - Use `userEvent` over synthetic events for interaction simulation.
17
- - Use MSW for network mocking. Do not mock fetch or axios manually.
18
- - Select elements by accessibility attributes first (`getByRole`, `getByLabelText`).
15
+ - Simulate interaction with `userEvent` over `fireEvent`, since it refuses what a browser would, such as a click on a hidden element.
16
+ - Mock the network with MSW. Never mock `fetch` or axios by hand, and never let a unit test make a real call.
17
+ - Query by role or label first, such as `getByRole` and `getByLabelText`, and by test ID only when neither matches.
19
18
 
20
19
  ## End-to-end
21
20
 
22
21
  - Use Playwright for end-to-end tests.
23
- - Place all Playwright tests within the `e2e/` directory.
24
- - Never place Playwright tests inside `src/`.
25
- - Scope the three rules above to tests the Playwright runner executes. A Vitest test importing a browser driver to exercise project code stays beside its module, where Vitest looks for it.
26
- - Keep specs apart from their fixtures, page objects, and helpers inside `e2e/`. Load the `canon:codebase-layout` skill for the folder shape.
22
+ - Place every test the Playwright runner executes under `e2e/`, never `src/`. A Vitest test that drives a browser stays beside its module.
27
23
 
28
24
  ## Timers and async
29
25
 
30
- - Never use `vi.useFakeTimers()` in `beforeEach` when tests use `waitFor`, `act`, or `userEvent`.
31
- - Scope fake timers to the individual test that needs them.
32
- - Restore real timers with `vi.useRealTimers()` in a matching `afterEach`.
26
+ - Pass `advanceTimers: vi.advanceTimersByTime` to `userEvent.setup()` whenever fake timers are on.
27
+ - Restore real timers with `vi.useRealTimers()` in `afterEach`, after `vi.runOnlyPendingTimers()`.
33
28
 
34
29
  ## Conventions
35
30
 
36
- - Use `.test.ts` / `.test.tsx` for unit tests.
37
- - Use `.spec.ts` / `.spec.tsx` for integration tests and for Playwright tests under `e2e/`.
38
- - Do not make real network calls in unit tests.
39
- - `describe()` labels use the exact identifier of the subject under test in its natural casing.
40
- - `it()` descriptions use "should" + sentence case.
31
+ - Name a unit test `.test.ts` or `.test.tsx`, and an integration or Playwright test `.spec.ts` or `.spec.tsx`.
@@ -9,17 +9,15 @@ paths:
9
9
 
10
10
  ## Type inference
11
11
 
12
- - Use `z.infer<typeof Schema>` to generate TypeScript types (Single Source of Truth).
13
- - Do not manually declare interfaces that duplicate Zod schemas.
14
- - Do not export the runtime Schema if only the inferred Type is required by consumers.
12
+ - Derive a schema's type with `z.infer<typeof Schema>`, never a hand-written interface that duplicates the schema.
15
13
 
16
14
  ## Boundary validation
17
15
 
18
- - Use `.strict()` for untrusted external API boundaries to prevent data pollution.
19
- - Use `.parse()` for blocking validation (env vars) and `.safeParse()` for recoverable flows (forms).
20
- - Restrict `z.coerce` to I/O boundaries (e.g., URL params). Never use it for internal data flow.
16
+ - Parse untrusted input with `z.strictObject()` so an unknown key fails, never with a method the Zod 4 changelog marks legacy.
17
+ - Narrow a schema with `.pick()` or `.omit()`, never by passing unknown keys through with `z.looseObject()`.
18
+ - Call `.parse()` where a failure should throw, and `.safeParse()` where the caller recovers, such as a form.
19
+ - Restrict `z.coerce` to string input at an I/O boundary such as URL params, since it converts with `String()` or `Boolean()`.
21
20
 
22
21
  ## Schema safety
23
22
 
24
- - Use `z.unknown()` for truly ambiguous inputs instead of `z.any()`.
25
- - Prefer `.strict()` at boundaries or explicit `.pick()`/`.omit()` over `.passthrough()`.
23
+ - Use `z.unknown()` for an input of unknown shape, never `z.any()`, which infers `any` and switches off checking downstream.
@@ -16,14 +16,12 @@ paths:
16
16
  - Write a comment only when it records a fact the reader cannot recover from the code: an external contract, a rejected alternative, or the reason a surprising line is correct.
17
17
  - Do not restate in prose what the line beside it already says.
18
18
  - Do not comment a self-contained function whose signature and body already carry its behavior.
19
- - Let comment density follow how much of a file's behavior is decided outside that file. Treat density as an outcome, never as a target.
20
- - Do not add or delete a comment to move a file toward a density figure.
19
+ - Do not add or delete a comment to move a file toward a density figure, since density follows how much of its behavior is decided outside it.
21
20
 
22
21
  ## What a comment may claim
23
22
 
24
- - State only what is true of the code as written.
23
+ - Keep each comment true of the code as written, and update or delete one a change invalidates in that same change.
25
24
  - Describe a function's contract and its constraints, never its steps line by line.
26
- - Update or delete an invalidated comment in the same change that invalidates it.
27
25
  - Do not name a person, a ticket, or a date in place of the fact itself.
28
26
 
29
27
  ## What never goes in a comment
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Keep comments terse in dotfiles, config, and workflow files
2
+ description: Keep comments in dotfiles, config, and workflow files to what a key does or accepts
3
3
  paths:
4
4
  - '**/.env*'
5
5
  - '**/.gitignore'
@@ -16,7 +16,4 @@ paths:
16
16
 
17
17
  ## Comments
18
18
 
19
- - Keep each comment to one short line. Do not wrap a single key in a multi-line explanation.
20
- - Prefer a one-word category label over a sentence for a group header.
21
- - Match the comment density of the surrounding file. Do not add a verbose comment next to terse ones.
22
19
  - Comment what a key does or its allowed values. Do not restate the key name.
@@ -15,7 +15,7 @@ paths:
15
15
  ## Declaration
16
16
 
17
17
  - Declare a package in the project manifest before importing it anywhere in the source.
18
- - Add a package with the package manager command that writes the manifest and the lockfile together, such as `bun add` or `uv add`. Never hand-edit the manifest and never install without recording the result.
18
+ - Add a package with the command that writes the manifest and the lockfile together, such as `bun add` or `uv add`. Re-lock in the same change after any hand edit to the manifest.
19
19
  - Commit the lockfile with the manifest change in the same commit.
20
20
  - Declare a package used only by tests, builds, or tooling as a development dependency.
21
21
  - Never import a package that arrives only as a transitive dependency of another package.
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Keyboard interaction, focus management, and ARIA accessibility for rendered UI
2
+ description: Semantics, text alternatives, contrast, and reflow for rendered UI
3
3
  paths:
4
4
  - '**/*.tsx'
5
5
  - '**/*.jsx'
@@ -8,56 +8,27 @@ paths:
8
8
  - '**/*.css'
9
9
  ---
10
10
 
11
- # Accessibility and keyboard standards
11
+ # Accessibility standards
12
12
 
13
- ## Focus styles
13
+ ## Semantics
14
14
 
15
- - All interactive elements must use the project focus ring. Do not define per-component focus styles.
16
- - Never apply `outline-none` without a custom focus ring in the same rule.
17
- - Focus ring must have 3:1 contrast against its background in both light and dark modes.
15
+ - Use a native `<button>` or `<a>` over a `<div>` or `<span>` carrying a click handler, since the native element brings its role, focus, and keyboard activation.
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
+ - 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
+ - Give an interactive element with no visible text label a name through `aria-label` or `aria-labelledby`.
18
19
 
19
- ## Keyboard interaction model
20
+ ## Text alternatives
20
21
 
21
- - Tab / Shift+Tab: move focus sequentially through interactive elements in DOM order.
22
- - Enter: activates buttons and links, submits forms.
23
- - Space: activates buttons and checkboxes, toggles selection in listboxes.
24
- - Arrow keys: navigate within composite widgets. Do not let them exit the widget.
25
- - Escape: closes any overlay, popover, dialog, or dropdown. Cancels in-progress edits.
26
- - Do not introduce non-standard key bindings for common actions.
27
- - Give every author-defined drag a single-pointer alternative and a keyboard path, such as move buttons or arrow-key reordering (WCAG 2.2 Dragging Movements, 2.5.7).
22
+ - Give every `<img>` an `alt`, and use `alt=""` for a decorative image.
23
+ - Describe what an image means, or the action an icon control takes, never its appearance. Do not prefix it with "Image of" or "Photo of".
28
24
 
29
- ## Pointer targets
25
+ ## Contrast and color
30
26
 
31
- - 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.2 Target Size Minimum, 2.5.8).
32
- - Size a native touch target at the platform figure, 44 points on iOS and 48 dp on Android. Do not apply the web figure to native, and do not apply the native figure as the web minimum.
33
-
34
- ## Composite widgets
35
-
36
- - Roving tabindex for interactive collections: one item in the tab sequence at a time.
37
- - Combobox: arrow keys navigate options, Enter selects, Escape closes, typing filters.
38
-
39
- ## Focus management
40
-
41
- - Move focus into any overlay, popover, or dialog on open. Return focus to the trigger on close.
42
- - Never move focus on hover. Only on keyboard input or explicit pointer activation.
43
- - Do not let a sticky header, footer, or overlay fully cover the focused control. Scroll it into view clear of them (WCAG 2.2 Focus Not Obscured, 2.4.11).
44
-
45
- ## ARIA semantics
46
-
47
- - Use semantic HTML over custom elements: `<button>` over a `<div>` carrying a click handler, `<a>` over a `<span>` carrying one.
48
- - A `<div>` with a click handler requires a role, a tab index, and keyboard handlers. Use `<button>` instead.
49
- - Spell an attribute the way the file's syntax spells it: `onclick` and `tabindex` in HTML and Astro markup, `onClick` and `tabIndex` in JSX.
50
- - Set role on custom controls: `role="combobox"`, `role="listbox"`, `role="menu"`, `role="option"`.
51
- - Synchronize state attributes with visual state: `aria-expanded`, `aria-selected`, `aria-checked`, `aria-disabled`.
52
- - Add `aria-label` or `aria-labelledby` to interactive elements with no visible text label.
53
- - Always provide `alt` on `<img>`. Use `alt=""` for decorative images.
54
- - Describe the content or function of the image, not its appearance. Do not prefix with "Image of" or "Photo of".
55
- - Alt text for functional images (icons, buttons) should describe the action, not the graphic.
56
- - Give the visual boundary of a control and every graphic that carries meaning at least 3:1 contrast against adjacent colors (WCAG Non-text Contrast, 1.4.11).
57
- - Never make color the only carrier of a state, error, or distinction. Pair it with text, an icon, or a pattern (WCAG Use of Color, 1.4.1).
27
+ - 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
+ - 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).
58
29
 
59
30
  ## Reflow
60
31
 
61
- - Let content reflow at a viewport 320 CSS pixels wide with no loss of content or function and no two-dimensional scrolling. Only content whose meaning depends on both axes, such as a data table, a map, or a diagram, may scroll sideways (WCAG Reflow, 1.4.10, Level AA).
62
- - Treat 320 as the criterion's own test condition rather than a device width. It is equivalent to a 1280 pixel window at 400 percent zoom, so a layout that breaks there breaks for a person who zooms.
63
- - Hold the same 320 floor for the content region beside persistent chrome a person can resize. The criterion measures the viewport, so this extension is this rule's own rather than the criterion's: a panel widened to 480 in a 768 window leaves 288 for the content, under the floor at a window the criterion passes. `surface-capture` states where the frame for it gets taken.
32
+ - Let content reflow at 320 CSS pixels wide with no loss and no two-dimensional scrolling, except a data table, map, or diagram (WCAG 1.4.10).
33
+ - Treat 320 as a 1280 pixel window at 400 percent zoom rather than a device width, so a layout breaking there breaks for a person who zooms.
34
+ - Hold the same 320 floor for the content region beside persistent chrome a person can resize. This extends the criterion, which measures the viewport alone.
@@ -11,21 +11,18 @@ paths:
11
11
 
12
12
  ## Punctuation
13
13
 
14
- - Do not use em dashes (`—`) or semicolons (`;`). Use a comma or period, or restructure the sentence.
15
- - Do not add punctuation to button labels or short action strings.
14
+ - Write no em dash (`—`) or semicolon in rendered copy. Use a comma or a period, or restructure the sentence.
15
+ - Add no trailing punctuation to a button label or a short action string.
16
16
 
17
17
  ## Button copy
18
18
 
19
- - Use imperative verbs for actions: `Save`, `Delete`, `Connect`, `Cancel`.
20
- - Avoid padded phrasing: `Save` over `Save changes`, `Delete` over `Click to delete`.
19
+ - Label a button with the verb of the action it performs, such as `Save` or `Delete`, never with filler such as `Click to delete`.
21
20
 
22
21
  ## Error messages
23
22
 
24
- - State what to do, not what went wrong: `Enter a valid email` over `Email is invalid`.
25
- - Keep messages short and actionable.
26
- - One sentence maximum.
23
+ - Tell the person how to fix the error, such as `Enter an email address` over `Email is invalid`.
24
+ - Keep an error message to one short sentence in plain language, with no technical jargon or error codes.
27
25
 
28
26
  ## Placeholder text
29
27
 
30
- - Show format examples over instructions: `name@example.com` over `Enter your email here`.
31
- - Reserve instructions for labels or helper text below the input.
28
+ - 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.
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Form validation timing, save-blocking, and derived state for rendered forms
2
+ description: Form validation timing, submission, error placement, and derived state for rendered forms
3
3
  paths:
4
4
  - '**/*.tsx'
5
5
  - '**/*.jsx'
@@ -11,35 +11,29 @@ paths:
11
11
 
12
12
  ## Validation timing
13
13
 
14
- - Validate on blur, not on every keystroke. Exception: realtime feedback that is explicitly part of the feature (e.g. character count, live search).
15
- - After a field shows its first error (on blur), re-validate on every change so the error clears as soon as the input becomes valid.
16
- - Apply the same validation timing to all fields in a form. Do not mix blur-only and change-only validation within one form.
17
- - Do not show an error on a field the user has never touched.
14
+ - Validate when the person submits or continues, never when focus leaves a field. Realtime feedback the feature exists for, such as a character count, is the exception.
15
+ - Re-validate a field on every change once it shows an error, so the error clears as soon as the input is valid.
18
16
 
19
- ## Save blocking
17
+ ## Submission
20
18
 
21
- - Block save when any required field is empty, invalid, or has never been touched.
22
- - Treat whitespace-only values as empty for required fields.
19
+ - Refuse a submit while a required field is empty, whitespace-only, or invalid, and show each error. Keep the submit button enabled rather than disabling it.
23
20
 
24
21
  ## Error placement
25
22
 
26
- - Show the error directly under the field that caused it, not under an unrelated field.
27
- - When a change to field A causes a conflict involving field B, show the error under field A (the field the user edited), not under field B.
28
-
29
- ## Submission errors
30
-
31
- - When a failed submission carries several errors, move focus to a summary that links to each failing field. Keep the inline error beside each field.
23
+ - Show each error next to the field that caused it, never under an unrelated field.
24
+ - Show a cross-field conflict under the field the person edited, not under the field it conflicts with.
25
+ - Move focus to an error summary linking to each failing field when a submission fails, and keep the inline error beside each field.
32
26
 
33
27
  ## Authentication and re-entry
34
28
 
35
- - Let a password manager fill sign-in fields and accept a pasted value. Do not block paste or autofill on a password or code field (WCAG 2.2 Accessible Authentication, 3.3.8).
36
- - Do not ask for information the user already gave earlier in the same flow. Prefill it or offer it for selection (WCAG 2.2 Redundant Entry, 3.3.7).
29
+ - Let a password manager fill sign-in fields and accept a pasted value. Never block paste or autofill on a password or code field (WCAG 3.3.8).
30
+ - Never ask again for information the person gave earlier in the same flow. Prefill it or offer it for selection (WCAG 3.3.7).
37
31
 
38
32
  ## Input sanitization
39
33
 
40
- - Trim leading and trailing whitespace from text inputs on blur or submit, not on every keystroke.
41
- - If a field is case-sensitive, surface that constraint near the field. Do not silently treat `Foo` and `foo` as different values without warning.
34
+ - Trim leading and trailing whitespace from a text input on submit, never on every keystroke.
35
+ - Say near a case-sensitive field that it is case-sensitive, rather than silently treating `Foo` and `foo` as different values.
42
36
 
43
37
  ## Derived display state
44
38
 
45
- - Reset status indicators, counts, and derived display values when their source input changes.
39
+ - Reset a status indicator, count, or derived value to neutral when its source input changes.
@@ -13,19 +13,17 @@ paths:
13
13
 
14
14
  ## Sentence case
15
15
 
16
- - Use sentence case for all rendered interface text: headings, labels, nav items, tab titles, and dialog titles.
17
- - Retain original casing for proper nouns and product names: `GitHub`, `macOS`, `TypeScript`.
18
- - Treat title case on every heading as a template tell, since it reads as a default rather than a choice.
16
+ - 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.
17
+ - Keep the original casing of a proper noun or product name, such as `GitHub`, `macOS`, or `TypeScript`.
19
18
 
20
19
  ## Uppercase labels
21
20
 
22
- - Keep small uppercase labels above headings to one per three sections, with the first screen counting as one. More than `ceil(sections / 3)` is too many, and the fix is usually to delete the label, since a section's position already says what it is.
23
- - Treat the count as a judgment, since a glob cannot check it.
21
+ - 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.
24
22
 
25
23
  ## Where it applies
26
24
 
27
- - The rule covers markup, MDX, and content modules under a `content/` folder. Copy kept elsewhere, such as a locale file, is not reached, so apply the same casing there without the rule firing.
25
+ - Apply the same casing to interface copy kept outside the globs, such as a locale file, which this rule never fires on.
28
26
 
29
27
  ## Overriding
30
28
 
31
- - Depart from sentence case where the case needs it, such as an acronym, a brand mark, or a set-in-caps identity the design chose on purpose.
29
+ - 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.
@@ -0,0 +1,38 @@
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
+ # Keyboard and focus standards
12
+
13
+ ## Focus styles
14
+
15
+ - Style focus through the project's one focus ring rather than a per-component focus style.
16
+ - Never set `outline: none` or `outline-none` without a replacement focus indicator in the same rule.
17
+ - Give the focus ring 3:1 contrast against its background in every theme the project ships.
18
+
19
+ ## Keyboard operation
20
+
21
+ - Close a dialog, popover, menu, or inline confirmation on Escape, and cancel an in-progress edit the same way.
22
+ - 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
+ ## Composite widgets
26
+
27
+ - 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
+ - Open a combobox popup on Down Arrow, accept the focused option on Enter, and close the popup on Escape without changing the value.
29
+
30
+ ## Focus management
31
+
32
+ - Move focus into a dialog when it opens, and return it to the element that opened it when it closes.
33
+ - 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.
@@ -11,9 +11,9 @@ paths:
11
11
 
12
12
  ## Default target
13
13
 
14
- - Open a link in the same tab. Reserve `target="_blank"` for a destination that would discard in-progress work if it replaced the current page, such as a document a user is midway through elsewhere.
15
- - Do not add `target="_blank"` as a default for every external link.
14
+ - 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.
15
+ - Never add `target="_blank"` as a default for every external link.
16
16
 
17
17
  ## mailto: links
18
18
 
19
- - Open a `mailto:` link in the same tab. It hands off to the mail client rather than replacing page content, so a new tab leaves an empty tab behind.
19
+ - 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.
@@ -12,12 +12,12 @@ paths:
12
12
 
13
13
  ## Moving content
14
14
 
15
- - Give any content that moves, blinks, or scrolls automatically for more than five seconds a control to pause, stop, or hide it (WCAG Pause, Stop, Hide, 2.2.2).
15
+ - Give any content that moves, blinks, or scrolls automatically for more than five seconds a control to pause, stop, or hide it (WCAG 2.2.2).
16
16
  - Halt an auto-advancing carousel or ticker while it holds keyboard focus or pointer hover.
17
- - Do not flash content more than three times in any one second.
17
+ - Never flash content more than three times in any one second (WCAG 2.3.1).
18
18
 
19
19
  ## Reduced motion
20
20
 
21
21
  - Honor `prefers-reduced-motion: reduce` for every animation and transition that conveys no state. Remove it or replace it with an instant change.
22
22
  - Keep essential state changes visible under reduced motion, using a fade or a static indicator instead of movement.
23
- - Do not start video or animated backgrounds on their own when the preference is set.
23
+ - Start no video or animated background on its own when the preference is set.
@@ -12,39 +12,27 @@ paths:
12
12
 
13
13
  ## What a surface is
14
14
 
15
- - A surface is anything the project renders for a person to look at. A framework route is one. A page the project generates is another, whoever generates it.
16
- - Judge a generated page by the same rule as a route. Reading its markup reports nothing about how it composes.
17
- - A component the production build strips out is not a surface, such as a dev-only scenario switcher gated behind a build flag. The build removes it before anything renders, so no comparison exists to capture.
15
+ - Treat anything the project renders for a person as a surface, a generated page as much as a route.
16
+ - Skip a component the production build strips out, such as a dev-only switcher.
18
17
 
19
18
  ## When to capture
20
19
 
21
- - Run the project's capture command after changing what a surface renders. Report it rather than proceeding silently when the project has none.
22
- - Capture against a running preview server. Do not capture against a dev server.
23
- - Capture every theme the surface ships. Do not capture the default theme alone.
24
- - Capture again after fixing a defect a capture found. A repair inside a shared stylesheet can cancel a rule written earlier in the same file.
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.
25
22
 
26
23
  ## What a capture covers
27
24
 
28
- - Capture the full page. Do not capture a component in isolation.
29
- - Declare the widths a layout case captures. Always include 320, the reflow floor from the reflow criterion in `a11y`, then add each breakpoint bucket the project writes rules for, read from the `## Layout` section of `DESIGN.md`.
30
- - Fall back to the 320 floor alone when the project has no `DESIGN.md` or its record carries no `## Layout` section. Do not impose another project's breakpoints.
31
- - Add a layout case at each bound when a surface renders persistent chrome a person can resize, such as a draggable sidebar or a split pane, one with the chrome at its narrowest and one at its widest. Take both at the narrowest declared width where the chrome stays persistent rather than collapsing, since a frame where it has turned into an overlay shows none of the width it takes.
32
- - Read those bounds from the code that clamps the chrome, since `## Layout` has no slot for them. Judge each frame by the content width left beside the chrome rather than by the window width, against the 320 floor `a11y` holds for that region.
33
- - Apply the declaration to a case that covers layout only. A case driving a menu open or an answer chosen tests a state, so it takes one width rather than the full set.
34
- - Read a capture at 320 as proof that a frame was taken there, not that the page reflows correctly. The criterion is stated in `a11y` and nothing here enforces it.
35
- - Write the capture into a folder named `evidence`. The image is collected for the pull request comment when any segment of its path is literally `evidence` and its filename carries an image extension, so the folder name is fixed and its position in the tree is the project's own.
36
- - Several `evidence/` folders in one project is the ordinary shape rather than a problem to consolidate. One per surface is how a project with more than one rendered surface ends up.
37
- - Drive a state a screenshot cannot reach. An initial render reports nothing about a menu that opens, an answer that is chosen, or a rail that tracks scrolling.
38
- - Add a case to the capture record when adding a surface.
39
- - Remove a surface's case in the change that removes the surface.
25
+ - Capture the full page, never a component in isolation.
26
+ - 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
+ - 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.
30
+ - Add a surface's case with the surface, and remove it with the surface.
40
31
 
41
32
  ## Sharing a capture
42
33
 
43
- - Do not commit the sweep. It stays ignored.
44
- - Commit a flagged case's evidence output so the pull request carries the comparison, rather than attaching it by hand.
45
- - A project whose own established convention already commits that same comparison may route a flagged case's evidence there instead of a separate evidence folder. Only an established convention already committing the same comparison qualifies, not a preference for skipping a second folder.
46
- - Commit an evidence case for the first time only after running the capture twice with no code change between the runs and confirming the two outputs are byte-identical.
47
- - Mask the element carrying a value that moves between runs, such as an elapsed-time counter, a clock, or a relative date, in the state's capture case before the double capture, so the check still runs on everything else in the frame. Mask the smallest element holding the value, never the state.
48
- - Do not commit the state as evidence when the masked outputs still differ, which happens when the value's width reflows its neighbors. Name the variance in the pull request instead, and never re-run toward a match.
49
- - Recommitting an unbounded sweep on every run reaches a gigabyte of repository history inside a hundred merges. A small, committed evidence set is what a reviewer needs and what lets GitHub draw its own before-and-after comparison on the pull request.
50
- - `git-pr` and `git-followup` maintain a comparison comment on the pull request automatically once a case is committed, so a reviewer never has to open Files Changed to see it.
34
+ - Write a capture into a folder named `evidence`, which the pull request comment collects from.
35
+ - Commit a flagged case's evidence output and never the sweep, unless the project already commits the same comparison elsewhere.
36
+ - Commit a new evidence case only after two captures with no code change between them match byte for byte.
37
+ - Mask the smallest element holding a value that moves between runs, such as a clock, before the double capture.
38
+ - Name the variance in the pull request when masked outputs still differ, never re-running toward a match.
@@ -10,56 +10,33 @@ paths:
10
10
 
11
11
  # UX completeness standards
12
12
 
13
- ## Mutation feedback
13
+ ## Feedback
14
14
 
15
- - Every user-initiated mutation (save, delete, sync, import, export) must show inline feedback on success.
16
- - Feedback must be transient: auto-dismiss after 2-3 seconds without requiring user action.
17
- - Show inline error feedback when a mutation fails. Do not fail silently.
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
+ - 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
+ - Show no optimistic status, such as a green dot or "connected", while unsaved edits are pending.
18
18
 
19
19
  ## Empty states
20
20
 
21
- - Every list, table, or collection view must handle the empty state explicitly.
22
- - Empty states must include a next action: a button, link, or instruction that tells the user what to do.
23
- - Distinguish between "nothing exists yet" (onboarding) and "nothing matches your filter" (recovery). Use different copy for each.
24
- - Filter-driven empty states must include a way to clear the filter (link or button).
21
+ - Give every list, table, or collection an explicit empty state carrying a next action, such as a button or link.
22
+ - Write different copy for "nothing exists yet" and "nothing matches your filter", and give the filtered state a way to clear the filter.
25
23
 
26
24
  ## Loading states
27
25
 
28
- - Every async operation visible to the user must show a loading indicator (spinner, skeleton, or disabled state).
29
- - Do not show stale content while new content is loading. Either show a loading state or keep the previous content with a progress indicator.
26
+ - Show a progress indicator for any operation a person waits on for longer than about one second.
27
+ - Mark previous content as updating while new content loads, rather than showing it unmarked as current.
30
28
 
31
29
  ## Destructive actions
32
30
 
33
- - Destructive actions (delete, disconnect, discard) must require confirmation before executing.
34
- - Confirmation UI must be dismissible via Escape in addition to a cancel button.
31
+ - Confirm a destructive action, such as a delete, disconnect, or discard, before it runs, unless it can be undone afterward.
35
32
 
36
- ## Inline confirmations
33
+ ## Element states
37
34
 
38
- - All inline confirmation rows (delete, discard, cancel) must be dismissible via Escape.
39
- - Confirmation labels and destructive buttons must have sufficient contrast in both light and dark modes.
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.
40
37
 
41
- ## Status indicators
38
+ ## Overflow
42
39
 
43
- - Status indicators (dots, badges, connection status) must reset to a neutral state when their source input changes.
44
- - Do not show optimistic status (green dot, "connected") while unsaved edits are pending.
45
-
46
- ## State transitions
47
-
48
- - Do not flash intermediate states during transitions (e.g., white flash on theme load, layout jump before data arrives).
49
- - Use CSS transitions or deferred rendering to prevent visible flicker between states.
50
-
51
- ## Interactive element states
52
-
53
- - All interactive elements must visually respond to hover, active, focus, and disabled states.
54
- - Disabled elements must use reduced opacity or muted colors and `cursor: not-allowed`.
55
- - Do not rely on a single state (e.g., focus only) to communicate interactivity.
56
-
57
- ## Overflow and truncation
58
-
59
- - Long text in constrained containers must truncate with ellipsis, not overflow or wrap unexpectedly.
60
- - Truncated text must be accessible via `title` attribute or expandable interaction.
61
-
62
- ## Scroll and clipping
63
-
64
- - Focus rings and interactive borders must not be clipped by parent `overflow: hidden` or `overflow: auto` containers.
65
- - Add padding or adjust overflow to prevent clipping on edge items in scrollable lists.
40
+ - Truncate long text in a constrained container with an ellipsis rather than letting it overflow.
41
+ - 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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/canon",
3
3
  "type": "module",
4
- "version": "5.44.0",
4
+ "version": "5.45.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": {
@@ -100,7 +100,7 @@ log_step "Assert scaffold"
100
100
  # Authoring references name no path because they ship inside the plugin's
101
101
  # skills rather than installing into a target. The two
102
102
  # rule paths stand for the `claude` and `canon` groups `base` takes whole.
103
- for path in "CLAUDE.md" ".claude/wiki/index.md" ".claude" "canon/context/index.md" \
103
+ for path in "CLAUDE.md" ".claude" "canon/context/index.md" \
104
104
  ".oxfmtrc.json" ".lintstagedrc" ".husky/pre-commit" ".github/workflows/verify.yml" "scripts/verify.ts" \
105
105
  ".claude/rules/canon/claude/output.md" ".claude/rules/canon/canon/scratch.md"; do
106
106
  if [ ! -e "$TARGET_DIR/$path" ]; then
package/src/cli/help.ts CHANGED
@@ -29,7 +29,6 @@ export const COMMAND_GROUPS: { title: string; rows: CommandRow[] }[] = [
29
29
  ['gov [cmd]', 'Governance rules'],
30
30
  ['tooling [cmd]', 'Tooling stacks'],
31
31
  ['claude [cmd]', 'Claude workflow'],
32
- ['wiki [cmd]', 'Wiki pages'],
33
32
  ['indexes [cmd]', 'Regenerate index.md files'],
34
33
  ['docs [cmd|topic]', 'Emit toolkit reference docs'],
35
34
  ],