Skip to content

feat(webui): add accessibility static-audit gate - #148

Merged
George-RD merged 2 commits into
mainfrom
feat/webui-a11y-static-audit-gate
Jun 23, 2026
Merged

feat(webui): add accessibility static-audit gate#148
George-RD merged 2 commits into
mainfrom
feat/webui-a11y-static-audit-gate

Conversation

@George-RD

Copy link
Copy Markdown
Collaborator

What

Adds scripts/check-a11y.sh, a deterministic, dependency-free accessibility gate over the hand-authored web surfaces, mirroring the accepted dec.webui-design-token-gate pattern (scripts/check-design-tokens.sh).

Default targets: src/ui_assets/index.html, src/ui_assets/app.js, docs/landing/index.html. Override one target via CAIRN_A11Y_TARGET.

Checks (statically decidable WCAG criteria the surfaces already satisfy)

Element-level (every surface):

  • 1.1.1 every <img> carries an alt (tag-aware, multi-line safe; empty alt="" decorative images pass)
  • 2.4.3 no positive tabindex overrides focus order (0/-1 allowed; data-tabindex not flagged)

Document-level (full HTML documents only, so JS/htm fragments are exempt):

  • 3.1.1 <html> declares lang
  • 2.4.2 a <title> exists
  • 1.4.4 the viewport does not disable pinch zoom (user-scalable=no / maximum-scale=1; maximum-scale=1.5 passes)

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 webui job, Makefile check target (+ a a11y-check phony).

Tests

tests/check_a11y.rs: table-driven behaviour cases (incl. regressions for empty alt, data-tabindex, and maximum-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 a data-tabindex false-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-config all green locally.

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.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@George-RD, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aadee359-9f62-4dd8-b570-3a09c9291a4c

📥 Commits

Reviewing files that changed from the base of the PR and between 5977ef3 and a0c0501.

📒 Files selected for processing (2)
  • scripts/check-a11y.sh
  • tests/check_a11y.rs
📝 Walkthrough

Walkthrough

A new accessibility static-audit gate is introduced via scripts/check-a11y.sh, which enforces WCAG-aligned text-level checks (alt text, tabindex, lang, title, viewport zoom) by stripping comments before scanning. The gate is documented in a new ADR, validated with Rust integration tests, and wired into pre-commit, CI, and the Makefile check target.

Changes

Accessibility Static-Audit Gate

Layer / File(s) Summary
Decision record
meta/decisions/webui-a11y-static-audit-gate.md
New ADR defines the gate scope, WCAG rules, comment-stripping requirement, target selection mechanism, wiring plan, and operational consequences for blocked commits and CI failures.
Audit script
scripts/check-a11y.sh
Introduces strip_comments (awk-based, line-number-preserving) and check_target (img alt, positive tabindex, and document-level lang/title/viewport checks). CLI wiring selects targets via CAIRN_A11Y_TARGET or a default file list and exits 0/1.
Integration tests and gate wiring
tests/check_a11y.rs, Makefile, .github/workflows/ci.yml, .pre-commit-config.yaml
Rust tests write temp fixtures and assert pass/fail with stderr substrings; a second test runs against real repo assets. Makefile adds a11y-check as a phony target and extends check. CI adds an audit step to the webui job. Pre-commit adds the a11y-check hook.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop, hop, I check each tag with care,
alt on images, lang declared right there,
No sneaky tabindex that's positive and rude,
Zoom stays unlocked — accessibility's good!
My shell script guards the gate without a fuss,
WCAG rules enforced, no library or bus. 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(webui): add accessibility static-audit gate' directly and clearly summarizes the main change: adding an accessibility static-audit gate to the webui.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the what, checks, wiring, tests, scope, and verification of the accessibility static-audit gate implementation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/webui-a11y-static-audit-gate

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 84fbf94 and 5977ef3.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • Makefile
  • meta/decisions/webui-a11y-static-audit-gate.md
  • scripts/check-a11y.sh
  • tests/check_a11y.rs

Comment thread scripts/check-a11y.sh Outdated
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.
@George-RD
George-RD merged commit b38d8eb into main Jun 23, 2026
11 checks passed
@George-RD
George-RD deleted the feat/webui-a11y-static-audit-gate branch June 23, 2026 18:36
George-RD added a commit that referenced this pull request Jun 23, 2026
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).
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.

1 participant