hatch3r 1.7.1 → 1.8.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 (189) hide show
  1. package/README.md +38 -12
  2. package/agents/hatch3r-a11y-auditor.md +4 -0
  3. package/agents/hatch3r-architect.md +4 -0
  4. package/agents/hatch3r-ci-watcher.md +4 -0
  5. package/agents/hatch3r-context-rules.md +26 -6
  6. package/agents/hatch3r-creator.md +6 -1
  7. package/agents/hatch3r-dependency-auditor.md +4 -0
  8. package/agents/hatch3r-devops.md +4 -0
  9. package/agents/hatch3r-docs-writer.md +4 -0
  10. package/agents/hatch3r-fixer.md +4 -0
  11. package/agents/hatch3r-handoff-loader.md +243 -0
  12. package/agents/hatch3r-handoff-preparer.md +134 -0
  13. package/agents/hatch3r-implementer.md +12 -0
  14. package/agents/hatch3r-learnings-loader.md +5 -1
  15. package/agents/hatch3r-lint-fixer.md +4 -0
  16. package/agents/hatch3r-perf-profiler.md +8 -0
  17. package/agents/hatch3r-researcher.md +4 -0
  18. package/agents/hatch3r-reviewer.md +94 -0
  19. package/agents/hatch3r-security-auditor.md +24 -0
  20. package/agents/hatch3r-test-writer.md +4 -0
  21. package/agents/modes/requirements-elicitation.md +4 -1
  22. package/agents/modes/similar-implementation.md +6 -0
  23. package/agents/modes/user-flows.md +76 -0
  24. package/agents/shared/quality-charter.md +128 -0
  25. package/agents/shared/user-content-templates.md +31 -1
  26. package/commands/hatch3r-agent-customize.md +4 -0
  27. package/commands/hatch3r-api-spec.md +7 -0
  28. package/commands/hatch3r-benchmark.md +7 -0
  29. package/commands/hatch3r-board-fill.md +8 -0
  30. package/commands/hatch3r-board-groom.md +4 -0
  31. package/commands/hatch3r-board-init.md +51 -0
  32. package/commands/hatch3r-board-pickup.md +8 -0
  33. package/commands/hatch3r-board-refresh.md +4 -0
  34. package/commands/hatch3r-board-shared.md +6 -6
  35. package/commands/hatch3r-bug-plan.md +7 -0
  36. package/commands/hatch3r-codebase-map.md +8 -0
  37. package/commands/hatch3r-command-customize.md +4 -0
  38. package/commands/hatch3r-context-health.md +5 -0
  39. package/commands/hatch3r-create.md +59 -4
  40. package/commands/hatch3r-debug.md +7 -0
  41. package/commands/hatch3r-dep-audit.md +4 -0
  42. package/commands/hatch3r-feature-plan.md +7 -0
  43. package/commands/hatch3r-handoff.md +133 -0
  44. package/commands/hatch3r-healthcheck.md +4 -0
  45. package/commands/hatch3r-hooks.md +4 -0
  46. package/commands/hatch3r-learn.md +16 -0
  47. package/commands/hatch3r-migration-plan.md +7 -0
  48. package/commands/hatch3r-onboard.md +7 -0
  49. package/commands/hatch3r-pr-resolve.md +12 -1
  50. package/commands/hatch3r-project-spec.md +8 -0
  51. package/commands/hatch3r-quick-change.md +11 -2
  52. package/commands/hatch3r-recipe.md +4 -0
  53. package/commands/hatch3r-refactor-plan.md +7 -0
  54. package/commands/hatch3r-release.md +5 -0
  55. package/commands/hatch3r-revision.md +7 -0
  56. package/commands/hatch3r-roadmap.md +8 -0
  57. package/commands/hatch3r-rule-customize.md +4 -0
  58. package/commands/hatch3r-security-audit.md +4 -0
  59. package/commands/hatch3r-skill-customize.md +4 -0
  60. package/commands/hatch3r-test-plan.md +7 -0
  61. package/commands/hatch3r-workflow.md +11 -1
  62. package/dist/cli/index.js +4814 -1130
  63. package/dist/cli/index.js.map +1 -1
  64. package/package.json +10 -5
  65. package/rules/hatch3r-accessibility-standards.md +21 -0
  66. package/rules/hatch3r-accessibility-standards.mdc +21 -0
  67. package/rules/hatch3r-agent-orchestration-detail.md +3 -0
  68. package/rules/hatch3r-agent-orchestration-detail.mdc +3 -0
  69. package/rules/hatch3r-agent-orchestration.md +34 -3
  70. package/rules/hatch3r-agent-orchestration.mdc +34 -3
  71. package/rules/hatch3r-ai-evals.md +158 -0
  72. package/rules/hatch3r-ai-evals.mdc +154 -0
  73. package/rules/hatch3r-ai-ux-patterns.md +131 -0
  74. package/rules/hatch3r-ai-ux-patterns.mdc +127 -0
  75. package/rules/hatch3r-api-design.md +67 -9
  76. package/rules/hatch3r-api-design.mdc +67 -9
  77. package/rules/hatch3r-api-versioning.md +119 -0
  78. package/rules/hatch3r-api-versioning.mdc +115 -0
  79. package/rules/hatch3r-auth-patterns.md +170 -0
  80. package/rules/hatch3r-auth-patterns.mdc +166 -0
  81. package/rules/hatch3r-component-conventions.md +30 -0
  82. package/rules/hatch3r-component-conventions.mdc +30 -0
  83. package/rules/hatch3r-container-hardening.md +131 -0
  84. package/rules/hatch3r-container-hardening.mdc +127 -0
  85. package/rules/hatch3r-contract-testing.md +117 -0
  86. package/rules/hatch3r-contract-testing.mdc +113 -0
  87. package/rules/hatch3r-deep-context.md +2 -0
  88. package/rules/hatch3r-deep-context.mdc +2 -0
  89. package/rules/hatch3r-dependency-management.md +73 -1
  90. package/rules/hatch3r-dependency-management.mdc +72 -0
  91. package/rules/hatch3r-design-system-detection.md +142 -0
  92. package/rules/hatch3r-design-system-detection.mdc +138 -0
  93. package/rules/hatch3r-event-schema-evolution.md +90 -0
  94. package/rules/hatch3r-event-schema-evolution.mdc +86 -0
  95. package/rules/hatch3r-handoff-readiness.md +45 -0
  96. package/rules/hatch3r-handoff-readiness.mdc +40 -0
  97. package/rules/hatch3r-i18n.md +13 -0
  98. package/rules/hatch3r-i18n.mdc +13 -0
  99. package/rules/hatch3r-iteration-summary.md +2 -0
  100. package/rules/hatch3r-iteration-summary.mdc +2 -0
  101. package/rules/hatch3r-migrations.md +61 -16
  102. package/rules/hatch3r-migrations.mdc +61 -16
  103. package/rules/hatch3r-observability-logging.md +1 -1
  104. package/rules/hatch3r-observability-logging.mdc +1 -1
  105. package/rules/hatch3r-observability-metrics.md +1 -1
  106. package/rules/hatch3r-observability-metrics.mdc +1 -1
  107. package/rules/hatch3r-observability-tracing-detail.md +8 -149
  108. package/rules/hatch3r-observability-tracing-detail.mdc +7 -149
  109. package/rules/hatch3r-observability-tracing.md +154 -6
  110. package/rules/hatch3r-observability-tracing.mdc +154 -6
  111. package/rules/hatch3r-observability.md +1 -0
  112. package/rules/hatch3r-observability.mdc +1 -0
  113. package/rules/hatch3r-operability.md +149 -0
  114. package/rules/hatch3r-operability.mdc +145 -0
  115. package/rules/hatch3r-passkey-server.md +181 -0
  116. package/rules/hatch3r-passkey-server.mdc +177 -0
  117. package/rules/hatch3r-progressive-delivery.md +120 -0
  118. package/rules/hatch3r-progressive-delivery.mdc +116 -0
  119. package/rules/hatch3r-resilience-patterns.md +154 -0
  120. package/rules/hatch3r-resilience-patterns.mdc +150 -0
  121. package/rules/hatch3r-secrets-management.md +29 -0
  122. package/rules/hatch3r-secrets-management.mdc +29 -0
  123. package/rules/hatch3r-testing.md +139 -43
  124. package/rules/hatch3r-testing.mdc +139 -43
  125. package/rules/hatch3r-ux-states-and-flows.md +149 -0
  126. package/rules/hatch3r-ux-states-and-flows.mdc +145 -0
  127. package/skills/hatch3r-a11y-audit/SKILL.md +14 -0
  128. package/skills/hatch3r-agent-customize/SKILL.md +10 -0
  129. package/skills/hatch3r-ai-feature/SKILL.md +136 -0
  130. package/skills/hatch3r-api-spec/SKILL.md +73 -0
  131. package/skills/hatch3r-architecture-review/SKILL.md +14 -0
  132. package/skills/hatch3r-bug-fix/SKILL.md +5 -0
  133. package/skills/hatch3r-ci-pipeline/SKILL.md +14 -0
  134. package/skills/hatch3r-cli-aichat/SKILL.md +84 -0
  135. package/skills/hatch3r-cli-ast-grep/SKILL.md +85 -0
  136. package/skills/hatch3r-cli-az-devops/SKILL.md +89 -0
  137. package/skills/hatch3r-cli-bat/SKILL.md +85 -0
  138. package/skills/hatch3r-cli-comby/SKILL.md +85 -0
  139. package/skills/hatch3r-cli-csvkit/SKILL.md +84 -0
  140. package/skills/hatch3r-cli-delta/SKILL.md +86 -0
  141. package/skills/hatch3r-cli-difftastic/SKILL.md +84 -0
  142. package/skills/hatch3r-cli-docker/SKILL.md +89 -0
  143. package/skills/hatch3r-cli-duckdb/SKILL.md +84 -0
  144. package/skills/hatch3r-cli-fd/SKILL.md +85 -0
  145. package/skills/hatch3r-cli-fzf/SKILL.md +84 -0
  146. package/skills/hatch3r-cli-gh/SKILL.md +90 -0
  147. package/skills/hatch3r-cli-glab/SKILL.md +89 -0
  148. package/skills/hatch3r-cli-jq/SKILL.md +89 -0
  149. package/skills/hatch3r-cli-lazygit/SKILL.md +78 -0
  150. package/skills/hatch3r-cli-llm/SKILL.md +84 -0
  151. package/skills/hatch3r-cli-miller/SKILL.md +84 -0
  152. package/skills/hatch3r-cli-mods/SKILL.md +84 -0
  153. package/skills/hatch3r-cli-overview/SKILL.md +60 -0
  154. package/skills/hatch3r-cli-playwright/SKILL.md +89 -0
  155. package/skills/hatch3r-cli-podman/SKILL.md +84 -0
  156. package/skills/hatch3r-cli-qsv/SKILL.md +91 -0
  157. package/skills/hatch3r-cli-ripgrep/SKILL.md +85 -0
  158. package/skills/hatch3r-cli-rtk/SKILL.md +91 -0
  159. package/skills/hatch3r-cli-sd/SKILL.md +85 -0
  160. package/skills/hatch3r-cli-stagehand/SKILL.md +111 -0
  161. package/skills/hatch3r-cli-taplo/SKILL.md +84 -0
  162. package/skills/hatch3r-cli-yq/SKILL.md +85 -0
  163. package/skills/hatch3r-cli-zstd/SKILL.md +85 -0
  164. package/skills/hatch3r-command-customize/SKILL.md +10 -0
  165. package/skills/hatch3r-context-health/SKILL.md +14 -0
  166. package/skills/hatch3r-cost-tracking/SKILL.md +14 -0
  167. package/skills/hatch3r-customize/SKILL.md +17 -0
  168. package/skills/hatch3r-dep-audit/SKILL.md +14 -0
  169. package/skills/hatch3r-design-system-detect/SKILL.md +164 -0
  170. package/skills/hatch3r-feature/SKILL.md +2 -0
  171. package/skills/hatch3r-gh-agentic-workflows/SKILL.md +13 -0
  172. package/skills/hatch3r-handoff-prepare/SKILL.md +160 -0
  173. package/skills/hatch3r-handoff-resume/SKILL.md +171 -0
  174. package/skills/hatch3r-incident-response/SKILL.md +14 -0
  175. package/skills/hatch3r-issue-workflow/SKILL.md +5 -0
  176. package/skills/hatch3r-logical-refactor/SKILL.md +14 -0
  177. package/skills/hatch3r-migration/SKILL.md +14 -0
  178. package/skills/hatch3r-observability-verify/SKILL.md +134 -0
  179. package/skills/hatch3r-perf-audit/SKILL.md +14 -0
  180. package/skills/hatch3r-pr-creation/SKILL.md +14 -0
  181. package/skills/hatch3r-qa-validation/SKILL.md +18 -0
  182. package/skills/hatch3r-recipe/SKILL.md +14 -0
  183. package/skills/hatch3r-refactor/SKILL.md +14 -0
  184. package/skills/hatch3r-release/SKILL.md +14 -0
  185. package/skills/hatch3r-reliability-verify/SKILL.md +146 -0
  186. package/skills/hatch3r-rule-customize/SKILL.md +10 -0
  187. package/skills/hatch3r-skill-customize/SKILL.md +10 -0
  188. package/skills/hatch3r-ui-ux-verify/SKILL.md +138 -0
  189. package/skills/hatch3r-visual-refactor/SKILL.md +15 -1
