V1 Web PWA · Walk result

Accessibility result: customer contrast-token handoff

A dated evidence record for V1 Web PWA: observed behavior, current source reconciliation, automation evidence, and explicit proof limits.

verdict: partial· 2026-05-30
8sections5 minread1table

On this page
  • Walked: 2026-05-30–31 during the customer accessibility repair campaign. The dated sweep reduced 402 recorded contrast nodes to a 25-node floor classified as intentional specimens or invalid-parameter skeletons.
  • Reconciled: 2026-07-18 against the current Lilith tokens, readableInk helper, stylesheet contract tests, system-specimen policy, and canonical desktop/mobile customer accessibility matrices. This was a source reconciliation, not a fresh all-route contrast sweep.
  • Verdict: partial — the historical record explains a substantial and traceable token repair campaign, and the key fixes remain present in current source. Current automation guards representative customer surfaces and explicitly treats diagnostic specimen pages as render-only. It does not reproduce the dated 181-route inventory or justify carrying “every real customer surface is AA” forward as a current universal claim.
  • Current signoff specs: wcag-aa-signoff-v1-p2-3510.spec.ts, wcag-aa-signoff-v1-p2-3511.spec.ts, and lilith-public-routes.spec.ts.

Result at a glance#

Evidence lane Recorded or current result Authority limit
2026-05-30 starting sweep 402 customer color-contrast nodes Historical build, route manifest, runner, and raw JSONL
2026-05-31 recorded floor 25 nodes: 17 intentional specimen/showcase cases and 8 invalid-parameter skeleton cases Dated classification, not a current scan
Current semantic token repairs Cream --l-muted, --l-warn, and --l-accent-2-text values remain in the Lilith stylesheet Source presence, not rendered coverage
Current data-color repair readableInk darkens six-digit hex text colors toward the cream-surface target and leaves other inputs unchanged Helper contract; callers and backgrounds still matter
Current customer signoff matrix Eleven primary/domain surfaces run WCAG 2.1 A/AA at desktop and 390 × 844 Serious/critical release threshold, representative routes
Current specimen policy Five /system* diagnostic pages render publicly with axe skipped for intentional sub-AA demonstrations Exclusion needs continued ownership and clear semantics

Evidence map#

The useful outcome is not the original count alone. The campaign moved repeated component literals into semantic text tokens and a reusable data-color helper, then retained a smaller portable accessibility matrix.

flowchart LR A[402 dated contrast nodes] --> B[Trace actual foreground and background] B --> C[Component literal repairs] B --> D[readableInk for data colors] B --> E[Semantic text tokens] C --> F[25-node dated floor] D --> F E --> F F --> G[17 intentional specimens] F --> H[8 invalid-param skeletons] I[Current desktop matrix: 11 surfaces] --> J[Serious and critical gate] K[Current mobile matrix: same 11] --> J L[System specimen routes] --> M[Render-only policy] F -. historical only .-> N[Current posture] J --> N M --> N

Proven observations#

Historical remediation trail#

  • The repair record documents a descent from 402 customer contrast nodes to 25 through repeated scan, node-level foreground/background tracing, component fixes, shared-token changes, and cross-surface regression checks.
  • Data-driven category and domain colors moved through readableInk where a literal six-digit hex was used as text on the cream surface. The helper preserves hue while darkening and intentionally leaves CSS variables, gradients, and rgba inputs unchanged.
  • Text usages that could not safely reuse brighter fill/icon colors gained semantic variants, including --l-accent-2-text. The current cream token is #8f4a1e; the original accent remains distinct at #c97247.
  • The cream warning token remains at the repaired #6f5220, and cream muted text remains #574d3f. The stylesheet contract maps the TypeScript token variants back to the CSS custom properties so later theme drift is testable.

Corrections preserved from the dated investigation#

  • The apparent #637b4f token transformation was a stale probe, not a runtime color-transform layer. The later trace established that the named tokens resolved to their CSS definitions.
  • The final plan-review diagnosis also superseded the earlier opacity theory. Actual axe nodes showed --l-warn at full opacity on warmer card backgrounds; darkening the cream warning token, rather than removing animation, closed the measured near-misses.
  • The final historical note therefore classified the remaining 25 nodes as 17 intentional demonstrations and eight invalid-parameter skeletons, with no remaining real-content defect in that dated manifest.

Current durable contract#

  • The canonical desktop and mobile signoff specs each cover Home, Library, Search, notifications, Profile, and the Tara, Veritas, Nyx, Arete, Nisaba, and Metis domain entries. They run the WCAG 2.1 A/AA rule set and fail serious or critical findings.
  • lilith-public-routes.spec.ts keeps the system galleries public and renderable while documenting why their contrast scan is skipped: the pages display palette, ratio, faded-preview, and edge-state specimens, including deliberately sub-AA examples.
  • This current matrix is portable repository evidence. The original parallel /tmp/walk runner and JSONL report are historical provenance only.

Boundaries and gaps#

  • The 402-to-25 sequence is historical. It belongs to the 2026-05 route manifest and build. This reconciliation did not rerun that temporary all-customer scanner against today's tree.
  • A source token value is not rendered conformance. Backgrounds, opacity, font size/weight, state, animation, blending, nested themes, and user content determine the actual axe result.
  • readableInk has a narrow contract. It handles six-digit hex inputs for cream-surface text. CSS variables and non-hex colors pass through unchanged, so callers must choose a semantic text token for those cases.
  • Specimen exclusions are scoped, not global waivers. The current policy skips contrast on named diagnostic galleries because low contrast is the demonstrated subject. The same token pairing on a task surface remains a defect.
  • Invalid-parameter skeletons are not valid dynamic-route evidence. Their faded states explained dated findings but do not certify real ids, empty states, error copy, or every current dynamic route.
  • The current release gate is representative. Eleven desktop/mobile surfaces fail serious/critical findings; moderate/minor findings and the rest of the customer route/state inventory need separate coverage.
  • Automated contrast is not full accessibility. Forced colors, zoom/reflow, user theme overrides, display calibration, cognition, and assistive- technology task completion remain outside this record.

Re-run evidence#

The current portable browser evidence can be run serially with:

bash
PW_BROWSER_CHANNEL=chrome pnpm exec playwright test \
  -c apps/oshun/web/playwright.config.ts \
  apps/oshun/web/e2e/wcag-aa-signoff-v1-p2-3510.spec.ts \
  apps/oshun/web/e2e/wcag-aa-signoff-v1-p2-3511.spec.ts \
  apps/oshun/web/e2e/lilith-public-routes.spec.ts \
  --workers=1

That command verifies the maintained representative matrix and specimen render policy. It does not recreate the historical 181-route contrast sweep or its 25-node floor.

Source trail#

Cross-references#

Open questions#

  • What generated route/state inventory should replace the dated 181-route manifest for a safe, repeatable customer contrast sweep?
  • Should current CI retain serious/critical as the release threshold while a scheduled job records every axe severity and node-level trend?
  • How will diagnostic specimen exclusions be identified semantically so a route-name allowlist cannot hide ordinary product content?
  • Which tests should pin contrast for semantic text tokens across cream, cream-high-contrast, dusk, warmer cards, disabled states, and motion frames?
  • Where should versioned JSON axe artifacts live so future claims can be compared to this repair history rather than reconstructed from prose?