Trawling

두 AI가 서로의 코드를 30일간 리뷰하게 했다 — 그러나 결정적 버그는 사람이 5분 만에 잡았다

저자가 30일간 작성 에이전트와 별도의 '회의론자(skeptic)' 리뷰 에이전트를 운영한 실험 기록입니다. AI 리뷰어는 41개 실제 이슈 중 38개를 잡았지만, Stripe 웹훅의 'ack-before-persist' 같은 조용한 데이터 정합성 버그는 같은 모델 계열 특유의 공통 맹점 때문에 놓쳤고, 시니어 엔지니어는 과거 장애 경험으로 5분 만에 발견했습니다.

본문

지난달 'AI가 코드를 100% 작성하게 한 30일 실험'에서 저자가 얻은 가장 큰 교훈은 '코드를 작성한 주체는 리뷰어가 될 수 없다'는 것이었습니다. 모델은 자기 숙제를 스스로 채점하면 항상 통과시키기 때문입니다. 이번 달에는 그 다음 단계로, 작성 에이전트(author)와 이를 공격적으로 검증하는 별도 에이전트(skeptic)를 두고 사람을 리뷰 루프에서 완전히 배제해 구조만으로 어디까지 갈 수 있는지를 시험했습니다.

실험 설계 — '독립성'은 같은 모델에 두 번 묻는 게 아니다

작성 에이전트는 '기능을 만들고 테스트를 통과하라'는 일반 브리프를 받았고, skeptic은 '리뷰해 달라'가 아니라 적대적 브리프를 받았습니다. '이 코드가 깨져 있다고 가정하라. 고객에게 손해를 입히는 입력을 만들어라. 이미 존재하는 것을 재구현한 부분을 찾아라. 아무도 설계하지 않은 상태를 찾아라'가 그것입니다. 채점자는 '예'라고 말할 이유를 찾지만, 실패를 사냥하는 skeptic은 코드를 깨뜨리는 단 하나의 입력을 찾기 때문에 관점 자체가 다릅니다. 저자는 이 간극이 두 번째 에이전트에 토큰을 쓸 이유라고 말합니다.

결과 — 41개 중 38개를 잡은 AI 리뷰어

skeptic이 잡아낸 것 중 대표적인 사례는 세 가지입니다. 첫째, 아키텍처 드리프트입니다. 작성 에이전트는 이미 존재하는 formatCurrency를 모르고 두 번째 것을 만들었고, 미들웨어와 중복되는 인라인 auth 체크, 미묘하게 다른 User 타입도 한 번의 패스로 잡아냈습니다. 컴파일되고 테스트도 통과하지만 코드베이스를 조용히 썩게 만드는 종류의 문제로, '피곤한 오후 6시의 사람보다 낫다'고 저자는 평가합니다. 둘째, try/catch로 모든 것을 감싸고 로그만 남긴 채 계속 진행하는 '삼켜진 에러'들을 '이 코드가 숨기는 실패가 무엇인가'라는 프레임으로 걸러냈습니다. 셋째, 두 요청이 락 없이 하나의 카운터를 건드리는 실제 레이스 컨디션을, '최악의 입력은 동시에 두 개가 오는 것'이라는 추론으로 발견했습니다.

놓친 세 개 — 같은 계열 모델의 공통 맹점

살아남은 세 개의 버그는 모두 '불행한 경로에서의 조용한 데이터 정합성 실패'였습니다. 대표 사례는 Stripe 웹훅 핸들러가 이벤트를 DB에 저장하기 전에 200을 반환해 ack한 것입니다. 테스트에서는 완벽하게 동작하지만, 프로덕션에서 ack와 쓰기 사이에 DB 장애가 발생하면 Stripe은 전달 완료로 간주하고 고객은 결제했는데 권한도 기록도 없는 상태가 됩니다. skeptic은 이 코드를 승인했을 뿐 아니라 '웹훅 레이턴시를 낮추는 깔끔한 조기 ack'라고 칭찬까지 했습니다.

저자는 이유를 명확히 짚습니다. 작성자와 리뷰어가 같은 모델 계열이기 때문에 훈련 분포와 본능, '깨끗한 웹훅 코드'의 기준이 동일합니다. skeptic은 맹점을 반박한 게 아니라 더 자신감 있는 목소리로 재도출한 것이며, '그건 리뷰가 아니라 매너 좋은 에코'라고 표현합니다. '작성자 ≠ 리뷰어'는 필요조건이지 충분조건이 아니라는 것이 이번 실험의 핵심입니다.

사람이 5분 만에 잡은 이유 — 훈련될 수 없는 '흉터 조직'

같은 핸들러를 본 시니어 엔지니어는 'ack가 쓰기보다 먼저네 — 2021년에 정확히 이걸로 호출당했어'라고 즉시 반응했습니다. 모델보다 똑똑해서가 아니라, 실제로 당해본 경험(scar tissue)이 있기 때문입니다. 모델은 dual-write 문제에 대한 설명을 수백만 개 읽었지만, 그녀는 새벽 2시의 정합성 복구를 살아냈고 이 둘은 같은 지식이 아니라고 저자는 말합니다. 나아가 AI가 엔트리 레벨 작업을 모두 가져가면 그런 흉터를 쌓을 사람이 없어지고, 두 에이전트가 계속 통과시킬 버그를 잡을 사람도 사라진다는 구조적 문제를 지적합니다.

독립성을 사는 세 가지 방법

저자는 맹점을 없애는 방법으로 세 가지를 제시합니다. 첫째, 다른 모델 계열을 리뷰어로 쓰는 것 — 훈련 분포가 달라 맹점도 다르며, 가장 저렴한 개선이고 이 변경 하나로 웹훅 버그도 잡혔을 가능성이 있다고 봅니다. 둘째, '이게 맞나?'가 아닌 '돈을 잃게 만드는 트랜잭션을 만들어라' 같은 적대적 프레임 — 같은 가중치라도 목적이 다르면 결과가 다르며, 이것이 38개까지 도달하게 해줬습니다. 셋째, 머지 버튼에 흉터 조직을 가진 사람을 두는 것 — 기계를 능가하려는 게 아니라, 정확히 이 버그로 대가를 치러본 기억을 보유하기 위해서입니다. 이 세 층을 쌓으면 버그는 다른 모델, 적대적 목적, 대가를 치러본 사람을 모두 통과해야 하므로 숨을 곳이 없습니다.

dev.to 반응

(추출된 댓글이 없어 생략)

원문: dev.to / 번역·요약: Trawling

참고 자료

오류 제보