@@ -8,17 +8,24 @@ alwaysApply: false
8
8
  ## Core Principles
9
9
 
10
10
  - Unit tests: project test runner. Integration: test runner + emulators/mocks. E2E: browser automation (Playwright or equivalent).
11
- - **Deterministic.** Mock time where needed. No wall clock dependency.
12
- - **Isolated.** Each test sets up and tears down its own state.
11
+ - **Deterministic.** Mock time, seed RNG, pin timezone/locale. See Determinism Contract below.
12
+ - **Isolated.** Each test sets up and tears down its own state. Vitest `isolate: true`; Jest `--runInBand` only for serialized DB tests.
13
13
  - **Fast.** Unit tests < 50ms. Integration tests < 2s.
14
14
  - **Named clearly.** Describe behavior: `"should award 15 XP for 25-min focus block"`.
15
15
  - **Regression.** Every bug fix includes a test that fails before the fix and passes after.
16
- - **No network.** Unit tests must not make network calls. Use mocks.
16
+ - **No network.** Unit tests must not make network calls. Use mocks or Testcontainers (pinned by digest).
17
17
  - No type escape hatches in tests. No `.skip` without a linked issue.
18
18
  - Write tests to `tests/unit/`, `tests/integration/`, `tests/e2e/`, or equivalent.
19
19
  - Use test fixtures from `tests/fixtures/` or equivalent.
20
20
  - **Browser verification.** For UI changes, verify visually in the browser via browser automation MCP after automated tests pass. Capture screenshots as evidence.
21
21
 
22
+ ## Test Pyramid / Honeycomb / Trophy — Pick by Architecture
23
+
24
+ Pick exactly one shape and document it in `docs/testing.md` (or equivalent):
25
+ - **Pyramid** (heavy unit, light E2E): monoliths with rich domain logic.
26
+ - **Honeycomb** (heavy integration, light unit + E2E): microservices; ~48% of microservice teams (Spotify model).
27
+ - **Trophy** (unit + integration + E2E in similar ratios, light static): serverless functions; ~42% of serverless teams (Kent C. Dodds shape).
28
+
22
29
  ## Coverage Thresholds
23
30
 
24
31
  - **Statement coverage:** 80% minimum across the project. New code must not decrease overall coverage.
@@ -29,6 +36,10 @@ alwaysApply: false
29
36
  - Generate coverage reports in CI and publish as PR comments or artifacts for visibility.
30
37
  - Exclude generated code, type declarations, and config files from coverage metrics.
31
38
 
39
+ ## Coverage That Matters — Coverage AND Mutation
40
+
41
+ Coverage alone is necessary, not sufficient. A PR that raises line coverage but drops mutation score is a regression. Reviewers verify the right test classes per the Per-Feature Mandate Map below; coverage numbers are a floor, not a finish line.
42
+
32
43
  ## Mocking Strategy
33
44
 
34
45
  - **Prefer fakes over mocks** for stateful dependencies (databases, caches). Fakes implement the real interface with in-memory state, making tests more realistic.
@@ -39,59 +50,144 @@ alwaysApply: false
39
50
  - **Type-safe mocks.** Mock implementations must satisfy the same TypeScript interface as the real dependency. Avoid `as any` in mock setup.
40
51
  - **No mocking the unit under test.** If you need to mock part of the module you are testing, the module has too many responsibilities — refactor first.
41
52
 
42
- ## Property-Based Testing
53
+ ## Contract Testing
54
+
55
+ Every cross-service interaction is covered by both consumer-side (Pact) and provider-side (Schemathesis against the OpenAPI/AsyncAPI schema) contract tests. `pact-broker can-i-deploy` gates production deploys: if the consumer/provider contract pair is incompatible, the deploy is blocked. See `rules/hatch3r-contract-testing.md` for the full pattern (broker setup, provider state handlers, versioning, breakage triage).
56
+
57
+ ## Property-Based Testing — Per Ecosystem
58
+
59
+ Required for any pure function, parser, serializer, state machine, or invariant-bearing function. Default 100 trials per property; raise to 1000 for security-sensitive code. Shrinking must be enabled.
60
+
61
+ - **TypeScript / JavaScript:** `fast-check` (latest 3.x). Use for pure functions, parsers, state machines (`fc.commands`).
62
+ - **Python:** `Hypothesis` 6.151+. Stateful PBT via `RuleBasedStateMachine`.
63
+ - **Rust:** `proptest`. Shrinks to minimal failing case.
64
+ - **Scala:** `ScalaCheck`. Use for case-class invariants.
65
+ - **Java:** `jqwik` (modern) or `junit-quickcheck`.
66
+ - **Go:** `gopter` or stdlib `testing/quick` (limited shrinking).
43
67
 
