코드를 서버에 올리기 전에 “검사 증거가 진짜인가”를 확인하는 자동 검사기가 있다. 그게 12일 동안 죽어 있었다. 그런데 문은 계속 닫혀 있어서 아무도 몰랐다.
문지기는 계속 문을 막고 있었다. 다만 그는 아무것도 보고 있지 않았다.
먼저 배경을 짧게. 저는 코드를 서버에 올리기 전에 자동으로 문을 막는 장치를 여러 개 두고 씁니다. 그중 하나가 QA 게이트입니다. 화면을 진짜로 열어보고 버튼을 눌러봤다는 증거 파일을 요구하고, 그 증거가 제대로 채워졌는지 검사한 다음, 통과해야만 올리기를 허용합니다.
이 사건은 그 “검사” 부분이 조용히 죽어 있었다는 이야기입니다. 그런데 문은 계속 닫혀 있었습니다. 그래서 12일 동안 아무도 눈치채지 못했습니다.
“죽었다”는 건 주장입니다. 그래서 결함이 있던 시점의 게이트를 그대로 꺼내, 격리된 빈 저장소에서 세 번 돌려봤습니다. 결과가 판정을 대신합니다.
| 실험 | 검사기 | 넣은 증거 | 게이트가 뱉은 말 |
|---|---|---|---|
| A | 죽음 | 완벽하게 채운 증거 | 증거 검사가 결과를 내지 못했습니다(빈 출력 — 실행 실패 가능) |
| B | 살아있음 | 같은 증거 (A와 동일) | screenshot_evidence 비어있음; api_logs.captured=false; db_verification.crud_roundtrip=MISSING … |
| C | 죽음 | 일부러 망가뜨린 증거 | 증거 검사가 결과를 내지 못했습니다(빈 출력 — 실행 실패 가능) |
A와 C를 비교하세요. 완벽한 증거를 줘도, 일부러 망가뜨린 증거를 줘도 토씨 하나 똑같은 말이 나옵니다. 죽은 검사기는 증거를 읽지 않습니다. 무엇을 넣든 같은 값을 뱉는 상수가 된 겁니다.
B는 살아있는 검사기가 같은 증거에서 실제로 무엇을 짚어내는지 보여줍니다 — 스크린샷 증거가 비었고, API 로그를 안 찍었고, DB 왕복 확인이 없다는 구체적인 4건. 이게 원래 나왔어야 할 말입니다.
검사기는 셸 스크립트 안에 파이썬 코드를 큰따옴표로 감싸서 집어넣는 방식이었습니다. 이렇게 생겼습니다.
#은 주석이 아니다. 문자열 안이면 그냥 글자다. 그래서 주석에 있던 따옴표가 문자열을 닫아버렸다.셸은 파이썬 문법을 모릅니다. #이 주석이라는 것도 모릅니다. 셸이 아는 건 “따옴표가 열렸으니 다음 따옴표까지가 문자열” 하나뿐입니다. 그래서 주석 안에 있던 따옴표에서 문자열을 닫아버렸고, 파이썬은 앞의 26줄만 받아 문법 오류로 죽었습니다.
더 아픈 건 그 주석의 내용입니다. “독립 리뷰 지적”이라고 적혀 있습니다. 이전 리뷰 지적을 고치면서 설명을 붙이다가 검사기를 죽인 겁니다. 고치는 행위가 고장을 냈습니다.
검사기가 죽으면 보통은 티가 납니다. 이 경우엔 세 가지가 겹쳐서 신호가 하나도 밖으로 안 나왔습니다.
고장이 “정상처럼 보이는 방향”으로 났다는 게 이 사건의 핵심입니다. 죽은 검사기가 문을 열어젖혔다면 그날 바로 들켰을 겁니다. 문을 닫아버렸기 때문에 12일을 버텼습니다.
검사기가 죽은 채로 12일이었는데 잘못된 코드가 나간 적은 없습니다. 그 이유는 한 달 전에 넣어둔 다른 규칙 때문입니다.
이 “결과 없으면 차단” 규칙은 사건보다 먼저 들어가 있었습니다. 커밋 메시지가 그대로 남아 있습니다 — 증거 검사가 결과를 못 내면 통과가 아니라 차단. 그때는 이런 사고를 예상하고 넣은 게 아니었는데, 결과적으로 이걸 막았습니다.
측정할 수 없다는 것은 통과했다는 뜻이 아니다.
저는 코드를 올리기 전에 다른 회사 AI에게 교차 리뷰를 시킵니다. 제 코드를 쓴 모델과 검토하는 모델이 다릅니다. 같은 모델은 자기가 놓친 걸 또 놓치기 때문입니다.
이번엔 그 리뷰가 게이트 자체를 파고들었습니다. 라운드가 거듭될수록 다른 결함이 나왔습니다.
| 지적 | 무엇이 문제였나 | 어떻게 드러났나 |
|---|---|---|
| 검사기 사망 | 주석 안 따옴표가 파이썬을 끊었다 | 빈 출력 + 에러 버려짐 |
| push 다중 우회 | 한 줄에 두 번 올리면 두 번째를 안 봤다 | 명령 파서가 첫 건만 인식 |
| 다른 저장소 판정 | A를 올리는데 B의 증거를 검사했다 | 작업 폴더 추적 누락 |
| 빈 칸 소실 | 구분자를 탭으로 써서 빈 값이 사라졌다 | 탭·공백은 연속되면 하나로 뭉개진다 |
| 구버전 셸 사망 | 최신 셸은 통과, 실제 실행 셸은 죽었다 | 맥 기본 셸이 옛 버전 |
여기서 제가 배운 건 조금 다릅니다. 리뷰가 제 코드를 막아준 게 아닙니다. 리뷰는 제 감시 장치가 죽어 있다는 걸 찾아냈습니다. 감시자를 감시할 사람이 필요하다는 게 이 사건의 결론입니다.
한 번 고치고 끝내면 다음에 또 같은 식으로 죽습니다. 그래서 이 종류의 죽음을 자동으로 찾아내는 검사기를 따로 만들었습니다.
문서에 “따옴표 조심하세요”라고 적는 것으로는 부족합니다. 문서는 읽히지 않거나, 읽혀도 잊힙니다. 종료 코드로 판정되는 규칙만 실제로 강제됩니다.
이 검사기가 모든 무음 사망을 막지는 못합니다. 남은 구멍을 적어둡니다.
감시 장치가 있다는 사실은, 그것이 살아 있다는 증거가 아니다.