@erclx/canon 5.43.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/backlog-triage/references/apply.md +6 -6
- package/claude/skills/canon-cli/SKILL.md +4 -5
- package/claude/skills/canvas-board/REQUIREMENT.md +1 -1
- package/claude/skills/canvas-board/SKILL.md +1 -1
- package/claude/skills/context-fold/references/context.md +1 -1
- package/claude/skills/create-skill/REQUIREMENT.md +1 -1
- package/claude/skills/create-skill/SKILL.md +2 -2
- package/claude/skills/create-skill/references/skill-requirement.md +68 -9
- package/claude/skills/create-skill/references/skill.md +1 -1
- package/claude/skills/design-identity/REQUIREMENT.md +40 -0
- package/claude/skills/design-identity/SKILL.md +138 -0
- package/claude/skills/{draft-identity → design-identity}/references/card-route.md +2 -2
- package/claude/skills/design-taste/REQUIREMENT.md +6 -6
- package/claude/skills/design-taste/SKILL.md +2 -2
- package/claude/skills/design-taste/references/kinds.md +1 -1
- package/claude/skills/design-taste/references/preflight.md +1 -1
- package/claude/skills/draft-and-pick/REQUIREMENT.md +8 -69
- package/claude/skills/draft-and-pick/SKILL.md +3 -153
- package/claude/skills/draft-doc/REQUIREMENT.md +9 -30
- package/claude/skills/draft-doc/SKILL.md +4 -76
- package/claude/skills/draft-figure/REQUIREMENT.md +8 -42
- package/claude/skills/draft-figure/SKILL.md +3 -77
- package/claude/skills/draft-identity/REQUIREMENT.md +8 -23
- package/claude/skills/draft-identity/SKILL.md +3 -130
- package/claude/skills/draft-ready/REQUIREMENT.md +8 -37
- package/claude/skills/draft-ready/SKILL.md +3 -128
- package/claude/skills/draft-screencast/REQUIREMENT.md +8 -23
- package/claude/skills/draft-screencast/SKILL.md +3 -62
- package/claude/skills/draft-slides/REQUIREMENT.md +8 -27
- package/claude/skills/draft-slides/SKILL.md +3 -72
- package/claude/skills/draw-figure/REQUIREMENT.md +59 -0
- package/claude/skills/draw-figure/SKILL.md +85 -0
- package/claude/skills/{draft-figure → draw-figure}/references/architecture-set.md +2 -2
- package/claude/skills/{draft-figure → draw-figure}/references/hand-drawn.md +2 -2
- package/claude/skills/{draft-figure → draw-figure}/references/mermaid-path.md +2 -2
- package/claude/skills/{draft-figure → draw-figure}/references/mermaid.md +1 -1
- package/claude/skills/make-deck/REQUIREMENT.md +44 -0
- package/claude/skills/make-deck/SKILL.md +80 -0
- package/claude/skills/markdown-craft/REQUIREMENT.md +1 -1
- package/claude/skills/markdown-craft/SKILL.md +2 -2
- package/claude/skills/pick-by-eye/REQUIREMENT.md +36 -0
- package/claude/skills/pick-by-eye/SKILL.md +161 -0
- package/claude/skills/plan-feature/SKILL.md +2 -1
- package/claude/skills/plan-feature/references/plan.md +24 -10
- package/claude/skills/plan-groundwork/SKILL.md +1 -1
- package/claude/skills/plan-intake/SKILL.md +1 -1
- package/claude/skills/plan-ready/REQUIREMENT.md +54 -0
- package/claude/skills/plan-ready/SKILL.md +136 -0
- package/claude/skills/{draft-ready → plan-ready}/references/assembly.md +1 -1
- package/claude/skills/{draft-ready → plan-ready}/references/ready.md +1 -1
- package/claude/skills/record-screencast/REQUIREMENT.md +3 -3
- package/claude/skills/record-screencast/SKILL.md +2 -2
- package/claude/skills/role-orchestrator/REQUIREMENT.md +16 -99
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +5 -2
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +18 -13
- package/claude/skills/role-planner/REQUIREMENT.md +15 -73
- package/claude/skills/role-planner/SKILL.md +2 -1
- package/claude/skills/role-worker/REQUIREMENT.md +13 -41
- package/claude/skills/role-worker/SKILL.md +9 -0
- package/claude/skills/script-screencast/REQUIREMENT.md +40 -0
- package/claude/skills/script-screencast/SKILL.md +70 -0
- package/claude/skills/{draft-screencast → script-screencast}/references/beats-template.md +2 -2
- package/claude/skills/search-craft/REQUIREMENT.md +4 -4
- package/claude/skills/search-craft/SKILL.md +1 -1
- package/claude/skills/target-setup/SKILL.md +3 -2
- package/claude/skills/target-setup/references/detect.md +0 -1
- package/claude/skills/target-setup/references/verify.md +2 -2
- package/claude/skills/task-board/SKILL.md +11 -9
- package/claude/skills/task-board/references/board.md +15 -12
- package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
- package/claude/skills/teach-workspace/SKILL.md +1 -1
- package/claude/skills/teach-workspace/references/lesson-craft.md +2 -2
- package/claude/skills/teach-workspace/references/promotion.md +5 -5
- package/claude/skills/ui-checklist/SKILL.md +2 -0
- package/claude/skills/write-doc/REQUIREMENT.md +46 -0
- package/claude/skills/write-doc/SKILL.md +83 -0
- package/claude/skills/{draft-doc → write-doc}/references/context.md +2 -2
- package/claude/skills/{draft-doc → write-doc}/references/docs.md +2 -2
- package/claude/skills/{draft-doc → write-doc}/references/readme.md +2 -2
- package/claude/skills/{draft-doc → write-doc}/references/wiki-kind.md +3 -3
- package/docs/agents/install-and-sync.md +2 -2
- package/docs/agents/markdown-audit.md +4 -2
- package/docs/agents/migrate.md +2 -2
- package/docs/agents/output-shape.md +1 -2
- package/docs/target/migrations.md +35 -4
- package/docs/target/projects.md +2 -3
- package/docs/target/scenarios.md +4 -1
- package/docs/workflow/parallel-features.md +3 -2
- package/docs/workflow/skill-map-on-request.md +19 -13
- package/docs/workflow/skill-map.md +13 -12
- package/docs/workflow/visual-design-workflow.md +2 -2
- package/governance/detect.toml +4 -0
- package/governance/ledger/framework/astro.md +73 -0
- package/governance/ledger/framework/fastapi.md +76 -0
- package/governance/ledger/framework/nextjs.md +86 -0
- package/governance/ledger/framework/react.md +83 -0
- package/governance/ledger/framework/shadcn.md +60 -0
- package/governance/ledger/framework/tailwind.md +55 -0
- package/governance/ledger/lang/go.md +61 -0
- package/governance/ledger/lang/php.md +50 -0
- package/governance/ledger/lang/python.md +68 -0
- package/governance/ledger/lang/typescript.md +64 -0
- package/governance/ledger/lib/database.md +65 -0
- package/governance/ledger/lib/e2e-reliability.md +57 -0
- package/governance/ledger/lib/pydantic.md +61 -0
- package/governance/ledger/lib/security-server.md +62 -0
- package/governance/ledger/lib/security-web.md +51 -0
- package/governance/ledger/lib/tanstack-query.md +57 -0
- package/governance/ledger/lib/test-scope.md +43 -0
- package/governance/ledger/lib/testing-go.md +57 -0
- package/governance/ledger/lib/testing-php.md +51 -0
- package/governance/ledger/lib/testing-py.md +67 -0
- package/governance/ledger/lib/testing-ts.md +63 -0
- package/governance/ledger/lib/zod.md +47 -0
- package/governance/ledger/tooling/ci-workflow.md +33 -0
- package/governance/ledger/tooling/code-comments.md +48 -0
- package/governance/ledger/tooling/config-comments.md +27 -0
- package/governance/ledger/tooling/dependencies.md +38 -0
- package/governance/ledger/ui/a11y.md +55 -0
- package/governance/ledger/ui/copy.md +49 -0
- package/governance/ledger/ui/design-reference.md +42 -0
- package/governance/ledger/ui/design-taste.md +19 -0
- package/governance/ledger/ui/forms.md +71 -0
- package/governance/ledger/ui/interface-casing.md +47 -0
- package/governance/ledger/ui/keyboard.md +68 -0
- package/governance/ledger/ui/link-behavior.md +29 -0
- package/governance/ledger/ui/motion.md +33 -0
- package/governance/ledger/ui/surface-capture.md +69 -0
- package/governance/ledger/ui/ux-completeness.md +79 -0
- package/governance/rules/framework/astro.md +12 -14
- package/governance/rules/framework/fastapi.md +20 -24
- package/governance/rules/framework/nextjs.md +19 -27
- package/governance/rules/framework/react.md +22 -33
- package/governance/rules/framework/shadcn.md +11 -15
- package/governance/rules/framework/tailwind.md +12 -14
- package/governance/rules/lang/go.md +7 -16
- package/governance/rules/lang/php.md +3 -3
- package/governance/rules/lang/python.md +9 -18
- package/governance/rules/lang/typescript.md +9 -19
- package/governance/rules/lib/database.md +5 -5
- package/governance/rules/lib/e2e-reliability.md +4 -6
- package/governance/rules/lib/pydantic.md +14 -16
- package/governance/rules/lib/security-server.md +4 -4
- package/governance/rules/lib/security-web.md +6 -10
- package/governance/rules/lib/tanstack-query.md +10 -12
- package/governance/rules/lib/test-scope.md +4 -4
- package/governance/rules/lib/testing-go.md +1 -2
- package/governance/rules/lib/testing-php.md +4 -5
- package/governance/rules/lib/testing-py.md +11 -19
- package/governance/rules/lib/testing-ts.md +7 -16
- package/governance/rules/lib/zod.md +6 -8
- package/governance/rules/tooling/code-comments.md +2 -4
- package/governance/rules/tooling/config-comments.md +1 -4
- package/governance/rules/tooling/dependencies.md +1 -1
- package/governance/rules/ui/a11y.md +16 -45
- package/governance/rules/ui/copy.md +6 -9
- package/governance/rules/ui/forms.md +13 -19
- package/governance/rules/ui/interface-casing.md +5 -7
- package/governance/rules/ui/keyboard.md +38 -0
- package/governance/rules/ui/link-behavior.md +3 -3
- package/governance/rules/ui/motion.md +3 -3
- package/governance/rules/ui/surface-capture.md +15 -27
- package/governance/rules/ui/ux-completeness.md +16 -39
- package/governance/rules/writing/markdown.md +1 -1
- package/package.json +1 -1
- package/scripts/core/install-check.sh +1 -1
- package/src/claude/cases/authoring.ts +15 -3
- package/src/claude/cases/misc.ts +12 -0
- package/src/claude/cases/workflow.ts +19 -1
- package/src/claude/skills-audit.ts +113 -1
- package/src/cli/help.ts +0 -1
- package/src/cli.ts +0 -2
- package/src/commands/claude.ts +34 -11
- package/src/commands/demo.ts +1 -1
- package/src/commands/gov.ts +4 -0
- package/src/commands/init.ts +2 -2
- package/src/commands/markdown.ts +1 -1
- package/src/commands/migrate.ts +4 -0
- package/src/commands/pr.ts +30 -6
- package/src/commands/tasks.ts +383 -2
- package/src/commands/tooling.ts +18 -5
- package/src/context/audit.ts +1 -1
- package/src/demo/beats.ts +1 -1
- package/src/design/components.ts +1 -1
- package/src/gov/audit.ts +25 -4
- package/src/init/plan.ts +1 -8
- package/src/init/steps.ts +0 -8
- package/src/inventory/subjects.ts +1 -1
- package/src/markdown/scope.ts +49 -35
- package/src/migrate/record-layout.ts +1 -1
- package/src/migrate/scratch-evidence.ts +12 -4
- package/src/migrate/skill-names.ts +68 -21
- package/src/pr/frames.ts +14 -3
- package/src/records/backup.ts +3 -3
- package/src/records/validate.ts +31 -0
- package/src/roots/record.ts +17 -8
- package/src/tasks/board.ts +854 -0
- package/src/tasks/record.ts +20 -1
- package/src/tasks/validate.ts +206 -9
- package/src/tooling/inject.ts +26 -7
- package/src/tooling/package.ts +32 -0
- package/src/tooling/read.ts +46 -3
- package/src/tooling/scan.ts +8 -2
- package/tooling/astro/configs/card-src/pages/og-card.astro +1 -1
- package/tooling/astro/reference.md +64 -93
- package/tooling/base/configs/.github/workflows/phase-label-gate.yml +1 -1
- package/tooling/base/configs/scripts/verify.ts +1 -1
- package/tooling/base/reference.md +1 -9
- package/tooling/base/seeds/canon/context/{ci.md → development/ci.md} +1 -1
- package/tooling/base/seeds/canon/context/development/index.md +11 -0
- package/tooling/base/seeds/canon/context/{development.md → development/setup.md} +8 -12
- package/tooling/base/seeds/canon/context/index.md +1 -2
- package/tooling/claude/manifest.toml +1 -5
- package/tooling/claude/reference.md +36 -59
- package/tooling/claude/seeds/.claude/hooks/board-validate.sh +65 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +3 -10
- package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -4
- package/tooling/claude/seeds/.claude/settings.json +4 -0
- package/tooling/nextjs/reference.md +0 -6
- package/tooling/php/reference.md +0 -4
- package/tooling/web/configs/.github/workflows/verify.yml +28 -0
- package/tooling/web/configs/.oxlintrc.json +7 -0
- package/tooling/web/configs/e2e/capture-types.ts +35 -0
- package/tooling/web/configs/e2e/screenshot.ts +23 -72
- package/tooling/web/manifest.toml +1 -1
- package/tooling/web/reference.md +77 -124
- package/tooling/web/seeds/e2e/capture/cases.ts +47 -0
- package/src/commands/wiki.ts +0 -100
- package/src/wiki/init.ts +0 -85
- /package/claude/skills/{draft-figure → draw-figure}/references/figures.md +0 -0
- /package/claude/skills/{draft-slides → make-deck}/references/deck.md +0 -0
- /package/claude/skills/{draft-and-pick → pick-by-eye}/references/live-arms.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/agent-facing.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/application.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/cli.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/library.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/plugin.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/requirements.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/wiki.md +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Surface capture rule ledger
|
|
3
|
+
description: Sources for governance/rules/ui/surface-capture.md, one row per bullet
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Surface capture rule ledger
|
|
7
|
+
|
|
8
|
+
The rule states canon's own evidence procedure for a rendered change, so most rows are house choices naming the bug the bullet prevents. The 320 floor rests on WCAG 2.2, and each explanation the old rule carried moved into a row here.
|
|
9
|
+
|
|
10
|
+
## What a surface is
|
|
11
|
+
|
|
12
|
+
| Bullet | Source | Read |
|
|
13
|
+
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
14
|
+
| Generated pages are surfaces | House choice: reading a generated page's markup reports nothing about how it composes, so a page nobody captured ships its layout unseen | 2026-10-18 |
|
|
15
|
+
| Skip build-stripped components | House choice: the production build removes a dev-only switcher before anything renders, so a capture of it compares nothing a person sees | 2026-10-18 |
|
|
16
|
+
|
|
17
|
+
## When to capture
|
|
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
|
+
|
|
24
|
+
## What a capture covers
|
|
25
|
+
|
|
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 |
|
|
34
|
+
|
|
35
|
+
## Sharing a capture
|
|
36
|
+
|
|
37
|
+
| Bullet | Source | Read |
|
|
38
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
39
|
+
| An `evidence` folder | House choice: the pull request comment collects an image only when a path segment is literally `evidence`, so any other name drops the capture. Several such folders, one per surface, is the ordinary shape. | 2026-10-18 |
|
|
40
|
+
| Commit flagged cases only | House choice: recommitting an unbounded sweep on every run reaches a gigabyte of history inside a hundred merges, while a small committed set lets GitHub draw its own before and after comparison | 2026-10-18 |
|
|
41
|
+
| Byte-identical twice | House choice: a case whose output varies between runs shows a diff on every pull request, so the comparison stops meaning a change | 2026-10-18 |
|
|
42
|
+
| Mask the moving value | House choice: an elapsed-time counter or a relative date differs on every run, and masking the smallest element keeps the check running on the rest of the frame | 2026-10-18 |
|
|
43
|
+
| Name the variance | House choice: a value whose width reflows its neighbors survives the mask, and re-running until two frames match hides the variance rather than removing it | 2026-10-18 |
|
|
44
|
+
|
|
45
|
+
## Declined
|
|
46
|
+
|
|
47
|
+
Every bullet the rewrite removed or reshaped, grouped by why.
|
|
48
|
+
|
|
49
|
+
### Moved into a row as the reason
|
|
50
|
+
|
|
51
|
+
- Moved "judge a generated page by the same rule as a route, since reading its markup reports nothing" into the generated pages row.
|
|
52
|
+
- Moved "read a capture at 320 as proof that a frame was taken there, not that the page reflows" into the 320 row.
|
|
53
|
+
- Moved "several `evidence/` folders in one project is the ordinary shape" into the folder row.
|
|
54
|
+
- Moved "recommitting an unbounded sweep reaches a gigabyte of repository history" into the commit row.
|
|
55
|
+
- Moved "do not commit the state as evidence when the masked outputs still differ" into the variance bullet and its row.
|
|
56
|
+
|
|
57
|
+
### Cut as stated elsewhere
|
|
58
|
+
|
|
59
|
+
- Cut "`git-pr` and `git-followup` maintain a comparison comment automatically", which those skills own and which directs nothing at the edit.
|
|
60
|
+
- Cut "fall back to the 320 floor alone when the project has no `DESIGN.md`", merged into the 320 bullet's "or at 320 alone".
|
|
61
|
+
- Cut "read those bounds from the code that clamps the chrome", merged into the chrome bullet's "clamp".
|
|
62
|
+
- Cut "do not impose another project's breakpoints", which the bullet reading `## Layout` already prevents.
|
|
63
|
+
|
|
64
|
+
### Merged or reworded
|
|
65
|
+
|
|
66
|
+
- Merged "run the capture command", "against a running preview", "every theme", and "capture again" into two bullets.
|
|
67
|
+
- Merged "do not commit the sweep" with "commit a flagged case's evidence" and the established convention exception.
|
|
68
|
+
- Merged "add a case" and "remove a surface's case" into one bullet.
|
|
69
|
+
- Shortened every bullet past 200 characters, cutting the rule from 27 bullets and 840 words to 15 and under 300.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: UX completeness rule ledger
|
|
3
|
+
description: Sources for governance/rules/ui/ux-completeness.md, one row per bullet
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UX completeness rule ledger
|
|
7
|
+
|
|
8
|
+
The field is interaction design, and the authorities are the Nielsen Norman Group's research articles, WCAG 2.2 for timing, MDN for the `title` attribute and CSS truncation, and web.dev for layout shift.
|
|
9
|
+
|
|
10
|
+
## Feedback
|
|
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 |
|
|
17
|
+
|
|
18
|
+
## Empty states
|
|
19
|
+
|
|
20
|
+
| Bullet | Source | Read |
|
|
21
|
+
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
22
|
+
| Empty state with a next action | [Designing empty states](https://www.nngroup.com/articles/empty-state-interface-design/): designed empty states "Provide direct pathways for getting started with key tasks" | 2026-10-18 |
|
|
23
|
+
| Distinguish new from filtered | [Designing empty states](https://www.nngroup.com/articles/empty-state-interface-design/): after a filter returns nothing, people wonder "Did an error occur? Did I set the wrong filters or parameters?", and "Totally empty states cause confusion" | 2026-10-18 |
|
|
24
|
+
|
|
25
|
+
## Loading states
|
|
26
|
+
|
|
27
|
+
| Bullet | Source | Read |
|
|
28
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
29
|
+
| 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
|
+
| 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
|
+
## 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
|
+
## Overflow
|
|
46
|
+
|
|
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 |
|
|
52
|
+
|
|
53
|
+
## Declined
|
|
54
|
+
|
|
55
|
+
Every bullet the rewrite removed or reshaped, grouped by why.
|
|
56
|
+
|
|
57
|
+
### Contradicted by the source
|
|
58
|
+
|
|
59
|
+
- Replaced the `title`-or-expand truncation bullet with the never-`title`-alone bullet, since MDN calls the attribute "highly problematic" for touch and keyboard users.
|
|
60
|
+
- Qualified "feedback must auto-dismiss after 2 to 3 seconds" against WCAG 2.2.1, since a message carrying the only copy of its information sets a time limit on reading it.
|
|
61
|
+
- Rewrote "do not show stale content while new content is loading", which offered keeping the previous content as its own alternative, to the marking bullet.
|
|
62
|
+
|
|
63
|
+
### Moved to a sibling rule
|
|
64
|
+
|
|
65
|
+
- Moved "confirmation UI must be dismissible via Escape" and "inline confirmation rows must be dismissible via Escape" to the Escape bullet in `keyboard.md`.
|
|
66
|
+
- Moved "status indicators must reset to a neutral state when their source input changes" to `forms.md`, which held the same bullet for derived values.
|
|
67
|
+
- Cut "confirmation labels and destructive buttons must have sufficient contrast", which `a11y.md` holds for every control.
|
|
68
|
+
|
|
69
|
+
### Cut without a source or a bug class
|
|
70
|
+
|
|
71
|
+
- Cut "disabled elements must use muted colors and `cursor: not-allowed`", a convention Claude already follows that no source sets.
|
|
72
|
+
- Cut "use CSS transitions or deferred rendering to prevent visible flicker", merged into the intermediate flash bullet as its remedy.
|
|
73
|
+
|
|
74
|
+
### Merged or reworded
|
|
75
|
+
|
|
76
|
+
- Merged the `## Inline confirmations`, `## Status indicators`, `## State transitions`, `## Interactive element states`, and `## Scroll and clipping` H2s into six, the merge the plan suggested.
|
|
77
|
+
- Merged "every list must handle the empty state" with "empty states must include a next action", and the two filter bullets into one.
|
|
78
|
+
- Merged "do not rely on a single state to communicate interactivity" into the distinct states bullet.
|
|
79
|
+
- Reworded "every async operation must show a loading indicator" to NN/g's one second threshold, since a shorter spinner distracts.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce
|
|
2
|
+
description: Enforce Astro static-first rendering, explicit island hydration, content collections, and asset placement
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.astro'
|
|
5
5
|
- 'src/pages/**'
|
|
@@ -11,31 +11,29 @@ paths:
|
|
|
11
11
|
|
|
12
12
|
## Static first
|
|
13
13
|
|
|
14
|
-
- Write
|
|
15
|
-
-
|
|
16
|
-
- Prefer server-rendered content over client-fetched data.
|
|
14
|
+
- Write a component as `.astro` when it has no client-side state or event handlers, since it renders to HTML with no client JS.
|
|
15
|
+
- Fetch page data in the component frontmatter, which runs at build or request time, not in a client island.
|
|
17
16
|
|
|
18
17
|
## Islands
|
|
19
18
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
- Keep islands leaf-level. Do not wrap layout chrome in a framework component to enable nested islands.
|
|
19
|
+
- Put a `client:*` directive on the framework component itself, imported directly into a `.astro` file.
|
|
20
|
+
- Use `client:visible` for a component below the fold and `client:idle` for a low-priority one. Keep `client:load` for interactive UI above the fold.
|
|
23
21
|
|
|
24
22
|
## Routing and layouts
|
|
25
23
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
24
|
+
- Give a dynamic `[param].astro` route a `getStaticPaths()` in static output, which builds only the paths it returns.
|
|
25
|
+
- Wrap pages in a layout from `src/layouts/` that renders the page through `<slot />`.
|
|
28
26
|
|
|
29
27
|
## Content
|
|
30
28
|
|
|
31
|
-
-
|
|
32
|
-
-
|
|
29
|
+
- Define collections in `content.config.ts` at the root of `src/`, each with a `glob()` or `file()` loader and a Zod schema.
|
|
30
|
+
- Read entries through `getCollection()` and `getEntry()`, never by importing content files directly.
|
|
33
31
|
|
|
34
32
|
## Styles and assets
|
|
35
33
|
|
|
36
|
-
-
|
|
37
|
-
-
|
|
34
|
+
- Keep component styles scoped. Use `is:global` or `:global()` only for a reset or base style in a layout.
|
|
35
|
+
- Keep local images in `src/` so Astro optimizes them. Use `public/` only for files served as-is.
|
|
38
36
|
|
|
39
37
|
## Environment
|
|
40
38
|
|
|
41
|
-
- Read
|
|
39
|
+
- Read variables through `astro:env` with a schema, or `import.meta.env`, and prefix client-exposed ones with `PUBLIC_`.
|
|
@@ -1,43 +1,39 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce FastAPI
|
|
2
|
+
description: Enforce FastAPI routers, sync and async handlers, dependency injection, lifespan, and error mapping
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.py'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# FastAPI standards
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Routers
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- Use an `app_factory()` callable over a module-level `app = FastAPI()` for testability.
|
|
11
|
+
- Declare path operations on one `APIRouter` per feature and add each with `app.include_router()`, not on `FastAPI()` directly.
|
|
12
|
+
- Put a dependency every route in a group needs, such as auth, in the router's `dependencies=[...]`.
|
|
14
13
|
|
|
15
|
-
##
|
|
14
|
+
## Path operations
|
|
16
15
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- Return pydantic models and set `response_model=` on the decorator for serialization control.
|
|
16
|
+
- Declare a path operation `async def` only when every I/O call in it is awaited. Use plain `def` for a blocking library, which FastAPI runs in a threadpool.
|
|
17
|
+
- Declare the return type or `response_model` as a model that omits secrets, since FastAPI filters the output to it.
|
|
18
|
+
- Take a request body as a Pydantic model parameter, never by parsing `await request.json()` by hand.
|
|
21
19
|
|
|
22
|
-
##
|
|
20
|
+
## Dependencies
|
|
23
21
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
22
|
+
- Declare a dependency as `Annotated[T, Depends(fn)]`, and share a repeated one as a type alias.
|
|
23
|
+
- Open a database session in a `yield` dependency and close it after the `yield`, so each request gets its own.
|
|
24
|
+
- Replace a dependency in tests through `app.dependency_overrides`, never by patching the module.
|
|
27
25
|
|
|
28
|
-
## Lifespan and
|
|
26
|
+
## Lifespan and settings
|
|
29
27
|
|
|
30
|
-
-
|
|
31
|
-
- Load settings
|
|
28
|
+
- Run startup and shutdown in a `lifespan` context manager, never `@app.on_event`, which stops running once `lifespan` is set.
|
|
29
|
+
- Load settings through `pydantic_settings.BaseSettings` behind an `@lru_cache` dependency, so `.env` is read once and tests can override it.
|
|
32
30
|
|
|
33
31
|
## Errors
|
|
34
32
|
|
|
35
|
-
- Raise `HTTPException`
|
|
36
|
-
-
|
|
37
|
-
-
|
|
33
|
+
- Raise `HTTPException` with an explicit status code for a client error.
|
|
34
|
+
- Map a domain exception to a response in one `@app.exception_handler`, over a try and except in each route.
|
|
35
|
+
- Return a safe summary from a handler, never the exception's message or traceback.
|
|
38
36
|
|
|
39
|
-
##
|
|
37
|
+
## Middleware
|
|
40
38
|
|
|
41
|
-
-
|
|
42
|
-
- Apply `dependencies=[Depends(auth)]` at the router or app level for cross-cutting auth.
|
|
43
|
-
- Configure CORS, trusted hosts, and HTTPS redirects through middleware, not per-route checks.
|
|
39
|
+
- Configure CORS through `CORSMiddleware`, listing origins explicitly when `allow_credentials=True`, since a wildcard is refused then.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce Next.js App Router
|
|
2
|
+
description: Enforce Next.js App Router boundaries, caching, Server Action security, and built-in primitives
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.tsx'
|
|
5
5
|
- '**/*.ts'
|
|
@@ -7,42 +7,34 @@ paths:
|
|
|
7
7
|
|
|
8
8
|
# Next.js standards
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Routing
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
12
|
+
- Add routes under `app/` with the App Router, never under `pages/`.
|
|
13
|
+
- Await `params` and `searchParams`, which are Promises in a page, a layout, and a route handler.
|
|
14
14
|
|
|
15
15
|
## Server and client components
|
|
16
16
|
|
|
17
|
-
- Default to Server Components. Add `
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
17
|
+
- Default to Server Components. Add `'use client'` only to a file needing state, event handlers, effects, or browser APIs.
|
|
18
|
+
- Put `'use client'` on the interactive leaf, not a layout, since every module it imports joins the client bundle.
|
|
19
|
+
- Pass a Client Component only serializable props holding the fields it renders, never a whole database record.
|
|
20
|
+
- Add `import 'server-only'` to a module that reads secrets or the database.
|
|
21
21
|
|
|
22
|
-
## Data
|
|
22
|
+
## Data and caching
|
|
23
23
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
24
|
+
- Cache with `'use cache'` and a `cacheLife` call where Cache Components is on, the default for new apps. A `fetch` is not cached by default.
|
|
25
|
+
- Wrap a component reading `cookies()`, `headers()`, or uncached data in `<Suspense>` with a fallback.
|
|
26
|
+
- Call `revalidatePath` or `revalidateTag` in the Server Action after a mutation.
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Mutations
|
|
29
29
|
|
|
30
|
-
-
|
|
31
|
-
- Validate Server Action
|
|
32
|
-
- Return serializable values. Do not return Response or stream objects from a Server Action.
|
|
33
|
-
|
|
34
|
-
## Route handlers
|
|
35
|
-
|
|
36
|
-
- Place HTTP endpoints in `app/**/route.ts`. Do not add `pages/api/`.
|
|
37
|
-
- Export named methods (`GET`, `POST`, ...). Return `NextResponse` over raw `Response` for typed helpers.
|
|
38
|
-
- Read params from the function signature (`{ params }`), not from the request URL.
|
|
30
|
+
- Verify authentication and resource ownership inside every Server Action, since each is reachable by a direct POST.
|
|
31
|
+
- Validate every Server Action argument before use, and return only the fields the UI needs.
|
|
39
32
|
|
|
40
33
|
## Built-in primitives
|
|
41
34
|
|
|
42
|
-
- Use `next/link`
|
|
43
|
-
-
|
|
35
|
+
- Use `next/link` for internal navigation and `next/image` for raster images.
|
|
36
|
+
- Give `next/image` a `width` and `height` for a remote source, or `fill` inside a positioned parent.
|
|
44
37
|
|
|
45
|
-
##
|
|
38
|
+
## Environment
|
|
46
39
|
|
|
47
|
-
-
|
|
48
|
-
- Prefix browser-exposed env vars with `NEXT_PUBLIC_`. Never read unprefixed server-only env vars from a client component.
|
|
40
|
+
- Prefix a variable with `NEXT_PUBLIC_` only when the browser needs it, since its value is inlined at build time.
|
|
@@ -1,51 +1,40 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce
|
|
2
|
+
description: Enforce React render purity, state derivation, memoization, and boundary placement
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.tsx'
|
|
5
5
|
- '**/*.ts'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# React
|
|
8
|
+
# React standards
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Rendering
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
## Project structure
|
|
16
|
-
|
|
17
|
-
- Place domain logic in `src/features/` and restrict `src/components/` to shared UI.
|
|
18
|
-
- Do not place feature-specific components in the global components folder.
|
|
19
|
-
- Import environment variables only from the validated configuration module.
|
|
20
|
-
|
|
21
|
-
## Component patterns
|
|
22
|
-
|
|
23
|
-
- Use function declarations for components over arrow functions.
|
|
24
|
-
- Define TypeScript interfaces for props immediately above the component.
|
|
25
|
-
- Use `<>` shorthand for fragments unless key prop is required.
|
|
26
|
-
- Use stable, unique keys for list items over array index.
|
|
27
|
-
- Extract components when JSX exceeds a single responsibility.
|
|
12
|
+
- Keep components and hooks pure during render. Move side effects and `Math.random()` into an event handler or an effect.
|
|
13
|
+
- Never mutate props or state. Build a new value and pass it to the `useState` setter.
|
|
14
|
+
- Key list items by a stable ID from the data, never by array index or a value generated during render.
|
|
28
15
|
|
|
29
16
|
## State and effects
|
|
30
17
|
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
- Lift the state to a parent and reset the child with a `key` prop, over running a reset effect in the child.
|
|
36
|
-
- Return a sentinel (`undefined` or a `useSyncExternalStore` placeholder) from hooks that hydrate asynchronously and gate consumers on it, over running a hydration effect.
|
|
18
|
+
- Calculate a value derivable from props or state during render, never in an effect that syncs it into state.
|
|
19
|
+
- Reset a child's state by passing it a new `key`, over a reset effect in the child.
|
|
20
|
+
- Read a browser or external store with `useSyncExternalStore` and a `getServerSnapshot` matching the server output.
|
|
21
|
+
- Wrap a data-fetching effect in a custom hook whose cleanup ignores stale responses, when the framework has no fetching primitive.
|
|
37
22
|
|
|
38
23
|
## Memoization
|
|
39
24
|
|
|
40
|
-
-
|
|
41
|
-
-
|
|
25
|
+
- Leave memoization to React Compiler where it is enabled, as React recommends for new code. Add `useMemo` only for precise control.
|
|
26
|
+
- Without the compiler, memoize only a calculation measured at 1ms or more, or a value a `memo` child or a Hook dependency reads.
|
|
27
|
+
|
|
28
|
+
## Composition
|
|
29
|
+
|
|
30
|
+
- Pass props first, then extract components and pass JSX as `children`. Reach for context only when neither works.
|
|
42
31
|
|
|
43
|
-
##
|
|
32
|
+
## Error and loading boundaries
|
|
44
33
|
|
|
45
|
-
-
|
|
34
|
+
- Place an error boundary where an error message makes sense, such as around a list and each item, never around every component.
|
|
35
|
+
- Expect Suspense to catch `lazy`, `use` on a cached Promise, or a framework loader, never a fetch inside an effect.
|
|
36
|
+
- Place Suspense boundaries to match the loading sequence the user should see.
|
|
46
37
|
|
|
47
|
-
##
|
|
38
|
+
## Exports
|
|
48
39
|
|
|
49
|
-
-
|
|
50
|
-
- Place Suspense at data-fetching boundaries.
|
|
51
|
-
- Do not use a single root-level error boundary as the only safety net.
|
|
40
|
+
- Use named exports for components and hooks, since a default export renamed at import drifts from its name in a search.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce shadcn/ui
|
|
2
|
+
description: Enforce shadcn/ui component ownership, typed primitives, semantic tokens, and composition props
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.tsx'
|
|
5
5
|
- '**/*.jsx'
|
|
@@ -9,26 +9,22 @@ paths:
|
|
|
9
9
|
|
|
10
10
|
## Source files
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
12
|
+
- Edit an installed component in place when the design needs it, since the code is the project's own.
|
|
13
|
+
- Read `shadcn add --diff` before running `--overwrite` on a component, since overwriting discards local edits.
|
|
14
|
+
- Import components and `cn` through the aliases in `components.json`, which the CLI uses to place files and rewrite imports.
|
|
15
15
|
|
|
16
16
|
## Component authoring
|
|
17
17
|
|
|
18
|
-
-
|
|
19
|
-
- Add `data-slot="
|
|
18
|
+
- Type a component's props as `React.ComponentProps<typeof Primitive>`, not `React.forwardRef`.
|
|
19
|
+
- Add `data-slot="<name>"` to the root of a new primitive, matching the installed components.
|
|
20
20
|
|
|
21
21
|
## Tokens and styling
|
|
22
22
|
|
|
23
|
-
- Use semantic
|
|
24
|
-
-
|
|
25
|
-
- Do not override shadcn component internals with arbitrary classes.
|
|
26
|
-
- Extend via `className` prop only.
|
|
23
|
+
- Use semantic tokens such as `bg-background`, `text-foreground`, and `border-border` over hardcoded colors.
|
|
24
|
+
- Merge classes with `cn()` from `@/lib/utils`, so a caller's `className` overrides the component's defaults.
|
|
27
25
|
|
|
28
26
|
## Composition
|
|
29
27
|
|
|
30
|
-
- Compose
|
|
31
|
-
-
|
|
32
|
-
- Use `
|
|
33
|
-
- Do not wrap primitives in extra DOM elements.
|
|
34
|
-
- Use `sonner` for toasts over the deprecated `toast` component.
|
|
28
|
+
- Compose through `render` in a Base UI project, the default for new ones, and through `asChild` in a Radix one.
|
|
29
|
+
- Style a link as a button with `buttonVariants()`, never a Base UI `Button` rendering an `<a>`, which forces `role="button"`.
|
|
30
|
+
- Use `sonner` for toasts, since the `toast` component is deprecated.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce Tailwind CSS v4
|
|
2
|
+
description: Enforce Tailwind CSS v4 theme variables, dark mode, layout spacing, and class application
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.tsx'
|
|
5
5
|
- '**/*.jsx'
|
|
@@ -11,22 +11,20 @@ paths:
|
|
|
11
11
|
|
|
12
12
|
## Theme variables
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- Define dark mode color overrides in `.dark { }` at root level over `@layer base`.
|
|
17
|
-
- Always pair light and dark utilities explicitly: `bg-white dark:bg-gray-900`.
|
|
14
|
+
- Define a token in a top-level `@theme` block when it needs a utility class, and in `:root` when it does not.
|
|
15
|
+
- Add `@custom-variant dark (&:where(.dark, .dark *))` when a `.dark` class toggles dark mode, since `dark:` follows `prefers-color-scheme` by default.
|
|
18
16
|
|
|
19
17
|
## Layout and spacing
|
|
20
18
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
- Use `
|
|
24
|
-
-
|
|
25
|
-
- Mobile-first: default styles apply to mobile. Use `sm:` and up to override.
|
|
19
|
+
- Lay out flow content with `flex` or `grid`, never `float` or `absolute`, which pulls an element out of flow so it overlaps at other widths.
|
|
20
|
+
- Space siblings with `gap-*` on the parent over margins on the children, which leave a stray edge when an item wraps or hides.
|
|
21
|
+
- Use `size-*` over a matching `w-*` and `h-*` pair.
|
|
22
|
+
- Write unprefixed utilities for mobile and add `sm:` and up for wider screens, since `sm:` means that breakpoint and above.
|
|
26
23
|
|
|
27
24
|
## Class application
|
|
28
25
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
- Use
|
|
26
|
+
- Write every class name in full, mapping a prop to a complete class, since Tailwind cannot detect a class built by concatenation.
|
|
27
|
+
- Never put two conflicting utilities on one element. Merge a caller's override through `cn()`, which drops the losing class.
|
|
28
|
+
- Add the trailing `!` modifier only when no other way to manage specificity exists.
|
|
29
|
+
- Use an arbitrary value such as `bg-[#316ff6]` for a static one-off, never an inline `style`.
|
|
30
|
+
- Keep inline `style` for a value from a dynamic source, or to set a CSS variable a utility reads.
|
|
@@ -1,40 +1,31 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce Go
|
|
2
|
+
description: Enforce Go error wrapping, context passing, interface placement, and package boundaries
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.go'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Go standards
|
|
8
8
|
|
|
9
|
-
## Casing conventions
|
|
10
|
-
|
|
11
|
-
- Use `MixedCaps` for exported names and `mixedCaps` for unexported ones. Never use underscores in a Go identifier.
|
|
12
|
-
- Name packages with one short lowercase word. Do not use `util`, `common`, or `helpers` as a package name.
|
|
13
|
-
- Do not repeat the package name in an exported identifier (`user.New`, not `user.NewUser`).
|
|
14
|
-
- Keep initialisms in one case (`userID`, `HTTPClient`), never `userId` or `HttpClient`.
|
|
15
|
-
|
|
16
9
|
## Errors
|
|
17
10
|
|
|
18
|
-
- Return an error as the last result value.
|
|
19
11
|
- Wrap an error with `fmt.Errorf("...: %w", err)` when adding context.
|
|
20
|
-
- Match an error with `errors.Is` or `errors.As`. Never compare `err.Error()` strings.
|
|
21
|
-
- Never discard an error with `_`.
|
|
22
|
-
-
|
|
12
|
+
- Match an error with `errors.Is` or `errors.As`. Never compare with `==` or on `err.Error()` strings, which miss a wrapped error.
|
|
13
|
+
- Never discard an error with `_`. Handle it, return it, or panic on a broken invariant.
|
|
14
|
+
- Return an `error` for a failure a caller can expect. Reserve `panic` for a broken invariant.
|
|
23
15
|
|
|
24
16
|
## Context
|
|
25
17
|
|
|
26
18
|
- Pass `context.Context` as the first parameter, named `ctx`.
|
|
27
|
-
- Never store a `context.Context` in a struct field.
|
|
19
|
+
- Never store a `context.Context` in a struct field. Pass it to each function that needs it.
|
|
28
20
|
- Do not pass a `nil` context. Use `context.TODO()` where none is available yet.
|
|
29
21
|
|
|
30
22
|
## Interfaces
|
|
31
23
|
|
|
32
|
-
- Declare an interface in the package that consumes it,
|
|
33
|
-
- Keep an interface to the methods its consumer calls.
|
|
24
|
+
- Declare an interface in the package that consumes it, holding only the methods that consumer calls.
|
|
34
25
|
- Accept interfaces and return concrete types.
|
|
35
26
|
|
|
36
27
|
## Packages
|
|
37
28
|
|
|
38
29
|
- Place code no other module may import under `internal/`.
|
|
39
30
|
- Do not perform side effects in `init`. Wire dependencies explicitly from `main`.
|
|
40
|
-
- Do not hold mutable state in a package-level variable.
|
|
31
|
+
- Do not hold mutable state in a package-level variable. Pass it through a struct the caller owns.
|
|
@@ -19,7 +19,7 @@ paths:
|
|
|
19
19
|
|
|
20
20
|
## Data shapes
|
|
21
21
|
|
|
22
|
-
- Use
|
|
22
|
+
- Use an `enum` for a closed set over class constants, backed by a string or int when the value is stored or serialized.
|
|
23
23
|
- Use `readonly` properties or a `readonly` class for value objects.
|
|
24
24
|
- Declare classes `final` unless they are designed for extension.
|
|
25
25
|
- Do not pass an associative array across a public boundary where a typed object fits.
|
|
@@ -27,5 +27,5 @@ paths:
|
|
|
27
27
|
## Errors
|
|
28
28
|
|
|
29
29
|
- Throw a domain exception for a failure. Do not return `false` or `null` to signal one.
|
|
30
|
-
- Never suppress an error with the `@` operator.
|
|
31
|
-
- Do not use `extract`, variable variables, or `eval`.
|
|
30
|
+
- Never suppress an error with the `@` operator. Check the condition first or catch the exception.
|
|
31
|
+
- Do not use `extract`, variable variables, or `eval`. Name each variable and call each function directly.
|