44
- - Use a property-based testing library (fast-check or equivalent) for functions with wide input domains.
45
- - **Priority targets:** parsers, serializers, validators, encoders/decoders, mathematical functions, and any pure function with complex input types.
46
- - Define invariants as properties: round-trip (encode then decode equals original), idempotency (applying twice equals applying once), monotonicity, commutativity.
47
- - Use `fc.assert` with at least 100 runs per property. Increase to 1000 for critical paths.
48
- - When a property test finds a failure, add the minimal counterexample as a dedicated regression unit test.
49
- - Shrinking must be enabled — it reduces failing inputs to the smallest reproduction case.
50
- - Property tests belong alongside unit tests in `tests/unit/`. Name them clearly: `"property: round-trip serialization for UserProfile"`.
68
+ Invariants to encode: round-trip (encode then decode equals original), idempotency (applying twice equals once), monotonicity, commutativity. When a property test finds a failure, add the minimal counterexample as a dedicated regression unit test.
51
69
 
52
- ## Mutation Testing
70
+ ## Mutation Testing — Per Ecosystem + Thresholds
53
71
 
54
- - Use Stryker (or equivalent mutation testing framework) on critical modules to measure test effectiveness beyond line coverage.
55
- - **Mutation score target:** 70% minimum on critical modules (auth, data layer, business rules). 60% minimum project-wide.
56
- - Run mutation testing in CI on a weekly schedule (not per-PR too slow). Report results as a CI artifact.
57
- - **Surviving mutants** indicate tests that pass regardless of code changes these are false-coverage tests. Fix them by adding assertions that detect the mutation.
58
- - Focus mutation testing effort on modules where a bug would cause data loss, security vulnerability, or financial impact.
59
- - Exclude test files, generated code, and UI presentation logic from mutation analysis.
72
+ Run on a nightly schedule (not per-commit) due to runtime cost. Mutation score is a quality gate alongside coverage. Surviving mutants indicate tests that pass regardless of code changes — fix by adding assertions that detect the mutation.
73
+
74
+ - **TypeScript / JavaScript:** Stryker. Thresholds: break 50 / low 60 / high 80 (Stryker defaults).
75
+ - **Python:** `mutmut` (88.5% score on reference suite, faster) or `Cosmic Ray` (82.7%, thorough).
76
+ - **Java:** PIT 1.22 (November 2025). Business logic target 80–90.
77
+ - **Go:** `go-mutesting` or `gremlins-dev/gremlins`.
78
+ - **.NET:** `Stryker.NET`.
79
+
80
+ **Mutation score target:** 70% minimum on critical modules (auth, data layer, business rules), 60% project-wide, 80%+ on payment/billing logic. Exclude test files, generated code, and UI presentation logic from mutation analysis.
81
+
82
+ ## Fuzz Testing — Per Ecosystem
83
+
84
+ Required for any parser, deserializer, network handler, file-format handler, or untrusted-input boundary. Crash + hang + OOM detection; corpus minimization; persisted crash inputs become regression fixtures.
85
+
86
+ - **Java:** jazzer (OSS-Fuzz integrated).
87
+ - **JavaScript:** jazzer.js OSS was discontinued in 2025 — fall back to property-based testing for JS-only paths, or fuzz the underlying native binding.
88
+ - **Python:** `atheris` (Google).
89
+ - **Rust:** `cargo-fuzz` + libFuzzer.
90
+ - **Go:** native `testing.F` (Go 1.18+); for advanced workflows use `gosentry` (Trail of Bits, 2026-05-12 fork of the discontinued jazzer.js workflow adapted for Go).
91
+ - **C / C++:** AFL++ + OSS-Fuzz.
92
+
93
+ ## Determinism Contract
94
+
95
+ Every test must be deterministic. Mandates:
96
+ - **Clock injection.** Production code never calls `new Date()` / `time.Now()` / `datetime.now()` directly; inject a clock interface. In tests: `vi.useFakeTimers()` / `freezegun` / `mock.patch('time.time')`.
97
+ - **Seeded RNG.** Every random call uses an injected seedable RNG. In tests: fixed seed per test.
98
+ - **Pinned timezone and locale.** `TZ=UTC` and `LC_ALL=C.UTF-8` in the CI environment.
99
+ - **Sorted iteration.** Any test asserting on map / dict iteration order sorts first.
100
+ - **OS-assigned ports.** Never bind to a fixed port in tests — bind to `0` to get an OS-assigned port.
101
+ - **Test isolation.** Vitest `isolate: true` (default); Jest `--runInBand` only when needed for serialized DB tests.
60
102
 
61
103
  ## Flaky Test Handling
62
104
 
63
- - **Zero tolerance policy.** A flaky test erodes trust in the entire suite. Fix or quarantine within 48 hours of detection.
64
- - **Quarantine process:** Move the flaky test to a `tests/quarantine/` directory or tag with `.skip("FLAKY: #issue-number")`. Create a tracking issue immediately.
65
- - **Retry strategy in CI:** Allow a maximum of 1 automatic retry for the full test suite. Never retry individual tests silently — that masks flakiness.
66
- - **Root cause investigation:** Common causes are shared mutable state, timing dependencies (real clocks, `setTimeout`), port conflicts, uncontrolled randomness, and external service calls.
67
- - **Fix patterns:** Replace `setTimeout` with fake timers, replace shared state with per-test setup, replace port binding with dynamic ports, seed random generators deterministically.
68
- - **Flaky test metrics:** Track flaky test rate over time. Target < 0.5% flaky rate (flaky runs / total runs). Alert when rate exceeds 1%.
69
- - **Quarantine review:** Review quarantined tests weekly. Tests quarantined for more than 30 days must be either fixed or deleted with justification.
105
+ - **Detection.** CI retries failed tests once; tests failing on retry but passing on rerun are tagged `flake-suspected`.
106
+ - **Quarantine.** Any test that flakes twice in 7 days moves to `tests/quarantine/` (runs but does not block PRs). Issue auto-filed with the `flake` label.
107
+ - **SLA.** 14 days to root-cause and fix; otherwise the test is deleted. Quarantined tests reviewed weekly.
108
+ - **Retry policy.** Allow at most 1 automatic retry for the full test suite. Never silently retry individual tests that masks flakiness.
109
+ - **Categorization on intake.** Tag each flake by root cause: timing (use fake timers), network (use mocks / Testcontainers), ordering (sort assertions), pollution (test isolation), resource (cleanup).
110
+ - **Fix patterns.** Replace `setTimeout` with fake timers; replace shared state with per-test setup; replace fixed ports with OS-assigned (`0`); seed random generators deterministically.
111
+ - **Metrics.** Track flaky rate over time. Target < 0.5% (flaky runs / total runs). Alert at 1%.
112
+ - **Cost awareness.** Datadog 2026 telemetry reports 6–8 hrs/eng/week lost to flakes when quarantine + SLA is not enforced.
113
+
114
+ ## E2E Strategy
115
+
116
+ - **Playwright is the 2026 default** (95k stars, ~290 ms/action, native sharding via `--shard`). Use for cross-browser, accessibility (`@axe-core/playwright`), and visual regression (`toHaveScreenshot()`).
117
+ - Cypress requires paid Cloud for serious parallelization; WebdriverIO is the niche choice for web + mobile parity.
118
+ - Retry policy: `retries: 2` for transient infra; never `retries: >= 5` (masks bugs).
119
+
120
+ ## Snapshot Testing
121
+
122
+ - **Use sparingly.** 2–4 snapshots per component max. Appropriate for serialized output (JSON API responses, CLI output, rendered HTML structure) where the exact output matters and is stable.
123
+ - **Not appropriate for:** UI component visual appearance (use visual regression tests via `toHaveScreenshot()` or `jest-image-snapshot`), objects with timestamps or random IDs (unstable), large objects (unreadable diffs).
124
+ - **Review discipline.** Snapshot updates (`--update-snapshots`) must be reviewed with the same rigor as code changes. Reviewers verify the new snapshot is intentionally correct, not just "different."
125
+ - **Keep snapshots small.** Files > 100 lines suggest the test is asserting too broadly. Narrow the assertion to the relevant subset.
126
+ - **Inline snapshots** are preferred over external `.snap` files for short outputs (< 20 lines) — keeps the assertion co-located with the test.
127
+ - **Design-system components:** Storybook + Chromatic.
70
128
 
71
129
  ## Test Data Management
72
130
 
73
- - **Factories over fixtures.** Use factory functions (builder pattern) to generate test data with sensible defaults and per-test overrides. Factories produce valid objects by default; tests override only the fields relevant to the scenario.
74
- - **Builder pattern example:** `buildUser({ role: "admin" })` returns a full valid User with admin role and random but valid defaults for all other fields.
75
- - **No shared mutable fixtures.** If multiple tests read the same fixture data, each test must get its own copy. Use `structuredClone()` or factory functions.
76
- - **Realistic data.** Use faker or equivalent for generating realistic names, emails, dates. Avoid magic strings like `"test"`, `"foo"`, `"abc123"`.
77
- - **Deterministic seeding.** When using random data generators, seed them per test file so failures are reproducible.
78
- - **Fixture files** (JSON, YAML) are acceptable for large, complex, or externally-sourced test inputs (API response snapshots, configuration samples). Store in `tests/fixtures/`.
79
- - **Database state:** Integration tests that require database state must set up and tear down within the test using helpers. Never depend on database state from a previous test.
131
+ - **Factories over fixtures.** Use factory functions (factory-bot for Ruby, Fishery for TS, factory-boy for Python) seeded with Faker pinned to a fixed version.
132
+ - **Builder pattern example:** `buildUser({ role: "admin" })` returns a full valid `User` with admin role and valid defaults for all other fields.
133
+ - **No shared mutable fixtures.** If multiple tests read the same fixture data, each test gets its own copy via `structuredClone()` or a factory function.
134
+ - **Realistic data.** Avoid magic strings like `"test"`, `"foo"`, `"abc123"`.
135
+ - **Deterministic seeding.** Seed generators per test file so failures reproduce.
136
+ - **Fixture files** (JSON, YAML) are acceptable for large, complex, or externally-sourced inputs (API response snapshots, configuration samples). Store in `tests/fixtures/`.
137
+ - **Database state:** Integration tests set up and tear down within the test via helpers. Never depend on database state from a previous test. Enforce tenancy isolation via per-test schema or transaction rollback.
138
+ - **Testcontainers** pinned by image digest, not tag.
80
139
 
