@brunosps00/dev-workflow 0.10.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +78 -6
  2. package/lib/constants.js +20 -20
  3. package/lib/init.js +44 -4
  4. package/lib/migrate-skills.js +129 -0
  5. package/lib/removed-bundled-skills.js +16 -0
  6. package/lib/uninstall.js +6 -2
  7. package/lib/utils.js +51 -4
  8. package/package.json +1 -1
  9. package/scaffold/en/agent-instructions.md +68 -0
  10. package/scaffold/en/commands/dw-analyze-project.md +61 -0
  11. package/scaffold/en/commands/dw-autopilot.md +1 -1
  12. package/scaffold/en/commands/dw-brainstorm.md +1 -1
  13. package/scaffold/en/commands/dw-bugfix.md +3 -3
  14. package/scaffold/en/commands/dw-code-review.md +28 -0
  15. package/scaffold/en/commands/dw-create-prd.md +16 -0
  16. package/scaffold/en/commands/dw-create-tasks.md +42 -0
  17. package/scaffold/en/commands/dw-create-techspec.md +18 -1
  18. package/scaffold/en/commands/dw-deps-audit.md +1 -1
  19. package/scaffold/en/commands/dw-fix-qa.md +1 -1
  20. package/scaffold/en/commands/dw-functional-doc.md +2 -2
  21. package/scaffold/en/commands/dw-help.md +1 -1
  22. package/scaffold/en/commands/dw-redesign-ui.md +7 -7
  23. package/scaffold/en/commands/dw-run-qa.md +4 -4
  24. package/scaffold/en/commands/dw-run-task.md +2 -2
  25. package/scaffold/en/templates/constitution-template.md +111 -0
  26. package/scaffold/pt-br/agent-instructions.md +68 -0
  27. package/scaffold/pt-br/commands/dw-analyze-project.md +61 -0
  28. package/scaffold/pt-br/commands/dw-autopilot.md +1 -1
  29. package/scaffold/pt-br/commands/dw-brainstorm.md +1 -1
  30. package/scaffold/pt-br/commands/dw-bugfix.md +3 -3
  31. package/scaffold/pt-br/commands/dw-code-review.md +28 -0
  32. package/scaffold/pt-br/commands/dw-create-prd.md +16 -0
  33. package/scaffold/pt-br/commands/dw-create-tasks.md +42 -0
  34. package/scaffold/pt-br/commands/dw-create-techspec.md +18 -1
  35. package/scaffold/pt-br/commands/dw-deps-audit.md +1 -1
  36. package/scaffold/pt-br/commands/dw-fix-qa.md +1 -1
  37. package/scaffold/pt-br/commands/dw-functional-doc.md +2 -2
  38. package/scaffold/pt-br/commands/dw-help.md +1 -1
  39. package/scaffold/pt-br/commands/dw-redesign-ui.md +7 -7
  40. package/scaffold/pt-br/commands/dw-run-qa.md +4 -4
  41. package/scaffold/pt-br/commands/dw-run-task.md +2 -2
  42. package/scaffold/pt-br/templates/constitution-template.md +111 -0
  43. package/scaffold/skills/dw-council/SKILL.md +1 -1
  44. package/scaffold/skills/dw-testing-discipline/SKILL.md +148 -0
  45. package/scaffold/skills/dw-testing-discipline/references/ai-agent-gates.md +170 -0
  46. package/scaffold/skills/dw-testing-discipline/references/anti-patterns.md +336 -0
  47. package/scaffold/skills/dw-testing-discipline/references/flaky-discipline.md +163 -0
  48. package/scaffold/skills/dw-testing-discipline/references/iron-laws.md +128 -0
  49. package/scaffold/skills/dw-testing-discipline/references/playwright-recipes.md +282 -0
  50. package/scaffold/skills/dw-testing-discipline/references/positive-patterns.md +241 -0
  51. package/scaffold/skills/{webapp-testing → dw-testing-discipline}/references/security-boundary.md +1 -1
  52. package/scaffold/skills/dw-ui-discipline/SKILL.md +128 -0
  53. package/scaffold/skills/dw-ui-discipline/references/accessibility-floor.md +225 -0
  54. package/scaffold/skills/dw-ui-discipline/references/anti-slop.md +162 -0
  55. package/scaffold/skills/dw-ui-discipline/references/curated-defaults.md +195 -0
  56. package/scaffold/skills/dw-ui-discipline/references/hard-gate.md +142 -0
  57. package/scaffold/skills/dw-ui-discipline/references/state-matrix.md +101 -0
  58. package/scaffold/templates-overrides-readme.md +75 -0
  59. package/scaffold/skills/ui-ux-pro-max/LICENSE +0 -21
  60. package/scaffold/skills/ui-ux-pro-max/SKILL.md +0 -659
  61. package/scaffold/skills/ui-ux-pro-max/data/_sync_all.py +0 -414
  62. package/scaffold/skills/ui-ux-pro-max/data/app-interface.csv +0 -31
  63. package/scaffold/skills/ui-ux-pro-max/data/charts.csv +0 -26
  64. package/scaffold/skills/ui-ux-pro-max/data/colors.csv +0 -162
  65. package/scaffold/skills/ui-ux-pro-max/data/design.csv +0 -1776
  66. package/scaffold/skills/ui-ux-pro-max/data/draft.csv +0 -1779
  67. package/scaffold/skills/ui-ux-pro-max/data/google-fonts.csv +0 -1924
  68. package/scaffold/skills/ui-ux-pro-max/data/icons.csv +0 -106
  69. package/scaffold/skills/ui-ux-pro-max/data/landing.csv +0 -35
  70. package/scaffold/skills/ui-ux-pro-max/data/products.csv +0 -162
  71. package/scaffold/skills/ui-ux-pro-max/data/react-performance.csv +0 -45
  72. package/scaffold/skills/ui-ux-pro-max/data/stacks/angular.csv +0 -51
  73. package/scaffold/skills/ui-ux-pro-max/data/stacks/astro.csv +0 -54
  74. package/scaffold/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  75. package/scaffold/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  76. package/scaffold/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
  77. package/scaffold/skills/ui-ux-pro-max/data/stacks/laravel.csv +0 -51
  78. package/scaffold/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  79. package/scaffold/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
  80. package/scaffold/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  81. package/scaffold/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  82. package/scaffold/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
  83. package/scaffold/skills/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
  84. package/scaffold/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  85. package/scaffold/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  86. package/scaffold/skills/ui-ux-pro-max/data/stacks/threejs.csv +0 -54
  87. package/scaffold/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  88. package/scaffold/skills/ui-ux-pro-max/data/styles.csv +0 -85
  89. package/scaffold/skills/ui-ux-pro-max/data/typography.csv +0 -74
  90. package/scaffold/skills/ui-ux-pro-max/data/ui-reasoning.csv +0 -162
  91. package/scaffold/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  92. package/scaffold/skills/ui-ux-pro-max/scripts/core.py +0 -262
  93. package/scaffold/skills/ui-ux-pro-max/scripts/design_system.py +0 -1148
  94. package/scaffold/skills/ui-ux-pro-max/scripts/search.py +0 -114
  95. package/scaffold/skills/ui-ux-pro-max/skills/brand/SKILL.md +0 -97
  96. package/scaffold/skills/ui-ux-pro-max/skills/design/SKILL.md +0 -302
  97. package/scaffold/skills/ui-ux-pro-max/skills/design-system/SKILL.md +0 -244
  98. package/scaffold/skills/ui-ux-pro-max/templates/base/quick-reference.md +0 -297
  99. package/scaffold/skills/ui-ux-pro-max/templates/base/skill-content.md +0 -358
  100. package/scaffold/skills/ui-ux-pro-max/templates/platforms/agent.json +0 -21
  101. package/scaffold/skills/ui-ux-pro-max/templates/platforms/augment.json +0 -18
  102. package/scaffold/skills/ui-ux-pro-max/templates/platforms/claude.json +0 -21
  103. package/scaffold/skills/ui-ux-pro-max/templates/platforms/codebuddy.json +0 -21
  104. package/scaffold/skills/ui-ux-pro-max/templates/platforms/codex.json +0 -21
  105. package/scaffold/skills/ui-ux-pro-max/templates/platforms/continue.json +0 -21
  106. package/scaffold/skills/ui-ux-pro-max/templates/platforms/copilot.json +0 -21
  107. package/scaffold/skills/ui-ux-pro-max/templates/platforms/cursor.json +0 -21
  108. package/scaffold/skills/ui-ux-pro-max/templates/platforms/droid.json +0 -21
  109. package/scaffold/skills/ui-ux-pro-max/templates/platforms/gemini.json +0 -21
  110. package/scaffold/skills/ui-ux-pro-max/templates/platforms/kilocode.json +0 -21
  111. package/scaffold/skills/ui-ux-pro-max/templates/platforms/kiro.json +0 -21
  112. package/scaffold/skills/ui-ux-pro-max/templates/platforms/opencode.json +0 -21
  113. package/scaffold/skills/ui-ux-pro-max/templates/platforms/qoder.json +0 -21
  114. package/scaffold/skills/ui-ux-pro-max/templates/platforms/roocode.json +0 -21
  115. package/scaffold/skills/ui-ux-pro-max/templates/platforms/trae.json +0 -21
  116. package/scaffold/skills/ui-ux-pro-max/templates/platforms/warp.json +0 -18
  117. package/scaffold/skills/ui-ux-pro-max/templates/platforms/windsurf.json +0 -21
  118. package/scaffold/skills/webapp-testing/SKILL.md +0 -138
  119. package/scaffold/skills/webapp-testing/assets/test-helper.js +0 -56
  120. /package/scaffold/skills/{webapp-testing → dw-testing-discipline}/references/three-workflow-patterns.md +0 -0
