@pugi/cli 1.0.0-alpha.26 → 1.0.0-alpha.261

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 (207) hide show
  1. package/README.md +19 -8
  2. package/THIRD_PARTY_NOTICES.md +39 -0
  3. package/bin/pugi +95 -8
  4. package/models.json +1 -0
  5. package/package.json +30 -10
  6. package/postinstall.mjs +158 -23
  7. package/release.json +8 -0
  8. package/skills/a11y/SKILL.md +27 -0
  9. package/skills/ab-test-analysis/SKILL.md +15 -0
  10. package/skills/ai-sdk/SKILL.md +27 -0
  11. package/skills/api-integration/SKILL.md +27 -0
  12. package/skills/architecture-review/SKILL.md +19 -0
  13. package/skills/brand-voice/SKILL.md +27 -0
  14. package/skills/ci-cd-pipeline/SKILL.md +15 -0
  15. package/skills/code-review/SKILL.md +27 -0
  16. package/skills/competitor-analysis/SKILL.md +27 -0
  17. package/skills/content-design/SKILL.md +35 -0
  18. package/skills/css-tailwind/SKILL.md +39 -0
  19. package/skills/css-tailwind/quirks.md +86 -0
  20. package/skills/db-vector/SKILL.md +27 -0
  21. package/skills/design-radix/SKILL.md +35 -0
  22. package/skills/design-system/SKILL.md +35 -0
  23. package/skills/detecting-data-anomalies/SKILL.md +15 -0
  24. package/skills/docker-deploy/SKILL.md +15 -0
  25. package/skills/edge-case-finder/SKILL.md +27 -0
  26. package/skills/fonts/SKILL.md +34 -0
  27. package/skills/framework-grammy/SKILL.md +27 -0
  28. package/skills/framework-mastra/SKILL.md +27 -0
  29. package/skills/framework-nestjs/SKILL.md +27 -0
  30. package/skills/framework-prisma/SKILL.md +27 -0
  31. package/skills/funnel-optimization/SKILL.md +19 -0
  32. package/skills/ha-prototype-web/LICENSE-APACHE-2.0 +201 -0
  33. package/skills/ha-prototype-web/NOTICE.md +126 -0
  34. package/skills/ha-prototype-web/SKILL.md +25 -0
  35. package/skills/icons/SKILL.md +34 -0
  36. package/skills/landing-templates/SKILL.md +35 -0
  37. package/skills/market-research/SKILL.md +27 -0
  38. package/skills/metrics-dashboard/SKILL.md +19 -0
  39. package/skills/monitoring-setup/SKILL.md +15 -0
  40. package/skills/motion/SKILL.md +27 -0
  41. package/skills/nestjs-api/SKILL.md +38 -0
  42. package/skills/nestjs-api/quirks.md +36 -0
  43. package/skills/nextjs-page/SKILL.md +27 -0
  44. package/skills/od-blog-post/LICENSE-APACHE-2.0 +201 -0
  45. package/skills/od-blog-post/NOTICE.md +126 -0
  46. package/skills/od-blog-post/SKILL.md +81 -0
  47. package/skills/od-contact-widget/LICENSE-APACHE-2.0 +201 -0
  48. package/skills/od-contact-widget/NOTICE.md +126 -0
  49. package/skills/od-contact-widget/SKILL.md +132 -0
  50. package/skills/od-craft/LICENSE-APACHE-2.0 +201 -0
  51. package/skills/od-craft/NOTICE.md +126 -0
  52. package/skills/od-craft/SKILL.md +58 -0
  53. package/skills/od-craft/references/README.md +108 -0
  54. package/skills/od-craft/references/accessibility-baseline.md +203 -0
  55. package/skills/od-craft/references/animation-discipline.md +156 -0
  56. package/skills/od-craft/references/anti-ai-slop.md +86 -0
  57. package/skills/od-craft/references/color.md +90 -0
  58. package/skills/od-craft/references/form-validation.md +223 -0
  59. package/skills/od-craft/references/laws-of-ux.md +298 -0
  60. package/skills/od-craft/references/rtl-and-bidi.md +188 -0
  61. package/skills/od-craft/references/state-coverage.md +136 -0
  62. package/skills/od-craft/references/typography-hierarchy-editorial.md +184 -0
  63. package/skills/od-craft/references/typography-hierarchy.md +167 -0
  64. package/skills/od-craft/references/typography.md +124 -0
  65. package/skills/od-critique/LICENSE-APACHE-2.0 +201 -0
  66. package/skills/od-critique/NOTICE.md +126 -0
  67. package/skills/od-critique/SKILL.md +259 -0
  68. package/skills/od-dashboard/LICENSE-APACHE-2.0 +201 -0
  69. package/skills/od-dashboard/NOTICE.md +126 -0
  70. package/skills/od-dashboard/SKILL.md +77 -0
  71. package/skills/od-design-brief/LICENSE-APACHE-2.0 +201 -0
  72. package/skills/od-design-brief/NOTICE.md +126 -0
  73. package/skills/od-design-brief/SKILL.md +260 -0
  74. package/skills/od-docs-page/LICENSE-APACHE-2.0 +201 -0
  75. package/skills/od-docs-page/NOTICE.md +126 -0
  76. package/skills/od-docs-page/SKILL.md +81 -0
  77. package/skills/od-email-marketing/LICENSE-APACHE-2.0 +201 -0
  78. package/skills/od-email-marketing/NOTICE.md +126 -0
  79. package/skills/od-email-marketing/SKILL.md +85 -0
  80. package/skills/od-eng-runbook/LICENSE-APACHE-2.0 +201 -0
  81. package/skills/od-eng-runbook/NOTICE.md +126 -0
  82. package/skills/od-eng-runbook/SKILL.md +52 -0
  83. package/skills/od-faq-page/LICENSE-APACHE-2.0 +201 -0
  84. package/skills/od-faq-page/NOTICE.md +126 -0
  85. package/skills/od-faq-page/SKILL.md +113 -0
  86. package/skills/od-finance-report/LICENSE-APACHE-2.0 +201 -0
  87. package/skills/od-finance-report/NOTICE.md +126 -0
  88. package/skills/od-finance-report/SKILL.md +62 -0
  89. package/skills/od-frontend-design/LICENSE-APACHE-2.0 +201 -0
  90. package/skills/od-frontend-design/LICENSE.txt +177 -0
  91. package/skills/od-frontend-design/NOTICE.md +126 -0
  92. package/skills/od-frontend-design/SKILL.md +86 -0
  93. package/skills/od-hr-onboarding/LICENSE-APACHE-2.0 +201 -0
  94. package/skills/od-hr-onboarding/NOTICE.md +126 -0
  95. package/skills/od-hr-onboarding/SKILL.md +53 -0
  96. package/skills/od-invoice/LICENSE-APACHE-2.0 +201 -0
  97. package/skills/od-invoice/NOTICE.md +126 -0
  98. package/skills/od-invoice/SKILL.md +49 -0
  99. package/skills/od-kanban-board/LICENSE-APACHE-2.0 +201 -0
  100. package/skills/od-kanban-board/NOTICE.md +126 -0
  101. package/skills/od-kanban-board/SKILL.md +51 -0
  102. package/skills/od-login-flow/LICENSE-APACHE-2.0 +201 -0
  103. package/skills/od-login-flow/NOTICE.md +126 -0
  104. package/skills/od-login-flow/SKILL.md +49 -0
  105. package/skills/od-login-flow/references/checklist.md +19 -0
  106. package/skills/od-magazine-poster/LICENSE-APACHE-2.0 +201 -0
  107. package/skills/od-magazine-poster/NOTICE.md +126 -0
  108. package/skills/od-magazine-poster/SKILL.md +90 -0
  109. package/skills/od-meeting-notes/LICENSE-APACHE-2.0 +201 -0
  110. package/skills/od-meeting-notes/NOTICE.md +126 -0
  111. package/skills/od-meeting-notes/SKILL.md +48 -0
  112. package/skills/od-mobile-app/LICENSE-APACHE-2.0 +201 -0
  113. package/skills/od-mobile-app/NOTICE.md +126 -0
  114. package/skills/od-mobile-app/SKILL.md +103 -0
  115. package/skills/od-mobile-app/assets/template.html +442 -0
  116. package/skills/od-mobile-app/references/checklist.md +46 -0
  117. package/skills/od-mobile-app/references/layouts.md +312 -0
  118. package/skills/od-mobile-onboarding/LICENSE-APACHE-2.0 +201 -0
  119. package/skills/od-mobile-onboarding/NOTICE.md +126 -0
  120. package/skills/od-mobile-onboarding/SKILL.md +54 -0
  121. package/skills/od-pm-spec/LICENSE-APACHE-2.0 +201 -0
  122. package/skills/od-pm-spec/NOTICE.md +126 -0
  123. package/skills/od-pm-spec/SKILL.md +53 -0
  124. package/skills/od-pricing-page/LICENSE-APACHE-2.0 +201 -0
  125. package/skills/od-pricing-page/NOTICE.md +126 -0
  126. package/skills/od-pricing-page/SKILL.md +80 -0
  127. package/skills/od-redesign-skill/LICENSE +21 -0
  128. package/skills/od-redesign-skill/LICENSE-APACHE-2.0 +201 -0
  129. package/skills/od-redesign-skill/NOTICE.md +126 -0
  130. package/skills/od-redesign-skill/SKILL.md +205 -0
  131. package/skills/od-reference-design-contract/LICENSE-APACHE-2.0 +201 -0
  132. package/skills/od-reference-design-contract/NOTICE.md +126 -0
  133. package/skills/od-reference-design-contract/SKILL.md +131 -0
  134. package/skills/od-reference-design-contract/references/checklist.md +26 -0
  135. package/skills/od-saas-landing/LICENSE-APACHE-2.0 +201 -0
  136. package/skills/od-saas-landing/NOTICE.md +126 -0
  137. package/skills/od-saas-landing/SKILL.md +125 -0
  138. package/skills/od-social-carousel/LICENSE-APACHE-2.0 +201 -0
  139. package/skills/od-social-carousel/NOTICE.md +126 -0
  140. package/skills/od-social-carousel/SKILL.md +92 -0
  141. package/skills/od-team-okrs/LICENSE-APACHE-2.0 +201 -0
  142. package/skills/od-team-okrs/NOTICE.md +126 -0
  143. package/skills/od-team-okrs/SKILL.md +48 -0
  144. package/skills/od-waitlist-page/LICENSE-APACHE-2.0 +201 -0
  145. package/skills/od-waitlist-page/NOTICE.md +126 -0
  146. package/skills/od-waitlist-page/SKILL.md +229 -0
  147. package/skills/od-waitlist-page/assets/template.html +457 -0
  148. package/skills/od-waitlist-page/references/checklist.md +42 -0
  149. package/skills/od-web-design-guidelines/LICENSE +21 -0
  150. package/skills/od-web-design-guidelines/LICENSE-APACHE-2.0 +201 -0
  151. package/skills/od-web-design-guidelines/NOTICE.md +126 -0
  152. package/skills/od-web-design-guidelines/SKILL.md +66 -0
  153. package/skills/od-web-design-guidelines/references/guidelines.md +133 -0
  154. package/skills/od-web-prototype/LICENSE-APACHE-2.0 +201 -0
  155. package/skills/od-web-prototype/NOTICE.md +126 -0
  156. package/skills/od-web-prototype/SKILL.md +102 -0
  157. package/skills/od-web-prototype/assets/template.html +348 -0
  158. package/skills/od-web-prototype/references/checklist.md +47 -0
  159. package/skills/od-web-prototype/references/layouts.md +247 -0
  160. package/skills/od-web-prototype-taste-brutalist/LICENSE-APACHE-2.0 +201 -0
  161. package/skills/od-web-prototype-taste-brutalist/LICENSE-MIT-Leonxlnx +21 -0
  162. package/skills/od-web-prototype-taste-brutalist/NOTICE.md +126 -0
  163. package/skills/od-web-prototype-taste-brutalist/SKILL.md +64 -0
  164. package/skills/od-web-prototype-taste-editorial/LICENSE-APACHE-2.0 +201 -0
  165. package/skills/od-web-prototype-taste-editorial/LICENSE-MIT-Leonxlnx +21 -0
  166. package/skills/od-web-prototype-taste-editorial/NOTICE.md +126 -0
  167. package/skills/od-web-prototype-taste-editorial/SKILL.md +61 -0
  168. package/skills/od-web-prototype-taste-soft/LICENSE-APACHE-2.0 +201 -0
  169. package/skills/od-web-prototype-taste-soft/LICENSE-MIT-Leonxlnx +21 -0
  170. package/skills/od-web-prototype-taste-soft/NOTICE.md +126 -0
  171. package/skills/od-web-prototype-taste-soft/SKILL.md +64 -0
  172. package/skills/od-webgl-experience/LICENSE-APACHE-2.0 +201 -0
  173. package/skills/od-webgl-experience/NOTICE.md +126 -0
  174. package/skills/od-webgl-experience/SKILL.md +81 -0
  175. package/skills/od-wireframe-annotated/LICENSE-APACHE-2.0 +201 -0
  176. package/skills/od-wireframe-annotated/NOTICE.md +126 -0
  177. package/skills/od-wireframe-annotated/SKILL.md +90 -0
  178. package/skills/od-wireframe-greybox/LICENSE-APACHE-2.0 +201 -0
  179. package/skills/od-wireframe-greybox/NOTICE.md +126 -0
  180. package/skills/od-wireframe-greybox/SKILL.md +90 -0
  181. package/skills/od-wireframe-mobile-flow/LICENSE-APACHE-2.0 +201 -0
  182. package/skills/od-wireframe-mobile-flow/NOTICE.md +126 -0
  183. package/skills/od-wireframe-mobile-flow/SKILL.md +96 -0
  184. package/skills/od-wireframe-sketch/LICENSE-APACHE-2.0 +201 -0
  185. package/skills/od-wireframe-sketch/NOTICE.md +126 -0
  186. package/skills/od-wireframe-sketch/SKILL.md +98 -0
  187. package/skills/orchestrating-multi-agent-systems/SKILL.md +19 -0
  188. package/skills/preprocessing-data/SKILL.md +15 -0
  189. package/skills/project-memory-keeper/SKILL.md +19 -0
  190. package/skills/public-apis/SKILL.md +27 -0
  191. package/skills/pugi-patterns/SKILL.md +19 -0
  192. package/skills/react-component/SKILL.md +27 -0
  193. package/skills/sprint-planning/SKILL.md +19 -0
  194. package/skills/stack-selection/SKILL.md +15 -0
  195. package/skills/standup-summary/SKILL.md +15 -0
  196. package/skills/task-decomposition/SKILL.md +19 -0
  197. package/skills/team-routing/SKILL.md +15 -0
  198. package/skills/tech-survey/SKILL.md +15 -0
  199. package/skills/test-plan/SKILL.md +15 -0
  200. package/skills/typescript-refactor/SKILL.md +15 -0
  201. package/skills/ui-components/SKILL.md +35 -0
  202. package/skills/ux-patterns/SKILL.md +35 -0
  203. package/skills/web-platform/SKILL.md +27 -0
  204. package/skills/web-scrape/SKILL.md +27 -0
  205. package/skills/web-search/SKILL.md +15 -0
  206. package/skills/webapp-testing/SKILL.md +37 -0
  207. package/skills/webapp-testing/quirks.md +26 -0
