기술

가드를 지워도 테스트 24건이 그대로 통과했습니다

2026.09.229분 읽기

자사 AI 활용 프로젝트에서 고객사 매뉴얼 사이트를 세 번째로 만들었습니다. 형식과 문체, 빌드 도구는 공개된 매뉴얼 사이트 킷이 이미 다 주고 있었습니다. 세 번째 프로젝트에서 실제로 고친 줄을 세어보니 킷이 준 1,672줄 중 18줄이었습니다.

이미지 처리 스크립트 0줄, 관리 화면 0줄, 스킬 정의 8줄, 규격 문서 10줄입니다. 그런데도 매번 사람 손이 드는 층이 둘 남았습니다. 사이트를 처음 세우는 부트스트랩, 그리고 무엇을 쓸지 정하는 층입니다. 둘 다 킷에는 없는 층입니다.

절차를 글로만 담은 인계 문서가 386줄, 사람이 직접 쓴 문서 목록이 618줄이었는데 그것을 실행하는 주체가 없었습니다. 더 근본적으로는 킷의 스킬이 생성된 사이트 안에 들어 있어서, 사이트가 서기 전에는 스킬이 없었습니다.

그래서 이 두 층을 에이전트 플러그인으로 묶었습니다. 초기화 스크립트 235줄과 테스트 24건, 스킬 4개, 에이전트 2개가 나왔습니다. 이 글은 그 결과물 이야기가 아닙니다. 만드는 동안 「됐다」는 보고가 세 번 뒤집혔고, 셋 다 에러가 안 났다는 이야기입니다.


「됐다」가 세 번 뒤집혔습니다

첫 번째는 「연기 시험 통과」였습니다. 인증 모드 산출물이 연기 시험을 통과했다는 보고를 받았는데, 실제로는 안 돌았습니다. 정적 산출물 폴더가 남아 있어 인증 없이 서빙되고 있었고, 런타임이 설치조차 안 된 저장소에 빌드 초록불이 떠 있었습니다.

그 초록불은 제가 만든 인증 경로가 낸 것이 아니었습니다. 킷이 원래 갖고 있던 정적 빌드 경로가 낸 것이었습니다. 저는 종료 코드 하나만 봤습니다.

두 번째는 「전부 고쳤다」였습니다. 고칠 자리를 목록으로 만들고, 그 목록을 다 고쳤다는 보고를 받았습니다. 산출물의 로그인 화면을 열어보니 첫 줄에 이전 프로젝트 이름이 그대로 떠 있었습니다. 목록은 다 고쳤는데, 그 목록이 완전한지는 아무도 확인하지 않았습니다.

세 번째는 「죽은 포인터 0건」이었습니다. 문서가 가리키는 파일이 실제로 있는지 훑었고 0건이라는 숫자가 나왔습니다. 숫자는 맞았습니다. 스킬 폴더만 세고 에이전트 폴더를 빼먹은 것이 문제였습니다. 어디를 세었는가가 틀렸습니다.

셋 중 어떤 것은 하위 에이전트의 보고였고 어떤 것은 제 판단이었습니다. 다만 결함은 셋 다 같은 자리에 있습니다. 그 보고를 검증 없이 받은 것이 저입니다. 에이전트가 「통과」라고 하면 저는 무엇이 통과했는지를 묻지 않았습니다.

가드를 지워도 테스트 24건이 그대로 통과했습니다 그림 1


같은 실패가 모양만 바꿔 세 번 나왔습니다

시간 순으로 놓고 보면 세 건은 다른 실수가 아닙니다. 1차는 초록불의 출처를 안 봤습니다. 종료 코드는 「성공했다」는 말해주지만 「무엇이 성공했나」는 말해주지 않습니다. 2차는 「전부」를 세지 않았습니다. 목록을 다 처리한 것과, 처리할 것이 목록에 다 있는 것은 다른 일입니다.

3차는 「0건」의 범위를 안 물었습니다. 도구가 준 숫자에도 정의가 있습니다. 그 정의를 안 물으면 맞는 숫자로 틀린 결론을 냅니다.

세 번째에서야 문제를 다시 세웠습니다. 「검증을 더 꼼꼼히 한다」로는 안 됩니다. 제 검증이 무엇을 안 보고 있는지를 제가 모른다는 것이 문제였습니다. 안 보고 있는 자리는 아무리 오래 봐도 안 보입니다. 그래서 통과하는 테스트를 믿는 대신, 테스트가 무엇을 지키는지를 직접 시험하는 쪽으로 갔습니다.


가드를 한 줄씩 지워봤습니다

방법은 단순합니다. 코드 안의 가드를 하나 골라 지우거나 조건을 뒤집습니다. 그 상태로 테스트를 돌립니다. 빨간불이 뜨면 그 가드는 테스트가 지키고 있는 것입니다. 초록불이 그대로면 그 가드는 테스트가 지키고 있지 않은 것입니다. 변이 시험이라고 부르는 방법인데, 여기서는 도구 없이 손으로 했습니다.

화재경보기의 시험 버튼과 같은 원리입니다. 전원 램프가 초록이어도 감지 회로가 죽어 있으면 불이 나도 안 웁니다. 램프는 전원이 들어온다는 사실만 말하고, 연기를 감지할 수 있는지는 말하지 않습니다. 그래서 연기 없이 감지 회로를 직접 건드리는 버튼이 따로 달려 있습니다. 테스트 초록불은 램프 쪽이고, 가드를 지우는 것이 시험 버튼입니다.

가드를 지워도 테스트 24건이 그대로 통과했습니다 그림 2

