July Demo Candidate 0.1 — accessibility + rendered-browser walkthrough evidence
Truth label. DEV/DEMO, fixture-mode, single-actor, fictional data. This document
records an accessibility and rendered-browser review of the member-shell v0 reference
client (web/member-shell/) — the human-facing surface of July Demo Candidate 0.1.
It is proof of path, not deployment readiness. It is not production, not a pilot, not
federation, not NYCN activation, not real member data, and makes no signed/partner claim.
This is an evidence/documentation pass. No runtime behavior was changed.
1. What was run, and what was not
| Path | Status |
|---|---|
Rendered-browser walkthrough of member-shell fixture mode (?mode=demo) |
RUN (headless Chromium, this pass) |
Automated WCAG scan (axe-core; tags wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22aa — WCAG 2.0/2.1 A & AA plus 2.2 AA) |
RUN (this pass) |
| Keyboard-navigation + visible-focus trace | RUN (this pass) |
| 200% zoom (CSS), narrow/mobile reflow, reduced-motion render | RUN (this pass) |
| Live member-shell against a running gateway (discharge mutation) | NOT run here — no live appliance/gateway in this environment. The live seed → discharge → verify → reset/reseed + 13/13 receipt-chain loop was run and sealed separately on 2026-06-13 (operator evidence: ~/artifacts/icn/demo-image-20260612/EVIDENCE-MAP.md). This pass does not re-run or re-claim it. |
| Screen-reader (VoiceOver/NVDA/Orca) smoke | NOT run — no AT in this headless environment. Remains owed (matches the client's own declared gap). |
| Human low-vision / switch-control / low-end-device verification | NOT run — automated proxies only; human pass remains owed. |
Participation access is architecture, not polish. A demo surface with blocked keyboard, zoom, or screen-reader access is not organizer-ready. This pass clears the automated and rendered-structural floor; the human AT pass is explicitly recorded as still owed.
2. Method (reproducible, zero new dependencies)
- Served the repo's
web/directory statically (python3 -m http.server), opened…/member-shell/?mode=demo. - Drove headless Chromium via Playwright +
@axe-core/playwright, which are declared devDependencies ofweb/pilot-ui(@axe-core/playwrightper #1735) — so no new dependency stack is introduced for this pass. - Committed audit script: `web/member-shell/a11y-walkthrough.cjs`
(repo-safe; a dev/audit tool, not loaded by the shell). Reproduce (the serve port and the
script's base-URL argument must match — the script defaults to
:8099):( cd web/pilot-ui && npm ci && npx playwright install chromium ) ( cd web && python3 -m http.server 8099 --bind 127.0.0.1 & ) # serve the web/ root on :8099 NODE_PATH=web/pilot-ui/node_modules node web/member-shell/a11y-walkthrough.cjs http://127.0.0.1:8099 ./out - Browser-revision provenance (honest): Playwright resolves its own pinned Chromium for the
installed Playwright version, so the exact binary is environment-dependent, not a single
pinned revision. This run used the install already present in
web/pilot-ui/node_modules(Playwright 1.58.1 → chromium-1208). The lockfile pins Playwright 1.60.0, so a reviewer who runsnpm cifirst installs 1.60.0 and a newer Chromium and validates on that browser — not on 1208. These are static-surface WCAG checks (semantic HTML, ARIA, contrast, focus); the 0-violation result is expected to be stable across recent Chromium revisions, but the recorded numbers below are specifically for 1.58.1/chromium-1208. A fresh-checkout reviewer should confirm on their installed version. - Fixtures consumed:
web/pilot-ui/fixtures/icn-organizer-demo/{standing,action-cards}.json(CI-drift-guarded, #2021) andweb/member-shell/fixtures/demo-completion-receipt.json(fictionaldid:icn:example-*, illustrativerecord_hash, nothing signed).
3. Rendered walkthrough — observed
The fixture-mode page renders the participation spine as read views: standing → action cards → a completion receipt → plain-language evidence. (The fixture path does not perform a live discharge mutation; the discharge→receipt step is exercised by the sealed live run, not here. In fixture mode the receipt shown is the pre-seeded receipt fixture.)
| Observation | Result |
|---|---|
| Honesty banner text (permanently visible) | Fixture-backed demo — no live node, nothing signed. |
| Standing pane visible; memberships / roles rendered | yes — 2 memberships, 2 roles |
| Action cards pane visible; cards rendered | yes — 3 cards |
| Receipts pane visible; receipt rendered | yes — 1 receipt |
| Plain-language evidence + "Show evidence detail" disclosure present | yes (2 evidence disclosures) |
| Landmarks present | header, nav, main, footer |
| Skip link present | yes (a.skip-link → #main) |
| Credential in URL (demo mode) | none (url_has_no_credential = true) |
| Mobile (360px) horizontal scroll | none (clean reflow) |
Screenshots (desktop, 200% zoom, mobile-360, reduced-motion) are archived in the artifact class (see §8). No credential, token, JWT, key, private IP/hostname, or passphrase appears in any screenshot (demo mode pastes nothing; the only credential field is live-mode and was never exercised).
4. Automated check results
| Check | Result |
|---|---|
axe-core (tags wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22aa) |
0 violations, 25 passes |
| Keyboard: focusable elements reached by Tab | 15 |
Keyboard: every focused element had a visible outline (outline-style≠none, width≠0) |
true |
| 200% CSS zoom render | no layout break observed in screenshot |
prefers-reduced-motion: reduce render |
standing pane renders identically (client uses no motion) |
Automated scans are a floor, not a substitute for human AT testing. 0 axe violations means no machine-detectable WCAG failures on the rendered fixture view; it does not certify screen-reader comprehension or human low-vision usability.
5. Organizer / member accessibility gate — 12-category outcome
Per docs/design/ORGANIZER_MEMBER_ACCESSIBILITY_GATE.md §5. Outcomes: Pass /
Pass w/ follow-ups / Blocked / N/A.
- 3.1 Language access — Pass. Plain-language English copy; canonical terms (standing,
action card, receipt, provenance, DID) each paired with an inline explanation; no kernel jargon
in member copy. The language-modularity infrastructure (i18n seam) is now implemented —
landed in #2043 (closes #2042): a locale-keyed message catalog the UI reads via
t()with a per-key English fallback,?lang=/navigator.languageresolution,<html lang>+dirwith RTL, a translation-pending fallback, and a pseudo-locale coverage test. Adding a language is a catalog entry, not a code change; axe is 0 aten/ pseudo /ar; raw identifiers stay literal; thearRTL demo announces its English fallback as English (lang=en) honestly. Still owed (separate lanes, not blocking this DEV/DEMO English evidence pass): real translations and a human language-quality pass for each shipped locale — the seam ships onlyen+ a pseudo-locale- an RTL fallback demo, no real translations yet; the broader website multilingual path is #1740. Language access is access — the seam is the infrastructure floor; translations are the next lane.
- 3.2 Screen-reader / non-visual access — Pass with documented follow-ups (#2041).
Semantic HTML, landmarks, headings,
role="status"/aria-liveregions, list views,aria-describedby. Real screen-reader testing not performed — remains owed (tracked in #2041; the client also declares this gap) before calling this surface organizer-ready. - 3.3 Low-vision access — Pass with documented follow-ups (#2041). 200% CSS zoom
rendered without layout break (screenshot); rem units throughout; contrast ratios documented
per token in
shell.css. Human low-vision + external contrast-audit-tool verification not performed — owed (tracked in #2041). - 3.4 Color-independent meaning — Pass. Status carries glyph + text label (risk level is "glyph + label, never color alone" per spec/README); axe found no color-contrast violations.
- 3.5 Keyboard / switch / non-pointer access — Pass with documented follow-ups (#2041).
15 focusables reached by Tab, all with a visible focus outline; skip link present; no
hover-only controls in markup; buttons/inputs sized ≥44px (2.75rem) per
shell.css. Switch- control software not exercised — owed (tracked in #2041). - 3.6 Captions, transcripts, non-audio access — N/A with reason: the reference client ships no audio/video/narration media.
- 3.7 Cognitive load and step complexity — Pass. Single column, fixed section order,
progressive disclosure (
<details>for DID, technical detail, evidence). The one mutation (mark-complete, live mode only) is gated behind a pre-confirm summary stating what changes, authority basis, scope, receipt expected, and permanence, with distinct Confirm/Cancel (per README/spec; not exercised in fixture mode). - 3.8 Low-bandwidth / low-device access — Pass. Dependency-free static HTML/CSS/vanilla JS; no framework, build, animation, or autoplay. Follow-up (not blocking): no offline tolerance / cache / draft queue (declared gap).
- 3.9 Assistive-technology compatibility — Pass with documented follow-ups (#2041).
Real HTML elements over
div[role]; standard inputs. AT exercised: none (headless environment, no screen reader / switch). This single line keeps the surface from being called "organizer-ready" until an AT pass is done — owed (tracked in #2041). - 3.10 Privacy-preserving accommodation path — N/A with reason: no accommodation profile exists in this reference client; no disability/medical/accommodation data is collected, rendered, or committed. (A real deployment must add this; tracked as a declared gap, not a regression.)
- 3.11 Receipts, provenance, evidence access — Pass. Receipt shows a plain-language
summary first (who acted, what obligation, when); record class, ids, actor DID, and raw
record_hashsit behind "Show evidence detail". The fixture maturity tier ("Fixture-backed demo — nothing signed") is visible on screen — a member can tell it is fixture-only without parsing JSON. - 3.12 Governance and action access — Pass. Action cards expose authority basis, status, scope, an authorization check against the member's own scopes, consequence, and a what-happens-if-I-act line in plain language; the mandate/receipt-expected is stated before the confirm step (live mode). "Ask for help" path is present (steward contact, unwired in the reference client by design).
Surface readiness conclusion: member-facing reference-client floor cleared for automated +
rendered-structural review; the language-modularity infrastructure (3.1) is now implemented
(#2043, merged); NOT yet organizer-ready / pilot-ready until (a) the owed human AT pass
(3.2 / 3.9, and human 3.3 / 3.5) is completed, and (b) real translations + a human language-quality
pass ship for the target locales (the i18n seam exists but ships only en + a pseudo-locale +
an RTL fallback demo). No category is hard-Blocked; the human-AT items (#2041) and the
translations/human-language lane remain owed-follow-ups that gate the "organizer-ready" label.
6. Findings
Finding: Real screen-reader / AT testing not performed.
Evidence: §1, gate 3.2 / 3.9; environment is headless with no VoiceOver/NVDA/Orca; the client's
own README declares this gap.
Impact: Cannot honestly call the member surface "organizer-ready" or "pilot-ready" without it.
Recommendation: One human (or AT-equipped) pass with at least one screen reader + one non-mouse
input; tracked in #2041 — attach results there.
Blocking? no (for DEV/DEMO review) / yes (for organizer-ready / pilot-ready labeling)
Finding: Human low-vision / 200% browser-zoom / low-end-device verification not performed.
Evidence: §4 used CSS zoom + narrow viewport as automated proxies; no human confirmation.
Impact: Automated zoom proxy can miss real reflow/comprehension problems.
Recommendation: Human 200% browser-zoom + small-device pass; fold into #2041.
Blocking? no (DEV/DEMO) / important follow-up (organizer-ready)
Finding: Automated WCAG scan is clean (0 axe violations, 25 passes) on the fixture render.
Evidence: §4.
Impact: Positive — machine-detectable WCAG floor is met on the rendered fixture view.
Recommendation: Keep axe in the loop; re-run if member-shell markup changes.
Blocking? no — verified okay.
Finding: Fixture mode renders read views only; it does not perform a live discharge mutation.
Evidence: §3; fixture mode shows a pre-seeded receipt fixture.
Impact: A reviewer could mistake the fixture receipt for a live-proven one.
Recommendation: Keep the "nothing signed / fixture-backed" banner prominent (it is); cite the
sealed live run for the discharge→receipt→13/13 proof rather than implying the fixture proves it.
Blocking? no — verified okay (banner already present).
Finding: Language-modularity infrastructure — RESOLVED by #2043 (merged). Language access is
accessibility, and the member shell now has an i18n seam.
Evidence: §5 gate 3.1; #2043 added a locale-keyed message catalog read via `t()` with per-key
English fallback, `?lang=`/`navigator.language` resolution, `<html lang>`/`dir` + RTL, a
translation-pending fallback, and a pseudo-locale coverage test; axe 0 at en/pseudo/ar.
Impact: The surface can now be made modular with language — adding a language is a catalog entry,
not a code change. **Still owed (separate lane):** real translations + a human language-quality
pass per shipped locale (the seam ships only `en` + a pseudo-locale + an RTL fallback demo);
the broader website multilingual path is #1740.
Recommendation: Open/queue a translations lane (real per-locale catalogs + human language QA) when
a target locale is chosen; the seam (#2043) is the infrastructure floor.
Blocking? no (DEV/DEMO English demo; seam implemented) / important follow-up: real translations +
human-language QA before organizer-/pilot-ready for non-English cooperatives
Classification: 1 important-follow-up (screen-reader/AT #2041), 1 follow-up (human zoom/device #2041), 1 resolved (language-modularity infrastructure — i18n seam landed in #2043; real translations + human-language QA remain a separate lane), 2 verified-okay. No blockers for the DEV/DEMO English review; the human-AT pass (#2041) and the translations/human-language lane gate the organizer-/pilot-ready label.
7. Interface review — does the UI keep the distinctions honest?
| Distinction | Made clear? |
|---|---|
| DEV/DEMO posture | yes — permanent honesty banner + footer reference-client disclaimer |
| Fixture vs live-local mode | yes — Mode nav + per-mode banner text ("Fixture-backed demo…" vs "Live-local node — dev rehearsal…") |
| Launcher vs manual fallback | yes — launcher section ("Start local demo", no paste) and "Connect manually instead" both present |
| Reset vs reseed | n/a in member-shell (operator-side; documented in HANDS_ON §8 / DEMO_QUICKSTART / OPERATOR_CHECKLIST) — UI does not conflate them |
| Receipt vs proof/audit | yes — plain summary first; raw record_hash/class/ids behind "Show evidence detail"; fixture caption says nothing is signed |
| Proof of path vs production readiness | yes — banner + footer ("not the production member shell… claims no live-federation or production posture") |
8. Artifacts
The audit script is committed: `web/member-shell/a11y-walkthrough.cjs`
— so the checks are runnable from committed materials (see §2). The screenshots and the
axe/keyboard JSON report live in the operator's local artifact store under the artifact class
july-demo-accessibility-<date> (sibling to the sealed-image evidence) — repo-safe (no
credentials/keys/IPs) but kept out of the repo per the evidence-log convention (they are binary /
machine output). This doc is the committed, shareable summary; the committed script lets a reviewer
regenerate them.
9. Owed before "organizer-ready / pilot-ready"
A reproducible human-tester packet for the owed items below — exact setup/launch commands, per-category fill-in checklists, expected observations, and evidence/pass-fail templates — is in `JULY_DEMO_CANDIDATE_0.1_HUMAN_A11Y_VALIDATION.md`. It is a template, not a completed pass.
- Screen-reader smoke (≥1 of VoiceOver/NVDA/Orca) + ≥1 non-mouse input (3.2 / 3.9). [#2041]
- Human 200% browser-zoom + small-device pass (3.3 / 3.5 / 3.8). [#2041]
- External contrast-audit-tool confirmation of the documented ratios (3.3).
- Language-modularity infrastructure (3.1) — DONE (i18n seam landed in #2043, closes #2042):
locale-keyed catalog,
t()+ per-key English fallback,?lang=/navigator.language,lang/dir- RTL, translation-pending fallback, pseudo-locale coverage. Still owed: real translations +
a human language-quality pass per shipped locale (the seam ships only
en+ a pseudo-locale + an RTL fallback demo); the broader website multilingual path is #1740.
- RTL, translation-pending fallback, pseudo-locale coverage. Still owed: real translations +
a human language-quality pass per shipped locale (the seam ships only
- (Declared, separate lanes, not this pass) glossary endpoint #1610, multi-language #1740, offline tolerance, privacy-preserving accommodation path, deadline-justice metadata.