Tend A11y — the herald
이 저장소의 마크업에서 가장 높은 우선순위의 접근성, UX, 또는 카피 톤 이슈를 하나 찾아내고, 최소한으로 수정한 후 검증하여 검토용 diff를 제시합니다. 한 번 실행에 하나의 이슈만 처리합니다.
0. 설정 로드
.claude/tend/config.yaml을 읽습니다.skills.a11y(제외 경로(globs),notes)를 사용합니다. 이 스킬은 기능 모듈(capability modules)이 없습니다. 모듈 게이팅 단계를 완전히 건너뛰며, 여기에는modules:게이팅 단계가 없습니다.- 설정이 없나요? 코어 티어로 실행합니다: 코어 SvelteKit + TS 가정, 보수적인 내장 제외 경로(절대 lockfiles, CI,
.env, 설정을 건드리지 않음). 한 번 출력: "tend-onboard를 실행하면 설정이 선명해집니다." 계속 진행합니다.
1. 분류
references/scan-core.md를 반드시 읽으세요.
- 제외 경로 집합을 설정합니다: 설정의
skills.a11y.off-limits+ 내장 레일(절대 lockfiles, CI 설정,.env, 프로젝트 설정, 또는 백엔드/API 라우트 로직을 건드리지 않음 — 이 스킬은 프레젠테이션 전용입니다). - 진입점을 설정합니다: 이 저장소의 마크업 파일 —
.svelte컴포넌트,+page.svelte/+layout.svelte라우트, 또는 스택이 실제로 사용하는 템플릿 파일.skills.a11y.notes에서 명명된 컴포넌트 라이브러리 디렉토리(예:src/lib/components/ui)를 확인합니다. 있다면, 해당 디렉토리의 내보내기(export)가 2단계에서 "원시 HTML 대신 사용할 대상" 목록이 됩니다. - 스캔하기 전에 기존 컴포넌트 1-2개를 읽어 저장소의 실제 컴포넌트 라이브러리 및 상태/로딩 관례를 학습합니다. 실제 패턴을 파악한 후에야 그 패턴에서 벗어난 것을 위반 사항으로 부를 수 있습니다.
완료 기준: 제외 경로 집합 파악, 컴포넌트 라이브러리 관례(있는 경우) 식별, 진입점 글로브(glob) 식별.
2. 스캔 — 우선순위 순서, 첫 번째 실제 적중에서 멈춤
가장 가치가 높은(사용자에게 가장 조용한) 순서대로 정렬 — 첫 번째 실제 증거 기반 적중에서 멈춥니다:
- 컴포넌트 라이브러리 대체제가 존재하는 원시 대화형 HTML — 저장소 다른 곳에
Button/Link/Input내보내기가 있음에도 원시<button>/<a>/<input>가 있는 경우. - 아이콘 전용 또는 아이콘 우선 대화형 요소에 접근 가능한 이름이 누락된 경우 —
aria-label, 시각적으로 숨겨진 텍스트,title폴백이 없음. alt가 없는<img>— 속성 누락이 위반 사항입니다. 장식용 이미지에 의도적인 빈alt=""는 위반이 아닙니다.- 연결된 레이블이 없는 폼 입력 —
label for=,aria-label, 또는 컴포넌트 라이브러리 레이블 prop이 없음. 템플릿뿐만 아니라 렌더링된 개수도 감사합니다: 루프({#each}또는 동등 구문) 안에서 생성된 입력은 런타임에 N개의 익명 컨트롤을 생성합니다. role="button"(또는 비대화형 요소의onclick)에 연결된 키보드 핸들러가 누락된 경우 — Enter + Space에 대한onkeydown. 네이티브<button>은 이를 자동으로 얻습니다. 이는 원시 요소 이스케이프 해치에서만 발생합니다.- 비동기 성공/오류/로딩 피드백이 평범하고 공개되지 않은 요소로 렌더링된 경우 —
role="alert"/role="status",aria-live, 또는 저장소 다른 곳에서 이미 사용 중인 기존 컴포넌트 라이브러리 배너/토스트 기본 요소가 없음. - 파괴적 작업(삭제/제거/재설정)이 적용되기 전에 확인 단계가 없는 경우.
- 카피 톤 위반, 설정 기반 허용/거부 목록(
skills.a11y.notes, 또는 그 목록이 가리키는 프로젝트 톤 문서)에 대해 확인. 저장소별 목록이 없으면, 일반 기본값으로 폴백: 검증/오류 지시 앞에 명령형 완화어 "Please"(예: "Enter a name" 대신 "Please enter a name"), 또는 일상적인 확인/안내 카피에 불필요한 느낌표 사용. 렌더링된 마크업 텍스트와<script>블록 내의 문자열 리터럴 모두를 스캔 — 변수에 할당된 카피, toast/alert 호출에 전달된 카피, 또는.textContent/.innerText를 통해 설정된 카피는 마크업이 아닌 스크립트 블록에 존재하며, 마크업 전용 grep은 실제 검증 문자열을 놓칩니다.
3. 수정 — 하나의 원자적 변경
편집 전에 다음 질문에 답하세요:
- 이것이 실제 사용자(스크린 리더, 키보드 전용 사용자, 또는 톤을 읽는 사람)에게 진정으로 불명확하거나 접근 불가능한가? — 내 개인적 스타일 선호도가 아닌가?
- 수정이 프레젠테이션/카피에만 영향을 미치는가? — 로직, 백엔드, 새 종속성은 건드리지 않는가?
- 이 패턴에 대한 컴포넌트 라이브러리 대체제가 이미 존재하는가? 존재한다면, 원시 HTML 수정을 직접 만드는 대신 그것을 사용하라(저장소에 이미
role="alert"를 포함하는 상태/배너 컴포넌트가 있다면 원시<div>에role="alert"를 덧붙이지 마라).
기본 검증: 편집 전에 저장소의 린트/타입체크(그리고 빠르다면 테스트 스위트)를 실행 — 나중에 잘못 귀속시키지 않도록 기존 실패를 기록해 둡니다.
크기 예산: 마크업/구조 수정 시 변경 줄 ≤50줄, 순수 카피 텍스트 수정 시 ≤10줄; 한 번 실행에 하나의 컴포넌트 또는 페이지.
절대 제외 경로를 건드리지 마십시오. 실제 수정이 제외 경로를 건드려야 한다면, 중단하고 다른 곳에서 강제로 처리하는 대신 그 이유를 보고하십시오.
4. 검증 및 제시
린트/타입체크(그리고 3단계에서 테스트를 실행했다면 테스트도)를 다시 실행 — 자신의 변경이 새로운 실패를 도입한 경우에만 중단합니다. 기존 실패는 여기서 수정할 대상이 아닙니다. diff를 보여줍니다. 중단 — 커밋하지 말고, PR을 열지 마십시오.
절대 하지 말 것
-
절대 한 번 실행에 하나 이상의 이슈를 표시하거나 수정하지 마십시오 대신: 첫 번째 실제 적중에서 스캔을 멈추고, 수정한 후 제시하십시오. 이유: 일괄 처리된 접근성/카피 diff는 개별적으로 검토하기 어렵고, 어떤 특정 수정이 회귀를 일으켰는지 숨깁니다.
-
절대 컴포넌트 라이브러리 대체제가 이미 존재하는데 원시 HTML 수정을 직접 만들지 마십시오 대신: 저장소 자체의
Button/Input/Link/상태 배너 컴포넌트를 사용하십시오. 이유: 병렬적인 일회성 수정은 저장소의 나머지 부분이 이미 의존하는 하나의 패턴으로 수렴하는 대신 두 번째 불일치 패턴을 만듭니다. 다음 감사에서 표류(drift)로 다시 플래그될 것입니다. -
절대
skills.a11y.notes나 일반적이고 명확하게 레이블된 기본값에 의해 뒷받침되지 않는 카피 톤 규칙을 발명하지 마십시오 대신: 설정 기반 허용/거부 목록을 사용하거나, 명시적으로 일반 기본 패턴으로 폴백하고 있음을 밝히십시오. 이유: 즉석에서 발명된 규칙은 다음 실행에서 재사용 가능하거나 감사 가능하지 않으며, 저장소의 실제 하우스 스타일과 모순될 수 있습니다. -
절대 마크업만 스캔하고 카피 문자열을 위해
<script>블록을 건너뛰지 마십시오 대신:<script>블록 내의 문자열 리터럴도 grep하십시오 — 검증 및 피드백 카피는 종종 템플릿에 직접 작성되지 않고 변수에 할당됩니다. 이유: 실제 사용자 대상 문자열은 종종 템플릿에 보간된 변수입니다. 마크업 전용 grep은 보간 지점만 일치시키고 실제 문제가 되는 텍스트는 일치시키지 않아 수정할 내용을 보고하지 않습니다. -
절대 제외 경로를 건드리거나 커밋/PR을 열지 마십시오 대신:
skills.a11y.off-limits와 내장 레일을 존중하고, diff를 제시한 후 중단하십시오. 이유: 이 스킬의 작업은 "검증된 diff, 사람 검토 준비 완료"에서 끝납니다. 커밋하거나 제외된 경로를 건드리면 전체 워크플로가 의존하는 검토 게이트가 제거됩니다.
파일
references/scan-core.md— 핵심 검사 (1단계에서 로드됨)evals/— ai-forge-eval 어설션