Tend A11y — the herald
このリポジトリのマークアップから、最も優先度の高いアクセシビリティ、UX、またはコピートーンの問題を1つ特定し、最小限の修正を施して検証し、レビュー用の差分を提示します。1回の実行につき1つの問題のみ扱います。
0. 設定の読み込み
.claude/tend/config.yamlを読み込みます。skills.a11y(オフリミットグロブ、notes)を使用します。このスキルには機能モジュールはありません。モジュールゲーティングは完全にスキップします。ここにmodules:ゲーティングステップはありません。- 設定がない場合? コアティアで実行します: コアの SvelteKit + TS の前提、保守的な組み込みのオフリミット(ロックファイル、CI、
.env、設定には決して触れません)。一度だけ出力: "tend-onboardを実行して設定を精密化してください。" 続行します。
1. トリアージ
references/scan-core.md の読み込みが必須です。
- オフリミットセットを確立します: 設定の
skills.a11y.off-limitsと組み込みのガードレール(ロックファイル、CI設定、.env、プロジェクト設定、またはバックエンド/APIルートのロジックには決して触れません — このスキルはプレゼンテーションのみです)。 - エントリポイントを確立します: このリポジトリのマークアップファイル —
.svelteコンポーネント、+page.svelte/+layout.svelteルート、またはスタックが実際に使用するテンプレートファイル。skills.a11y.notesに名前付きのコンポーネントライブラリディレクトリ(例:src/lib/components/ui)がないか確認します。存在する場合、そのエクスポートがフェーズ2の「生のHTMLの代わりにこれを使用」対象リストとなります。 - スキャンする前に1~2個の既存コンポーネントを読み、リポジトリの実際のコンポーネントライブラリとステータス/ローディングの規約を学習します — 実際のパターンを把握してからでなければ、それからの逸脱を違反と呼べません。
完了基準: オフリミットセットが既知、コンポーネントライブラリの規約(存在する場合)が特定済み、エントリポイントグロブが特定済み。
2. スキャン — 優先順位順、最初の実際のヒットで停止
最も価値が高い(ユーザーにとって最も黙示的)ものから順に並べられています — 最初の実際の、エビデンスに裏付けられたヒットで停止します:
- コンポーネントライブラリの同等品が存在する生のインタラクティブHTML — リポジトリの別の場所に
Button/Link/Inputエクスポートが存在するのに、生の<button>/<a>/<input>が使用されている。 - アクセシブルな名前がないアイコンのみ、またはアイコン主体のインタラクティブ要素 —
aria-label、視覚的に隠されたテキスト、titleフォールバックがない。 altのない<img>— 属性の欠落が違反であり。装飾画像の意図的な空のalt=""は違反ではない。- 関連付けられたラベルのないフォーム入力 —
label for=、aria-label、またはコンポーネントライブラリのラベルプロップがない。テンプレートだけでなく、レンダリングされた数を監査します: ループ({#each}または同等のもの)内で生成された入力は、実行時にN個の匿名コントロールを生成します。 role="button"(または非インタラクティブ要素のベアonclick)に、対応するキーボードハンドラがない — Enter + Space のonkeydown。ネイティブの<button>はこれを自動的に取得します。これは生の要素エスケープハッチでのみ発動します。- 非同期の成功/エラー/ローディングフィードバックが、プレーンでアナウンスのない要素としてレンダリングされている —
role="alert"/role="status"、aria-live、またはリポジトリの他の場所ですでに使用されている既存のコンポーネントライブラリのバナー/トーストプリミティブがない。 - 確認ステップなしに効果を発揮する破壊的アクション(削除/除去/リセット)。
- コピートーンの違反。設定駆動の許可/拒否リスト(
skills.a11y.notes、またはそれが指すプロジェクトトーンドキュメント)に対してチェックします。リポジトリ固有のリストがない場合は、汎用のデフォルトにフォールバックします: 検証/エラー指示の前に付ける命令形の軟化語「ください」("名前を入力してください" vs "名前を入力")、または日常的な確認/指示コピーにおける不必要な感嘆符。レンダリングされたマークアップテキストと、<script>ブロック内の文字列リテラルの両方をスキャンします — 変数に代入され、トースト/アラート呼び出しに渡され、または.textContent/.innerTextで設定されたコピーは、マークアップだけでなくスクリプトブロックにも存在します。マークアップのみの grep では実際の検証文字列を見逃します。
3. 修正 — 1つのアトミックな変更
編集する前に、以下を確認します:
- これは実際のユーザー(スクリーンリーダー、キーボードのみ、またはトーンを読んでいる人)にとって本当に不明瞭またはアクセス不能なものですか? — 私のスタイル上の好みではありませんか?
- 修正はプレゼンテーション/コピーのみに触れますか? — ロジック、バックエンド、新しい依存関係はありませんか?
- このパターンに対してコンポーネントライブラリの同等品はすでに存在しますか? 存在する場合、生のHTML修正を手作りする代わりにそれを使用します(リポジトリにすでに status/banner コンポーネントがある場合、生の
<div>にrole="alert"をボルトオンしないでください)。
ベースライン検証: 編集前にリポジトリのリント/型チェック(および高速であればテストスイート)を実行します — 後で誤った属性にならないよう、既存の失敗をメモします。
サイズ予算: マークアップ/構造修正の場合は変更行数≤50行、純粋なコピーテキスト修正の場合は≤10行。1回の実行につき1つのコンポーネントまたはページ。
オフリミットパスには決して触れません。実際の修正がオフリミットパスに触れる必要がある場合は、停止して他の場所に強制しない理由を報告します。
4. 検証と提示
リント/型チェック(およびステップ3でテストを実行した場合はテスト)を再実行します — あなたの変更が新しい失敗を導入した場合のみ中断します。既存の失敗はここで修正するものではありません。差分を表示します。停止 — コミットせず、PRを開かないでください。
してはいけないこと
-
1回の実行で複数の問題をフラグ付けまたは修正してはいけません 代わりに: 最初の実際のヒットでスキャンを停止し、修正し、提示します。 理由: バッチ処理されたa11y/コピーの差分は個別にレビューするのが難しく、どの特定の修正がリグレッションを引き起こしたかを隠します。
-
コンポーネントライブラリの同等品がすでに存在する場合、生のHTML修正を手作りしてはいけません 代わりに: リポジトリ自身の
Button/Input/Link/status-banner コンポーネントを使用します。 理由: 並行して行う一回限りの修正は、リポジトリの残りが既に依存している1つに収束する代わりに、2つ目の矛盾したパターンを作成します — 次の監査でドリフトとして再フラグ付けされます。 -
skills.a11y.notesまたは汎用的で明確にラベル付けされたデフォルトに裏付けられていないコピートーンルールを発明してはいけません 代わりに: 設定駆動の許可/拒否リストを使用するか、汎用のデフォルトパターンにフォールバックしていることを明示します。 理由: その場で発明されたルールは再利用可能でも次回の実行で監査可能でもなく、リポジトリの実際のハウススタイルと矛盾する可能性があります。 -
マークアップのみをスキャンし、コピー文字列のために
<script>ブロックをスキップしてはいけません 代わりに:<script>ブロック内の文字列リテラルもgrepします — 検証およびフィードバックコピーは頻繁にそこで代入され、テンプレートに直接書き込まれません。 理由: 実際のユーザー向け文字列はテンプレートに補間される変数であることが多く、マークアップのみのgrepは補間サイトに一致し、実際の違反テキストには一致せず、修正すべきものを報告しません。 -
オフリミットパスに触れたり、コミットしたり、PRを開いたりしてはいけません 代わりに:
skills.a11y.off-limitsと組み込みのガードレールを尊重します。差分を提示した後で停止します。 理由: このスキルの役割は「検証済み差分、人間のレビュー準備完了」で終了します — コミットしたり除外パスに触れたりすると、ワークフロー全体が依存しているレビューゲートが取り除かれます。
ファイル
references/scan-core.md— コアチェック(フェーズ1で読み込み)evals/— ai-forge-eval アサーション