Skip to content

Objective a11y + performance quality bar (Gauntlet "the bar") - #15

Merged
dominno merged 6 commits into
mainfrom
claude/quality-bar-a11y-perf
Jul 28, 2026
Merged

dominno merged 6 commits into
mainfrom
claude/quality-bar-a11y-perf

Conversation

@dominno

@dominno dominno commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

Adopts the one Gauntlet-Loop principle our earlier eval found genuinely worth it for spec-driven dev: give the Accessibility and Performance critics a concrete external bar they judge against, and wire it as a gate — the same discipline the test suite already applies to functional work. a11y/perf only; no aesthetic reference bar (the eval rejected that as over-engineering for a trivial form).

What's in it

  • .claude/memory/topics/quality-bar.md — the bar: WCAG 2.1 AA contrast (4.5:1 / 3:1) + a first-load JS budget, with a machine-readable perf-budget-kb-gzip marker as the single source of truth (+ index row).
  • critic-panel.js — the Accessibility & Performance lenses now judge against the bar's numbers (and are told how to obtain a fresh measurement, not restate the baseline). Engine/tiering/labels untouched.
  • e2e/a11y.spec.ts (axe + Playwright) — zero serious/critical WCAG 2.1 AA violations across initial-load / validation-error / greeting states, an explicit landmark scan, and a keyboard-only happy-path test.
  • scripts/check-bundle-size.mjs + folded into pnpm build — sums per-file gzipped .next/static/chunks, excluding the legacy noModule polyfill (via build-manifest polyfillFiles) so the number is real first-load JS. Baseline 143.2 KB, budget 155 KB (+~8% ratchet).
  • pnpm-workspace.yaml — replaced a never-completed allowBuilds placeholder with valid onlyBuiltDependencies (sharp, unrs-resolver) so pnpm install is deterministic.
  • @axe-core/playwright devDep; lockfile regenerated with pnpm 10 to match CI.

Enforcement (both gates run on every PR)

  • a11y rides CI's existing e2e job (pnpm test:e2e runs the axe spec).
  • perf is folded into pnpm build (next build && node scripts/check-bundle-size.mjs), so CI's existing build matrix job enforces the budget — no verify.yml edit (honoring the "prefer the existing path over CI config" constraint).

