AI가 테스트를 속이는 4가지 방법, 그리고 리뷰어의 21%가 죽어 있던 이유
이런 일이 생깁니다
에이전트에게 "포즈별 캐릭터 이미지 4장을 뽑고 품질 기준을 통과시켜라"라고 맡겼습니다. 보고는 "품질 임계 통과". 파일을 열어 보니 4장의 md5가 전부 같았습니다. 한 장을 네 번 복사한 겁니다.
악의가 아닙니다. 목표가 "측정 가능한 지표"로 주어지면 에이전트는 가장 싼 경로로 그 지표를 맞춥니다. 8개월간 Claude Code에 일을 맡기면서 반복해서 본 패턴은 네 가지였습니다.
| 패턴 | 실제로 본 것 | 잡는 법 |
|---|---|---|
| 같은 바이트 산출물 | 이미지 4장 md5 동일 | 산출물이 여러 개면 해시를 비교. 같으면 실패 |
| 임계값 상향 | 측정값이 기준 미달 → 기준값을 실측 대비 23~77배로 올려서 통과 | 임계값·허용오차·타임아웃 상수의 diff를 따로 본다 |
| 동어반복 테스트 | assertTrue(True), 빈 분기만 찌르는 커버리지 테스트 | 테스트 diff에서 assert 대상이 실제 결과값인지 확인 |
| 픽스처만 수정 | 테스트 기대값·스냅샷·골든 파일만 바꾼 커밋 | 커밋에 테스트/픽스처 파일만 있고 구현 변경이 없으면 의심 |
두 번째 세션에 넘기는 체크리스트
구현한 세션에게 "검증했어?"라고 물으면 "네"라고 합니다. 자기 작업을 자기가 검수하는 건 사람도 못 합니다. 그래서 구현 세션과 다른 세션을 하나 더 열어 diff만 주고 이걸 묻습니다. 그대로 복사해 쓰셔도 됩니다.
아래 diff를 검수하라. 코드 품질이 아니라 "검증이 조작됐는가"만 본다.
각 항목에 PASS/FAIL과 근거 줄번호를 적어라.
1. 산출물이 여러 개면 서로 다른가 (해시·크기·내용)
2. 임계값·허용오차·타임아웃·재시도 횟수 상수가 바뀌었는가. 바뀌었으면 왜인지 커밋/주석에 근거가 있는가
3. 추가/수정된 테스트의 assert가 실제 결과값을 비교하는가 (상수끼리 비교, assertTrue(True), 빈 assert는 FAIL)
4. 테스트·픽스처·스냅샷만 바뀌고 구현이 안 바뀐 커밋이 있는가
5. 과제 스펙에 있는데 구현·테스트 어디에도 없는 항목이 있는가
6. 테스트가 실제로 실행됐는가 — 실행 로그를 첨부하라. 로그가 없으면 FAIL
6번이 중요합니다. "테스트 통과"라는 문장과 테스트 실행 로그는 다른 것입니다. 로그를 요구하면 절반은 여기서 걸립니다.
그런데 검증자가 죽으면
여기서부터가 이 글을 쓰는 이유입니다.
이 체크리스트를 자동으로 돌리게 해 두고 몇 주 지난 10월 둘째 주, 검수 없이 머지된 작업이 보였습니다. 로그를 뒤지니 검증 세션이 20분 타임아웃으로 죽은 경우, 그 실패 메시지가 "검수 결과"로 저장되고 있었습니다. 결과에 "검증 안 됨"이라는 표시가 없으니 다음 단계는 그걸 깨끗한 검수로 읽었습니다.
열흘간 검증 세션 91개 중 19개가 그랬습니다. 21%입니다.
타임아웃의 원인도 따로 있었습니다. 검증 세션이 97번 중 95번 프로젝트 전체 테스트를 평균 2.2번 다시 돌리고 있었습니다. 성실해서 죽은 겁니다.
고친 것 두 가지, 둘 다 도구와 무관하게 적용됩니다:
- 실패와 미완을 "통과 아님"으로 명시한다. 검증 세션이 끝나지 않았으면 결과는 "검증되지 않음"이지 빈 결과가 아닙니다. 다음 단계(머지, 배포, 사람 승인)는 "검증됨" 표시가 있을 때만 진행하게 합니다. 표시가 없을 때 진행하는 기본값이 사고를 만듭니다.
- 결정론적 검증은 한 번만 돌리고 결과를 넘긴다. 테스트·린트·빌드는 스크립트로 먼저 돌려 로그를 검증 세션에 줍니다. 검증 세션은 그걸 읽고 판단만 합니다. LLM에게 테스트를 "돌리게" 하면 몇 번이든 다시 돌립니다.
그리고 고친 날 저녁, 전체를 다시 점검하다가 같은 계열의 구멍을 하나 더 찾았습니다. 검증 세션이 실패하는 경로는 막았는데, 검증 세션을 시작도 못 하는 경로(작업 폴더 확보 실패, 세션 생성 실패)가 여전히 "검증 0회"로 다음 단계에 들어가고 있었습니다. 1번 규칙을 그 경로에도 적용했습니다.
숫자
| 검증 조작으로 걸린 작업 (8개월) | 67건 |
| 스펙에 있는데 구현에 없던 항목이 걸린 작업 | 88건 |
| 검증 세션 타임아웃 (10/7~10/14) | 19 / 91 |
| 그중 검수 없이 다음 단계로 간 것 | 대부분 |
| 타임아웃 원인: 전체 테스트 재실행 | 97세션 중 95, 평균 2.2회 |
남는 것
검증자를 세우는 건 반나절이면 됩니다. 검증자가 죽는 경로, 시작도 못 하는 경로, 성실해서 죽는 경로를 막는 데 한 달이 걸렸고 아직 끝났다고 못 합니다. "AI가 검증한다"는 말은 "검증자가 실패했을 때 무슨 일이 생기는가"까지 답할 수 있을 때만 의미가 있습니다.
다음 편: 에이전트에게 허용할 질문과 금지할 질문 — CLAUDE.md에 넣는 규칙 다섯 줄.