a11y-static-gate
Skill0 starsChanged 4 months agoMITView on GitHub
Read-only deterministic gate that fails a build when an interactive element has no accessible name / role / state — across Flutter (.dart), React (.tsx/.jsx) and PHP/HTML templates. Structure-aware (ancestor chain, not line windows), with a baseline + ratchet so a legacy repo can adopt it without a rewrite, and an anti-gaming refusal to grow the baseline. Triggers: a11y gate, accessibility gate, アクセシビリティ ゲート, semantics 欠落, accessible name, button role, alt 欠落, 記号ラベル, a11y baseline, ratchet.
In this repository46 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- a11y-standardsSkill
- adversarial-refute-voteSkill
- antigravity-buildSkill
- architecture-parity-gateSkill
- ci-required-check-installerSkill
- codex-buildSkill
- codex-imagegenSkill
- codex-spark-delegateSkill
- commit-convention-gateSkill
- commit-msg-quality-scoreSkill
- consumer-finding-ledgerSkill
- context-bloat-trackerSkill
- coverage-floor-lockSkill
- destructive-env-guardSkill
- dev-standardsSkill
- eval-dataset-buildSkill
- eval-regression-guardSkill
- fanout-verify-synthSkill
- gate-forgeSkill
- hallucination-rate-meterSkill
- harness-kpi-ledgerSkill
- judge-rubric-voteSkill
- knowledge-citation-coverageSkill
- knowledge-dedup-scanSkill
- knowledge-index-guardSkill
- live-state-verify-guardSkill
- maker-checker-relaySkill
- memory-distillSkill
- mistake-rule-distillSkill
- oneshotSkill
- prompt-ab-evalSkill
- report-shapeSkill
- retry-failure-classifierSkill
- review-finding-reproSkill
- rule-dedup-scanSkill
- rule-promote-auditSkill
- rule-promotion-extractSkill
- secret-scan-hardeningSkill
- self-heal-ciSkill
- session-length-compact-auditSkill
- startSkill
- subagent-usage-analyzerSkill
- task-success-rate-trackSkill
- token-codegen-gateSkill
- trigger-vocab-dedupSkill
The file
Files
a11y-static-gate
${CLAUDE_PLUGIN_ROOT:-.}/scripts/a11y-static-check.py は、コードツリーを走査して
「支援技術から操作できない UI 要素」 を決定論的に検出する。
「ちゃんとラベルを付けて」という指示は確率的だが、exit code は確率的でない。
何を見るか
構造(括弧/タグのスタックと祖先チェーン)を解析するので、「この tappable を包む祖先に ラベルがあるか」に正しく答えられる。行ウィンドウの grep はこれを両方向に間違える。
| rule | severity | 検出内容 |
A11Y-FLUTTER-NAME | error | GestureDetector/InkWell/IconButton 等に tap があるが名前が無い |
A11Y-FLUTTER-ROLE | error | ラベルはあるが Semantics(button: true) が無い自作ボタン |
A11Y-FLUTTER-SYMBOL-LABEL | error | ラベルが記号のみ(< × •••)=記号名で読み上げられる |
A11Y-FLUTTER-STATE | warn | 条件付きコールバックなのに Semantics(enabled:) が無い |
A11Y-FLUTTER-FIELD-NAME | error | TextField に名前が無い(hintText: '' は名前ではない) |
A11Y-FLUTTER-TOGGLE-NAME | error | Switch/Checkbox に名前が無い |
A11Y-FLUTTER-IMAGE-LABEL | warn | Image に semanticLabel も excludeFromSemantics も無い |
A11Y-WEB-INTERACTIVE-DIV | error | div/span に click があるが role/tabIndex/キーボード処理が無い |
A11Y-WEB-CONTROL-NAME | error | button/a に名前が無い(アイコンのみ) |
A11Y-WEB-SYMBOL-LABEL | error | button/a のラベルが記号のみ |
A11Y-WEB-IMG-ALT / A11Y-MARKUP-IMG-ALT | error | img に alt が無い(alt="" は装飾として許容) |
A11Y-WEB-FIELD-NAME / A11Y-MARKUP-FIELD-NAME | error | 入力要素に label 関連付けも aria-label も無い |
A11Y-WEB-FIELD-LABEL-UNVERIFIED | warn | id はあるが対応する <label for> を静的に確認できない |
A11Y-*-VIEWPORT-ZOOM | error | user-scalable=no / maximum-scale<2(拡大禁止) |
A11Y-*-POSITIVE-TABINDEX | error | 正の tabindex(タブ順が DOM 順から乖離) |
A11Y-PROJ-SCALE-TEST | warn | 最大文字サイズを再現する自動テストが無い(Flutter repo) |
A11Y-PROJ-WEB-LINT / -SUBSET | warn | a11y linter 未設定 / Next.js 既定の部分適用のみ |
Boundary(read-only)
- 検出のみ。
Semanticsを挿入したりコードを書き換えたりしない。修正は人(と PR)の仕事 - 自分を CI に配線しない。required status check / branch protection 化は self-lockout 側のリスクを持つ変更なので、人が意図して行う(→
examples/ci/a11y-gate-pattern.md) - gh / aws / git を呼ばない。ローカルのファイル読取だけ・python3 stdlib のみ
- 静的解析はアクセシビリティを証明しない。緑は「機械が見つけられる命名/役割の欠陥が無い」だけ。読み上げでの通し操作と拡大時のレイアウトは
a11y-standardsの自動テストと実機確認が担う
使い方
# 単発(新規プロジェクト・違反 0 が前提)
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/a11y-static-check.py" --root .
# 既存 repo(違反が既にある): 現状を凍結して以後の新規違反だけ落とす
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/a11y-static-check.py" --root . \
--baseline .a11y-baseline.json --update-baseline # 初回のみ
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/a11y-static-check.py" --root . \
--baseline .a11y-baseline.json # 以後(CI)主なオプション: --strict(warn も落とす)/ --format json / --rules <ID,...> /
--exclude <substr>(repeatable)/ --no-project-checks。
exit code: 0 新規違反なし / 1 新規違反あり / 2 引数・baseline 読取エラー
(baseline を指定して不在なら 2 — 「既知ゼロ・新規ゼロ」に倒さない)/
3 UNKNOWN = 走査対象 0 件(クリーンではなく --root/--exclude の誤り)。
出力は必ず分母を伴う(走査ファイル数・拡張子別・検査した操作要素数・rule 別件数・ 件数の多いファイル上位)。「0 件」だけを出して走査 0 件と区別できない状態にしない。
baseline と ratchet(レガシー導入の要)
- fingerprint は 内容ベース(rule + file + 正規化スニペット + 出現順)。行がずれても 新規違反として再発火しない
--update-baselineは件数が増える更新を拒否する。増やすには--allow-baseline-growthが必要で、その痕跡が diff と PR に残る (coverage-floor-lockの「floor を下げる diff 自体が違反」と同じ規律)- 修正後に
--update-baselineで fixed エントリを刈る。counts.errorは単調減少が期待値
誤検出への対処(除外より抑制を選ぶ)
// a11y-ignore: 装飾のヒット領域で、同じ操作を上のボタンが提供している
GestureDetector(onTap: noop, child: const Icon(Icons.circle))理由付きの a11y-ignore: <理由> のみが抑制する。理由の無い裸の a11y-ignore は抑制せず、
件数として報告される。ファイル単位の --exclude で黙らせるより、1 行の理由を残す。
Deterministic --check(self-test)
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/a11y-static-check.py" --self-testhermetic(mktemp の fixture のみ・repo に何も書かない)。各スタックの検出/非検出、
ratchet、baseline 成長拒否、走査 0 件 = UNKNOWN、抑制 pragma、そして実 repo で見つかった
偽陽性の再発ロック(<label> の暗黙関連付け・テンプレートリテラル内の JSX コード例・
monorepo の lint 設定・build 用 package.json を持つ PHP テーマ)を検査する。
期待値を 1 つ変えれば FAIL する(成功のハードコードなし)。
Related
- 設計標準(何を守るか):
a11y-standards - 実行時テストの雛形:
examples/a11y/flutter/a11y_smoke_test.dart/examples/a11y/web/eslint-a11y.config.md - CI 配線と ratchet 運用:
examples/ci/a11y-gate-pattern.md - 同じ族のゲート:
coverage-floor-lock(下限ロック)・architecture-parity-gate(構造違反)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

