feat(webui): add accessibility static-audit gate - #148
Conversation
Add scripts/check-a11y.sh, a deterministic, dependency-free gate over the hand-authored web surfaces (src/ui_assets/index.html, src/ui_assets/app.js, docs/landing/index.html), mirroring scripts/check-design-tokens.sh. Checks, all statically decidable WCAG criteria the surfaces already satisfy: - 1.1.1: every <img> carries an alt (tag-aware, multi-line safe). - 2.4.3: no positive tabindex overrides focus order. - 3.1.1 / 2.4.2 (documents only): <html lang> and a <title> exist. - 1.4.4 (documents only): the viewport does not disable pinch zoom. Wired into the same three places as the token gate: the pre-commit config, the CI webui job, and the Makefile check target. Covered by tests/check_a11y.rs (table-driven behaviour + real-surface conformance). Recorded in dec.webui-a11y-static-audit-gate. This is the deterministic, unblocked slice of cairn-y7p; the browser to AI-vision loop remains blocked on the two maintainer prerequisites on the bead.
|
Warning Review limit reached
More reviews will be available in 51 minutes and 3 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughA new accessibility static-audit gate is introduced via ChangesAccessibility Static-Audit Gate
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/check-a11y.sh`:
- Around line 104-105: The grep pattern on line 104 that checks for '<html' is
matching any substring containing '<html' rather than specifically the HTML root
element, causing false positives with JavaScript fragments or other content
containing that substring. Modify the grep pattern to be more specific by
requiring word boundaries or a space/closing bracket after 'html', such as using
'<html[\s>]' or '<html\b' to ensure you are only matching actual HTML root
elements and not partial string matches.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f8360f10-633a-4580-a932-96aba27365a1
📒 Files selected for processing (6)
.github/workflows/ci.yml.pre-commit-config.yamlMakefilemeta/decisions/webui-a11y-static-audit-gate.mdscripts/check-a11y.shtests/check_a11y.rs
CodeRabbit: document detection used grep '<html', which matches any
'<html' substring, so a JS/htm fragment merely mentioning the text could
wrongly trigger the document-level lang/title/zoom checks. Match the root
tag via a boundary char ('<html[[:space:]>]') instead. Add a fragment test
that contains a '<htmlblock' substring and must stay exempt.
Both deterministic halves of cairn-y7p shipped and are enforced on every commit/push/CI run: the design-token gate (PR #145, dec.webui-design-token-gate) and the a11y static-audit gate (PR #148, dec.webui-a11y-static-audit-gate). The only remaining scope was the browser -> AI-vision-critique -> patch -> reload loop, blocked on two maintainer prerequisites that conflict with the repo's deterministic-gates convention: a Node/Playwright toolchain in this package.json-less Rust repo, and a paid AI vision provider. The maintainer declined that scope. Record dec.webui-ai-vision-loop-declined captures the rationale and the condition to revisit, so the dev loop stops re-deriving this blocked seed. Close cairn-y7p (reconciled .beads export).
What
Adds
scripts/check-a11y.sh, a deterministic, dependency-free accessibility gate over the hand-authored web surfaces, mirroring the accepteddec.webui-design-token-gatepattern (scripts/check-design-tokens.sh).Default targets:
src/ui_assets/index.html,src/ui_assets/app.js,docs/landing/index.html. Override one target viaCAIRN_A11Y_TARGET.Checks (statically decidable WCAG criteria the surfaces already satisfy)
Element-level (every surface):
<img>carries analt(tag-aware, multi-line safe; emptyalt=""decorative images pass)tabindexoverrides focus order (0/-1allowed;data-tabindexnot flagged)Document-level (full HTML documents only, so JS/htm fragments are exempt):
<html>declareslang<title>existsuser-scalable=no/maximum-scale=1;maximum-scale=1.5passes)HTML and block comments are stripped first so markup in prose does not trip the gate.
Wiring
Same three places as the token gate: pre-commit config, CI
webuijob, Makefilechecktarget (+ aa11y-checkphony).Tests
tests/check_a11y.rs: table-driven behaviour cases (incl. regressions for empty alt,data-tabindex, andmaximum-scale=1.5) plus a real-surface conformance check.Review
Adversarial review surfaced and fixed a real zoom-regex false-positive (
maximum-scale=1.5) and adata-tabindexfalse-positive before submission; both are now covered by tests.Scope
Deterministic, unblocked slice of cairn-y7p. The browser to AI-vision loop remains blocked on the two maintainer prerequisites recorded on the bead.
Verification
cargo fmt --check,cargo clippy -D warnings,cargo test,cargo doc -D warnings,biome check,cairn scan(0 findings),cairn hook all(exit 0),prek validate-configall green locally.