
Fable 5로 자신의 개발 환경을 총점검하는 방법 — 「테스트 전원 통과(All Green)」의 이면에 4가지 허점이 있었던 이야기
요약
AI 기반 개발 환경에서 테스트가 모두 통과되더라도 존재할 수 있는 허점을 발견하기 위한 '검사와 피검사자의 분리' 전략을 소개합니다. Claude Code를 증거 수집 담당으로, Fable 5를 외부 평가 담당으로 분리하여 개발 환경의 신뢰성을 정밀 점검하는 방법론을 다룹니다.
핵심 포인트
- AI가 구현한 코드에 대해 동일한 AI가 자기 채점을 하면 관대해지는 경향이 있음
- Claude Code는 사실 기반의 증거 수집(Raw Data)만 수행하도록 제한해야 함
- Fable 5와 같은 외부 모델을 평가자로 활용하여 객관적인 검증을 수행함
- 모크(mock)나 실행되지 않는 검사 등 테스트 통과의 허점을 찾는 것이 핵심
AI에게 코드를 작성하게 하는 개발이 당연해지고 있습니다. 저도 개인 개발 SaaS에서 구현의 대부분을 Claude Code에 맡기고 있습니다. 사양서(spec)를 작성해 전달하고, 구현하게 하고, 테스트로 검증하는——이 루프 자체는 잘 돌아가고 있었습니다.
테스트는 전부 통과(Green). CI 상당의 로컬 검사도 전부 패스. 숫자상으로는 매우 건전함.
하지만 문득 불안해졌습니다.
이 「통과(Green)」, 정말 진짜를 보고 있는 걸까?
그래서 주말을 이용해, Claude의 최신 모델인 Fable 5에게 개발 환경 그 자체를 총점검하게 해보았습니다. 결과부터 말씀드리면——4가지 중대한 허점이 발견되었습니다. 테스트가 전부 통과된 상태 그대로, 그 이면에 말이죠.
이 기사에서는 제가 수행한 총점검 방법(복사해서 사용할 수 있는 프롬프트 포함)과 발견된 사항들을 공유합니다. 여러분의 환경에서도 이번 주말에 꼭 시도해 보시기 바랍니다.
규모감을 전달하기 위해 환경만 간단히 소개하자면:
- 개인 개발 SaaS (TypeScript / React / Node 모노레포)
- 구현은 Claude Code에 위임. 저는 spec을 작성해 전달하고, 결과물을 리뷰하는 역할
- 로컬에 20개 이상의 검사 게이트(타입 체크, unit 테스트, golden 테스트, 빌드 검증 등)를 묶은 「전체 검사」 스크립트가 있으며, 이것이 모두 통과되지 않으면 머지(merge)하지 않는 운영 방식
- 테스트는 수백 개, golden(기대 출력 고정)도 다수
즉, 「AI 구동 개발(AI-driven development)로서 나름대로 검사를 정비해 온」 환경입니다. 그럼에도 허점이 있었다,는 것이 이번 이야기의 핵심입니다.
처음에 생각한 것은, 「Claude Code에게 자신의 환경을 점검하게 해서 문제점을 보고하게 하면 된다」였습니다.
이것은 안 됩니다. 이유는 단순합니다. 구현한 본인(과 동일한 AI)에게 자기 채점을 시키면 무의식적으로 관대해지기 때문입니다. "이것은 의도적인 설계입니다", "실용상 문제가 없습니다"——자기 변호가 섞인 보고는 점검으로서 신뢰할 수 없습니다.
그래서 역할을 두 가지로 나누었습니다:
- 증거 수집 담당(Claude Code): 리포지토리 안에서 사실만을 수집한다. grep의 생(raw) 출력, 코드 실물, 테스트 목록. 평가·자기 채점·변호는 작성 금지
- 평가 담당(채팅 측의 Fable 5): 수집된 증거를 코드를 가지지 않은 외부의 눈으로 정밀 조사하고 등급을 매긴다
건강검진으로 치면, 검사 기사와 진단 의사를 나누는 것과 같습니다. 저는 이것을 「검사와 피검사자의 분리」라고 부릅니다.
Claude Code에 던진 프롬프트의 골격은 다음과 같습니다. 자신의 환경에 맞춰 조정해 주세요:
# 의뢰: 개발 환경 총점검·증거 수집【조사만 수행·구현 제로·평가 불필요】
## 이 의뢰의 성격
- 본 의뢰는 증거 수집만을 목적으로 함. 별도의 심사자가 외부의 눈으로 정밀 조사하기 위한 생(raw) 자료를 수집함.
...
포인트는 세 가지입니다:
- 「평가하지 말고 사실만 내놓아라」를 반복해서 명시한다 (이것이 없으면 자기 변호가 섞임)
- 「불리한 사실이야말로 가치가 있다」고 선언한다 (AI는 분위기를 읽고 허점을 숨기기 쉬움)
- 모크(mock)·복사본·실행되지 않은 검사를 지목해서 찾게 한다 (후술할 전형적인 허점 패턴)
저의 경우, 이를 통해 약 3,000행의 증거 리포트가 올라왔습니다.
수집된 증거를 코드를 가지지 않은 채팅 측의 Fable 5에게 전달하여 정밀 조사하게 합니다.
첨부된 것은 저의 개발 환경 총점검 증거 리포트입니다.
당신은 외부 심사자로서, 구현자의 자기 평가를 일절 신뢰하지 말고,
증거만을 바탕으로 다음을 판정해 주십시오:
...
여기서 Fable 5를 사용하는 의미가 나타납니다. 3,000행의 증거를 「어떤 테스트가 어떤 구현을 보고 있는가」, 「이 grep 결과는 무엇을 의미하는가」까지 구조 자체를 대조하며 읽어야 하며, 정밀 조사의 깊이가 곧 점검의 질이 되기 때문입니다.
가장 충격적이었던 것은 이것입니다. UI 측 테스트 20여 개 파일이, 실제 운영 마스터 데이터를 전혀 읽지 않고 빈 모크(mock)로 실행되고 있었다는 점입니다.
jest.mock('@/data/xxx', () => ({ ITEMS: [] })); // 모든 파일이 이와 같음
이유는 빌드 도구 의존적인 import가 테스트 환경에서 동작하지 않는다는 기술적인 사정 때문이었으며, 개별 테스트로서는 정당한 모크(mock)입니다. 하지만 결과적으로, 「진짜 데이터 × 진짜 로직」의 조합은 어떤 테스트도 단 한 번도 확인하지 않았습니다. 테스트는 수백 개, 전부 통과(Green). 전부, 가짜 세계의 통과였습니다.
어떤 테스트는 검사 대상인 로직을 테스트 내부에서 직접 재구현(사경, 写経)하여, 그 사경의 출력을 검사하고 있었습니다. 실제 화면은 전혀 그리지 않습니다.
실제로 진짜 화면을 망가뜨려 보았더니——**이 테스트는 여전히 초록색(Green)**이었습니다. 사경한 코드는 무사했기 때문입니다.
저는 이것을 「wrong-layer green(잘못된 계층의 초록색)」이라고 부르기로 했습니다. 실물이 아니라 실물의 복사본(설정의 복사, 로직의 재구현, 소스 코드의 문자열 잘라 붙이기)을 검사하는 테스트는, 실물이 망가져도 계속 초록색을 유지합니다.
실제 브라우저에서 제품을 한 바퀴 도는 E2E 테스트는 존재하고 있었습니다. 다만 CI 전용 설정이었고, 그 CI는 사정상 중단된 상태였습니다. 즉, 존재할 뿐 실행 횟수는 제로였습니다.
「테스트가 있다」와 「테스트가 돌아가고 있다」는 별개의 문제였습니다. 게다가 나중에 측정해 보니, 로컬 실행 비용은 단 몇 초에 불과했습니다. 「E2E는 무거우니까 CI에서만 돌린다」는 것은 선입견이었고, 단지 측정하지 않았을 뿐이었습니다.
사용자 입력을 포함한 Markdown을 HTML로 변환하여 화면에 표시하는 경로에 새니타이징(Sanitizing)이 전혀 없었습니다(XSS). 이는 AI 운운하기 이전에 고전적인 허점이지만, 기능 개발을 우선시하다 보면 이런 횡단적인 방어는 아무도 보지 않게 되는 전형적인 사례였습니다.
LLM에 전달하는 프롬프트 내의 안전상 중요한 문구(「당신은 제안만 할 뿐, 결정은 하지 않습니다」 계열의 제약)는, 한 글자만 바꿔도 모든 테스트가 초록색이었습니다. 약속이 조용히 사라져도 아무도 알아차릴 수 없는 상태였습니다.
찾아낸 허점을 고칠 때, 한 가지 규칙을 세웠습니다:
반드시 「예전에 빠져나갔던 파괴」를 신구(新舊) 양쪽 테스트에 적용하여, 「구형: 초록색 유지 / 신형: 빨간색」을 동시에 관측한 뒤에 완료한다.
예를 들어 허점 2(사경 테스트)를 수정할 때는, 과거에 실제로 빠져나갔던 파괴와 동일한 파괴를 재현하여 「사경 테스트는 초록색 유지 · 새로운 실제 묘사 테스트는 빨간색」임을 동시에 기록했습니다. 허점 3(E2E)에서는 「단위 테스트(Unit Test)도 타입 체크(Type Check)도 빌드(Build)도 전부 초록색인 상태에서, 실제 브라우저 테스트만이 잡아내는 파괴」를 실측했습니다.
이렇게 하면 「고쳤습니다」라는 말이 자기 선언이 아니라, 증거로서 리포지토리에 남게 됩니다.
토요일 오전: 위의 증거 수집 프롬프트를 자신의 환경에 맞춰 조정하여 Claude Code(Fable 5)에 던진다. 평가 금지 · 사실만 기록할 것,을 잊지 말 것 -
토요일 오후: 올라온 증거를 별도의 세션인 Fable 5에 전달하여 외부 심사를 받게 한다. 「격려 불필요 · 진짜 현재 위치를 알고 싶다」라고 덧붙인다 -
일요일: 중대 판정이 나온 것부터 고친다. 고칠 때는 「예전에 빠져나갔던 파괴 방식으로 새로운 테스트가 빨간색이 되는 것」을 확인한 뒤 완료한다
체크리스트 (내 환경에서 실제로 허점이었던 것들):
테스트는
실제 데이터와 설정을 읽고 있는가? (모의 객체(Mock)의 내용을 확인하라) - 실물이 아닌 「복사본」(설정 복사, 로직 재구현, 문자열 잘라 붙이기)을 검사하는 테스트는 없는가?
E2E는
실제로 돌아가고 있는가? (존재와 실행은 별개) - 사용자 입력 → 화면 표시 경로에 새니타이징이 있는가?
-
프롬프트의 중요 문구는, 바꾸었을 때 무언가가 빨간색이 되는가?
-
운영 규칙 문서는 실태와 일치하는가?
「테스트 전원 통과(All Green)」는 아무것도 보장하지 않는다.
물어야 할 것은 초록색의 개수가 아니라, 그 초록색이 실물을 보고 있는가이다 - 점검은 「검사와 피검사체의 분리」로. 구현한 AI에게 자기 채점을 시키지 말고, 증거만 수집하게 하여 다른 눈으로 심사하라
- 고칠 때는 대조 실험으로. 「예전에 빠져나갔던 파괴를 새로운 파수꾼이 잡아낸다」를 실측한 뒤 착지하라
- AI에게 구현을 맡기는 시대일수록 이것이 효과적이다.
약한 검사는 AI에게 거짓된 초록색을 학습시킨다. 토대가 먼저, 지능은 그다음이다
내 환경에서는 이 총점검과 수정 작업 일체가 Fable 5와의 공동 작업으로 실질적으로 2일 만에 끝났습니다. 발견된 허점들은 모두 방치했다면 몇 달 뒤에 훨씬 더 큰 대가를 치렀을 것들뿐이었습니다.
당신의 환경의 「초록색」은 실물을 보고 있습니까? 이번 주말, 확인해 보시기 바랍니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기