@@ -0,0 +1,223 @@
1
+ <!-- Vendored from nexu-io/open-design@78d5637cb49d (craft/form-validation.md), Apache-2.0, Copyright 2026 Open Design contributors. Modified by Pugi: this header line added; the text below is otherwise verbatim. Paths it names (apps/daemon/src/lint-artifact.ts, pnpm lint:craft, od.craft.requires) are upstream's, not Pugi's: the Pugi port of the linter is packages/opencode/src/session/design-lint.ts. See NOTICE.md in the skill root. -->
2
+
3
+ # Form validation craft rules
4
+
5
+ Universal rules for form validation lifecycle, error wiring beyond the
6
+ accessibility baseline, and the schema-as-contract layer that makes
7
+ the same validation work on the server and the client. The active
8
+ `DESIGN.md` decides how the field looks; this file decides *when* the
9
+ field tells the user it's wrong, *how* the error reaches assistive
10
+ tech, and *where* the rule lives.
11
+
12
+ > Grounded in primary sources: WHATWG HTML Living Standard
13
+ > (Constraint Validation section under "Form control infrastructure"),
14
+ > CSS Selectors L4 (`:user-invalid`), WCAG 2.2 SC 3.3.x
15
+ > Understanding pages, ARIA APG forms patterns, Standard Schema spec
16
+ > (`@standard-schema/spec`), Baymard 2024 inline-validation research
17
+ > checkout-UX benchmark, WebAIM Million 2026 forms findings.
18
+
19
+ ## Prior art and scope
20
+
21
+ Existing OSS forms guidance for AI agents pins to one layer at a time
22
+ — `szilu/ux-designer-skill` is UX-opinion grade with no spec anchors,
23
+ `Community-Access/accessibility-agents/forms-specialist` is
24
+ WCAG-anchored but AT-only and doesn't reach the platform validity
25
+ layer or the schema contract. This file connects the four layers a
26
+ real form spans: **WHATWG Constraint Validation as the platform
27
+ floor, validation timing as a state machine on the input, WCAG 3.3.x
28
+ as the announcement and recovery contract, schema as the cross-stack
29
+ truth.** A11y wiring lives next door in `accessibility-baseline.md`
30
+ (label + describedby + invalid + `role="alert"` for inline errors);
31
+ this file picks up where that ends.
32
+
33
+ ## The input state machine
34
+
35
+ Every input passes through these states. The names trace back to RHF /
36
+ Formik vocabulary on web; the *shape* applies regardless of stack.
37
+ Drive error chrome off the state, not off raw `:invalid` or
38
+ focus/blur booleans.
39
+
40
+ | State | Meaning | UI |
41
+ |---|---|---|
42
+ | `pristine` | User has not interacted | No error chrome, no green check |
43
+ | `dirty` | User has typed but not committed (still focused) | No error chrome yet |
44
+ | `touched` | User has blurred at least once after editing | Field-level constraint runs |
45
+ | `invalid-after-touched` | Constraint failed after blur | Show error, link via `aria-describedby` |
46
+ | `invalid-after-submit` | Submit attempted, field still invalid | Same plus focus management to summary or first invalid field |
47
+ | `recovering` | User editing an already-invalid field | Re-validate on `input`, not on next blur |
48
+ | `submitting` | Action in flight | Disable submit, announce status via a polite live region |
49
+ | `server-error` | Server returned an error for this field | Use server's message text; treat as `invalid-after-submit` |
50
+
51
+ Decision rule that collapses validation-timing debates: errors appear
52
+ on transition into `invalid-after-touched`, clear on transition out
53
+ of any invalid state, and never appear from `pristine` or plain
54
+ `dirty`. CSS `:user-invalid` matches the `invalid-after-touched` /
55
+ `invalid-after-submit` states for free.
56
+
57
+ ## Validation timing
58
+
59
+ Baymard's checkout-UX benchmark (2024-01-09 inline-validation article):
60
+ **31% of sites have no inline validation, and most of the rest fire
61
+ too early.** The participant quote that anchors the research: *"Why
62
+ are you telling me my email address is wrong, I haven't had a chance
63
+ to fill it all out yet?"* Premature firing is the loudest UX failure
64
+ in this space.
65
+
66
+ The four rules:
67
+
68
+ 1. **First blur after edit** runs the field-level constraint. Not on focus, not on first keystroke, not on every keystroke.
69
+ 2. **Once a field is invalid, switch to `input`-event re-validation** so the error clears the moment input becomes valid. Don't make the user blur again to dismiss it.
70
+ 3. **On submit**, run the schema parse. Move focus to the error summary at the top of the form (a heading-led container with `tabindex="-1"`, no `role="alert"` — see the wiring section), or to the first invalid field if no summary exists. Don't move focus on every keystroke.
71
+ 4. **Async checks** split into two paths. *Background preflight* (uniqueness while typing, address lookup) debounces 250-500 ms, announces via a polite live region, and never gates typing or keeps the submit button disabled indefinitely. *Authoritative server validation on submit* is different: the submit path must await the server's response and surface field errors from it, since the server is the truth. Don't conflate the two — the rule is "don't let a slow background check freeze the form," not "don't ever wait for the server."
72
+
73
+ CSS gets you most of timing rule 1 for free: style off `:user-invalid`
74
+ not `:invalid`. The `:user-invalid` selector is Baseline Newly
75
+ available 2023 (Chrome 119, Firefox 88, Safari 16.5; Firefox shipped
76
+ the prefixed `:-moz-ui-invalid` years earlier and unprefixed in v88)
77
+ and matches only after the user has either submitted the form or
78
+ blurred the field with bad input.
79
+
80
+ ## Constraint Validation API as the platform floor
81
+
82
+ Native HTML constraints are not an alternative to JS validation; they
83
+ are the substrate the rest of the layers run on. They survive JS
84
+ failure, they integrate with autofill, and they are what
85
+ `reportValidity()` and screen-reader native announcements key off.
86
+
87
+ ```html
88
+ <input type="email" name="email" required>
89
+ ```
90
+
91
+ Use these declaratively for every field that has them: `required`,
92
+ `type` (email, url, number, tel), `pattern`, `min`/`max`,
93
+ `minlength`/`maxlength`, `step`. Cross-field rules and dynamic
94
+ constraints go through `setCustomValidity()` on both `input` and
95
+ `change` events — autofill flows historically fired one without the
96
+ other on some browsers, so listening on both is the cheap defense.
97
+
98
+ Rules of the API:
99
+
100
+ - **Empty string clears `setCustomValidity`.** Not `null`, not no-arg.
101
+ - **`form.requestSubmit()` honors validation; `form.submit()` skips it.** Never call the second.
102
+ - `disabled` controls are barred from validation and not submitted. The HTML spec says `readonly` is also barred, but `readonly` only has defined behavior on `<input>` and `<textarea>` — implementations diverge for `<select readonly>` and `<button readonly>` ([whatwg/html#11841](https://github.com/whatwg/html/issues/11841)). For non-input controls where the value must still submit, the safe pattern is `disabled` plus a same-named hidden `<input>` carrying the value, or rendering the non-editable text alongside a hidden `<input>`. `aria-readonly` alone is not enough — a `<select>` or custom widget tagged `aria-readonly="true"` is still interactable, so the visible control can drift while the hidden input ships a stale or different value. If you do use `aria-readonly`, you must also block the interaction or keep both values in sync.
103
+ - `inputmode` is a virtual-keyboard hint, **not** validation. `<input type="text" inputmode="numeric" pattern="[0-9]*">` is the Baymard-recommended shape for ZIPs / OTPs / card numbers; `pattern="[0-9]*"` is the historical iOS-Safari trigger for the numeric keypad on top of `inputmode`. `type="number"` adds spinners, strips leading zeros, applies locale-decimal handling, and varies field width across browsers — wrong for any of these.
104
+
105
+ ## Error wiring beyond the baseline
106
+
107
+ The default error pattern in `accessibility-baseline.md` (`<label>` +
108
+ `aria-describedby` + `aria-invalid` + `role="alert"`) covers WCAG
109
+ 3.3.1 / 3.3.2. Three additions matter for real forms:
110
+
111
+ **Adaptive error messages.** Baymard 2023: 98% of audited sites use
112
+ generic catch-all errors ("Provide a valid phone number") rather than
113
+ the specific subrule that fired ("Phone number is too short"). The
114
+ back end already knows the subrule; surfacing it cuts re-submit
115
+ attempts. Ship 4-7 distinct messages per high-traffic complex field
116
+ (email, phone, card, postal code). The scale of the problem matches
117
+ WebAIM Million 2026: missing form-input labels appear on **51% of
118
+ the top 1M home pages** (input-level rate **33.1%** of all 6.9M
119
+ inputs sampled) — labels and error messages are the categories
120
+ trending sideways or worse year-over-year while overall a11y errors
121
+ drop.
122
+
123
+ **Error summary at the top, on submit only.** Long forms benefit from
124
+ a summary list of in-page anchor links to invalid fields, focused on
125
+ submit:
126
+
127
+ ```html
128
+ <div id="form-errors" tabindex="-1">
129
+ <h2>2 problems</h2>
130
+ <ul>
131
+ <li><a href="#email">Email is required</a></li>
132
+ <li><a href="#dob">Date of birth must be in the past</a></li>
133
+ </ul>
134
+ </div>
135
+ ```
136
+
137
+ The container is heading-led with `tabindex="-1"` so JS can move
138
+ focus to it on submit (render the summary into the DOM, *then*
139
+ `.focus()` it; a `hidden` element can't take focus). It does **not**
140
+ carry `role="alert"` because combining a moved-focus target with an
141
+ alert role causes double-announcement: alert fires on insertion,
142
+ focus fires the accessible name + role. Reserve `role="alert"` for
143
+ inline per-field errors that appear without focus moving — that's
144
+ the canonical baseline pattern in `accessibility-baseline.md`. WCAG
145
+ technique G139 covers the summary; not required, high-value for long
146
+ forms.
147
+
148
+ **Preserve user input on error.** Baymard 2024: 34% of audited
149
+ checkouts wipe the credit-card field when an unrelated error reloads
150
+ the page. Direct cause of abandonment. Either field-level-validate
151
+ non-sensitive fields first, or split the payment step. PCI-wise,
152
+ persisting card values across an error reload is fine via tokenized
153
+ hosted iframes; never store raw PAN in your own session.
154
+
155
+ ## Schema as the cross-stack contract
156
+
157
+ Validation expressed once, consumed everywhere. The 2026 React shape
158
+ — `useActionState` + Server Actions + Conform (which added Standard
159
+ Schema support during the v1.x line) + a Zod 4 / Valibot / ArkType
160
+ schema — is the most-cited concrete instance: one schema,
161
+ server-authoritative, validator hot-swappable via the `~standard`
162
+ interface. The same architecture works in TanStack Form, oRPC, Hono
163
+ validator middleware, Nuxt UForm, and any other consumer that reads
164
+ `~standard`.
165
+
166
+ ```ts
167
+ const Signup = z.object({
168
+ email: z.email(), // Zod 4 top-level form
169
+ password: z.string().min(12),
170
+ });
171
+ // Same schema parses on the Server Action and on the Conform client.
172
+ ```
173
+
174
+ Three rules that survive across stacks:
175
+
176
+ - **Server is the truth, client is the optimization.** Same schema runs in both. Returning `{ errors }` from the action (not throwing) is what feeds back into `useActionState`'s state slot — throwing routes to the Error Boundary and loses the form data.
177
+ - **Standard Schema is the contract, not Zod.** A form library that ships per-validator resolver shims (`zodResolver`, `valibotResolver`, etc.) is yesterday's stack. Accept any `~standard`-compliant validator.
178
+ - **`novalidate` on `<form>` does not mean "skip validation".** It means "let the form library repaint errors instead of the browser's bubble." But the trade-off is real: a literal server-rendered `<form novalidate>` disables the browser's submit-blocking and native validation UI **even when JS is unavailable**, which loses the no-JS constraint-validation floor. Pick one of two patterns. **A:** render `<form>` without `novalidate` server-side and have the form library set `form.noValidate = true` after hydration — the no-JS user keeps the browser's native validation, the JS user gets the library's chrome. **B:** ship `novalidate` from the start only when the submit path reaches server validation without JS (Server Action, classic POST handler) so the no-JS user is still protected by the server. Either way, keep `required` / `pattern` / `type` attributes — they survive JS failure and integrate with autofill. (HTML attribute is lowercase `novalidate`; the IDL property on the form element is `noValidate`.)
179
+
180
+ ## WCAG 3.3.x beyond Error Identification
181
+
182
+ `accessibility-baseline.md` covers 3.3.1 (Error ID), 3.3.2 (Labels),
183
+ and 3.3.7 (Redundant Entry). The rest of 3.3 binds harder on
184
+ transactional forms:
185
+
186
+ - **3.3.3 Error Suggestion (AA):** when the fix is determinable, suggest it in text. Adaptive errors satisfy this. "Date must be MM/DD/YYYY. You entered 5-3-26. Did you mean 05/03/2026?"
187
+ - **3.3.4 Error Prevention — Legal, Financial, Data (AA):** for any submission with legal / financial / data-modifying consequence, provide one of: reversibility, server-side check + correction step, or a confirm-summary screen before commit.
188
+ - **3.3.8 Accessible Authentication (AA, WCAG 2.2):** auth steps must not require a cognitive function test (remember a password, transcribe a code, recognize images) without an alternative. CAPTCHAs are the canonical thing this SC restricts; only object-recognition or personal-content variants escape via the narrow exceptions, and not all CAPTCHAs do. Practical floor: never block paste on password / verification-code fields, support password managers, accept verification-code paste from a clipboard.
189
+ - **3.3.9 Accessible Authentication, No Exception (AAA):** removes even the object-recognition / personal-content exceptions. Aspirational; flag if a project commits to it.
190
+
191
+ ## Native mobile parity
192
+
193
+ Web validation primitives don't auto-translate. Each platform has its
194
+ own validity machinery and its own AT path. Skills that emit web-only
195
+ artifacts can skim this section; it's the entry point for skills
196
+ that ship to mobile (mobile-onboarding, mobile-app, etc.).
197
+
198
+ | Platform | Validity primitive | Error announcement |
199
+ |---|---|---|
200
+ | iOS UIKit | Hand-rolled state on the view controller; `UITextField` doesn't carry a built-in invalid flag | `UIAccessibility.post(notification: .announcement, argument: "Email is required")` |
201
+ | iOS SwiftUI | `TextField` + `@State`-driven validation; no built-in `Form`-level validity API as of iOS 18 | `AccessibilityNotification.Announcement("…").post()` (iOS 17+) |
202
+ | Android Compose | `OutlinedTextField(isError = true, supportingText = { Text("…") })` — `isError` wires the AT error semantic for you | `Modifier.semantics { liveRegion = LiveRegionMode.Polite }` on the supporting-text node, or `LocalView.current.announceForAccessibility(message)` |
203
+ | Flutter | `TextFormField(validator: (v) => …)` inside a `Form`, `formKey.currentState!.validate()` | `SemanticsService.announce(message, Directionality.of(context))` — never hardcode `TextDirection.ltr`; pull ambient direction so Arabic / Hebrew / Persian flows announce correctly |
204
+ | React Native | Hand-rolled per field; no platform validity flag | `accessibilityLiveRegion="polite"` on the error node (Android) + `AccessibilityInfo.announceForAccessibility(...)` (iOS) |
205
+
206
+ Two parity rules that catch most AI-generated mobile forms:
207
+
208
+ - **Use the platform's native validation flag — and pair it with the platform's error-message semantic where one exists.** On Compose, `isError = true` is the right boolean state for the field visuals and AT error-state cue, but it does *not* carry the localized error message. Pair it with `Modifier.semantics { error(message) }` so accessibility services get the actual text — the same string you render in `supportingText`. The trap is duplication: a hand-rolled `Modifier.semantics { error("Email is required") }` next to a different supporting-text string desyncs. Source `error()` from the same state field as `supportingText` so they stay in sync.
209
+ - **Don't mirror web ARIA into mobile semantics.** `aria-describedby` on a SwiftUI `TextField` is a no-op. Use the platform announcement primitive (`AccessibilityNotification.Announcement` on SwiftUI, `UIAccessibility.post` on UIKit, `announceForAccessibility` on Android, `SemanticsService.announce` on Flutter) for state-change events that need to reach the screen reader.
210
+
211
+ ## Common mistakes (lint these)
212
+
213
+ - Styling off `input:invalid` instead of `input:user-invalid`. Red borders on page load is the loudest "this validation was added without testing" signal.
214
+ - Validating on every keystroke. Hostile; fires before the user has finished typing.
215
+ - Generic catch-all error messages ("Invalid input") when the back end already knows which subrule fired. Baymard 2023 found 98% of audited sites do this — the most-cited preventable validation failure in their corpus.
216
+ - Throwing from a Server Action on validation failure. Routes to the Error Boundary and loses the form data. Return `{ errors }` instead.
217
+ - `role="alert"` on the error-summary container that focus moves to. Double-announces. Reserve `role="alert"` for inline per-field errors that appear without focus moving.
218
+ - `aria-busy="true"` on the submit button while submitting. `aria-busy` is for stale containers; for buttons use `disabled` plus a polite live-region status message.
219
+ - Email-confirm fields ("retype your email"). 3.3.7 redundant entry — exceptions are essential / security / no-longer-valid, not "we want to catch typos." Allow paste and validate the single field instead.
220
+ - Per-validator resolver shims (`zodResolver`, `valibotResolver`) on a 2026 stack. Accept Standard Schema's `~standard` interface and the validator becomes swappable.
221
+ - Wiping the credit-card field when an unrelated field errors. Baymard 2024: 34% of audited e-commerce sites; direct abandonment cause.
222
+ - `setCustomValidity(null)` to clear an error. Pass empty string; `null` does not clear.
223
+ - Mirroring web ARIA onto SwiftUI / Compose / Flutter. Each platform has its own validity API; `aria-*` attributes don't reach the mobile AT path.
@@ -0,0 +1,298 @@
1
+ <!-- Vendored from nexu-io/open-design@78d5637cb49d (craft/laws-of-ux.md), Apache-2.0, Copyright 2026 Open Design contributors. Modified by Pugi: this header line added; the text below is otherwise verbatim. Paths it names (apps/daemon/src/lint-artifact.ts, pnpm lint:craft, od.craft.requires) are upstream's, not Pugi's: the Pugi port of the linter is packages/opencode/src/session/design-lint.ts. See NOTICE.md in the skill root. -->
2
+
3
+ # Laws of UX craft rules
4
+
5
+ Universal cognitive, perceptual, and behavioral heuristics that decide
6
+ what a UI composes — how many pricing tiers fit on a screen, where a
7
+ primary action anchors in scanning order, when a progress indicator
8
+ earns its place, why a settings list needs grouping. The active
9
+ `DESIGN.md` decides brand visual language; the existing craft files
10
+ decide rendering rules (color, typography, motion, states, ARIA, RTL,
11
+ forms); this file decides composition rules grounded in named research.
12
+
13
+ > Distilled from primary sources: Hick (1952) + Hyman (1953), Miller
14
+ > (1956) for chunking / `7±2` channel capacity, Cowan (2001) for the
15
+ > modern ~4 working-memory bound, Fitts (1954), Wertheimer (1923) for
16
+ > proximity / similarity / Prägnanz, Palmer (1992) for Common Region,
17
+ > Palmer & Rock (1994) for Uniform Connectedness, Kahneman /
18
+ > Fredrickson / Schreiber / Redelmeier (1993) for Peak-End, Zeigarnik
19
+ > (1927), Csíkszentmihályi (1975), Hull (1932), von Restorff (1933),
20
+ > Broadbent (1958), Sweller (1988), Postel (RFC 760, 1980), Carroll &
21
+ > Rosson (1987), Tversky & Kahneman (1974) for Anchoring, Kurosu &
22
+ > Kashimura (1995), Iyengar & Lepper (2000), Toffler (1970), Pareto
23
+ > (c.1906) / Juran (*Quality Control Handbook*, 1951), Ebbinghaus
24
+ > (1885), Ockham (14th c.), Tesler at Apple (1980s), Nielsen (2000),
25
+ > Norman *POET* (1988), Parkinson (1955).
26
+
27
+ ## Prior art and scope
28
+
29
+ Existing public catalogs of UX heuristics (Yablonski's lawsofux.com,
30
+ NN/g's 10 usability heuristics, Material 3 motion + interaction
31
+ guidance, Apple HIG, Baymard Institute checkout research) inventory the
32
+ laws but rarely tie each one to a concrete code-gen directive. This
33
+ file does the translation: every entry ends with one actionable move
34
+ for an HTML / Tailwind / React-emitting agent. Sibling craft files
35
+ (`accessibility-baseline.md`, `state-coverage.md`, `typography.md`,
36
+ `anti-ai-slop.md`, `color.md`, `animation-discipline.md`,
37
+ `form-validation.md`) own the auto-checked rules; this file names the
38
+ underlying law and surfaces the folklore. Out of scope: Weber-Fechner
39
+ psychophysics and Signal Detection Theory — both apply to UI but the
40
+ prompt-emission directives are too narrow to earn a slot here. Add
41
+ later if a skill needs them.
42
+
43
+ The rules below are guidance, not auto-checked. Reviewers and the agent
44
+ apply them; the linter does not. Where a law has a sibling rule already
45
+ auto-checked elsewhere — touch-target floor in
46
+ `accessibility-baseline.md`, the 300 ms / 2 s / 10 s / 30 s / 60 s
47
+ loading thresholds in `state-coverage.md`, ALL CAPS letter-spacing in
48
+ `typography.md`, the indigo / gradient / emoji-icon list in
49
+ `anti-ai-slop.md` — the entry below cross-references rather than
50
+ duplicates.
51
+
52
+ ## Perception and visual grouping
53
+
54
+ Five Gestalt laws plus three attention-and-recognition laws govern how
55
+ the eye groups elements before the brain reads them.
56
+
57
+ - **Law of Proximity** (Wertheimer, 1923). Objects near each other read
58
+ as a group. Cheapest grouping signal — cheaper than borders or shared
59
+ color. Apply variable vertical rhythm: 8–12 px within a group,
60
+ 32–48 px between groups. Uniform spacing reads as nothing being
61
+ grouped.
62
+ - **Law of Similarity** (Wertheimer, 1923). Visually similar elements
63
+ read as a group. Equivalent affordances must share treatment — every
64
+ list row identical class set, every secondary button identical, every
65
+ destructive action identical. Visible deviation is reserved for the
66
+ one item meant to draw attention (the recommended pricing tier, the
67
+ selected nav item).
68
+ - **Law of Common Region** (Palmer, 1992). A shared bounded area binds
69
+ enclosed elements. Use enclosure when proximity is not enough — and
70
+ reserve it. Concrete numbers: padding ≥16 px inside the region,
71
+ distinct surface (border + tinted background, or card chrome at
72
+ ≥1 px hairline). A page where every section is bordered destroys the
73
+ signal.
74
+ - **Law of Prägnanz / Good Figure** (Wertheimer, 1923). The eye
75
+ resolves complex layouts into the simplest underlying form. Designs
76
+ that align with a clear underlying grid (12-column, F-pattern,
77
+ 4-quadrant) feel inevitable; ornate breaks that add nothing semantic
78
+ feel arbitrary.
79
+ - **Law of Uniform Connectedness** (Palmer & Rock, 1994). The
80
+ strongest grouping signal in the Gestalt hierarchy: connected lines,
81
+ shared toolbars, or bracketing containers tie items together more
82
+ strongly than proximity or similarity. Use for wizard steps,
83
+ comparison sets, and explicit navigation flows.
84
+ - **Selective Attention** (Broadbent, *Perception and Communication*,
85
+ 1958). Cognitive bandwidth is finite. Users filter aggressively and
86
+ ignore anything that looks irrelevant to their goal — banner blindness
87
+ comes from this. Reserve the strongest visual contrast for the single
88
+ goal-relevant action; let supporting content recede in weight.
89
+ - **Von Restorff Effect** (von Restorff, 1933). The item that differs
90
+ from a uniform field is the one most likely to be remembered. Make
91
+ the recommended pricing tier, the active nav item, the warning state
92
+ visually distinct. Pair contrast with a non-color signal (icon, text
93
+ label, position) — `accessibility-baseline.md` rules out color-alone
94
+ signaling.
95
+ - **Aesthetic-Usability Effect** (Kurosu & Kashimura, Hitachi Design
96
+ Center, 1995). Visual polish biases perceived usability. Refined
97
+ typography, generous whitespace, and a calm palette earn the benefit
98
+ of the doubt for minor friction. Never substitutes for measurable
99
+ usability or for `state-coverage.md`'s required-states rule.
100
+
101
+ ## Decision-making
102
+
103
+ Six laws govern how fast and how well users decide when an interface
104
+ offers a choice.
105
+
106
+ - **Hick's Law** (Hick, 1952; Hyman, 1953 replication). Decision time
107
+ grows roughly log(n+1) with the number of equivalent options. Cap any
108
+ single decision-screen to 3–5 visible primary options; collapse the
109
+ rest behind a "More" / progressive disclosure pattern; visually
110
+ distinguish the recommended choice. Aggressive truncation that hides
111
+ the path forward is the opposite failure mode — surface the full
112
+ option set, just don't render every option at the same visual weight.
113
+ - **Choice Overload** (Iyengar & Lepper, *Journal of Personality and
114
+ Social Psychology*, 2000; framing dates to Toffler, *Future Shock*,
115
+ 1970). Too many roughly-equivalent options stall or abandon the
116
+ decision. Pricing pages: 3–4 tiers, exactly one marked recommended.
117
+ Product grids: 6–9 hero cards above the fold. Settings panels: ≤5
118
+ named groups. Never emit a flat wall of equivalents.
119
+ - **Anchoring** (Tversky & Kahneman, *Science* 185:1124–1131, 1974).
120
+ The first number a user sees re-weights every subsequent number.
121
+ Place the recommended pricing tier where it anchors the comparison;
122
+ render yearly-billing savings as concrete dollar deltas, not just
123
+ percentage badges; pre-select the safer default in radio groups.
124
+ Visual weight matches intended decision weight.
125
+ - **Pareto Principle / 80-20** (Pareto, c.1906; Juran, *Quality Control
126
+ Handbook*, 1951 — popularized the management-application framing). A
127
+ small share of features drives most of the value. Identify the 2–3 actions
128
+ that drive the dominant journey for the target persona; emphasize
129
+ those visually; demote the long tail to overflow menus, footer
130
+ surfaces, or settings.
131
+ - **Tesler's Law / Conservation of Complexity** (Tesler, Apple, 1980s).
132
+ Every product has an irreducible amount of complexity. The design
133
+ choice is *where* it lives — engineering team, interface, user — not
134
+ whether to eliminate it. When complexity reaches the user, surface
135
+ contextual guidance (tooltips, smart defaults, inline empty-state
136
+ coaching, progressive disclosure) at the exact step where it
137
+ surfaces. Hiding it is not the same as removing it.
138
+ - **Occam's Razor** (Ockham, 14th c.). Among options that explain the
139
+ data equally well, prefer the one with the fewest assumptions. Specify
140
+ a minimal element inventory; forbid decorative chrome that doesn't
141
+ serve a stated user task. The law constrains assumptions, not feature
142
+ count — a "minimum viable" framing misreads it.
143
+
144
+ ## Memory and learning
145
+
146
+ Five laws cover how working memory handles information density and
147
+ what the user retains afterward.
148
+
149
+ - **Miller's Law and Chunking** (Miller, *The Magical Number Seven,
150
+ Plus or Minus Two*, *Psychological Review*, 1956 — channel capacity /
151
+ `7±2` and chunking; Cowan, *Behavioral and Brain Sciences* 24:1, 2001
152
+ for the modern ~4-item working-memory bound). Working memory holds
153
+ about four items reliably and up to seven for short-term recall. Each
154
+ slot can hold a *larger familiar unit*, constrained by the user's
155
+ domain knowledge — chunking does not let you pack arbitrary content
156
+ into a single slot. Often misread as a rule about menu length;
157
+ Miller's paper is about chunks. Group related fields with clear
158
+ section headings, dividers, or card containers. A settings page with
159
+ sections "Account / Notifications / Privacy / Billing / Danger zone"
160
+ beats one flat list of 30 toggles.
161
+ - **Working Memory** (Baddeley & Hitch, 1974; lineage to Atkinson &
162
+ Shiffrin, 1968). Items decay in seconds without rehearsal. Recognition
163
+ beats recall: persisting prior context across screens, marking visited
164
+ elements, and surfacing comparison views beats forcing the user to
165
+ memorize. On dashboards specifically: sticky filter chips, last-N
166
+ selections persisted, breadcrumbs that include applied filters.
167
+ - **Serial Position Effect** (Ebbinghaus, *Über das Gedächtnis*, 1885).
168
+ Recall favors the extremes — primacy at the start, recency at the
169
+ end — while middle items fade. Anchor the most important nav items at
170
+ the leftmost and rightmost positions of a horizontal menu; cluster
171
+ utilities in the middle.
172
+ - **Peak-End Rule** (Kahneman, Fredrickson, Schreiber, Redelmeier,
173
+ *Psychological Science*, 1993). Memory of an experience is dominated
174
+ by the emotional peak and the ending, not the average. Stage a
175
+ high-effort celebratory success state; let intermediate steps stay
176
+ calm. Mediocre middles matter less than a strong close. The peak
177
+ belongs at the *end* of a flow, not as arbitrary mid-flow motion —
178
+ `animation-discipline.md` rejects motion that performs (rather than
179
+ confirms) a state change.
180
+ - **Zeigarnik Effect** (Zeigarnik, *Über das Behalten erledigter und
181
+ unerledigter Handlungen*, 1927). Uncompleted tasks create cognitive
182
+ tension that pulls the user back. Visible progress ("3 of 5 steps",
183
+ greyed-out next sections) converts that tension into completion
184
+ pressure. Reserve for genuinely beneficial flows like onboarding;
185
+ applying the same lever to streaks, daily-quest counters, or notification-
186
+ reduction nags is a dark pattern.
187
+
188
+ ## Interaction and motor
189
+
190
+ Five laws cover how fast and how accurately users can act on the UI.
191
+
192
+ - **Fitts's Law** (Fitts, *Journal of Experimental Psychology*, 1954).
193
+ Time to acquire a target depends on its distance and size — bigger
194
+ and closer is faster. Spacing between adjacent hit zones matters as
195
+ much as size. Pair with `accessibility-baseline.md`'s 24 × 24 CSS px
196
+ AA touch-target floor; on mobile, place high-frequency controls in
197
+ the natural thumb arc.
198
+ - **Doherty Threshold** (Doherty & Thadani, *IBM Systems Journal*,
199
+ 1982). Sub-second feedback keeps users in flow; latency above ~1 s
200
+ breaks attention. The implementable directive lives in
201
+ `state-coverage.md`'s loading-threshold table (no indicator under
202
+ 300 ms; skeleton 300 ms – 2 s; labelled spinner 2 – 10 s; determinate
203
+ bar with cancel 10 – 60 s; stop and offer error/retry past 60 s).
204
+ This entry exists to name the underlying law and flag its folklore
205
+ (the 400 ms number doesn't appear in the 1982 paper — see
206
+ `animation-discipline.md` for the 400 ms folklore trace).
207
+ - **Flow** (Csíkszentmihályi, *Beyond Boredom and Anxiety*, 1975). Flow
208
+ sits in the balance between challenge and skill — too hard breeds
209
+ frustration, too easy breeds boredom. Continuous feedback and a clear
210
+ sense of control keep the user inside the state. System friction and
211
+ latency are the fastest ways to break it.
212
+ - **Goal-Gradient Effect** (Hull, *Psychological Review*, 1932; Kivetz,
213
+ Urminsky, Zheng, 2006 for the punch-card replication). Motivation to
214
+ finish rises as the goal gets closer. Multi-step flows render with a
215
+ prominent progress indicator that reflects *real* endowed progress —
216
+ show completed prerequisites when they truly exist (saved profile,
217
+ imported team, prior survey answer). When no real prerequisite
218
+ exists, render the current step honestly as `1 of N` with the
219
+ empty/current-step state clearly marked. Hull's hypothesis is
220
+ descriptive; treating it as license for fabricated progress, streak
221
+ dark patterns, or loyalty-program quota inflation is a misread.
222
+ - **Postel's Law / Robustness Principle** (Postel, RFC 760, 1980). "Be
223
+ liberal in what you accept, conservative in what you send." Take
224
+ input in whatever shape users naturally give it (phone numbers with
225
+ or without dashes, dates in mixed formats, percentages with or
226
+ without `%`); normalize internally to a canonical form; emit one
227
+ consistent format on output. The error-timing and ARIA-wiring half
228
+ lives in `form-validation.md`; the input-tolerance half is the
229
+ directive above. RFC 9413 (Thomson, IAB, 2023; built on the earlier
230
+ `draft-iab-protocol-maintenance`) retracts the maxim for protocol
231
+ design citing security surface; the UX-input application stands.
232
+
233
+ ## Behavior and expectation
234
+
235
+ Five laws cover what users predict and how that prediction interacts
236
+ with the rendered surface.
237
+
238
+ - **Jakob's Law** (Nielsen, Nielsen Norman Group, 2000). Users spend
239
+ most of their time on other sites and expect yours to work the same.
240
+ Reuse category convention — nav placement, cart icon, settings gear,
241
+ primary CTA in the upper right of a SaaS landing — so the user spends
242
+ zero cycles relearning interaction grammar. Novelty must earn its
243
+ keep against the convention's ROI; "innovate everywhere" is the
244
+ opposite failure mode.
245
+ - **Mental Model** (Craik, *The Nature of Explanation*, 1943; Norman,
246
+ *POET / The Psychology of Everyday Things*, 1988). Every user
247
+ arrives with a prior built from competitor products and the physical
248
+ world. When the prediction holds, the product feels intuitive; when
249
+ it breaks, friction shows up as confusion, not curiosity. When the
250
+ brief names a reference product, anchor explicitly — capture the
251
+ reference in the prompt and the agent inherits a transferable
252
+ interaction grammar.
253
+ - **Paradox of the Active User** (Carroll & Rosson, in *Interfacing
254
+ Thought: Cognitive Aspects of Human-Computer Interaction*, MIT Press,
255
+ 1987, pp. 80–111). Users skip the manual and start using the
256
+ software immediately, even when reading it would speed them up. Bake
257
+ guidance into the surface itself — empty-state coaching, inline
258
+ tooltips, contextual hints — at the action point.
259
+ - **Parkinson's Law** (Parkinson, *The Economist*, 1955). Work expands
260
+ to fill the time allotted to it. Loose interfaces let users dawdle;
261
+ cut friction and pre-fill what you can — autofill, smart defaults,
262
+ saved state — so a checkout finishes faster than the user expected.
263
+ Beating anticipated duration becomes the felt win.
264
+ - **Cognitive Load** (Sweller, *Cognitive Science*, 1988). Total
265
+ mental effort splits into intrinsic (the task's inherent difficulty)
266
+ and extraneous (poor layout, jargon, inconsistent patterns, visual
267
+ noise). Designers can't reduce intrinsic load; they own extraneous
268
+ fully. The visual-restraint directives (single accent in `color.md`,
269
+ three-weight typography rhythm in `typography.md`, P0 anti-default
270
+ list in `anti-ai-slop.md`) already constrain extraneous load; this
271
+ entry exists to name the cognitive cost the sibling rules reduce.
272
+
273
+ ## Common mistakes (lint these)
274
+
275
+ Folklore corrections that don't survive a primary-source check, in the
276
+ same vein as the busts already documented in `animation-discipline.md`
277
+ and `accessibility-baseline.md`. The first three are attribution
278
+ corrections (year / venue / institution) the body entries already
279
+ applied — restated here so a reviewer reading just this section sees
280
+ them. The remainder are folklore not addressed in the body.
281
+
282
+ - "Anchoring effect = Tversky & Kahneman 1972." Wrong year. The
283
+ *Science* paper introducing the anchoring framing is 1974; the 1972
284
+ paper is "Subjective probability: A judgment of representativeness"
285
+ (different work).
286
+ - "Tesler's Law was developed at Xerox PARC." Tesler left PARC for
287
+ Apple in 1980; the Conservation-of-Complexity formulation traces to
288
+ his Apple years.
289
+ - "Paradox of the Active User was a CACM article." It's a chapter in
290
+ Carroll's *Interfacing Thought* (MIT Press, 1987), not CACM.
291
+ - "Selective Attention = solved by red dots and badges." Repeated
292
+ attention-grabbers train banner blindness. Reserve the strongest
293
+ contrast for one goal-relevant action per surface.
294
+ - "Fitts's Law alone is enough for touch targets." Fitts gives the
295
+ speed-accuracy tradeoff. WCAG 2.2 SC 2.5.8 sets the AA floor at
296
+ 24 × 24 CSS px (`accessibility-baseline.md`); iOS HIG suggests
297
+ 44 × 44 pt; Material 3 suggests 48 × 48 dp. Fitts plus the
298
+ platform floor — never just Fitts.