@@ -0,0 +1,241 @@
1
+ # Twelve positive patterns — pseudo-code that survives refactors
2
+
3
+ Each pattern survives across testing frameworks (Jest, Vitest, Playwright, Cypress, pytest, JUnit). Pseudo-code in JavaScript-flavored examples; translate to your stack.
4
+
5
+ ## 1. Query by behavior and accessible role, not CSS selectors
6
+
7
+ **Pattern:**
8
+
9
+ ```javascript
10
+ // GOOD — describes what the user does
11
+ const submitBtn = await page.getByRole('button', { name: 'Submit order' });
12
+ await submitBtn.click();
13
+ expect(await page.getByText(/order #\d+ confirmed/i)).toBeVisible();
14
+ ```
15
+
16
+ **Anti-pattern:**
17
+
18
+ ```javascript
19
+ // BAD — describes implementation
20
+ await page.click('.btn-primary.submit-btn');
21
+ expect(page.querySelector('.confirmation-toast')).toBeTruthy();
22
+ ```
23
+
24
+ The good version survives a CSS refactor, a className rename, a Tailwind migration. The bad version breaks on each.
25
+
26
+ ## 2. Selector hierarchy
27
+
28
+ When the role isn't enough, climb DOWN this ladder. Stop at the highest rung that disambiguates:
29
+
30
+ 1. **Role + name** — `getByRole('button', { name: 'Submit' })`
31
+ 2. **Label / form association** — `getByLabel('Email')`
32
+ 3. **Text content** — `getByText('Welcome back')`
33
+ 4. **Test-id** — `getByTestId('user-menu')` (escape hatch; do not start here)
34
+ 5. **Structural / CSS** — `querySelector('article:nth-child(3)')` (last resort; flags)
35
+
36
+ Test-id is fine. Test-id as your default is a sign you're not designing accessible UI.
37
+
38
+ ## 3. Wait on observable conditions, never wall-clock
39
+
40
+ **Pattern:**
41
+
42
+ ```javascript
43
+ // GOOD — waits for the actual condition
44
+ await expect(page.getByText('Order confirmed')).toBeVisible({ timeout: 5000 });
45
+ ```
46
+
47
+ **Anti-pattern:**
48
+
49
+ ```javascript
50
+ // BAD — wall-clock hopes
51
+ await page.waitForTimeout(3000);
52
+ expect(page.getByText('Order confirmed')).toBeVisible();
53
+ ```
54
+
55
+ `waitForTimeout` is the #1 source of flakiness. It races with the network, with rendering, with the event loop. Always wait on what you actually need to see.
56
+
57
+ ## 4. Each test independent and order-free
58
+
59
+ Every test runs cleanly when invoked in isolation (with `.only`) or in a randomized order.
60
+
61
+ **Pattern:**
62
+
63
+ ```javascript
64
+ beforeEach(async () => {
65
+ // Set up state THIS test needs
66
+ await db.users.create({ id: 'test-1', email: 'a@b.c' });
67
+ });
68
+
69
+ afterEach(async () => {
70
+ // Clean up — but if tests are independent, you may not need this
71
+ await db.users.deleteAll();
72
+ });
73
+ ```
74
+
75
+ **Anti-pattern:** Shared state in `beforeAll`. Tests passing only when run in suite order. Brittle CI runs.
76
+
77
+ **Healthier:** prefer setup in `beforeEach` over teardown in `afterEach`. A test that sets up its own state from a clean baseline never wonders "did the previous test corrupt me?"
78
+
79
+ ## 5. One behavior per test, as many assertions as that behavior needs
80
+
81
+ **Pattern:**
82
+
83
+ ```javascript
84
+ test('successful login redirects to dashboard and shows user name', async () => {
85
+ await login('user@example.com', 'password');
86
+
87
+ expect(await page.url()).toContain('/dashboard');
88
+ expect(await page.getByRole('heading', { name: /welcome/i })).toBeVisible();
89
+ expect(await page.getByText('user@example.com')).toBeVisible();
90
+ });
91
+ ```
92
+
93
+ ONE behavior ("successful login leads to dashboard with user info"). THREE assertions because that behavior has three observable parts.
94
+
95
+ **Anti-pattern:** Two unrelated behaviors crammed into one test ("login + then-also-test-search-works"). When it fails, you don't know which broke.
96
+
97
+ ## 6. Names read as specifications
98
+
99
+ **Pattern:**
100
+
101
+ ```
102
+ should reject invalid email when registering given no prior account
103
+ should approve refund within SLA given amount under threshold
104
+ should sync calendar events when user reconnects given offline edits
105
+ ```
106
+
107
+ Form: `should <expected outcome> when <triggering condition> [given <starting state>]`
108
+
109
+ **Anti-pattern:**
110
+
111
+ ```
112
+ test_login
113
+ test_email_1
114
+ testHappy
115
+ ```
116
+
117
+ These tell you nothing on failure. A spec-style name doubles as documentation when failure messages get noisy.
118
+
119
+ ## 7. Table-driven / parameterized when inputs vary
120
+
121
+ **Pattern:**
122
+
123
+ ```javascript
124
+ describe.each([
125
+ { input: '', expected: 'required' },
126
+ { input: 'a', expected: 'too short' },
127
+ { input: 'a'.repeat(100), expected: 'too long' },
128
+ { input: 'a@b.c', expected: 'valid' },
129
+ ])('validateEmail($input)', ({ input, expected }) => {
130
+ test(`returns ${expected}`, () => {
131
+ expect(validateEmail(input)).toBe(expected);
132
+ });
133
+ });
134
+ ```
135
+
136
+ Easy to add cases; impossible to forget one input class.
137
+
138
+ **Anti-pattern:** Five copy-pasted tests with one variable changed. Drift between them; one gets updated, others don't.
139
+
140
+ ## 8. Build test data via factories
141
+
142
+ **Pattern:**
143
+
144
+ ```javascript
145
+ const buildUser = (overrides = {}) => ({
146
+ id: 'u-' + Math.random().toString(36).slice(2),
147
+ email: 'test@example.com',
148
+ role: 'member',
149
+ createdAt: new Date(),
150
+ ...overrides,
151
+ });
152
+
153
+ test('admin can delete users', () => {
154
+ const admin = buildUser({ role: 'admin' });
155
+ const target = buildUser();
156
+ expect(canDelete(admin, target)).toBe(true);
157
+ });
158
+ ```
159
+
160
+ Tests focus on the FIELDS that matter to the behavior. Default everything else.
161
+
162
+ **Anti-pattern:** Literal 50-field JSON blobs copy-pasted across tests. When the schema changes, you update them all — or worse, miss some.
163
+
164
+ ## 9. Mock at boundaries you don't control
165
+
166
+ **Pattern:**
167
+
168
+ | Boundary | Test treatment |
169
+ |----------|---------------|
170
+ | Your own modules | Real (don't mock) |
171
+ | Your own DB (with testcontainers) | Real |
172
+ | Third-party HTTP API | Mock at fetch/axios level |
173
+ | Cloud SDK (AWS, GCP, Stripe) | Mock at SDK level OR sandbox account |
174
+ | System clock | Mock when test depends on time |
175
+ | RNG | Mock when test depends on randomness |
176
+ | File system (when external) | Mock; in tests of fs logic, real temp dir |
177
+
178
+ **Anti-pattern:** Mocking your own modules so the test is fast. You're now testing the mock setup, not the code.
179
+
180
+ ## 10. Real systems gate final merge
181
+
182
+ **Pattern:**
183
+
184
+ ```
185
+ unit (mocks ok) → every commit, run locally and in CI
186
+ integration (real DB) → every PR, run in CI
187
+ contract (boundary) → every PR
188
+ E2E (real services) → before merge to main, run in CI on preview env
189
+ ```
190
+
191
+ No merge to main without a real-system path going green. Mocks are speed, real is truth.
192
+
193
+ **Anti-pattern:** 100% mocked test suite. "It all passes locally" → first user request fails because the mock didn't match the real API shape.
194
+
195
+ ## 11. Mutation score over coverage percentage
196
+
197
+ **Pattern:**
198
+
199
+ Set up mutation testing (Stryker for JS/TS, mutmut for Python, etc.) ONCE per project. Run weekly on critical modules.
200
+
201
+ ```bash
202
+ npx stryker run
203
+ # Output: 87 mutants, 78 killed, 9 survived → mutation score 89.6%
204
+ ```
205
+
206
+ A surviving mutant means: this code path runs in tests, but the tests don't actually assert anything that breaks when the code changes. Investigate each.
207
+
208
+ **Anti-pattern:** 95% line coverage with assertions like `expect(result).toBeTruthy()` — every line ran, but mutations all survive. The suite is decorative.
209
+
210
+ ## 12. Page Object Model is a tool, not a religion
211
+
212
+ For small E2E suites (<20 tests, <5 pages), POM is over-engineering — direct queries are clearer.
213
+
214
+ For large suites (>50 tests, many pages, multi-step flows), POM pays off:
215
+
216
+ ```javascript
217
+ class CheckoutPage {
218
+ constructor(page) { this.page = page; }
219
+
220
+ async fillShipping(addr) { /* ... */ }
221
+ async selectPayment(method) { /* ... */ }
222
+ async place() { /* ... */ }
223
+ async waitForConfirmation() { return this.page.getByText(/confirmed/i); }
224
+ }
225
+
226
+ test('checkout end-to-end', async ({ page }) => {
227
+ const checkout = new CheckoutPage(page);
228
+ await checkout.fillShipping(defaultAddress);
229
+ await checkout.selectPayment('card');
230
+ await checkout.place();
231
+ await expect(checkout.waitForConfirmation()).toBeVisible();
232
+ });
233
+ ```
234
+
235
+ The page object hides the selector mess; tests read like specs. But for a 5-test suite, that wrapper is just noise.
236
+
237
+ **Rule of thumb:** apply POM when you have ≥3 tests sharing the same page interactions. Otherwise inline.
238
+
239
+ ## Applying these patterns
240
+
241
+ When `/dw-run-task` generates a new test, it must comply with these 12. `/dw-code-review` checks each diff hunk under test paths against these patterns and the anti-patterns in the sibling reference. Violations become findings.
@@ -1,6 +1,6 @@
1
1
  # Security boundary — every browser is hostile
2
2
 
3
- > Adapted from [`addyosmani/agent-skills/browser-devtools`](https://github.com/addyosmani/agent-skills/tree/main/browser-devtools) (MIT). Adopts the security-boundary principle to inform how webapp-testing scenarios should validate trust boundaries.
3
+ > Adapted from [`addyosmani/agent-skills/browser-devtools`](https://github.com/addyosmani/agent-skills/tree/main/browser-devtools) (MIT). Adopts the security-boundary principle to inform how browser-based testing scenarios validate trust boundaries.
4
4
 
5
5
  The browser is not a secure environment. Anything that runs there — JS, CSS, HTML, devtools — is under the user's control. When you write a webapp test, you're not just verifying functionality; you're often verifying that this assumption holds.
6
6
 
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: dw-ui-discipline
3
+ description: Use BEFORE any UI work — enforces a hard-gate (brand authorities or curated defaults, surface job, state matrix, scene sentence), 14 anti-slop patterns, and WCAG 2.2 AA floor so UI ships with discipline instead of training-data defaults.
4
+ ---
5
+
6
+ # UI Discipline
7
+
8
+ > **Inspired by** [`pedronauck/skills/ui-craft`](https://github.com/pedronauck/skills/tree/main/skills/mine/ui-craft) (MIT). Hard-gate protocol, anti-slop catalog, state matrix enforcement, and accessibility-floor patterns adapted from Pedro Nauck's work; specifics rewritten for dev-workflow's redesign and review loops.
9
+
10
+ The fastest path through UI work is the disciplined one. "It's just a small change" is the most common slop excuse. This skill blocks that excuse at four checkpoints before any design decision lands.
11
+
12
+ ## When this skill applies
13
+
14
+ - Any work invoked from `/dw-redesign-ui`, `/dw-create-techspec` (UI sections), `/dw-functional-doc`, or `/dw-code-review` when the diff touches UI.
15
+ - Adding new screens, components, or surfaces.
16
+ - Reviewing visual changes in a PR.
17
+ - Auditing accessibility on existing surfaces.
18
+
19
+ If you're tempted to skip the gate "because it's just a tweak" — that's the trigger. Run the gate.
20
+
21
+ ## The hard-gate (4 mandatory items before any UI work)
22
+
23
+ Before proposing colors, layouts, components, or any visual decision, complete all four:
24
+
25
+ ### 1. Brand authorities OR curated defaults
26
+
27
+ Locate the project's design source of truth:
28
+ - `.dw/rules/{frontend-module}.md` design system section
29
+ - `DESIGN.md`, `BRAND.md`, or design tokens config (Tailwind, CSS vars, theme file)
30
+ - Component library docs (shadcn/ui, MUI, Chakra, etc.)
31
+
32
+ If **none exist**, do NOT invent. Read `references/curated-defaults.md` — pick from the 10 neutral palettes + 10 font pairings shipped there. Mark the choice as a finding in the techspec ("no design authority found; used curated default <name>; recommend establishing one").
33
+
34
+ ### 2. Surface job sentence
35
+
36
+ Write one sentence: "This surface helps the user <do what> so that <outcome>." Vague language ("show data", "manage settings") fails — be specific ("filter overdue invoices so they can chase late payers in <30s").
37
+
38
+ If you can't write the sentence, the requirements are unclear. Stop and clarify before proceeding.
39
+
40
+ ### 3. Complete state matrix
41
+
42
+ Enumerate all states the surface can be in. See `references/state-matrix.md` for the full list:
43
+ - `default`, `hover`, `active`, `focus-visible`, `disabled`, `loading`, `empty`, `error`, `success`
44
+ - Plus any domain-specific states (read/unread, online/offline, etc.)
45
+
46
+ Missing a state at design time = production bug later. The "we'll add empty state later" trap is real.
47
+
48
+ ### 4. Scene sentence
49
+
50
+ One sentence describing the physical context: **who** is using this, **where** (mobile bus, office desktop, on-call laptop), **what light** (dark room, bright outdoor), **what mood** (rushed, exploring, troubleshooting).
51
+
52
+ This forcing function prevents category-level defaults from becoming the answer. A "dashboard for an on-call engineer at 3am in a dark room troubleshooting a fire" produces different decisions than "dashboard for a manager during business hours."
53
+
54
+ ## Required Reading Router
55
+
56
+ | Context | Read |
57
+ |---------|------|
58
+ | Any UI work | `references/hard-gate.md` (full protocol with examples) |
59
+ | Interactive widgets (buttons, forms, modals) | `references/accessibility-floor.md` (WCAG 2.2 AA non-negotiable) |
60
+ | Reviewing a UI diff | `references/anti-slop.md` (14 anti-patterns + 17 anti-defaults) |
61
+ | Designing state coverage | `references/state-matrix.md` (full enumeration + checklist) |
62
+ | No design authority exists in project | `references/curated-defaults.md` (10 palettes + 10 fonts) |
63
+
64
+ ## Anti-slop summary (full list in references/anti-slop.md)
65
+
66
+ The 14 patterns this skill catches:
67
+
68
+ 1. **Visual sameness** — every section looks like every other section.
69
+ 2. **Weak hierarchy** — nothing draws the eye to what matters first.
70
+ 3. **Fake interactivity** — hover states that don't change anything functional.
71
+ 4. **Emoji spam** — emojis as decoration where icons or restraint would serve.
72
+ 5. **Gradient crutch** — gradients used to mask weak composition.
73
+ 6. **Glass everything** — frosted glass on every panel.
74
+ 7. **Centered all the things** — center-aligned text when left-aligned reads better.
75
+ 8. **AI gray washing** — neutral grays everywhere, no character.
76
+ 9. **Generic CTAs** — "Get Started", "Learn More", "Click Here" with no specificity.
77
+ 10. **Stock illustration** — generic figure-with-laptop hero art.
78
+ 11. **Drop shadow soup** — shadows on cards on shadows on borders.
79
+ 12. **Loading spinner default** — spinner as the only loading state for everything.
80
+ 13. **Empty state void** — empty list with no guidance on what to do next.
81
+ 14. **Notification-soup tray** — every UI event becomes a toast.
82
+
83
+ Plus 17 anti-defaults (specific values to NEVER use without intent — `#3B82F6` blue, `rounded-lg` everywhere, etc.) in `references/anti-slop.md`.
84
+
85
+ ## Accessibility floor — non-negotiable
86
+
87
+ Before any interactive widget ships:
88
+
89
+ - [ ] Color contrast meets WCAG 2.2 AA (4.5:1 for body text, 3:1 for large text and UI components).
90
+ - [ ] Focus-visible state exists and is distinct from hover.
91
+ - [ ] Keyboard navigation works (tab order, escape closes modals, enter submits forms).
92
+ - [ ] ARIA labels for icon-only buttons.
93
+ - [ ] Form errors are announced to screen readers.
94
+ - [ ] No keyboard traps.
95
+
96
+ Full verification recipes in `references/accessibility-floor.md`. This is a hard gate — `/dw-code-review` fails verdict if any interactive widget ships without these.
97
+
98
+ ## When the gate bends
99
+
100
+ Real-world UI can't always be perfect:
101
+
102
+ - **Bug fix in existing UI** — gate applies only to the area touched, not the whole surface.
103
+ - **Pure copy change** — gate is just "scene sentence still holds?" — quick check.
104
+ - **Spike / exploration** — gate skipped if the spike is explicitly marked throwaway; production code must run the gate.
105
+
106
+ In all bend cases, document the bend in the PR description (one line). "I skipped the state matrix because this is a one-line copy fix" is fine. "I skipped because I was in a hurry" is not.
107
+
108
+ ## Integration with dev-workflow commands
109
+
110
+ - `/dw-redesign-ui` runs the gate end-to-end. Steps 4 (propose design) and 7 (validate WCAG) consult this skill.
111
+ - `/dw-create-techspec` UI sections must list which authorities were consulted (brand vs curated default) and reference the state matrix.
112
+ - `/dw-code-review` checks the diff against `references/anti-slop.md` and the accessibility floor.
113
+ - `/dw-functional-doc` documents the scene sentence in the overview.
114
+
115
+ ## Anti-patterns this skill prevents
116
+
117
+ - "Just use the same hero as the marketing page" — without verifying the surface job differs.
118
+ - "We'll add empty/error states later" — they're never added later.
119
+ - "It looks fine on my desktop" — without checking mobile + keyboard + screen reader.
120
+ - Designing in isolation from `.dw/rules/` documented patterns.
121
+ - Inventing color values when the design system has tokens that fit.
122
+ - Shipping interactive widgets without WCAG 2.2 AA verification.
123
+
124
+ ## Why this skill exists
125
+
126
+ The previous bundled skill (`ui-ux-pro-max`) provided 161 color palettes and 57 font pairings — a CATALOG of taste. It had no gates, no anti-patterns, no enforcement. Agents loaded KB of palette data and still produced slop because there was no DISCIPLINE.
127
+
128
+ This skill inverts that trade-off: 10 curated defaults (enough for 90% of cases) + a strong gate + an anti-slop catalog. Less context bytes, more leverage.
@@ -0,0 +1,225 @@
1
+ # Accessibility floor — WCAG 2.2 AA is the minimum, not the goal
2
+
3
+ This reference is read in full before any interactive widget ships. Skipping any item below is a hard-block in `/dw-code-review`.
4
+
5
+ ## The non-negotiables
6
+
7
+ ### 1. Color contrast
8
+
9
+ | Element | Minimum ratio (WCAG 2.2 AA) |
10
+ |---------|----------------------------|
11
+ | Body text (under 18pt or under 14pt bold) | 4.5:1 |
12
+ | Large text (18pt+ or 14pt+ bold) | 3:1 |
13
+ | UI components (button borders, icons, focus rings) | 3:1 |
14
+ | Decorative graphics | No requirement |
15
+
16
+ **Verification:**
17
+ - Use `axe DevTools` browser extension OR `playwright/test` with `@axe-core/playwright`.
18
+ - Manual quick check: `chrome://flags` → Enable "Simulate Vision Deficiencies" + try "Achromatopsia" (no colors). If buttons still legible, contrast is doing its job.
19
+
20
+ **Common violation:** Light gray text on white. `#9CA3AF` on white = 2.85:1. FAIL.
21
+
22
+ ### 2. Focus-visible state
23
+
24
+ Every interactive element must have a distinct focus-visible state when keyboard-focused.
25
+
26
+ **Rules:**
27
+ - `:focus-visible` MUST be distinct from `:hover` — keyboard users need an affordance.
28
+ - Default browser outline is acceptable; replacing with `outline: none` requires alternative (border, ring, shadow).
29
+ - Focus must be visible against any background the element can appear on (dark + light themes).
30
+
31
+ **Tailwind pattern:**
32
+ ```css
33
+ focus-visible:outline-none
34
+ focus-visible:ring-2
35
+ focus-visible:ring-offset-2
36
+ focus-visible:ring-blue-500
37
+ ```
38
+
39
+ **Verification:**
40
+ - Tab through the entire surface with keyboard. Every interactive element must light up visibly.
41
+ - If you can't tell what's focused, the contrast on the focus ring is too low.
42
+
43
+ ### 3. Keyboard navigation
44
+
45
+ | Capability | Requirement |
46
+ |------------|-------------|
47
+ | Tab order | Logical (left-to-right, top-to-bottom in LTR) |
48
+ | Modals | Tab cycles WITHIN modal; Escape closes; focus returns to trigger |
49
+ | Dropdowns / select | Arrow keys navigate options; Enter selects; Escape closes |
50
+ | Forms | Enter submits; Tab moves to next field; Shift+Tab moves back |
51
+ | Custom widgets | Match the ARIA Authoring Practices Guide patterns |
52
+
53
+ **Verification:**
54
+ - Unplug mouse. Complete the primary user flow with keyboard only.
55
+ - If you got stuck or couldn't reach an element, keyboard nav is broken.
56
+
57
+ ### 4. ARIA labels for icon-only interactives
58
+
59
+ Icon-only buttons (e.g., a trash can icon as a delete button) need `aria-label` describing the action.
60
+
61
+ ```html
62
+ <!-- BAD -->
63
+ <button><TrashIcon /></button>
64
+
65
+ <!-- GOOD -->
66
+ <button aria-label="Delete invoice"><TrashIcon /></button>
67
+ ```
68
+
69
+ Same applies to:
70
+ - Icon-only links
71
+ - Icon-only toggles
72
+ - Tooltips (the trigger needs aria-describedby pointing to the tooltip)
73
+ - Decorative images (`aria-hidden="true"` if purely decorative; `alt=""` not enough)
74
+
75
+ ### 5. Form errors announced to screen readers
76
+
77
+ When a form field errors:
78
+
79
+ ```html
80
+ <label for="email">Email</label>
81
+ <input
82
+ id="email"
83
+ type="email"
84
+ aria-describedby="email-error"
85
+ aria-invalid="true"
86
+ />
87
+ <span id="email-error" role="alert">
88
+ Email is required
89
+ </span>
90
+ ```
91
+
92
+ Key points:
93
+ - `aria-invalid="true"` on the input.
94
+ - `aria-describedby` links the input to the error message.
95
+ - `role="alert"` on the error message announces it.
96
+
97
+ **Anti-pattern:** Red border + tooltip on hover. Screen reader users get nothing.
98
+
99
+ ### 6. No keyboard traps
100
+
101
+ A "keyboard trap" is when focus enters a widget and can't leave with the keyboard. Most common cause: custom-built modals or carousels.
102
+
103
+ **Rule:** Every modal, drawer, or overlay must let Escape close it and return focus to the trigger element.
104
+
105
+ **Verification:**
106
+ - Open the widget with keyboard. Press Escape. Does focus return to where it was?
107
+ - Tab through the widget. After last element, does Tab cycle to first (within widget) instead of leaving the page?
108
+
109
+ ### 7. Touch target size (mobile)
110
+
111
+ Minimum 24x24 CSS pixels (WCAG 2.2 AA minimum). Recommended 44x44 (Apple HIG / Android touch target).
112
+
113
+ **Pattern:** Even when the visual icon is 16x16, give the button 44x44 hit area:
114
+
115
+ ```css
116
+ button {
117
+ width: 24px; height: 24px; /* WCAG 2.2 AA minimum */
118
+ /* Or */
119
+ width: 44px; height: 44px; /* Recommended */
120
+ padding: 14px; /* Visual icon inside */
121
+ }
122
+ ```
123
+
124
+ ### 8. Heading hierarchy
125
+
126
+ H1 → H2 → H3 etc. Don't skip levels. Don't use heading tags for visual sizing — use semantic level + CSS for size.
127
+
128
+ ```html
129
+ <!-- BAD -->
130
+ <h2>Section A</h2>
131
+ <h4>Subsection</h4> <!-- skipped h3 -->
132
+
133
+ <!-- GOOD -->
134
+ <h2>Section A</h2>
135
+ <h3>Subsection</h3>
136
+ ```
137
+
138
+ Screen readers navigate by heading; broken hierarchy disorients.
139
+
140
+ ### 9. Language attribute
141
+
142
+ Root `<html lang="en">` (or correct ISO code) for primary language. Sections in other language need `lang` attribute too.
143
+
144
+ ```html
145
+ <html lang="en">
146
+ <p>Welcome.</p>
147
+ <p lang="pt-br">Bem-vindo.</p>
148
+ </html>
149
+ ```
150
+
151
+ Screen readers switch pronunciation based on this.
152
+
153
+ ### 10. Reduced motion respect
154
+
155
+ Honor `prefers-reduced-motion`:
156
+
157
+ ```css
158
+ @media (prefers-reduced-motion: reduce) {
159
+ *, *::before, *::after {
160
+ animation-duration: 0.01ms !important;
161
+ transition-duration: 0.01ms !important;
162
+ }
163
+ }
164
+ ```
165
+
166
+ Or in Tailwind:
167
+ ```html
168
+ <div className="transition-all motion-reduce:transition-none">
169
+ ```
170
+
171
+ Vestibular disorders trigger on parallax, large slide-ins, infinite scroll animations.
172
+
173
+ ## Verification recipes
174
+
175
+ ### Automated (CI)
176
+
177
+ ```ts
178
+ // playwright + axe-core
179
+ import { test, expect } from '@playwright/test';
180
+ import AxeBuilder from '@axe-core/playwright';
181
+
182
+ test('homepage a11y', async ({ page }) => {
183
+ await page.goto('/');
184
+ const results = await new AxeBuilder({ page })
185
+ .withTags(['wcag2a', 'wcag2aa', 'wcag22a', 'wcag22aa'])
186
+ .analyze();
187
+ expect(results.violations).toEqual([]);
188
+ });
189
+ ```
190
+
191
+ Run on every PR. Block merge on violations.
192
+
193
+ ### Manual (PR review)
194
+
195
+ 1. Open the changed page.
196
+ 2. Tab through with keyboard only. Verify focus visible at every stop.
197
+ 3. Run axe DevTools, fix violations.
198
+ 4. Toggle prefers-reduced-motion in DevTools rendering panel. Verify animations stop.
199
+ 5. Test with screen reader (VoiceOver on Mac, NVDA on Windows) on at least one critical flow.
200
+
201
+ ### Spot checks
202
+
203
+ Color contrast: chrome devtools → element inspector → "Contrast" indicator next to text color. Click for actual ratio.
204
+
205
+ Touch target: Inspect element → check computed width/height. If < 24, flag.
206
+
207
+ ## When the floor bends
208
+
209
+ - **Iframes you don't control** — your wrapper still has to be accessible, the iframe is best-effort.
210
+ - **Third-party widgets** (analytics dashboards, payment SDKs) — wrap with ARIA landmarks; report violations upstream.
211
+ - **Legacy code being patched** — bring touched components up to floor; leave untouched ones for separate accessibility-debt work.
212
+
213
+ In all bend cases, file a tracking issue. Don't pretend the floor was met.
214
+
215
+ ## Common AI-generated UI violations
216
+
217
+ LLM-produced UI commonly fails on:
218
+ - `<div onClick>` instead of `<button>` (not keyboard-accessible).
219
+ - Icon-only buttons with no aria-label.
220
+ - `text-gray-400` on white (contrast 2.8:1 — fail).
221
+ - `outline: none` with no replacement focus state.
222
+ - Modals that trap focus only on success path, not on error.
223
+ - Auto-playing carousels with no pause control.
224
+
225
+ `/dw-code-review` runs axe-style checks on the diff for these.