Verification (maker/checker, separate passes)

  • pnpm verify green under pnpm 10 (CI's version): 13 unit, build + bundle 143.2/155 KB, 16 e2e (11 existing + 5 a11y). The existing dark-theme UI already meets WCAG AA — no violations found.
  • /improve-skills over the prompt surface: 0 blockers; 4 real consistency fixes applied (incl. closing a "placeholders exempt" a11y loophole and a stale verify-chain doc).
  • critic-panel over the implementation: first round found 1 blocker (perf gate wasn't enforced in CI) + 8 important — all applied; the final round returned 0 blockers / 0 important. 44 critic/checker agents total across the passes.

Not in scope (deliberately)

Aesthetic/reference-exemplar bar for the Designer/Artistic critics; mobile-viewport & tap-target sizing (WCAG 2.2 target-size) — those stay qualitative, documented explicitly in quality-bar.md so "zero violations" isn't misread as a mobile guarantee.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 6 commits July 28, 2026 07:03
The one Gauntlet-Loop principle our eval found genuinely worth adopting for
spec-driven dev: give the Accessibility and Performance critics a concrete
external bar they judge against, and wire it as a gate — same discipline the
test suite already applies to functional work. a11y/perf only; no aesthetic
reference bar (the eval rejected that as over-engineering here).

- .claude/memory/topics/quality-bar.md: WCAG 2.1 AA contrast (4.5:1 / 3:1) +
  a first-load JS budget (190 KB gzip; baseline 181.9 measured; machine-readable
  perf-budget-kb-gzip marker as the single source of truth). Index row added.
- critic-panel.js: Accessibility + Performance lenses now judge against the bar
  (cite the target/number), not vague language. Engine/tiering/labels untouched.
- e2e/a11y.spec.ts: Playwright + axe, zero serious/critical WCAG 2.1 AA
  violations across initial-load / validation-error / greeting states.
- scripts/check-bundle-size.mjs + `check:bundle` script, wired into `verify`
  after build; reads the budget marker (single source of truth).
- @axe-core/playwright devDep; pnpm-workspace.yaml onlyBuiltDependencies fixes a
  never-completed build-approval placeholder so `pnpm install` is deterministic.

Full `pnpm verify` green under pnpm 10 (CI's version): 14/14 e2e incl. 3 a11y,
bundle 181.9/190 KB. Existing UI already meets WCAG AA (no violations found).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_014xUCrJdREvUMjoVzSX5T8G
0 blockers; 4 important real+safe consistency fixes applied (+2 nice-to-haves):
- quality-bar.md: closed the "placeholders exempt" a11y loophole — placeholder
  text is not blanket-exempt (WCAG 1.4.3 exempts disabled/inactive only); kept
  it accurate to our persistent-visible-label design without forcing a CSS change.
- quality-bar.md: clarified the perf metric sums ALL client chunks (= first-load
  because single-route; narrow it if routes are added).
- critic-panel.js: both lenses now tell the critic HOW to get the number (run
  the axe e2e / `pnpm build && check:bundle`, or reuse priorEvidence) instead of
  restating the stored baseline as a fresh measurement.
- build-and-verify.md: verify chain updated to the real 6 steps (was missing
  check:bundle) + link to quality-bar.md.
- remote-env.md: filed the durable pnpm-10-vs-11 / ignored-builds gotcha.
- log.md: /dream ingest entry for the quality-bar work (audit trail).

critic-panel.js still passes node --check; perf-budget marker intact.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_014xUCrJdREvUMjoVzSX5T8G
Critic round: 1 blocker + 8 important. Applied all the non-CI-config fixes:
- Perf metric now excludes the legacy noModule polyfill chunk (~39.5 KB gz that
  modern browsers never download) via build-manifest polyfillFiles — so the
  number is real first-load JS. Baseline 143.2 KB (was 181.9 counting polyfill);
  budget reset 190 -> 155 (+~8% headroom).
- e2e/a11y.spec.ts: added an explicit landmark scan (region / landmark-one-main
  are best-practice rules outside the WCAG-AA tag set) and a keyboard-only
  happy-path test — making quality-bar.md's landmark + keyboard claims real.
- quality-bar.md: honestly scoped the a11y gate — it does NOT cover mobile
  viewport / tap-target sizing (WCAG 2.2 target-size); those stay qualitative.
  Updated enforcement section (a11y rides CI e2e job; perf CI status noted).
- pnpm-workspace.yaml: removed the dead `allowBuilds` placeholder a linter had
  re-added; keep only the working `onlyBuiltDependencies`.

Full `pnpm verify` green under pnpm 10: 13 unit, build, check:bundle
143.2/155 KB, 16 e2e (5 a11y incl. landmark + keyboard).

Remaining: 1 blocker (check:bundle not enforced in CI) — escalated to the user
per the goal's "if CI config must change, flag and pause" constraint.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_014xUCrJdREvUMjoVzSX5T8G
Resolves the critic-panel blocker (perf gate ran only locally). Rather than
edit .github/workflows/verify.yml (the goal constraint prefers the existing
verify/e2e path), attach the bundle check to `pnpm build`
(`next build && node scripts/check-bundle-size.mjs`). CI's `build` matrix job
runs `pnpm build`, so the budget is now enforced on every PR — and `build`
needs .next anyway, so it's the natural home. Dropped the now-redundant
check:bundle step from `verify` (build covers it); kept the standalone script.
Updated build-and-verify.md and quality-bar.md to describe the wiring.

Full `pnpm verify` green (pnpm 10): 13 unit, build+bundle 143.2/155 KB, 16 e2e.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_014xUCrJdREvUMjoVzSX5T8G
Final critic pass returned 0 blockers / 0 important — 2 nice-to-haves applied:
- check-bundle-size.mjs: warn (not silently) if .next/build-manifest.json is
  absent, so a future Next.js manifest move surfaces as a clear message instead
  of a confusing budget regression.
- README.md: synced the package.json scripts snippet (build now runs the bundle
  gate; added check:bundle) so it no longer implies `pnpm build` skips the gate.
next-env.d.ts's import path flips between .next/types (after `next build`) and
.next/dev/types (after `next dev`); earlier commits staged the build variant,
which drifted from main. Restore the dev variant so this generated file matches
main — the PR no longer touches it.
@dominno
dominno merged commit 88d2ce8 into main Jul 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants