AI 자가 검증의 함정: "위반 0개"라는 거짓말을 믿을 뻔한 이야기
발단: "0개 위반"인데 왜 화면이 깨져 보이지?
게임 맵 자동 생성 시스템을 Claude와 함께 개발하고 있었습니다. 타일 기반 지형을 생성하고, 9-slice 규칙에 따라 렌더링하는 구조인데요. 높이가 다른 타일 사이의 전이(transition)가 매끄럽게 이어지려면 꽤 까다로운 규칙을 지켜야 합니다.
문제는 Claude가 맵을 생성한 뒤 자체 검증 스크립트를 돌리고 "위반 0개"라고 자신 있게 보고하는데, 정작 스크린샷을 보면 렌더링이 뻔히 깨져 있다는 것이었습니다.
16x16 결과를 보니 규칙 체커는 0개 위반이라고 하는데, 스크린샷에선 분명 렌더링이 깨져 보입니다.
이 한 줄이 모든 것의 시작이었습니다. AI가 스스로 만든 코드를 스스로 검증하고, 스스로 "문제 없음"을 선언하는 구조. 이게 얼마나 위험한지 뼈저리게 느낀 하루였습니다.
첫 번째 함정: 검증 환경부터 틀렸다
가장 먼저 발견한 문제는 어이없을 정도로 단순했습니다. Claude가 검증에 사용한 맵 크기가 실제 타일 에디터의 기본값과 달랐던 겁니다.
타일 에디터 기본값은 12x12 (line 817-818:
|| 12)입니다. 제가 12x14로 돌렸네요.
코드에 분명히 || 12라고 기본값이 적혀 있는데, 디버그 스크립트에서는 12x14로 돌리고 있었습니다. 검증의 첫 단추부터 잘못 끼워진 셈이죠. "코드 로직으로 생성된 결과물을 검증하라고" 했더니, 검증 자체가 다른 조건에서 돌아가고 있었던 겁니다.
이건 마치 수학 시험에서 문제는 3번을 풀면서 답은 5번 답안지에 쓰는 것과 같습니다. 당연히 맞을 리가 없죠.
두 번째 함정: 체커가 놓치는 것들
맵 크기를 맞춰서 다시 돌려도 문제는 계속됐습니다. 16x16으로 생성한 맵에서 규칙 체커는 여전히 "0개 위반"을 외쳤지만, 실제 3D 렌더링에서는 클리프(절벽) 렌더링이 깨지고 있었습니다.
핵심은 이것이었습니다:
체커가 검증하는 것: 타일 높이 전이 규칙 (2D 배열 기준)
실제 렌더링에 필요한 것: BlockTerrainRenderer의 9-slice 판정 로직
체커는 2D 배열 상의 숫자만 보고 규칙을 판단했지만, 실제 렌더링 엔진은 그보다 훨씬 복잡한 판정을 합니다. 이웃 타일의 높이, 맵 경계(OOB) 처리, 코너 케이스 등을 모두 고려해야 하는데, 체커는 이 중 일부만 검사하고 있었던 것입니다.
체커가 놓치는 부분이 있을 수 있습니다.
Claude 스스로도 인정한 이 문장이 핵심입니다. 검증 도구의 커버리지가 불완전하면, "0개 위반"은 "0개 문제"가 아니라 "검사한 범위 내 0개 위반"일 뿐입니다.
세 번째 함정: 동서남북도 뒤집혀 있었다
맵 검증 과정에서 나침반 방향이 뒤집혀 있다는 사실까지 발견됐습니다. 이건 진짜 소름 끼치는 부분이었는데요.
// Babylon.js 왼손 좌표계에서
// alpha = -Math.PI / 4 카메라 각도일 때
// 낮은 x(-X)가 화면 오른쪽에 표시됨
// 기존 매핑 (잘못됨)
W → x = 0 (낮은 x) → 화면에서 오른쪽으로 보임 // W가 오른쪽?!
E → x = max (높은 x) → 화면에서 왼쪽으로 보임
맞습니다. N이 위에 있으면 오른쪽은 East여야 하는데 W로 표시되어 있네요. 타일 에디터의 방향 표기가 뒤집혀 있습니다.
나침반의 동서가 바뀌어 있으면, 입구 방향 지정도 영향을 받을 수 있습니다. 다행히 실제 게임 로직은 좌표 기반이라 게임플레이에는 영향이 없었지만, 디버깅하는 개발자 입장에서는 모든 방향 판단이 뒤집혀 보이는 셈이었습니다. "동쪽 입구에서 적이 안 나와요"라는 버그 리포트가 들어왔으면 한참을 헤맸을 겁니다.
네 번째 함정: 고쳐도 고쳐도 남는 위반
corridor 생성 로직을 전면 수정한 뒤에도 검증 결과는 완벽하지 않았습니다.
최종 맵 (12x12 corridor, 스무딩 완료):
스무딩 30회 풀 반복 (최대치)까지 돌았고, 그래도 9개 위반이 남아있습니다
30번이나 스무딩을 돌렸는데 9개 위반이 남다니. 절망적이었습니다. 하지만 여기서 한 가지 더 배운 것이 있습니다.
Z경로 연결 로직을 근본적으로 수정해서 입구 위치를 인식하고 연결하도록 바꾼 뒤, 위반은 2개까지 줄었습니다. 그리고 그 2개를 직접 검증해보니:
(4,0) h1: N=OOB(-1), S=h0, E=h0, W=h1 → outerNE 피스. 북쪽(맵 끝)+동쪽 모서리를 올바르게 렌더링. 정상. (2,9) h1: N=h0, S=h2, E=h1, W=h2 → sideN 피스. 북쪽 클리프만 렌더링. 정상.
둘 다 false positive였습니다. 맵 경계에서 OOB(Out of Bounds) 이웃이 없는 것은 위반이 아니라 정상 동작이었던 것입니다. 체커가 경계 조건을 제대로 처리하지 못한 거죠.
알려진 이슈 자체가 검증이 엉망이었던 것입니다.
교훈: AI 자가 검증을 다루는 법
이번 경험에서 얻은 교훈을 정리합니다.
1. "위반 0개"를 곧이곧대로 믿지 마세요
AI가 자체 검증 스크립트를 만들고 "문제 없음"이라고 하면, 가장 먼저 물어야 할 것은 **"뭘 검증한 건데?"**입니다. 검증 범위(커버리지)가 실제 문제 영역을 포함하는지 확인해야 합니다.
2. 검증 환경과 실제 환경을 일치시키세요
12x12가 기본값인데 12x14로 검증하면 아무 의미가 없습니다. AI에게 검증을 시킬 때는 실제 런타임과 동일한 조건을 명시적으로 지정해야 합니다.
3. 검증 로직 자체를 검증하세요
이번 케이스의 진짜 버그는 맵 생성 로직이 아니라 검증 로직이었습니다. 맵 경계에서 false positive를 내는 체커, 실제 렌더링 파이프라인을 반영하지 못하는 규칙 검사. 검증 도구가 신뢰할 수 없으면 그 결과도 신뢰할 수 없습니다.
4. 눈으로 직접 확인하는 단계를 빼지 마세요
아이러니하게도 가장 확실한 검증은 "스크린샷 찍어서 눈으로 보는 것"이었습니다. 자동화된 검증은 편하지만, 특히 시각적 결과물에서는 사람의 눈을 완전히 대체할 수 없습니다.
5. AI가 자신의 한계를 인정하면 귀 기울이세요
체커가 놓치는 부분이 있을 수 있습니다.
Claude가 스스로 이렇게 말했을 때가 가장 중요한 순간이었습니다. AI가 불확실성을 표현할 때, 그것을 무시하지 말고 그 불확실한 영역을 직접 파고들어야 합니다.
마무리
결국 이 에피소드는 나침반 방향 수정, corridor 생성 로직 재설계, 새로운 맵 템플릿(Citadel, S-Valley) 추가까지 이어지며 생산적으로 마무리됐습니다. 하지만 만약 처음에 "0개 위반"을 그대로 믿었다면, 깨진 렌더링과 뒤집힌 나침반을 안고 출시했을 겁니다.
AI와 함께 개발할 때 가장 위험한 순간은 AI가 틀렸을 때가 아닙니다. AI가 자신 있게 "문제 없음"이라고 할 때입니다. 그때야말로 "정말? 데이터로 보여줘"라고 추궁해야 할 때입니다.