81
140
  ## Error Path Coverage
82
141
 
83
142
  Error handling code is often under-tested because developers focus on happy paths. Enforce minimum error coverage:
143
+ - **Every exported function that can fail** must have at least one test exercising the error path. "Can fail" includes functions returning `Result<T, E>`, functions with `throw` statements, async functions calling external services, and functions with input validation.
144
+ - **Error message assertions.** Verify that messages, codes, and structured fields contain the expected values. Do not assert only that "an error was thrown" — verify the error content.
145
+ - **Error propagation.** When a function wraps or transforms errors from a dependency, verify the original error context is preserved (cause chain, stack trace, original error code).
146
+ - **Boundary error tests.** For each architectural boundary (API handler, event handler, background processor), verify that errors are caught, logged, and returned as safe responses without leaking internal details.
84
147
 
85
- - **Every exported function that can fail** must have at least one test exercising the error path. "Can fail" includes: functions returning `Result<T, E>`, functions with `throw` statements, async functions calling external services, and functions with input validation.
86
- - **Error message assertions.** Test that error messages, codes, and structured fields contain the expected values. Do not assert only that "an error was thrown" -- verify the error content.
87
- - **Error propagation.** When a function wraps or transforms errors from a dependency, test that the original error context is preserved (cause chain, stack trace, original error code).
88
- - **Boundary error tests.** For each architectural boundary (API handler, event handler, background processor), test that errors are caught, logged, and returned as safe responses without leaking internal details.
148
+ ## Load Testing in CI
89
149
 
90
- ## Snapshot Testing
150
+ - **k6** (k6 Operator v1.0 for Kubernetes-distributed runs), **Vegeta** (constant-rate, no coordinated omission), **Locust** (Python), **Artillery** (TS).
151
+ - Baseline vs current diff in CI; SLO regression detection on p95, p99, and error-rate thresholds. Block the PR when a tracked SLO regresses.
152
+
153
+ ## Security Testing in CI
154
+
155
+ - **SAST:** Semgrep + CodeQL.
156
+ - **SCA / container / IaC / secrets:** Trivy (one-shot multi-scanner).
157
+ - **DAST:** OWASP ZAP or Nuclei against an ephemeral environment.
158
+
159
+ See `rules/hatch3r-container-hardening.md` and `rules/hatch3r-dependency-management.md` for the operational policy around hardening and pinning.
160
+
161
+ ## AI-Assisted Test Generation
162
+
163
+ - **Qodo 2.0** (60.1% F1 on reference benchmark) for TS / JS unit tests + edge cases.
164
+ - **Diffblue Cover** (symbolic, 20× cited productivity uplift on legacy code) for Java.
165
+
166
+ These are accelerators, not substitutes for the Per-Feature Mandate Map. Every generated test still goes through review and must map to a required test class for the code under test.
167
+
168
+ ## Per-Feature Mandate Map
169
+
170
+ Reviewers verify each PR satisfies the required test classes for the code class touched. A PR that adds a parser without a fuzz harness, or a payment path without mutation testing, fails review even if coverage is green.
171
+
172
+ | Code class | Required test classes |
173
+ |------------|----------------------|
174
+ | Parser / deserializer | unit + property + fuzz |
175
+ | Network handler / RPC entry | integration + contract + fuzz |
176
+ | Payment / billing logic | unit + property + mutation (≥ 80 score) |
177
+ | State machine | unit + property (with `RuleBasedStateMachine` analogue) |
178
+ | Pure function | unit + property |
179
+ | Service / RPC client | unit + contract (consumer side) |
180
+ | Service / RPC server | integration + contract (provider side) + Schemathesis |
181
+ | UI component | unit + visual regression + a11y (via `hatch3r-ui-ux-verify`) |
182
+ | LLM feature | eval (via `hatch3r-ai-feature`) + unit on adapter + integration on fallback chain |
183
+ | Background job | unit + integration with poison-message handling |
184
+
185
+ ## References
91
186
 
