mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-09-26 17:07:53 +00:00
## Summary Dark-theme variants of the neighbor-graph role swatches (`#ngRoleChecks` labels on `/analytics?tab=neighbor-graph`) still failed WCAG AA after #1720's light-theme fix because the swatches used inline `style="color:#..."` from `customize.js` `DEFAULTS.nodeColors` (palette-700) — bypassing the theme tokens entirely. Measured before: | Role | Color | vs `#1a1a2e` (dark) | |---|---|---| | repeater | `#dc2626` | 3.53:1 ❌ | | companion | `#2563eb` | 3.30:1 ❌ | | observer | `#8b5cf6` | 4.02:1 ❌ | ## Fix - Defines `--role-{repeater,companion,room,sensor,observer}` in `:root` (palette-700, ≥4.5:1 on white) and overrides them in both dark blocks (`[data-theme="dark"]` + the `@media (prefers-color-scheme: dark)` mirror) with palette-400/500 shades that clear AA on `#1a1a2e`. - Refactors the neighbor-graph swatch DOM in `public/analytics.js` from inline `style="color:${hex}"` to class-based `<span class="role-swatch role-swatch--{role}">`, with matching CSS rules that read the tokens. - Removes all 5 `#1715` entries from `tests/a11y-allowlist.yaml` per the issue's acceptance criteria. After: | Role | Light (vs `#fff`) | Dark (vs `#1a1a2e`) | |---|---|---| | repeater | `#dc2626` 4.83:1 | `#ef4444` 4.53:1 | | companion | `#2563eb` 5.17:1 | `#3b82f6` 4.64:1 | | room | `#15803d` 5.02:1 | `#16a34a` 5.18:1 | | sensor | `#b45309` 5.02:1 | `#d97706` 5.35:1 | | observer | `#7c3aed` 5.70:1 | `#a78bfa` 6.27:1 | ## Tests - `test-a11y-1715-dark-role-swatches.js` — CSS-driven WCAG AA probes for the 5 per-theme `--role-*` tokens plus markup invariants (no inline color span; class names present in `#ngRoleChecks` block). - Red commit: `a09ec21c` — fails on assertion with 12 below-threshold/markup probes. - Green commit: `f87dcd64` — all probes PASS. - `tests/a11y-allowlist.yaml` shed all 5 entries; the umbrella `test-a11y-axe-1668.js` (CI) is now the live-browser net for those cells. ## Preflight overrides - `check-xss-sinks.sh` flags `public/analytics.js:2502` (label "observer" appears in an `innerHTML=\`tpl\`` line). The flagged token is a hardcoded literal string — no user-controlled data flows into that template. No template content changed in this PR; the flag is preexisting noise from the heuristic scan and the gate ultimately marks ✅ pass. Fixes #1715 --------- Co-authored-by: clawbot <clawbot@kpa.local> Co-authored-by: clawbot <bot@example.com>
38 lines
2.0 KiB
YAML
38 lines
2.0 KiB
YAML
# a11y allowlist — operator-flagged false-positives / temporary suppressions.
|
|
#
|
|
# Governance (M5 0-violation baseline policy, re-stated here per PR #1711):
|
|
# - The CI gate's net floor is ZERO. Every entry in this file CONSUMES
|
|
# one notional "I owe an a11y fix" credit.
|
|
# - No wildcards. Each entry MUST pin a specific node via either:
|
|
# selector: '...' # exact axe target string (legacy)
|
|
# selector_pattern: '...' # JS RegExp; requires count_max: N
|
|
# - selector_pattern + count_max (PR #1711, finding #1): when a single
|
|
# class of nodes can repeat under live data (table rows, fleet lists),
|
|
# use a pattern with an EXPLICIT cap. If matches exceed count_max,
|
|
# the gate FAILS so unbounded growth re-trips CI for a human review.
|
|
# - Every entry MUST cite a GH issue # tracking the underlying fix.
|
|
# - expires_at: YYYY-MM-DD is LOAD-BEARING. expires_at <= today is a
|
|
# HARD FAIL (filterAllowlist throws). Do NOT soften to a warning —
|
|
# the harness relies on this to prevent "sed forward" rot.
|
|
# - strict_unused (PR #1711, finding #4): when set to true, any entry
|
|
# that matches NOTHING during a CI run FAILS the gate. Default WARN.
|
|
# Env override: A11Y_STRICT_UNUSED=1 promotes WARN → FAIL.
|
|
# - Rolling expiry: do NOT all share one date. New contributions should
|
|
# stagger (e.g. +30d / +60d from authoring date) so the gate's
|
|
# re-trip cadence is steady, not cliff-shaped.
|
|
#
|
|
# Match semantics: route + rule + (selector == target OR selector_pattern.test(target)).
|
|
# Substring matching is REFUSED (`.btn` never suppresses `.btn-primary`).
|
|
#
|
|
# Entry shape:
|
|
# - route: '/analytics?tab=X'
|
|
# selector: '.foo' # OR selector_pattern: '^\.foo:nth-child' + count_max: 50
|
|
# rule: color-contrast
|
|
# issue: 1234
|
|
# expires_at: 2026-09-11
|
|
|
|
strict_unused: false
|
|
|
|
# (issue #1715 entries removed by the dark-theme role-swatch fix — see
|
|
# test-a11y-1715-dark-role-swatches.js for the CSS-driven regression gate)
|