Limit competitor substitution to brand-differentiation claims, add impact-scoped render measurement guidance to audit-gate, and correct motion, Range, and font-check wording found during review.
28 KiB
audit-gate — 자율 검증 폐쇄 루프
5단계(감사)를 완료 선언의 게이트로 만드는 문서다. 핵심 원칙은 하나다:
완료는 기능·프로젝트 계약·렌더 시각 평가가 함께 확인된 상태다. 사용자를 QA 로 쓰지 않는다.
"고쳤다"는 말의 근거는 검증 리포트의 수치와 실제 렌더 평가다. 게이트가 실패 항목을 내면 4단계로 돌아가 고치고, 변경한 영역과 연결된 회귀 위험을 다시 검사한다. 프로젝트가 정한 전체 검증 계약은 그대로 수행한다. 이 루프(구현 → 게이트 → 실패 → 수정 → 재게이트)가 designpaca의 기본 동작이며, 기능·접근성 자동 검사와 시각 평가(위계·브랜드·타입·구도·이미지·리듬)는 별도 결과로 보고한다.
왜 필요한가 — 실제 사고 목록
이 게이트의 각 검사는 사용자 보고로야 발견됐던 결함에서 왔다. 어느 검사가 어느 사고를 잡는지가 설계 근거다.
| 사고 (실제) | 검사 |
|---|---|
| CSS 닫는 중괄호 누락 — 이후 규칙 절반이 죽은 채 렌더 | stylelint(구문) + 중괄호 균형 |
| 브랜드가 모바일에서 1글자 폭으로 수축, 세로로 쌓임 | 수축 탐지(짧은 라벨 n줄 이상) + 브랜드 1줄 |
| 기기 글꼴 확대(안드로이드 큰 글꼴 1.3×)에서 제목 부서짐 | 스케일×폭 h1 행렬 |
| 본문 보조색이 배경 대비 4.4:1 (AA 미달) | 전 요소 대비 스캔(블렌드 계산) |
CSS color-mix()의 computed color(srgb …)를 0~255 rgb로 오독해 정상 대비를 1:1로 거짓 실패 |
CSS Color 4 color(srgb 0~1) 파싱 + 알파 합성 RED fixture |
.sr-only·aria-hidden 장식·빈 overlay의 범위를 보이는 셀/버튼 글자로 합산해 0px 여백 거짓 실패 |
text node 단위 실측 + 비가시 조상 제외. 화면에 보이는 글자만 인셋 판정 |
| 조사만 하고 안 고친 영역(관심 과목 등) | 전 뷰 순회 — 검사는 '내가 고친 것'이 아니라 전체 표면 |
| 대시보드 26명 ↔ 명단 12명 숫자 모순 | 콘텐츠 정합(요약 = 재계산 비교) |
| aria-label 을 div/ul 에 오용(보조기술 무시) | html-validate + axe |
dl 안 <p>, role="grid" 자식 구문 위반 |
html-validate + axe |
| 계산 로직 오류(행 배열을 값으로 셈 → 0/3) | 단위 테스트(브라우저 밖 경계값) |
| 같은 데이터 속성이 여러 뷰에 존재해 선택자 오작동 | 하니스 규칙: 선택자는 컨테이너 스코프 |
| 혼합 span 그리드의 자동 배치가 시간 라벨을 흩어놓음(같은 열 폭 40/78 혼재, Δ 불규칙) | 리듬·트랙 불변식 — 같은 부모·같은 클래스 형제 중 (a) 숫자/시간 라벨(등폭 의도)과 (b) 빈 격자 셀(트랙 균일 의도)은 폭이 균일해야 하고, 한 축 정렬·크기 균일 형제는 등간격이어야 한다. 한국어 라벨은 글자수가 같아도 내용 폭차가 자연스러우므로 폭 검사 대상에서 뺀다(오탐 방지). 근본 수칙: 혼합 span 그리드는 자동 배치를 믿지 않고 좌표를 명시하라 |
| 프리셋 전환(v7)에서 브랜드 표면이 누락 — theme-color·파비콘이 종이 시대 값으로 11버전 생존 | theme-color 정합(메타 값 ↔ 실제 배경색 비교) + 파비콘·og:image 존재. 토큰 마이그레이션은 브랜드 표면 3종을 갱신하기 전까지 끝나지 않는다 |
| 컴포넌트 제거 시 CSS/JS 잔존 — 미사용 선택자 12종·이중 계산 블록(첫 블록이 즉시 덮임) | 죽은 선택자 검사(CSS 클래스 ↔ HTML·JS 텍스트 사용률 대조). 제거는 HTML·CSS·JS 삼위일체 |
| 크롬에 컨트롤 1개 추가 → 그 줄의 최소폭 합 초과(320px +18px) | 오버플로 전 폭 검사(기존) + 규칙: 크롤에 컨트롤을 더하면 최소폭 합을 가장 좁은 폭에서 다시 잰다 |
| 같은 명시도의 숨김 규칙이 기본 규칙보다 앞에 있어 짐 — 모바일에서 숨기려던 kbd 안내가 렌더됨(6% 시각 diff) | 시각 회귀 + 규칙: 숨김 오버라이드는 기본 규칙보다 파일 뒤쪽에 두거나 컴포넌트 규칙 근처의 미디어쿼리로 |
| 탐색 차터가 결과를 단언하지 않아 "9288점" 입력이 조용히 통과(값을 덧붙인 타이핑) | 하니스 규칙 8(검사는 단언)·9(number 입력 조작) |
| 모바일 라운드 — 중앙 모달이 썸존 밖, 백 키가 앱을 통째로 종료, safe area 무시, 입력 확대 | L6 시나리오(백·시트·터치타깃 스윕) + references/mobile-app-ux.md 표준 — OS 관습은 조사 없이 바꾸지 않는다 |
전역 * { margin: 0 }가 native dialog의 UA 중앙 여백을 지워 좌상단에 고정, 짧은 화면의 패널은 고정 크롬에 눌려 내부 scroll이 0px |
dialog의 fixed/inset/margin:auto를 명시하고 390·1440·2560 중심 오차, viewport rect, html scroll lock, short-height scroll owner를 hard fail로 측정. 모달 행동은 WAI-ARIA APG를 따른다 |
| 2560px 분할 히어로에서 사진이 1400px 이상으로 팽창하고 카피 열은 200px 안팎으로 붕괴 | hero·copy·media·후속 정보 레일의 rect 계약. stage/media/copy/workbench 토큰을 분리하고 media 상한·copy 최소폭·정렬을 hard fail로 측정 |
| 탭 전환 스크롤 잔류 — 짧은 뷰에서 클램프되어 헤더 반쯤 잘림, 뷰마다 크롬 위치 제각각 | 뷰 전환 scrollTo(0,0) 단언(M5) + mobile-app-ux.md |
| 크럼을 헤더로 내보내 빈약한 헤더 — 계측 전부 통과했지만 사용자에게 '깨져 보인다' | 헤더 sticky·브랜드+액션 구조 단언 + 시각 무게 평가(눈) — mobile-app-ux.md |
| 왼쪽 인셋 리듬 불일치(제목 16 vs 앱바·카드 24) — 오버플로 검사는 오른쪽만 보므로 통과 | M6 왼쪽 인셋 스위트(텍스트 시작점 ≥12px·같은 축 ±10px) + preflight §0-E |
모바일에서 절대 배치 지도 자식의 부모를 position: static으로 바꿈 — offsetParent가 BODY가 되어 격자·핀이 히어로 전체를 덮음. 기하 게이트 8/8 통과 |
상태별 실제 캡처를 열어 보는 시각 E2E + absolute/fixed 자식의 containing block 단언(하니스 규칙 19) |
새 관리자·가맹 서브페이지가 생겼지만 public/work/*/index.html만 검사 — 새 HTML 오류 8건이 검증 밖 |
정적 입력을 public/work/**/*.html·**/*.css로 재귀화 + 검사 대상 파일 수 단언(하니스 규칙 20) |
| 마케팅 h1의 의도적 2줄 때문에 범용 줄 수 규칙을 강제할 위험 | 페이지별 읽기 폭·문구·글꼴 확대의 계약을 기록하고 375·390 × 글꼴 확대에서 실제 줄 수와 가독성을 판정. 줄 수를 맞추려고 글자 크기를 축소하지 않음 |
7계층
tools/design-gate.mjs 가 한 파일로 돌리는 것과 프로젝트가 보강하는 것이 있다.
| 계층 | 도구 | 비고 |
|---|---|---|
| L0 정적 | stylelint + html-validate | 문법·구문 위반을 브라우저 켜기 전에 |
| L1 단위 | 순수 계산 로직 추출(calc.js) + 경계값 테스트 | 프로젝트별 작성 — 0명/만석/초과/빈배열. 입력 검증·신청 가능 같은 '판정'(가능/불가+사유)도 여기 둔다 — UI 는 판정을 문장으로 번역만 |
| L2 불변식 | design-gate.mjs — 오버플로·제목 존재/가시성·수축·대비·SEO/meta·죽은 선택자·토큰 위생·theme-color 정합. 명시한 양의 h1MaxLines만 줄 수 계약으로 검사 |
전 뷰 × 전 폭 |
| L3 시각 회귀 | 기준 화면 pixelmatch diff (≥0.1% 실패) + 핵심 상태 캡처 | 갱신은 검증된 배포 후 --update-baseline. 캡처 존재와 사람의 시각 판정은 별개다 |
| L4 WebKit | Playwright webkit | 사파리 엔진 렌더 차이 |
| L5 탐색 | 키보드 완전 통과 + 사용자 여정 차터 | 프로젝트별 작성 — 마우스 금지 |
| L6 시나리오 E2E | 실사용자 여정 재현 — 페르소나의 하루·장기 과업 포함 | 프로젝트별 작성. 기대값 단언 필수(하니스 규칙 8), 백 키·시트·양방향 흐름은 mobile-app-ux.md 패턴 기준. 실측: RED 1,742 단언 중 318 실패가 신규 기능에 정확히 집중 — 시나리오를 먼저 쓰면 미구현이 수치로 드러난다 |
렌더 측정 계약
자동 측정은 실제 장면을 재현할 때만 의미가 있다. 새 범용 JS 엔진을 만들라는 뜻이 아니다. 프로젝트의 기존 E2E·시각 회귀 도구에 아래 계약을 적고, 페이지와 기능의 위험에 맞는 단언만 구현한다.
1. 장면과 레이아웃
각 artifact에는 빌드·revision 식별자, URL, viewport의 너비·높이·종횡비·zoom, 스크롤 위치, UI 상태, 로드한 폰트·이미지·영상 자산을 함께 남긴다. 폭만 적어서는 같은 폭에서 높이가 달라진 크롭, 짧은 화면의 고정 크롬, 확대에 따른 줄바꿈을 재현할 수 없다. 짧은 가로·긴 세로·확대가 결과에 영향을 주면 대표 장면에 포함한다. 배경 위치, 분기 종횡비, 헤더 높이, viewport 단위 선택은 프로젝트 계약으로 정한다.
화면 맞춤 hero는 헤더가 overlay인지, 문서 흐름에서 높이를 차지하는지 먼저 구분한다. 그 역할을 포함해 첫 화면의 남은 높이를 재고, 내용이 고정 높이보다 커지면 자연스럽게 확장되어야 한다. 모든 페이지 섹션에 100vh를 강요하지 않는다. 컨테이너의 overflow=0만으로 피사체·카피·행동의 안전 영역이 보존됐다고 판정하지 말고, 실제 크롭과 인접 콘텐츠의 겹침을 화면에서 확인한다.
2. 모션과 상태
reveal·전환은 실제 UI 스크롤·클릭·키보드 이벤트로 장면을 먼저 활성화한다. 그 장면에 필요한 폰트·이미지가 준비된 뒤 대상과 전환에 관여하는 조상 요소의 유한 전환 완료를 관측하고, 프로젝트가 의도한 최종 가시성·색·대비·위치에 도달했는지 확인한다. 최종 가시성은 opacity: 1을 일괄 요구하는 값이 아니다. 의도한 반투명 텍스트도 조상 opacity 합성을 포함한 실제 대비와 상태 계약으로 판정한다. 정한 상한 시간 안에 끝나지 않으면 실패 또는 미검증으로 기록하고 원인을 남긴다.
계속 움직이는 배경·카운터·캔버스는 별도 상태 계약으로 관측한다. 모든 페이지 애니메이션이 끝날 때까지 기다리는 검사는 만들지 않는다. 정지 상태의 대비, 일반 설정에서 trigger와 완료가 실제로 작동하는지, prefers-reduced-motion 경로를 각각 보고한다. 안정한 정상 상태의 대비가 영구 애니메이션의 저대비나 발화 실패까지 통과시키지 않는다.
고정 sleep, 검사 중 opacity: 1 강제, animation: none 주입으로 제품 모션 검사를 GREEN으로 만들지 않는다. 썸네일·OG용 정지 프레임은 별도 산출물이다. 그 경우에는 완성된 프레임을 고정하고 축소 모션을 적용할 수 있지만, 실제 동작 검수의 대체가 아니다.
3. 텍스트·클리핑·폰트
Range.getClientRects()는 선택 범위의 요소 box와 텍스트 font metric에 따른 사각형이며 글리프 잉크 경계가 아니다. heading·line box 밖 rect만으로 실제 잘림을 확정하지 않는다. viewport 밖 rect는 가시성 후보로 계속 검사하되, viewport와 실제 overflow clipping 조상을 함께 추적한다. clip-path·mask·transform처럼 rect만으로 설명하기 어려운 경계는 실제 렌더를 열어 수동 판정한다. 텍스트 후보가 보이면 인접 콘텐츠와 겹치거나 읽기 영역을 침범하는지도 함께 확인한다. CSSOM View의 Range.getClientRects() 편집 초안을 2026-09-20에 확인했다.
document.fonts.ready와 FontFaceSet 상태는 로드 준비의 근거일 뿐, 모든 화면 문자가 의도한 폰트로 그려졌다는 증명은 아니다. 필요한 문자·언어·숫자·기호와 웨이트를 실제 카피로 렌더하고, 브라우저가 제공하는 rendered-font 확인 또는 필요한 글리프 검증과 화면 관찰을 결합한다. 폰트 선택·subset·fallback의 세부 절차는 typography.md를 따른다.
4. 실패와 증거
실패는 제품 결함, 측정기 오류, 계약 변경으로 분류한다. 실패 artifact와 원문 결과는 보존한다. 의도 변경 근거와 전후 렌더 증거 없이 기대값을 고치거나 assertion을 완화해 통과시키지 않는다. 측정기가 틀렸다면 UI를 먼저 고치지 말고 RED 재현을 남겨 측정기를 고친 뒤 같은 사례를 GREEN으로 확인한다.
artifact 한 건에는 빌드·revision, viewport·zoom·스크롤·상태, 기대값과 관측값, 자동 결과, 실제 화면의 시각 판정을 같이 남긴다. 수치와 스크린샷이 서로 다른 장면이면 증거가 아니다.
| 작은 재현 예제 | 재현 조건 | 정상 기대 | 오판 / 금지되는 처리 |
|---|---|---|---|
| reveal 진행 중 / 완료 뒤 저대비 | 실제 스크롤로 reveal을 시작한 직후와 유한 전환 종료 뒤를 각각 캡처한다 | 진행 중 프레임은 완료 판정에서 제외하고, 종료 뒤에는 의도한 색·합성 대비와 가시성을 확인한다 | sleep 한 번 뒤 진행 프레임을 PASS로 쓰거나, 종료했지만 실제 색 대비가 부족한 텍스트를 통과시킨다 |
| line box 넘침 / 실제 hidden 조상 clip | 같은 긴 문장의 실제 잉크가 heading·line box 밖으로 나가게 두고, 한쪽은 overflow: visible, 다른 쪽은 잉크가 경계를 넘는 overflow: hidden 조상 안에 둔다 |
전자는 실제 잉크와 인접 영역을 보고 보존 여부를 판정하며, 후자는 실제 clip을 화면에서 확인한다 | Range rect 하나로 두 사례를 모두 잘림 또는 모두 정상으로 확정한다 |
| 같은 폭, 다른 높이의 피사체 크롭 | 같은 폭의 이미지 장면을 짧은 viewport와 긴 viewport에서 header 역할·스크롤 위치를 같게 맞춘다 | 피사체와 행동의 안전 영역이 두 높이에서 의도대로 남는지 비교한다 | 폭만 기록해 짧은 화면에서 잘린 얼굴·문구를 놓친다 |
| 의도 변경 없는 낡은 expected 값 | 렌더가 달라졌지만 디자인 의도 변경 기록이 없는 시각 회귀를 만든다 | 기존 기대값을 유지하고 제품 결함 또는 측정기 오류를 분류한다 | diff를 없애려고 expected·baseline만 무단 갱신한다 |
설치 (프로젝트에 게이트 심기)
node <스킬>/tools/design-gate.mjs --init # gate.config.json 초안
# pages[].views 를 실제 뷰 목록으로, viewAttribute 를 data-view 등으로
npm i -D puppeteer-core # CHROME_PATH 또는 자동 탐색
package.json: "verify": "node <스킬>/tools/design-gate.mjs"
배포는 항상: npm run verify && build && deploy # verify 실패(exit 1)면 배포 불가
L1·L5 는 프로젝트 안에 tools/unit/*.test.mjs, tools/exploratory.mjs 로 보강하고 verify 체인에 묶는다. 근거와 완성 예는 designpaca 저장소 apps/site/tools/ 가 정본 샘플이다.
SEO / meta 감사 (design-gate 내장)
조사 기준(2026): title 1065자·유일, description 60165자, viewport, html lang, charset, canonical(프로덕션), og:title/description/image/url, twitter:card, favicon, h1 유일, img alt 전부, JSON-LD 파싱. 데모·로컬 페이지는 canonical/robots 없음을 허용한다 — 검사는 맥락을 존중하되 나열 근거는 리포트에 남긴다.
OS · 브라우저 특성 — 검사에 반영할 것
- Windows: 스크롤바가 오버레이가 아니다 —
overflow-x:auto짝에는overflow-y:hidden+scrollbar-width검토. 스크롤바 자체가 레이아웃을 민다. - iOS/Safari(WebKit):
100vh주소창 문제(100dvh), 텍스트 인플레이션(-webkit-text-size-adjust:100%), WebKit 만의 flex/행높이 차이 → L4 로 재검. - 안드로이드: 시스템 글꼴 확대는 제목·컨트롤을 수축시킬 수 있다. gate의
fontScales와 computed root 스케일은 회귀 신호일 뿐, px 고정 서체의 실제 OS 확대를 보장하지 않는다. 실제 접근성 확대와 WCAG 200% zoom은 별도 브라우저·기기 검증으로 보고한다. - 폰트 스왑:
font-display: swap의 CLS — 폴백 메트릭 보정(typography.md §4) 없이 검사 통과를 선언하지 않는다.
하니스 규칙 (테스트를 만드는 테스트)
- 선택자는 스코프필수 — 같은 data-* 가 다른 뷰에 있으면 숨은 요소를 잡는다(
#as-table [data-assign]처럼). - page.evaluate 클로저 금지 — Node 스코프 함수를 페이지 안에서 부르지 않는다. 측정 코드는 문자열로 주입.
- 줄 수 측정의 오탐 두 종류 — 폰트 메트릭 top 차이(±5px 허용오차), 인라인 아이콘과 텍스트의 top 차이(텍스트 노드만 분리 측정). line box와 실제 글리프 잘림의 구분은 렌더 측정 계약을 따른다.
- CSS 수정 직후 검증은 캐시 차단(
setCacheEnabled(false)) + 실제 로드된?v=확인. - 비전(모델) 검수는 '여부'가 아니라 '지점 평가'에만 — 여부는 계측으로.
- 모달 닫힘 직후 포커스 강탈 — 뷰 전환+타깃 포커스는 한 evaluate 로, settle 후 유실 재포커스.
- 게이트를 통과해도 리포트에 수치를 남긴다 — "ALL PASS"가 아니라 "무엇을 몇으로 확인했나".
- 검사는 단언한다 —
pass("차터", st)처럼 상태를 상세로만 찍는 건 검사가 아니다. 실측 사고: 점수 입력에 "88"을type()하면 기존 값에 덧붙어 "9288"이 되었고, 차터는 상태 텍스트만 인쇄해 통과했다. 기대값과 비교해 pass/fail 을 내라. - number 입력은 선택-덮어쓰기가 안 된다 — 트리플 클릭 선택이 무시된다. 값을 비우고 타이핑하거나
el.value = x; dispatchEvent(new Event("input"))로 설정한다. - 등장 모션과 캡처 상태를 맞춘다 — 모션 지속시간은 사용자 경험의 목적·입력 반응·감소 모션 계약으로 정한다. 시각 회귀는 그 값을 줄이라고 요구하지 않고, 실제 완료를 관측한 뒤 캡처한다. 임의 sleep으로 진행 프레임을 통과시키지 않으며 실제 모션 검수는 렌더 측정 계약을 따른다.
- 같은 diff 수치가 반복되면 패치가 적용되지 않은 것 — 수정하고도 시각 diff %가 소수점까지 동일하면 수정이 렌더에 닿지 않았다(캐시·캐스케이드 순서·잘못된 파일). 고치기를 반복하지 말고 적용 자체를 의심해라.
- 페이지→노드 직렬화는 NaN 방어 —
getComputedStyle(el).fontSize등을 문자열 보간하면 "16px"이 NaN이 되고, 하니스는 NaN을null로 받아"////px"같은 고장난 상세를 리포트한다. 수치는 항상parseFloat(x) || 0로 감싼다. position: fixed요소의 보임 판정은 offsetParent 로 하지 마라 — fixed 는 offsetParent 가null이다. display 계산값·높이로 판정한다.- 실기기(에뮬레이터) 검증은 텍스트 근거로 —
uiautomator dump의text="…"에서 화면 제목·활성 탭을 읽어 단언한다. 스크린샷+비전은 "백 직후 전환 중 프레임"을 잡는 타이밍 오탐이 있다(실측 사고). 물리 폰이 붙어 있으면adb -s <emulator>로 대상을 한정한다. - 시각 기준 갱신은 의도 변경 리뷰를 동반한다 — "달라졌으니 갱신"으로 결함이 기준에 박힌다(실측: 왼쪽 인셋 결함 화면이 기준 갱신으로 '정상'이 되어 재발을 숨겼다). 갱신 전에 무엇이 의도적으로 바뀌었는지 한 줄씩 나열하고, 사용자 보고가 있던 화면은 수리 후 재촬영한다. 증거 보존과 실패 분류는 렌더 측정 계약을 따른다.
- 사용자 보고 스크린샷은 비전 요약이 아니라 픽셀 판정으로 해부한다 — 비전 모델의 픽셀 추정("~0px", "~16px")은 부정확하다. pngjs 등으로 화면을 가로 밴드로 나눠 각 밴드의 텍스트 시작 x를 직접 재면(보임 행만, 왼쪽 테두리 아티팩트 제외) "무엇이 어디서 어긋났는지"가 수치로 나온다. 실측: '제목이 가장자리에 붙는다'는 보고가 앱바 24px·제목 16px의 리듬 불일치로 확정됐다.
- 새 검사는 수정 전 코드로 RED 재현 후 GREEN — 검사 자체의 측정 하자(오탐)도 이렇게 잡는다. 실측: 왼쪽 인셋 검사 초안이 ①
display:none요소의 rect=0, ②전폭 컨테이너의 보더박스(텍스트가 아님)로 38개 오탐 — RED 단계에서 발견해 교정했다. - 시각 E2E는 기본 화면만 찍지 않는다 — URL별 390·1440 기본 화면에 더해 결과가 바뀐 입력, 오류/검토, 모달/차단 상태를 찍는다. 하니스는 파일 개수·가로세로·0바이트·해시 중복을 단언하고, 에이전트는 파일을 실제로 열어 시장 적합성·위계·크롭·반복을 판정한다. 스크린샷을 저장했다는 사실만으로 PASS하지 않는다.
- absolute/fixed 자식은 containing block을 잰다 — 모바일 미디어쿼리에서 부모의
position을 바꿨다면 각 절대 배치 자식의offsetParent또는 기준 rect가 의도한 컨테이너인지 단언한다.overflow-x:hidden으로 누수를 숨기지 않는다. - 정적 검사는 재귀 입력과 대상 수를 잠근다 — 서브페이지가 생기는 저장소에서 한 단계 glob은 금지한다. 실행 전에 발견한 HTML/CSS/JS 파일 수를 출력하고 0개 또는 이전 계약보다 적으면 실패시킨다.
- 시나리오·단언·캡처 수를 hard-lock한다 — 대규모 E2E는
EXPECTED_SCENARIOS,EXPECTED_ASSERTIONS,EXPECTED_CAPTURES를 둔다. 리팩터링으로 검사가 삭제돼도 전체가 조용히 GREEN이 되지 않게 한다. 수를 채우기 위한 중복 단언은 금지하고 공통·정상·오류·부작용·접근성·시각 상태로 분류한다. - 사용자 승인과 검증 결과는 다른 상태다 — 사용자가 방향 게이트를 자율 승인했어도 기계·기능·시각 게이트는 면제되지 않는다. 승인됨/검증됨을 보고서에서 별도 표기한다.
- 혼합 액션 행은 직접 자식 hitbox 중심을 비교한다 — 같은 액션 묶음·같은 행의 직접 자식인 채운 버튼과 텍스트 링크가 둘 다 44px 이상인지,
rect.top + rect.height / 2차이가 브라우저 CSS 픽셀 2px 이하인지 단언한다. 중첩 아이콘·배지나 모바일 세로 스택은 비교 대상이 아니다.align-items:center선언 존재는 검사가 아니다. - 연속 섹션 토폴로지를 목록화한다 — 섹션별
역할 / DOM 골격 / 회색조 실루엣을 적는다. 역할이 다른 연속 3개가 같은제목+목록골격이면 시각 RED다. 반복 데이터처럼 같은 골격이 맞는 경우는 이유를 기록한다. - 조건부 패널의 닫힘은 트랙 회수까지 단언한다 — 데스크톱 분할 작업대는
display:none만 검사하지 않는다. 인스펙터가 닫히면 주 표면의 오른쪽 끝과 작업대 끝 차이가 CSS 픽셀 2px 이하인지, 다시 선택하면 분할 트랙이 복원되는지 잰다. 모바일 시트·전체 화면 패널은 트랙 대신 닫힘·배경 복귀·포커스 복원을 검증한다. - 진실 라벨은 개수가 아니라 의미 범위를 단언한다 — 같은 상태·출처·행동 가능성을 공유하는 자식은 제목과 경계가 분명한 가장 가까운 공통 부모가 한 번 소유하고 프로그램적으로 연결한다. 상태가 다른 자식만 예외 라벨을 둔다. 같은 공개 문구가 한 그룹의 모든 자식에 복제되면 범위 설계를 다시 본다.
- 보이는 입력과 판정 의존성을 같은 SSOT로 잠근다 — 폼의 사용자 조건 이름 집합과 순수 판정 함수가 참조하는 사용자 조건 집합을 비교한다. 숨은 기본값을 사용자 선호로 세지 않고, 보이는 입력을 무시하지 않으며, 분석 전 완료 결과가 없고 복합 비용 일부로 적합을 확정하지 않는지 단언한다.
- 공개와 관리 콘텐츠 소유권을 테스트한다 — 공개 DOM에는 내부 ID·원문 출처 원장·규제 채널 상수·감사 로그를 복제하지 않는다. 대신 사용자 행동을 막거나 바꾸는 제한과 해석 가능한 이유는 남긴다. 관리자는 그 요약을 재현하는 출처·검증 이벤트·판정 기록을 가진다.
- 색·가시성 측정기는 새 CSS 문법과 보이는 텍스트를 구분한다 — computed color가 CSS Color 4
color(srgb r g b / a)이면 01 채널을 0255으로 변환하고, 반투명 배경은 자식에서 부모 방향으로 올바르게 합성한다.Range.selectNodeContents()로 sr-only·aria-hidden장식·빈 overlay까지 합산하지 말고 실제 보이는 text node의 rect만 잰다. 두 경우 모두 UI를 고치기 전에 RED fixture → 파서 수정 → 같은 fixture GREEN 순서로 검사기 자체를 검증한다. - native dialog의 위치를 UA 스타일에 맡기지 마라 — 전역 reset은 dialog의 기본 margin을 지울 수 있다. open 상태에서
(left + width/2, top + height/2)와 viewport 중심의 오차, 화면 안 rect,htmloverflow, Escape 뒤 복귀를 390·1440·2560에서 측정한다. 내용이 길면 dialog 또는 내부 본문 하나만 scroll owner여야 한다. - 초광폭 히어로는 비율 계약을 잰다 — 2560 같은 실제 wide viewport에서 hero 폭/정렬, copy 최소 폭, media 최대 폭, 다음 정보 레일 폭을 함께 단언한다. media만 넓고 카피가 가늘어지는 상태를
overflow=0으로 통과시키지 않는다. 절대 수치는 페이지별 토큰이 소유하며, 풀블리드 편집 사진 예외는 이유를 기록한다. - 캐시 무효화도 사용자 화면에서 단언한다 — static CSS/JS를 덮어쓴 뒤 HTML만 새 URL이면 브라우저는 이전 stylesheet를 계속 쓴다. stylesheet와
@import의 버전을 같이 바꾸고, 공개 URL에서 실제 href·새 토큰/핵심 computed value를 검사한다. HTTP 200과 새 HTML만으로 배포 성공을 선언하지 않는다. - 썸네일은 안정한 프레임만 저장한다 — 캡처 전 local HTTP 경로에서
document.fonts.ready·모든 이미지decode()·bounded settle을 기다리고,prefers-reduced-motion: reduce를 적용한다. 그 뒤 video/audio·CSS/WAAPI·rAF canvas를 멈추고, local 4xx·pageerror·깨진 이미지가 하나라도 있으면 실패시킨다. 원리는animation:none으로 초기 상태를 재현하는 것이 아니라 완성된 한 프레임을 고정하는 것이다. 이는 실제 모션 검수와 별도다. 카드·OG·핵심 상태가 같은 계약을 공유하는지 파일 치수·0바이트·시각 검수까지 단언한다. - 초광폭 text-media split은 가족별로 잰다 — hero가 통과했다고 과정·추천·가맹 분할이 통과한 것이 아니다. 서로 다른 DOM/여백 규칙을 가진 각 split root에서 1920·2560의 rail, copy/media rect, heading의 실제 내용 폭과 줄 수를 hard fail로 기록한다. wide override는 양쪽 logical padding을 명시하고, 상위 container의
max-width가 specificity 때문에 named stage를 다시 줄이지 않는지 단언한다. grid 바깥 rect가 정상이어도 text content가 한 글자 열로 수축하면 실패다.
리포트 양식
게이트: 기능·접근성 자동 검사 / 시각 평가를 별도 보고 · 총 Ns
| 범주 | 결과 | 항목 | 소요 | 근거 |
실패 상세는 원문 테일 포함. 시각 평가는 같은 viewport·상태·자산을 전후로 보존해 위계·브랜드·타입·구도·이미지·리듬을 기록한다. 사용자 성과의 인과나 취향 우승을 검증 없이 주장하지 않는다. 리포트 파일(gate-report.md / verify-report.md)은 커밋 대상이다.