92
- - **Use sparingly.** Snapshots are appropriate for serialized output (JSON API responses, CLI output, rendered HTML structure) where the exact output matters and is stable.
93
- - **Not appropriate for:** UI component visual appearance (use visual regression tests), objects with timestamps or random IDs (unstable), large objects (unreadable diffs).
94
- - **Review discipline.** Snapshot updates (`--update-snapshots`) must be reviewed with the same rigor as code changes. Reviewers must verify the new snapshot is intentionally correct, not just "different."
95
- - **Keep snapshots small.** Snapshot files > 100 lines suggest the test is asserting too broadly. Narrow the assertion to the relevant subset.
96
- - **Inline snapshots** (where supported) are preferred over external `.snap` files for short outputs (< 20 lines) because they keep the assertion co-located with the test.
97
- - **Name snapshot files** to match their test file: `auth.test.ts` → `auth.test.ts.snap`.
187
+ - Stryker (mutation testing): https://stryker-mutator.io/
188
+ - fast-check (property-based testing, TS): https://fast-check.dev/
189
+ - Hypothesis (property-based testing, Python): https://hypothesis.readthedocs.io/
190
+ - proptest (property-based testing, Rust): https://github.com/proptest-rs/proptest
191
+ - Pact (consumer-driven contract testing): https://docs.pact.io/
192
+ - Schemathesis (OpenAPI provider testing): https://schemathesis.readthedocs.io/
193
+ - OWASP Web Security Testing Guide: https://owasp.org/www-project-web-security-testing-guide/
@@ -0,0 +1,149 @@
1
+ ---
2
+ id: hatch3r-ux-states-and-flows
3
+ type: rule
4
+ description: Four-state surface contract (loading/empty/error/partial), user-flow decomposition before implementation, and microcopy + tone discipline for end-user UIs
5
+ scope: "**/*.vue,**/*.jsx,**/*.tsx,**/*.svelte,**/components/**,**/*.html,**/messages/**,**/locales/**,**/copy/**"
6
+ tags: [ux, ui, frontend]
7
+ quality_charter: agents/shared/quality-charter.md
8
+ cache_friendly: true
9
+ ---
10
+ # UX States and Flows
11
+
12
+ ## User-Flow Decomposition (Mandatory Before Implementation)
13
+
14
+ Every user story produces three explicit flows before any UI code is written. Skipping this step is a regression — the implementer rejects specs lacking flow decomposition.
15
+
16
+ 1. **Happy Path** — numbered sequence of user actions paired with system responses and decision points covering the success route end-to-end. Includes entry point (route, prior screen, deep link), authentication state assumed, and exit point (resulting state, next screen).
17
+ 2. **Alternative Paths** — every documented branch (filters applied, multi-step forms, optional sections, permission tiers, locale variants). Each branch is numbered and references the decision point in the Happy Path where it diverges. Re-converges named.
18
+ 3. **Error-Recovery Path** — what the user does when a step fails (network drop, validation failure, expired session, permission denied, server outage, conflict on concurrent edit). Names the recovery action (retry, undo, refresh credential, contact support, drop changes) at every failure point.
19
+
20
+ Each flow is a numbered list with three columns: user action, system response, decision/branch. Reference `agents/modes/user-flows.md` for the canonical template. A flow is incomplete if any documented decision point has no specified branch outcome. The implementer treats acceptance criteria as a downstream artifact of the flow set — flows come first, criteria are derived.
21
+
22
+ Flow decomposition is also the contract between the feature designer and the reviewer: the reviewer walks every flow during code review and asserts each numbered step maps to a code path. A code path with no flow step is dead code or undocumented surface; a flow step with no code path is a missing implementation.
23
+
24
+ ## Four-State Surface Contract
25
+
26
+ Every async view renders all four states. Missing any state on an async view is a blocker — NN/g 2025 measured 92% of AI-generated dashboards omit empty state and 78% omit error state, so this is the regression bar to beat.
27
+
28
+ | State | Trigger | Rendering rules |
29
+ |-------|---------|-----------------|
30
+ | Loading | Request in flight >300ms | Skeleton matches final content dimensions (explicit width/height) to keep CLS <=0.1; spinner only for short modal actions <500ms; loading state announced via `aria-busy="true"` on the container |
31
+ | Empty | Successful response, 0 results | Distinguish three sub-types below: cold start, active filter, no permission. Each has a distinct heading, visual cue, and CTA |
32
+ | Error | Network failure, server error, validation failure | Plain-language cause + retry CTA + fallback or contact path; no "Oops" or "Something went wrong" — corrective verb required; render in `role="alert"` for assistive tech announcement |
33
+ | Partial | Some data succeeded, some failed | Banner naming the failed subset + degraded data rendered for the succeeded subset + retry option for the failed subset; never silently drop the failed subset |
34
+
35
+ State machines drive these transitions — model the view as `idle | loading | success | empty | error | partial` and assert every state has a render path in the component. Snapshot every state in tests (Storybook play function or vitest + Testing Library): missing snapshots are blockers.
36
+
37
+ Transitions between states have their own rules. Loading -> success swaps the skeleton for content without layout shift (the skeleton was already the final dimensions). Loading -> error replaces the skeleton with the error surface and announces it via `role="alert"`. Loading -> empty replaces the skeleton with the sub-typed empty surface (cold / filter / permission). Success -> partial overlays the banner without re-rendering the succeeded subset. Every transition has a measurable duration and an announcement strategy — never silent.
38
+
39
+ ## First-Run vs Filter vs Network — Content Structure
40
+
41
+ | State type | Heading level | Visual cue | CTA | Example |
42
+ |------------|---------------|------------|-----|---------|
43
+ | Cold start | h2 | Onboarding illustration | "Create your first <noun>" | "No <items> yet — create your first to begin" |
44
+ | Active filter | h3 inside results | Filter icon | "Clear filters" | "No results match these filters" |
45
+ | Network error | role=alert | Error icon | "Retry" + "Contact support" | "Couldn't load <items> — check your connection" |
46
+ | No permission | h3 | Lock icon | "Request access" | "You don't have access to <thing>" |
47
+
48
+ Cold start and active filter are not interchangeable — a first-run view directs the user to the onboarding action; an active-filter view offers "Clear filters" because the data exists behind the filter. Rendering "Clear filters" on a cold-start view is a usability defect (the button has no effect). Detect the sub-type from a state predicate (item count vs filter count vs auth scope), not from a single boolean.
49
+
50
+ Predicate ordering matters: check permission first (no-permission overrides everything), then filter state (active-filter overrides cold-start), then total count (cold-start when zero items exist anywhere). Inverting the order renders the wrong empty sub-type and the wrong CTA — a frequent source of "the button does nothing" bug reports.
51
+
52
+ ## Form UX
53
+
54
+ - Inline validation timing: validate on `blur`. After the first error on a field appears, re-validate on every keystroke with a 150ms debounce so the error tracks the user's correction in flight.
55
+ - Error recovery: clear the inline error immediately when the field becomes valid (no debounce on clear); re-enable the submit button in real time so the user sees recovery without re-tabbing.
56
+ - Error summary on submit: render at the top of the form with anchor links to each invalid field. Move focus to the summary heading (not to the first error field) so screen-reader users hear the count and list before being dropped into one field. Anchor link target is the input itself; the link text is the field label, not "Error 1".
57
+ - Required attributes per input: `autocomplete` (e.g., `email`, `tel`, `cc-number`, `one-time-code`), `inputmode` (e.g., `numeric`, `decimal`, `email`), `aria-describedby` pointing at the error or help text, and `aria-invalid="true"` when invalid. `enterkeyhint` on multi-step forms maps the soft-keyboard enter key to the next action.
58
+ - Never use a disabled submit button as the only error signal — users assume the page is broken. Allow submission and render validation outcome on submit. A submit attempt with invalid fields renders the summary, sets focus on it, and leaves the submit button operable for retry.
59
+ - Identifier-first auth: separate email and password screens; offer passkeys via WebAuthn Conditional UI (`autocomplete="username webauthn"`) so the OS surfaces the credential inline in autofill rather than behind a separate button. Passkey enrollment copy states the user-visible benefit in one sentence ("Sign in with your fingerprint — no password to remember").
60
+ - Positive confirmation for non-trivial fields (email, password strength, username availability): when valid, render an inline check or short affirmation. Pair with a screen-reader-only `aria-live="polite"` announcement.
61
+ - Multi-step forms render a step indicator with current step, total steps, and per-step labels. Each step is a separate `<form>` with its own validation and submit; never collect all fields on one screen behind tabs. Browser back button maps to previous step without data loss.
62
+ - Autosave drafts where the user expects persistence (long-form composition, settings panels). Surface autosave state with a passive indicator ("Saved 2s ago" or "Saving..."), never with a blocking modal.
63
+
64
+ ## Error-Recovery Patterns
65
+
66
+ - Retry button retries the same operation with the same input. Disable for 1s after click to avoid duplicate submits; re-enable on completion.
67
+ - Fallback offers an alternative path when retry will not help: cached view, contact support, alternate route. Render fallback below retry, not above.
68
+ - Undo for reversible mutations: surface a toast with the undo action and a >=10-second timeout. Persist the undo action across screen navigations until the timeout fires or the user confirms.
69
+ - Conflict on concurrent edit: surface a diff with three options (keep mine, keep theirs, merge); never overwrite silently.
70
+ - Session expiration: re-auth inline (modal or banner with credential field), preserving the user's in-flight data. Forced re-auth that drops form data is a defect.
71
+
72
+ ## Microcopy and Tone
73
+
74
+ Anchored to GOV.UK Design System (error pattern, plain English) and IBM Carbon (voice + tone).
75
+
76
+ - Plain language; second person; corrective verb on every error string ("Enter your email address", not "Email is required"). The verb names the action the user takes to recover.
77
+ - No jargon visible to end users: never expose "FIDO2", "WebAuthn", "HTTP 500", "null", "undefined", "401". Translate the implementation detail to the action the user can take. Implementation labels live in logs and error reports, not in UI strings.
78
+ - CTA labels are action-oriented and specific: "Save changes", "Create account", "Delete project" — not "Submit", "OK", "Confirm". Destructive verbs name the object: "Delete project Foo permanently".
79
+ - Error tone explains cause and offers recovery; never blame the user. "We couldn't save your changes — try again." not "You did something wrong." Distinguish system-fault from user-fault wording — for user-fault, name the field; for system-fault, use first-person plural ("we couldn't").
80
+ - ICU MessageFormat for every translatable string. Never concatenate strings to build sentences — singular, plural, and gender variants all live in one message ID with explicit categories. Translator memory stays stable across releases when keys are stable; rename keys is a breaking change.
81
+ - Cross-reference `rules/hatch3r-i18n.md` for translation mechanics and the Microcopy & Tone subsection that defines voice consistency across locales. Reserve 30-40% extra width in layouts for languages like DE and FI.
82
+ - Treat AI as a copy assistant, not author — AI generates tone variants and the human approves final voice strings. Brand voice strings are owned by a named maintainer, not by a model.
83
+ - Forbidden filler in any user-visible string: "Oops", "Whoops", "Something went wrong", "An unexpected error occurred". Lint these via a string-scan check in CI against the locale files. Replacements name the failure and the action — "Couldn't load <items>. Check your connection and retry."
84
+ - Empty-state copy follows the same plain-language rule: name what is absent and the action to fill it. "No drafts yet — start writing." beats "You have no drafts." because the action is in the same sentence.
85
+ - Truncation strategy: never mid-word in single-line truncations; use `text-overflow: ellipsis` with a tooltip or expand affordance for the full string. Multi-line truncation uses `-webkit-line-clamp` with a "Read more" affordance below.
86
+ - Time and date formatting: respect the user's locale via `Intl.DateTimeFormat`; never hard-code "MM/DD/YYYY" or "12:34 PM" in UI strings. Relative time ("3 minutes ago") for recent events; absolute for events >24h old.
87
+ - Numbers and units follow the locale's separator and grouping. Currency renders the user-selected currency, not the merchant's default. Round to the precision the user can act on — financial transactions to two decimals, weights to one.
88
+
89
+ ## Perceived Performance
90
+
91
+ - Skeleton show threshold: 300ms first-content latency. Below 300ms render the final view directly; above 300ms render skeleton first to avoid spinner flash. Implement via a delayed `setTimeout(showSkeleton, 300)` cleared on early response.
92
+ - Skeleton matches final content dimensions (explicit `width`, `height`, or `aspect-ratio`) so the layout does not shift when real content arrives — CLS <=0.1 baseline. Test by measuring CLS on the route under a throttled network profile (Slow 4G or 4x CPU).
93
+ - Optimistic UI for safe mutations (add to list, mark done, toggle like): apply the change in local state immediately and reconcile on server response. On reject, roll back the local state AND surface a non-blocking toast with retry. Use `useOptimistic` in React or framework equivalent.
94
+ - Pessimistic UI for destructive or financial actions (delete, payment, irreversible state change): wait for server confirmation before reflecting the change. Surface a progress indicator on the action itself, not on the page.
95
+ - Stale-while-revalidate for non-critical data: render the cached value immediately, refresh in the background, surface a non-blocking "Refresh available" affordance when the fresh value differs from the cached value. Never overwrite the rendered view silently — the user is mid-task on the stale data.
96
+ - 2026 Core Web Vitals gates at p75 of real-user data: LCP <=2.5s, INP <=200ms, CLS <=0.1. These are gating, not aspirational. Break long tasks (>50ms) with `scheduler.yield()` or `requestIdleCallback` to keep INP within budget.
97
+ - Streaming UI for long-running AI or tool responses: render tokens as they arrive without re-parsing the full buffer per chunk. Show a typing indicator only while no token has arrived; switch to streamed content on first delta. Provide cancel/abort at every streamed surface.
98
+ - Loading copy names the phase when total work is knowable ("Uploading 3 of 7..."), or names the activity when not ("Encoding..."). Generic "Loading..." is the fallback for sub-300ms cases that escape the skeleton threshold.
99
+
100
+ ## Streaming and Long-Running Operations
101
+
102
+ - Streaming text (AI responses, log tails, real-time data) renders incrementally. First-token latency target <=500ms; render the typing indicator only until first token, then switch to streamed content.
103
+ - Tool calls and side-effectful operations render as collapsible structured cards with status (pending, running, done, failed), arguments summary, duration, result preview. Hidden tool calls are a trust regression.
104
+ - Human-in-the-loop approval required for any side-effectful tool (write, send, pay, deploy). Default approval mode is opt-in; auto-accept lives behind an explicit setting with named scope and one-click revocation.
105
+ - Cancel/abort available at every long-running call. Abort triggers cleanup (rollback partial state, close streams, release locks). Show the user the post-abort state — never leave the UI in a "Cancelling..." limbo.
106
+ - Citation rendering for retrieval-grounded claims: inline link to the source span. Spans the model cannot ground from retrieved evidence are flagged visibly, not silently emitted.
107
+
108
+ ## Mobile and Touch
109
+
110
+ - Touch target minimum: 44pt on iOS HIG, 48dp on Material 3. The platform minimum supersedes WCAG SC 2.5.8 (24x24 CSS px) on touch surfaces — use the stricter bound.
111
+ - Spacing between adjacent interactive elements: >=8px to avoid mis-taps. Measure on the rendered DOM, not on the design comp — padding and margins count toward hit area only when they belong to the same interactive element.
112
+ - Avoid tap-to-reveal (hover-only tooltip) on touch surfaces. Use permanent labels or long-press with a visible affordance. Hover-only tooltips fail WCAG SC 1.4.13 Content on Hover or Focus on touch.
113
+ - Apply `env(safe-area-inset-*)` on full-bleed surfaces so primary CTAs do not sit under the iOS home indicator, notch, or Android gesture nav. Native equivalents: `safeAreaInsets` on iOS, `WindowInsets` on Android.
114
+ - Dynamic Type on iOS (`UIFont.preferredFont(forTextStyle:)` or SwiftUI `Font.body`) and rem-based font scaling on Android/web. Never use hard-coded `px` for text — fails text-resize verification at 200% zoom (WCAG SC 1.4.4) and 400% reflow (SC 1.4.10).
115
+ - Drag-only gestures (range slider, kanban reorder, swipe-to-delete) require a non-drag alternative per WCAG SC 2.5.7 — keyboard arrows, click-to-place, explicit "Delete" button.
116
+ - Pointer-event vs touch-event: prefer pointer events (`pointerdown`, `pointermove`, `pointerup`) so the same handler covers mouse, touch, pen. Synthesize click events on tap with a 300ms tolerance only on legacy mobile browsers — modern engines emit click immediately.
117
+ - Pinch-zoom: never disable user zoom on the viewport meta tag. WCAG SC 1.4.4 fails on disabled zoom. Use `maximum-scale=5` to allow up to 5x zoom while suppressing zoom-on-focus jitter.
118
+ - Orientation lock: respect WCAG SC 1.3.4 — content adapts to portrait and landscape unless an essential exception applies (e.g., piano keyboard, blueprint editor). Document the exception in the spec.
119
+
120
+ ## Heuristic Verification Gate
121
+
122
+ Run every check below before declaring a feature done. A "done" claim without these checks is not done.
123
+
124
+ - Nielsen 10 heuristics 5-minute walkthrough by a reviewer on the key user flow. Flag any heuristic violation (visibility of status, match to real world, user control, consistency, error prevention, recognition over recall, flexibility, minimalist design, error recovery, help/documentation); resolve before ship.
125
+ - Keyboard-only run through the flow (no mouse, no touch). Every step reachable, every focus state visible (>=2px outline at >=3:1 contrast), no traps, no off-screen focus.
126
+ - Screen-reader smoke test on the key route — one human pass per release using VoiceOver (macOS/iOS) or NVDA (Windows). Document the trace: which landmarks announced, which form labels heard, which dynamic updates registered.
127
+ - First-time-user walkthrough for P0 features: measure task-completion time and observe error recovery. Note where the user paused, backtracked, or asked for help. Three observed users per P0 feature minimum.
128
+ - State-coverage check: snapshot every async view in each of {loading, empty, error, partial, success} via Storybook play or component tests. Missing snapshots block the gate.
129
+ - Microcopy lint: a CI string-scan rejects banned filler ("Oops", "Whoops", "Something went wrong") in any locale file; rejects `disabled` on submit buttons without an accompanying error-state announcement; flags strings without a corrective verb on error keys (`error.*`, `validation.*`).
130
+ - Reduced-motion pass: toggle `prefers-reduced-motion: reduce` on the route and verify all non-essential transitions are removed; essential loaders simplify rather than disable.
131
+ - Reflow pass: zoom the route to 200% and 400% in a 1280x1024 viewport — no horizontal scroll, no clipped content, no overlapping interactive elements.
132
+
133
+ ## References
134
+
135
+ - WCAG 2.2 AA — new success criteria SC 2.5.8 (Target Size), SC 2.4.11 (Focus Not Obscured), SC 2.5.7 (Dragging Movements), SC 1.4.13 (Content on Hover or Focus)
136
+ - NN/g state-omission research 2025 — empty-state and error-state omission rates in AI-generated UIs (92% empty omitted, 78% error omitted)
137
+ - GOV.UK Design System — error message and error summary components, plain English readability guidance
138
+ - IBM Carbon Design System — voice and tone content guidelines, error message patterns
139
+ - Baymard Institute — inline form validation research and disabled-submit findings (top-10 form-abandonment driver)
140
+ - Google Core Web Vitals 2026 thresholds — LCP, INP, CLS at p75 real-user data
141
+ - Nielsen Norman Group — 10 usability heuristics for user interface design
142
+ - Mailchimp Content Style Guide — voice and tone baseline, clarity over cleverness
143
+ - Apple Human Interface Guidelines — Dynamic Type, safe area, touch target sizing
144
+ - Material 3 Design System — touch target sizing (48dp), state layers, ripple feedback
145
+ - W3C WAI-ARIA Authoring Practices — accessible widget patterns, live regions, focus management
146
+ - FIDO Alliance / Passkey Central — WebAuthn Conditional UI design guidelines for passwordless auth
147
+ - Vercel AI Elements — streaming message component patterns for AI chat surfaces
148
+ - Anthropic engineering blog — agent UI patterns, human-in-the-loop approval, tool-call transparency
149
+ - OpenAI Apps SDK UI guidelines — citation rendering, tool-result presentation
@@ -0,0 +1,145 @@
1
+ ---
2
+ description: Four-state surface contract (loading/empty/error/partial), user-flow decomposition before implementation, and microcopy + tone discipline for end-user UIs
3
+ globs: ["**/*.vue", "**/*.jsx", "**/*.tsx", "**/*.svelte", "**/components/**", "**/*.html", "**/messages/**", "**/locales/**", "**/copy/**"]
4
+ alwaysApply: false
5
+ ---
6
+ # UX States and Flows
7
+
8
+ ## User-Flow Decomposition (Mandatory Before Implementation)
9
+
10
+ Every user story produces three explicit flows before any UI code is written. Skipping this step is a regression — the implementer rejects specs lacking flow decomposition.
11
+
12
+ 1. **Happy Path** — numbered sequence of user actions paired with system responses and decision points covering the success route end-to-end. Includes entry point (route, prior screen, deep link), authentication state assumed, and exit point (resulting state, next screen).
13
+ 2. **Alternative Paths** — every documented branch (filters applied, multi-step forms, optional sections, permission tiers, locale variants). Each branch is numbered and references the decision point in the Happy Path where it diverges. Re-converges named.
14
+ 3. **Error-Recovery Path** — what the user does when a step fails (network drop, validation failure, expired session, permission denied, server outage, conflict on concurrent edit). Names the recovery action (retry, undo, refresh credential, contact support, drop changes) at every failure point.
15
+
16
+ Each flow is a numbered list with three columns: user action, system response, decision/branch. Reference `agents/modes/user-flows.md` for the canonical template. A flow is incomplete if any documented decision point has no specified branch outcome. The implementer treats acceptance criteria as a downstream artifact of the flow set — flows come first, criteria are derived.
17
+
18
+ Flow decomposition is also the contract between the feature designer and the reviewer: the reviewer walks every flow during code review and asserts each numbered step maps to a code path. A code path with no flow step is dead code or undocumented surface; a flow step with no code path is a missing implementation.
19
+
20
+ ## Four-State Surface Contract
21
+
22
+ Every async view renders all four states. Missing any state on an async view is a blocker — NN/g 2025 measured 92% of AI-generated dashboards omit empty state and 78% omit error state, so this is the regression bar to beat.
23
+
24
+ | State | Trigger | Rendering rules |
25
+ |-------|---------|-----------------|
26
+ | Loading | Request in flight >300ms | Skeleton matches final content dimensions (explicit width/height) to keep CLS <=0.1; spinner only for short modal actions <500ms; loading state announced via `aria-busy="true"` on the container |
27
+ | Empty | Successful response, 0 results | Distinguish three sub-types below: cold start, active filter, no permission. Each has a distinct heading, visual cue, and CTA |
28
+ | Error | Network failure, server error, validation failure | Plain-language cause + retry CTA + fallback or contact path; no "Oops" or "Something went wrong" — corrective verb required; render in `role="alert"` for assistive tech announcement |
29
+ | Partial | Some data succeeded, some failed | Banner naming the failed subset + degraded data rendered for the succeeded subset + retry option for the failed subset; never silently drop the failed subset |
30
+
31
+ State machines drive these transitions — model the view as `idle | loading | success | empty | error | partial` and assert every state has a render path in the component. Snapshot every state in tests (Storybook play function or vitest + Testing Library): missing snapshots are blockers.
32
+
33
+ Transitions between states have their own rules. Loading -> success swaps the skeleton for content without layout shift (the skeleton was already the final dimensions). Loading -> error replaces the skeleton with the error surface and announces it via `role="alert"`. Loading -> empty replaces the skeleton with the sub-typed empty surface (cold / filter / permission). Success -> partial overlays the banner without re-rendering the succeeded subset. Every transition has a measurable duration and an announcement strategy — never silent.
34
+
35
+ ## First-Run vs Filter vs Network — Content Structure
36
+
37
+ | State type | Heading level | Visual cue | CTA | Example |
38
+ |------------|---------------|------------|-----|---------|
39
+ | Cold start | h2 | Onboarding illustration | "Create your first <noun>" | "No <items> yet — create your first to begin" |
40
+ | Active filter | h3 inside results | Filter icon | "Clear filters" | "No results match these filters" |
41
+ | Network error | role=alert | Error icon | "Retry" + "Contact support" | "Couldn't load <items> — check your connection" |
42
+ | No permission | h3 | Lock icon | "Request access" | "You don't have access to <thing>" |
43
+
44
+ Cold start and active filter are not interchangeable — a first-run view directs the user to the onboarding action; an active-filter view offers "Clear filters" because the data exists behind the filter. Rendering "Clear filters" on a cold-start view is a usability defect (the button has no effect). Detect the sub-type from a state predicate (item count vs filter count vs auth scope), not from a single boolean.
45
+
46
+ Predicate ordering matters: check permission first (no-permission overrides everything), then filter state (active-filter overrides cold-start), then total count (cold-start when zero items exist anywhere). Inverting the order renders the wrong empty sub-type and the wrong CTA — a frequent source of "the button does nothing" bug reports.
47
+
48
+ ## Form UX
49
+
50
+ - Inline validation timing: validate on `blur`. After the first error on a field appears, re-validate on every keystroke with a 150ms debounce so the error tracks the user's correction in flight.
51
+ - Error recovery: clear the inline error immediately when the field becomes valid (no debounce on clear); re-enable the submit button in real time so the user sees recovery without re-tabbing.
52
+ - Error summary on submit: render at the top of the form with anchor links to each invalid field. Move focus to the summary heading (not to the first error field) so screen-reader users hear the count and list before being dropped into one field. Anchor link target is the input itself; the link text is the field label, not "Error 1".
53
+ - Required attributes per input: `autocomplete` (e.g., `email`, `tel`, `cc-number`, `one-time-code`), `inputmode` (e.g., `numeric`, `decimal`, `email`), `aria-describedby` pointing at the error or help text, and `aria-invalid="true"` when invalid. `enterkeyhint` on multi-step forms maps the soft-keyboard enter key to the next action.
54
+ - Never use a disabled submit button as the only error signal — users assume the page is broken. Allow submission and render validation outcome on submit. A submit attempt with invalid fields renders the summary, sets focus on it, and leaves the submit button operable for retry.
55
+ - Identifier-first auth: separate email and password screens; offer passkeys via WebAuthn Conditional UI (`autocomplete="username webauthn"`) so the OS surfaces the credential inline in autofill rather than behind a separate button. Passkey enrollment copy states the user-visible benefit in one sentence ("Sign in with your fingerprint — no password to remember").
56
+ - Positive confirmation for non-trivial fields (email, password strength, username availability): when valid, render an inline check or short affirmation. Pair with a screen-reader-only `aria-live="polite"` announcement.
57
+ - Multi-step forms render a step indicator with current step, total steps, and per-step labels. Each step is a separate `<form>` with its own validation and submit; never collect all fields on one screen behind tabs. Browser back button maps to previous step without data loss.
58
+ - Autosave drafts where the user expects persistence (long-form composition, settings panels). Surface autosave state with a passive indicator ("Saved 2s ago" or "Saving..."), never with a blocking modal.
59
+
60
+ ## Error-Recovery Patterns
61
+
62
+ - Retry button retries the same operation with the same input. Disable for 1s after click to avoid duplicate submits; re-enable on completion.
63
+ - Fallback offers an alternative path when retry will not help: cached view, contact support, alternate route. Render fallback below retry, not above.
64
+ - Undo for reversible mutations: surface a toast with the undo action and a >=10-second timeout. Persist the undo action across screen navigations until the timeout fires or the user confirms.
65
+ - Conflict on concurrent edit: surface a diff with three options (keep mine, keep theirs, merge); never overwrite silently.
66
+ - Session expiration: re-auth inline (modal or banner with credential field), preserving the user's in-flight data. Forced re-auth that drops form data is a defect.
67
+
68
+ ## Microcopy and Tone
69
+
70
+ Anchored to GOV.UK Design System (error pattern, plain English) and IBM Carbon (voice + tone).
71
+
72
+ - Plain language; second person; corrective verb on every error string ("Enter your email address", not "Email is required"). The verb names the action the user takes to recover.
73
+ - No jargon visible to end users: never expose "FIDO2", "WebAuthn", "HTTP 500", "null", "undefined", "401". Translate the implementation detail to the action the user can take. Implementation labels live in logs and error reports, not in UI strings.
74
+ - CTA labels are action-oriented and specific: "Save changes", "Create account", "Delete project" — not "Submit", "OK", "Confirm". Destructive verbs name the object: "Delete project Foo permanently".
75
+ - Error tone explains cause and offers recovery; never blame the user. "We couldn't save your changes — try again." not "You did something wrong." Distinguish system-fault from user-fault wording — for user-fault, name the field; for system-fault, use first-person plural ("we couldn't").
76
+ - ICU MessageFormat for every translatable string. Never concatenate strings to build sentences — singular, plural, and gender variants all live in one message ID with explicit categories. Translator memory stays stable across releases when keys are stable; rename keys is a breaking change.
77
+ - Cross-reference `rules/hatch3r-i18n.md` for translation mechanics and the Microcopy & Tone subsection that defines voice consistency across locales. Reserve 30-40% extra width in layouts for languages like DE and FI.
78
+ - Treat AI as a copy assistant, not author — AI generates tone variants and the human approves final voice strings. Brand voice strings are owned by a named maintainer, not by a model.
79
+ - Forbidden filler in any user-visible string: "Oops", "Whoops", "Something went wrong", "An unexpected error occurred". Lint these via a string-scan check in CI against the locale files. Replacements name the failure and the action — "Couldn't load <items>. Check your connection and retry."
80
+ - Empty-state copy follows the same plain-language rule: name what is absent and the action to fill it. "No drafts yet — start writing." beats "You have no drafts." because the action is in the same sentence.
81
+ - Truncation strategy: never mid-word in single-line truncations; use `text-overflow: ellipsis` with a tooltip or expand affordance for the full string. Multi-line truncation uses `-webkit-line-clamp` with a "Read more" affordance below.
82
+ - Time and date formatting: respect the user's locale via `Intl.DateTimeFormat`; never hard-code "MM/DD/YYYY" or "12:34 PM" in UI strings. Relative time ("3 minutes ago") for recent events; absolute for events >24h old.
83
+ - Numbers and units follow the locale's separator and grouping. Currency renders the user-selected currency, not the merchant's default. Round to the precision the user can act on — financial transactions to two decimals, weights to one.
84
+
85
+ ## Perceived Performance
86
+
87
+ - Skeleton show threshold: 300ms first-content latency. Below 300ms render the final view directly; above 300ms render skeleton first to avoid spinner flash. Implement via a delayed `setTimeout(showSkeleton, 300)` cleared on early response.
88
+ - Skeleton matches final content dimensions (explicit `width`, `height`, or `aspect-ratio`) so the layout does not shift when real content arrives — CLS <=0.1 baseline. Test by measuring CLS on the route under a throttled network profile (Slow 4G or 4x CPU).
89
+ - Optimistic UI for safe mutations (add to list, mark done, toggle like): apply the change in local state immediately and reconcile on server response. On reject, roll back the local state AND surface a non-blocking toast with retry. Use `useOptimistic` in React or framework equivalent.
90
+ - Pessimistic UI for destructive or financial actions (delete, payment, irreversible state change): wait for server confirmation before reflecting the change. Surface a progress indicator on the action itself, not on the page.
91
+ - Stale-while-revalidate for non-critical data: render the cached value immediately, refresh in the background, surface a non-blocking "Refresh available" affordance when the fresh value differs from the cached value. Never overwrite the rendered view silently — the user is mid-task on the stale data.
92
+ - 2026 Core Web Vitals gates at p75 of real-user data: LCP <=2.5s, INP <=200ms, CLS <=0.1. These are gating, not aspirational. Break long tasks (>50ms) with `scheduler.yield()` or `requestIdleCallback` to keep INP within budget.
93
+ - Streaming UI for long-running AI or tool responses: render tokens as they arrive without re-parsing the full buffer per chunk. Show a typing indicator only while no token has arrived; switch to streamed content on first delta. Provide cancel/abort at every streamed surface.
94
+ - Loading copy names the phase when total work is knowable ("Uploading 3 of 7..."), or names the activity when not ("Encoding..."). Generic "Loading..." is the fallback for sub-300ms cases that escape the skeleton threshold.
95
+
96
+ ## Streaming and Long-Running Operations
97
+
98
+ - Streaming text (AI responses, log tails, real-time data) renders incrementally. First-token latency target <=500ms; render the typing indicator only until first token, then switch to streamed content.
99
+ - Tool calls and side-effectful operations render as collapsible structured cards with status (pending, running, done, failed), arguments summary, duration, result preview. Hidden tool calls are a trust regression.
100
+ - Human-in-the-loop approval required for any side-effectful tool (write, send, pay, deploy). Default approval mode is opt-in; auto-accept lives behind an explicit setting with named scope and one-click revocation.
101
+ - Cancel/abort available at every long-running call. Abort triggers cleanup (rollback partial state, close streams, release locks). Show the user the post-abort state — never leave the UI in a "Cancelling..." limbo.
102
+ - Citation rendering for retrieval-grounded claims: inline link to the source span. Spans the model cannot ground from retrieved evidence are flagged visibly, not silently emitted.
103
+
104
+ ## Mobile and Touch
105
+
106
+ - Touch target minimum: 44pt on iOS HIG, 48dp on Material 3. The platform minimum supersedes WCAG SC 2.5.8 (24x24 CSS px) on touch surfaces — use the stricter bound.
107
+ - Spacing between adjacent interactive elements: >=8px to avoid mis-taps. Measure on the rendered DOM, not on the design comp — padding and margins count toward hit area only when they belong to the same interactive element.
108
+ - Avoid tap-to-reveal (hover-only tooltip) on touch surfaces. Use permanent labels or long-press with a visible affordance. Hover-only tooltips fail WCAG SC 1.4.13 Content on Hover or Focus on touch.
109
+ - Apply `env(safe-area-inset-*)` on full-bleed surfaces so primary CTAs do not sit under the iOS home indicator, notch, or Android gesture nav. Native equivalents: `safeAreaInsets` on iOS, `WindowInsets` on Android.
110
+ - Dynamic Type on iOS (`UIFont.preferredFont(forTextStyle:)` or SwiftUI `Font.body`) and rem-based font scaling on Android/web. Never use hard-coded `px` for text — fails text-resize verification at 200% zoom (WCAG SC 1.4.4) and 400% reflow (SC 1.4.10).
111
+ - Drag-only gestures (range slider, kanban reorder, swipe-to-delete) require a non-drag alternative per WCAG SC 2.5.7 — keyboard arrows, click-to-place, explicit "Delete" button.
112
+ - Pointer-event vs touch-event: prefer pointer events (`pointerdown`, `pointermove`, `pointerup`) so the same handler covers mouse, touch, pen. Synthesize click events on tap with a 300ms tolerance only on legacy mobile browsers — modern engines emit click immediately.
113
+ - Pinch-zoom: never disable user zoom on the viewport meta tag. WCAG SC 1.4.4 fails on disabled zoom. Use `maximum-scale=5` to allow up to 5x zoom while suppressing zoom-on-focus jitter.
114
+ - Orientation lock: respect WCAG SC 1.3.4 — content adapts to portrait and landscape unless an essential exception applies (e.g., piano keyboard, blueprint editor). Document the exception in the spec.
115
+
116
+ ## Heuristic Verification Gate
117
+
118
+ Run every check below before declaring a feature done. A "done" claim without these checks is not done.
119
+
120
+ - Nielsen 10 heuristics 5-minute walkthrough by a reviewer on the key user flow. Flag any heuristic violation (visibility of status, match to real world, user control, consistency, error prevention, recognition over recall, flexibility, minimalist design, error recovery, help/documentation); resolve before ship.
121
+ - Keyboard-only run through the flow (no mouse, no touch). Every step reachable, every focus state visible (>=2px outline at >=3:1 contrast), no traps, no off-screen focus.
122
+ - Screen-reader smoke test on the key route — one human pass per release using VoiceOver (macOS/iOS) or NVDA (Windows). Document the trace: which landmarks announced, which form labels heard, which dynamic updates registered.
123
+ - First-time-user walkthrough for P0 features: measure task-completion time and observe error recovery. Note where the user paused, backtracked, or asked for help. Three observed users per P0 feature minimum.
124
+ - State-coverage check: snapshot every async view in each of {loading, empty, error, partial, success} via Storybook play or component tests. Missing snapshots block the gate.
125
+ - Microcopy lint: a CI string-scan rejects banned filler ("Oops", "Whoops", "Something went wrong") in any locale file; rejects `disabled` on submit buttons without an accompanying error-state announcement; flags strings without a corrective verb on error keys (`error.*`, `validation.*`).
126
+ - Reduced-motion pass: toggle `prefers-reduced-motion: reduce` on the route and verify all non-essential transitions are removed; essential loaders simplify rather than disable.
127
+ - Reflow pass: zoom the route to 200% and 400% in a 1280x1024 viewport — no horizontal scroll, no clipped content, no overlapping interactive elements.
128
+
129
+ ## References
130
+
131
+ - WCAG 2.2 AA — new success criteria SC 2.5.8 (Target Size), SC 2.4.11 (Focus Not Obscured), SC 2.5.7 (Dragging Movements), SC 1.4.13 (Content on Hover or Focus)
132
+ - NN/g state-omission research 2025 — empty-state and error-state omission rates in AI-generated UIs (92% empty omitted, 78% error omitted)
133
+ - GOV.UK Design System — error message and error summary components, plain English readability guidance
134
+ - IBM Carbon Design System — voice and tone content guidelines, error message patterns
135
+ - Baymard Institute — inline form validation research and disabled-submit findings (top-10 form-abandonment driver)
136
+ - Google Core Web Vitals 2026 thresholds — LCP, INP, CLS at p75 real-user data
137
+ - Nielsen Norman Group — 10 usability heuristics for user interface design
138
+ - Mailchimp Content Style Guide — voice and tone baseline, clarity over cleverness
139
+ - Apple Human Interface Guidelines — Dynamic Type, safe area, touch target sizing
140
+ - Material 3 Design System — touch target sizing (48dp), state layers, ripple feedback
141
+ - W3C WAI-ARIA Authoring Practices — accessible widget patterns, live regions, focus management
142
+ - FIDO Alliance / Passkey Central — WebAuthn Conditional UI design guidelines for passwordless auth
143
+ - Vercel AI Elements — streaming message component patterns for AI chat surfaces
144
+ - Anthropic engineering blog — agent UI patterns, human-in-the-loop approval, tool-call transparency
145
+ - OpenAI Apps SDK UI guidelines — citation rendering, tool-result presentation
@@ -12,6 +12,7 @@ cache_friendly: true
12
12
 
