지난달 말, 우리 리포에 PR 하나가 열렸습니다. 시크릿 테인트를 워크플로 단계 사이로 전파하는 보안 기능이었고, 숫자는 이랬습니다. 파일 83개, 추가 21,962줄, 커밋 36개. 그리고 머지에 도달하기까지 리뷰 대화 209개, 이틀. 코드를 쓴 것도 Codex였고, 리뷰한 것도 Codex였습니다.
그 209개의 대화가 남긴 질문이 이 글의 주제입니다.
리뷰의 90%는 정확했다
먼저 분명히 해둘 것이 있습니다. Codex의 PR 리뷰는 잘합니다. 제 체감으로 지적의 90%는 정확합니다. 놓친 엣지 케이스, 어긋난 시맨틱, 사람 리뷰어라면 피곤해서 지나쳤을 자리를 집어냅니다. Codex 전에 여러 방법을 시도해봤습니다. 메인 에이전트에게 리뷰를 시키고, 다른 모델을 서브에이전트 리뷰어로 붙이고, 2스테이지로 돌리고. 그렇게 거른 코드에서도 Codex는 꼭 한두 개를 더 걸어냅니다.
하지만 이 글은 Codex 칭찬이 아닙니다. 정확한 리뷰가 무한히 공급될 때 무슨 일이 생기는지에 관한 이야기입니다. 정확한 것과 필요한 것은 다르니까요.
꼬리가 꼬리를 문다
첫날 오후의 기록이 그대로 남아 있습니다. 13시 12분에 리뷰를 요청했고, 15시 8분까지 두 시간 동안 “최신 지적을 고쳤습니다"로 시작하는 코멘트를 열두 번 달았습니다. 10분에 한 라운드꼴입니다. 한쪽 Codex가 지적하고, 다른 쪽 Codex가 고치고, 고쳐진 코드에 새 지적이 달리고, 그 수정에 또 달리고.
지적 하나하나를 떼어놓고 보면 반박할 게 없었습니다. P1, P2 등급을 달고 온 정확한 지적들이었으니까요. 문제는 방향의 합입니다. 라운드가 쌓일수록 변경은 점점 잘게 쪼개진 엣지 케이스 쪽으로 흘러갔고, 이 기능이 무엇을 위해 존재하는지에서는 멀어지고 있었습니다.
이건 Codex의 결함이 아닙니다. 구조입니다. 코딩 에이전트도 리뷰 에이전트도 끝까지 하도록 학습돼 있고, 이 PR에서는 심지어 둘이 같은 모델이었습니다. 끝까지 고치려는 Codex와 끝까지 찾아내려는 Codex를 마주 세워놓으면, 무한 사이클은 사고가 아니라 기본값입니다.
끝을 정해주지 않으면, 그 끝은 내가 오르려던 산이 아니다
그래서 사람의 일이 옮겨갑니다. 리뷰를 읽고 그대로 고치는 일은 이제 에이전트가 사람보다 성실하게 합니다. 남는 일은 끝을 정의하는 것입니다. 이 PR이 어디에 도달하면 충분한지, 어떤 지적은 이 산에 속하고 어떤 지적은 옆 산으로 가는 길인지.
모델은 그걸 모릅니다. 알 수가 없습니다. 제품의 본질이 무엇이고 이번 등반이 어느 봉우리를 향하는지는 코드 안에 없는 정보니까요. 끝을 정해주지 않으면 모델은 성실하게, 정확하게, 내가 오르려던 적 없는 산의 정상까지 갑니다.
그 PR도 그렇게 끝났을 겁니다. 그날 밤에는 지적을 따라 고치는 대신 이렇게 적었습니다. 인증에만 쓰는 크리덴셜은 계속 쓸 수 있다. 시크릿 값과 그 파생물은 자동으로 막힌다. 이 두 문장을 이 기능의 기준으로 확정했습니다. 다음 날 아침, 코멘트의 첫 줄이 달라졌습니다. “최신 지적을 고쳤다"가 아니라 “확정된 기준을 중심으로 재작업했다”. 그 뒤로는 작은 후속 하나, 최종 리뷰 요청 하나. 전날 두 시간에 열두 라운드를 돌던 사이클이 코멘트 두 개 만에 수렴했고, PR은 머지됐습니다.
끝을 정한다는 건 PR을 죽이는 일이 아니었습니다. 지적을 하나씩 상대하는 대신, 무엇이 이 기능의 본질인지 박아두는 일이었습니다. 기준이 생기자 정확한 지적들이 저절로 갈렸습니다. 지키는 데 필요한 것과, 정확하지만 이 산이 아닌 것으로.
사이클이 남긴 원칙 넷
이런 사이클을 몇 번 겪고 Codex 리뷰를 대하는 원칙을 세웠습니다. 원칙이라기엔 아직 2주짜리지만, 그 2주 동안 매 PR에서 확인하며 지금까지 유효한 것은 넷입니다.
- 제품의 작동 관점에서 코멘트를 읽어라. 코드 관점에서 맞는 지적인지가 아니라, 이대로 고치면 사용자가 겪는 무엇이 달라지는지를 먼저 묻는다.
- 사용자 임팩트로 경중을 따져라. 같은 “정확한” 지적이라도 크래시를 막는 것과 네이밍을 다듬는 것은 다른 등급이다.
- 바로 고치지 마라. 코멘트에 반응해서 코드를 고치기 전에, 고쳐질 코드와 기존 코드의 관계를 먼저 이해한다. 사이클이 도는 PR에서 급한 수정은 다음 라운드의 재료가 된다.
- 머지 블로커가 아니면 이슈로 보내라. 그것도 아니면 무시하라. 정확하지만 지금 필요하지 않은 지적의 자리는 이슈 트래커지, 이 PR이 아니다.
넷의 공통점이 보이실 겁니다. 전부 리뷰를 더 많이 받아들이는 기술이 아니라, 덜 받아들이는 기술입니다.
무시는 게으름이 아니라 판단이다
무시한 코멘트들을 나중에 돌아보면 대부분 잘한 무시였습니다. 처음에는 이게 불편합니다. 정확한 지적을 무시하는 건 게으름처럼 느껴지니까요. 하지만 90%가 정확한 리뷰가 무한히 공급되는 환경에서 전부 받아들이는 건 성실이 아니라 방향 상실입니다. 무시는 “이 지적은 우리 산이 아니다"라는 판단이고, 그 판단이야말로 사람이 루프에 있는 이유입니다.
이 원칙의 전제
정직하게 선을 긋겠습니다. 이 원칙들은 제품의 본질을 아는 사람이 루프 안에 있을 때만 작동합니다. 무엇이 본질인지 모르는 채로 무시하면 그건 정말 게으름이고, 사이클을 끊는 게 아니라 품질을 끊는 게 됩니다.
그리고 숙제가 하나 남습니다. 그 본질을 에이전트에게 미리 넘겨줄 수는 없을까요. 사람이 매번 끝을 정하는 대신, 끝의 기준 자체를 넘겨주는 것. 저는 지금 그걸 실험하고 있고, 결과가 쌓이면 여기에 적겠습니다.