diff options
| author | Christian Cleberg <[email protected]> | 2026-07-22 01:01:05 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-07-22 15:04:32 -0500 |
| commit | dd41ed2c51beae07288fdfa724e410e0d321d278 (patch) | |
| tree | 6d443925e7d7a323e726999e244fc269b0fb2ef0 /Docs | |
| parent | 7f917e98b929dcf0f7901d0bc4eb05e04db3aa0c (diff) | |
| download | domain-dig-dd41ed2c51beae07288fdfa724e410e0d321d278.tar.gz domain-dig-dd41ed2c51beae07288fdfa724e410e0d321d278.tar.bz2 domain-dig-dd41ed2c51beae07288fdfa724e410e0d321d278.zip | |
feat(a11y): engage the audit enforcement ratchet (#21)
The point of the Phase 0 harness finally lands: named findings in
textClipped, dynamicType, hitRegion, elementDetection,
sufficientElementDescription, and trait now FAIL the build on the
empty-state suite. Regressions in five phases of accessibility work are
gated, not narrated.
Three carve-outs, each earned by evidence rather than convenience:
- contrast stays report-only. The two long-standing Settings findings are
rows scrolled under the translucent tab bar, and their attribution
flips between a row name and nil run-to-run — no suppression is narrow
enough to keep CI stable. The centralised palette is the real guard.
- The seeded dense-row tests run reportOnly. Bisection showed the audit
degrades on children-ignored content — the correct VoiceOver treatment
for dense rows — emitting unattributed contrast/dynamicType failures on
rows that measure 6-7:1 and render correctly.
- Characterised noise is suppressed narrowly and always logged as
[noise: reason]: disabled controls (WCAG 1.4.3 exempt), "nearly passed"
near-misses, system field placeholders (flagged at any length — proven
by shortening them to no effect), and unattributed clipped/dynamic-type
artifacts. noiseReason(for:) records each rule's provenance inline.
Validated in both directions. Positive: the full 11-test suite passes
with enforcement live, dark and light, on an erased simulator. Negative:
re-injecting the Phase 3 icon-exposure regression produced two named
[FAIL] findings and a failed suite — on both screens sharing the
component — then went green again on revert.
Docs and the CI workflow comment updated to describe the engaged state.
Diffstat (limited to 'Docs')
| -rw-r--r-- | Docs/ACCESSIBILITY.md | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/Docs/ACCESSIBILITY.md b/Docs/ACCESSIBILITY.md index b35f02c..3f8b3ba 100644 --- a/Docs/ACCESSIBILITY.md +++ b/Docs/ACCESSIBILITY.md @@ -110,27 +110,38 @@ Users override it under Settings → Display. Dark mode reports 18 findings and light mode 21; the three extra are the section headers above. Everything the app actually controls passes in both schemes. -## Findings are reported, not enforced - -The audit surfaces violations that exist today, so failing on all of them would -block every unrelated change until the whole pass lands. Instead, findings are -logged and attached to the result bundle tagged `[report]` or `[FAIL]`. - -Enforcement is the committed constant -`AccessibilityAuditHarness.enforcedAuditTypes`. Widen it as each phase clears a -category: - -| After phase | Enforce | -| --- | --- | -| 2 — semantic colors + light mode | `.contrast` | -| 3 — Dynamic Type + reflow | `.textClipped`, `.dynamicType`, `.hitRegion` | -| 4 — VoiceOver | `.elementDetection`, `.sufficientElementDescription`, `.trait` | - -A constant rather than a CI setting, for two reasons. Environment variables do -not work: neither a plain `xcodebuild` env var nor a `TEST_RUNNER_`-prefixed -build setting reaches the UI test process, so the toggle silently did nothing. -And a committed value makes "when did contrast become enforced?" answerable with -`git blame` instead of CI tribal knowledge. +## Enforcement — the ratchet is engaged + +With phases 1–5 landed, `AccessibilityAuditHarness.enforcedAuditTypes` enforces +**`.textClipped`, `.dynamicType`, `.hitRegion`, `.elementDetection`, +`.sufficientElementDescription`, `.trait`** on the empty-state test suite. A +named finding in any of these fails CI — regressions in five phases of work are +now gated, not merely reported. + +Three deliberate carve-outs, each with its evidence: + +1. **`.contrast` stays report-only.** The two long-standing Settings findings + are rows scrolled under the translucent tab bar; their attribution flips + between a row name and nil run-to-run, so no suppression is narrow enough to + keep CI stable. The centralised palette in `Shared/Colors.xcassets` is the + actual guard against contrast regressions. +2. **The seeded tests run `reportOnly`.** Bisecting the row/badge accessibility + modifiers showed the audit degrades on `children: .ignore` content — the + *correct* VoiceOver treatment for dense rows — emitting unattributed + contrast/dynamicType failures on rows that measure 6–7:1 and render + correctly. Their burndown still prints; it just doesn't gate. +3. **Characterised noise is suppressed narrowly and always logged** with a + `[noise: reason]` marker — disabled controls (WCAG 1.4.3 exempt), "nearly + passed" near-misses, system field placeholders (clipped at any length — + proven by shortening them to no effect), and unattributed + clipped/dynamic-type artifacts. Nothing disappears silently; see + `noiseReason(for:)` for each rule's provenance. + +Enforcement is a committed constant rather than a CI setting, for two reasons. +Environment variables do not work: neither a plain `xcodebuild` env var nor a +`TEST_RUNNER_`-prefixed build setting reaches the UI test process, so the toggle +silently did nothing. And a committed value makes "when did clipping become +enforced?" answerable with `git blame` instead of CI tribal knowledge. ## Why coverage is split between local and CI |