13
13
  ```
14
14
  Task Progress:
15
+ - [ ] Step 0: Detect ambiguity (P8 B1)
15
16
  - [ ] Step 1: Read accessibility requirements from rules and specs
16
17
  - [ ] Step 2: Automated scan — run axe-core or similar on all pages/components
17
18
  - [ ] Step 3: Manual audit — load references/manual-audit-checklist.md
@@ -20,6 +21,19 @@ Task Progress:
20
21
  - [ ] Step 6: Verify fixes with re-scan and manual check
21
22
  ```
22
23
 
24
+ ## Step 0 — Detect Ambiguity (P8 B1)
25
+
26
+ Before any work, scan the invocation for unresolved questions in scope, intent, acceptance criteria, target environment, or irreversibility. If any are found, ask the user via the platform-native question tool per `agents/shared/user-question-protocol.md`. Do not proceed under silent assumption. Default path, not an exception. Triggers for THIS skill: WCAG conformance target (A vs AA vs AAA), scope (single component vs full app), surfaces to audit (which routes), fix authority (audit-only vs audit-and-fix), and screen-reader pass scope (per release vs per audit).
27
+
28
+ ## Fan-out Discipline (P8 B2)
29
+
30
+ This skill delegates per task size:
31
+ - Tier 1 (trivial single-file): inline execution acceptable.
32
+ - Tier 2 (multi-file or multi-concern): spawn parallel sub-agents per concern via the Task tool.
33
+ - Tier 3 (multi-module / high-risk): one fresh sub-agent per independent module or gate; orchestrator integrates only.
34
+
35
+ Never under-fan-out to save tokens. Token cost is dominated by quality and completeness gains. Emit `sub_agents_spawned: { count, rationale }` in your output.
36
+
23
37
  ## Progressive Disclosure
24
38
 
25
39
  - **Main skill file (this):** Workflow steps, automated scan, fix process, DoD.