결과는 3곳이었습니다. 테스트 24건이 전부 초록불인 상태에서, 가드를 지워도 그대로 통과하는 자리가 셋 있었습니다.

지운 가드

지운 뒤 테스트

가드가 없으면

사이트 이름 검사

통과

이름이 비어 있거나 잘못돼도 초기화가 그냥 진행됩니다

YAML 값 이스케이프

통과

따옴표 같은 특수문자가 든 값이 설정 파일을 깨뜨립니다

빌드 검증 단계

통과

빌드가 실패해도 초기화가 성공으로 끝납니다

셋 다 초기화 스크립트에서 가장 먼저 걸려야 할 자리입니다. 그런데 24건 중 어느 하나도 이 세 가드를 건드리지 않았습니다. 테스트 24건은 「정상 입력에서 정상 결과가 나온다」 쪽을 지키고 있었고, 「잘못된 입력을 막는다」 쪽은 비어 있었습니다. 세 자리에 테스트를 붙인 뒤, 다시 가드를 지워 이번에는 빨간불이 뜨는 것까지 확인했습니다.


만든 쪽과 검증하는 쪽을 갈랐습니다

같은 축에서 에이전트 구성도 바꿨습니다. 처음에는 집필과 검증을 한 에이전트가 했습니다. 위 세 건 중 둘이 자기가 만든 산출물을 자기가 검증한 형태였습니다. 자기 글을 자기가 검증하면 통과시킵니다. 무엇을 봐야 하는지를 이미 안다고 생각하기 때문에, 안 본 자리를 안 본 채로 넘어갑니다.

그래서 집필 에이전트와 검증 에이전트를 나눴습니다. 이것도 만능은 아닙니다. 검증 에이전트에 같은 잘못된 기준을 주면 둘 다 같은 방향으로 틀립니다. 나눈 효과는 기준이 다를 때만 납니다. 그래서 검증 쪽에는 「무엇을 만들었나」가 아니라 「산출물을 열면 무엇이 보이나」를 기준으로 줬습니다.


변이 시험이 못 잡는 것

이 방법의 한계를 셋 적어 둡니다. 첫째, 비쌉니다. 여기서는 스크립트가 235줄이라 손으로 셋을 지워보는 것으로 끝났습니다. 코드베이스가 커지면 전수 변이는 CI 시간을 통째로 잡아먹습니다. 가드가 있는 자리로 범위를 좁혀야 성립합니다.

둘째, 가드가 잡히는 것과 요구가 만족되는 것은 다른 일입니다. 변이 시험은 「테스트가 코드를 지키나」를 보는 것이지 「코드가 맞는 것을 하나」를 보지 않습니다. 위 2차 실패인 브랜딩 누락은 변이 시험으로도 안 잡혔을 겁니다. 그 자리에는 지울 가드가 애초에 없었습니다. 산출물을 사람이 한 번 열어봐야 나오는 종류입니다.

셋째, 아직 실전 전입니다. 부트스트랩을 실제 프로젝트에 자동으로 써본 적이 한 번도 없습니다. 공개 모드는 임시 디렉터리에서 여러 번 확인했지만, 다음 실제 건을 이걸로 세워봐야 「된다」가 됩니다. 「초록불을 믿지 않는다」는 이 글의 결론도 그때 한 번 더 뒤집힐 수 있습니다.

가드를 지워도 테스트 24건이 그대로 통과했습니다 그림 3


초록불을 받았을 때 묻는 것

이번에 세 번 틀리고 나서, 「됐다」는 보고를 받을 때 묻는 것을 정리했습니다. 사람에게 받든 에이전트에게 받든 같습니다.

그 초록불은 누가 냈나 — 내가 방금 만든 경로가 낸 것인지, 원래 있던 다른 경로가 낸 것인지

「전부」의 목록은 누가 만들었나 — 목록을 다 처리한 것과, 처리할 것이 목록에 다 있는 것은 다르다

「0건」은 어디를 세었나 — 숫자보다 범위를 먼저 받는다

만든 쪽과 검증한 쪽이 같은가 — 같으면 「통과」의 무게를 반으로 친다

가드를 하나 지워봤나 — 지우고 돌리는 데 몇 초면 된다


통과하는 테스트는 무엇을 지키는지 말해주지 않습니다

이 연작에서 초록불이 무엇을 안 지키고 있었는지를 사례로 봤습니다. 테스트는 통과했는데 실제로 도는 SQL 이 달랐고, 숫자는 0이 됐는데 검사기도 같이 바뀌어 있었고, 테스트용 설정 한 줄이 운영 테이블을 지웠습니다. 모양은 다 달랐지만 초록불은 매번 「무엇이 초록인가」를 말하지 않았고, 저는 그것을 묻지 않았습니다.

테스트 24건이 전부 초록불인 상태에서 가드 3개가 무방비였습니다. 「몇 건 통과」와 「무엇을 지킨다」는 다른 축입니다. 통과하는 테스트는 자기가 무엇을 지키고 있는지 말해주지 않습니다. 가드를 지워보면 그제야 말합니다. 가드 하나 지우고 테스트 한 번 돌리는 데 몇 초입니다. 그 몇 초를 안 써서 「통과했다」가 세 번 거짓이었습니다.


연작 「초록불이 거짓말한다」

이 글은 다섯 편 중 5편입니다. 테스트가 전부 통과했는데 실제로는 아무것도 지켜주지 않았거나 운영을 부순 사례를 이어서 다룹니다.

#변이시험#테스트#검증#에이전트#자동화#초록불#자기정정