Claude × Codex 핑퐁 리뷰 루프, 몇 번이 적정선인가
가설 — CLAUDE.md 상단에 "과설계 금지"만 단단히 박아두면, Claude ↔ Codex 핑퐁 루프가 아무리 길어져도 코드 비대화는 막을 수 있다.
결론 — 못 막습니다. 루프 횟수 자체가 과설계의 1차 변수이고, 프롬프트는 2차 변수에 불과합니다.
이 글은 그 결론에 도달한 과정의 회고입니다. 현장에서 실제로 돌아가는 멀티에이전트 구현체들이 디폴트 라운드 수를 어떻게 잡고 있는지를 먼저 살펴보고, 핑퐁이 길어질수록 왜 코드가 안전해지는 게 아니라 부풀어 오르는지를 메커니즘으로 풀어보겠습니다. 그리고 마지막에 직접 게이트 스킬을 설계할 때 반드시 들어가야 할 체크리스트를 정리합니다.
1. 시작 — 왜 "라운드 수"가 신경 쓰였나
최근에 Claude Code와 Codex를 짝지어 돌리는 사례를 자주 봅니다. 패턴은 단순합니다.
[요구사항]
↓
Claude: 설계 + 구현
↓
Codex: 리뷰 (corrections, edge cases, ...)
↓
Claude: 수정
↓
Codex: 재리뷰
↓
... (APPROVED 또는 N라운드 도달 시 종료)이걸 스킬 한 개로 묶어두면, 사람 손을 거의 안 거치고 한 번 트리거로 끝납니다. 매력적입니다. 그런데 직접 몇 번 돌려보다 보니 한 가지가 계속 걸렸습니다.
핑퐁이 길어질수록 코드가 더 안전해지는 게 아니라, 더 비대해지는 것 같다.
CLAUDE.md 맨 위에 "과설계 금지", "방어적 코드 금지", "YAGNI"를 줄 맞춰 박아둬도 그랬습니다. 이게 단순한 체감인지, 아니면 측정 가능한 현상인지 확인하려고 현장 구현체와 논문을 훑었습니다.
2. 현장 구현체가 잡은 상한선
먼저 실제로 Claude × Codex 루프를 코드로 구현한 프로젝트들이 어떤 숫자를 디폴트로 박아뒀는지 봅니다.
| 구현체 | 디폴트 상한 | 종료 조건 | 비고 |
|---|---|---|---|
| SmartScope SKILL.md | 5 라운드 | VERDICT: APPROVED (리뷰어가 "통과" 판정) 또는 5회 도달 | 5회 후 새 세션으로 한 번만 최종 검수 (루프 X) |
| The Pair (timwuhaotian) | 20 라운드 | 상한 도달 시 자동 종료가 아닌 "사람 검토 대기" 상태로 멈춤 | 20은 "정상 종료값"이 아니라 "이제 사람이 들어와야 한다는 알람" |
| Adversarial Review (alecnielsen) | 2 라운드 | 코드 레벨에서 못박은 상한 | 무한 루프 방지가 1순위 목적 |
| Self-Refine 논문 (Madaan 2023) | 평균 ~3회에서 수렴 | 품질 정체 구간 (더 돌려도 안 좋아지지 않음) | 과반 태스크에서 3회 후 성능 정체 |
숫자는 2부터 20까지 폭이 넓어 보입니다. 그런데 한 가지 공통점이 있습니다.
20을 잡은 The Pair조차도, 20을 "끝나는 지점"이 아니라 "사람이 들어와야 하는 지점"으로 정의합니다.
즉 "AI끼리 알아서 수렴하는 정상 횟수"의 상한은 사실상 5 안팎입니다. 그 이상은 자동 종료가 아니라 에스컬레이션 신호로 다뤄야 한다는 합의에 가깝습니다.
3. 왜 핑퐁이 길어지면 과설계로 가는가
직관이 아니라 분명한 메커니즘이 있습니다. 세 가지로 정리해 봤습니다.
3-1. 비평가 편향 — 리뷰어는 "지적 없음"을 못 견딘다
LLM 리뷰어(Codex)는 "지적할 게 없습니다"라고 말하는 걸 잘 못 합니다. 매 라운드마다 뭔가 코멘트할 거리를 찾으려는 본능이 강합니다. 라운드가 거듭될수록 진짜 큰 이슈는 이미 해결되어 있기 때문에, 남는 건 점점 사소한 트집(nitpick)과 "혹시 모르니까 더 막아두자"식 방어 제안뿐이게 됩니다.
라운드별로 어떻게 변질되는지 예를 들면 이렇습니다.
- 1라운드 — "이 함수에 null 체크가 없습니다" → 정당한 지적
- 2라운드 — "이 입력값도 검증(validation)하는 게 좋을 것 같습니다" → 애매함
- 3라운드 — "이 예외 케이스도 처리하면 더 안전합니다" → 대부분 YAGNI
(You Aren't Gonna Need It — "어차피 안 쓸 기능 미리 만들지 마라"는 원칙) - 4라운드 — "로깅을 추가하면 디버깅에 도움될 것 같습니다" → 요구사항 밖으로 스코프 이탈
3-2. 개별 합리성의 함정 — 누적은 보이지 않는다
각 제안을 개별적으로 보면 다 합리적입니다. 그래서 Claude도 그대로 받아들입니다. 문제는 여기서 일어납니다.
CLAUDE.md의 "과설계 금지"는 전체 누적 효과에 대한 규칙입니다. 그런데 매 라운드의 판단은 개별 제안 단위에서 일어납니다. 규칙과 판단의 단위가 어긋나 있는 셈입니다.
다시 말하면, CLAUDE.md는 "비대해진 코드 전체"를 보고 작동해야 하는데, 핑퐁 루프 안에서는 "비대해지기 직전의 한 줄"을 보고 작동해야 합니다. 후자는 거의 항상 통과됩니다 — 한 줄짜리 null 체크 하나가 과설계로 보이지는 않으니까요. 그 한 줄이 라운드마다 쌓여서 결국 비대해집니다.
3-3. 모호한 종료 조건
VERDICT: APPROVED(리뷰어가 "통과"라고 선언하는 신호)를 리뷰어의 주관에 맡겨두면, 리뷰어가 "이만하면 됐다"고 판단할 때까지 루프가 돕니다. 그런데 위 3-1번에서 본 비평가 편향 때문에, 그 판단이 자꾸 늦어집니다.
모호한 종료 조건 + 지적하려는 본능 = 자연 발산.
이 조합은 거의 결정론적으로 루프를 늘립니다.
4. ASCII로 본 발산 vs 수렴 핑퐁
라운드별 변경 줄 수를 그려보면 차이가 명확합니다.
수렴하는 핑퐁 (정상)
변경 줄 수 (LOC = Lines Of Code)
│
40├ ●
│ \
20├ ●
│ \
5├ ●____● ← 3라운드부터 변경량 미미, 종료해도 OK
└─────────────→ 라운드
1 2 3 4
발산하는 핑퐁 (병리)
변경 줄 수
│
40├ ● ● ← 4라운드 변경량이 1라운드와 맞먹음
│ \ ╱
30├ ● ╱ 방어 코드 + 트집(nitpick) 제안이 계속 누적
│ ╲╱
20├ ● ← 2라운드에 바닥 찍고 다시 상승
└─────────────→ 라운드
1 2 3 4규칙 하나로 요약하면 이렇습니다.
N+1 라운드의 변경량 > N 라운드면, 그 루프는 수렴이 아니라 발산입니다. 즉시 종료시켜야 합니다.
이 신호 하나만 코드 레벨에서 모니터링해도, 위 3-3번의 "모호한 종료 조건" 문제를 상당 부분 자동으로 잡을 수 있습니다.
5. 작업 유형별 권장 상한
지금까지의 근거를 종합해 작업 유형별로 라운드 수를 정리해 봤습니다.
| 작업 유형 | 권장 상한 |
|---|---|
| 버그 수정 · 소규모 변경 · 리네이밍 | 1~2회 또는 루프 생략 |
| 일반 기능 구현 | 2~3회 |
| 대규모 설계 (auth, 동시성, 데이터 모델) | 최대 5회 |
| 6회 이상 | 금지 — 사람이 들어와야 합니다 |
SmartScope 본인도 "작은 변경에는 SKILL.md 패턴 자체가 overkill"이라고 명시하고 있습니다. 핑퐁 루프 자체가 비용(토큰, 시간, 그리고 누적되는 과설계 위험)이라는 점을 잊으면 안 됩니다.
6. 핑퐁 게이트를 설계한다면 — 체크리스트 6가지
직접 핑퐁 게이트 스킬을 만든다면 아래는 반드시 들어가야 한다고 봅니다.
6-1. 절대 상한을 코드 레벨에서 못박는다
CLAUDE.md에 "3라운드 이내로 끝내라" 같은 자연어 가이드만 두면 거의 100% 지켜지지 않습니다. 스킬 코드 안에서 카운터 변수로 강제해야 합니다.
디폴트 3, 절대 상한 5.
6-2. 리뷰어 프롬프트에 "지적의 범위"를 못박는다
이게 빠지면 과설계는 거의 확정입니다. 아래처럼 명시적으로 화이트리스트와 블랙리스트를 줍니다.
다음만 지적할 것:
- 동작 오류 (correctness bug)
- 보안 취약점 (security vulnerability)
- 요구사항 미충족
다음은 지적 금지:
- 코드 스타일 / 포맷팅
- 리팩토링 제안
- 방어적 코드 추가 (defensive coding)
- 추가 입력 검증 / null 체크 (요구사항에 없는 경우)
- 로깅 / 관측성(observability) 추가 (요구사항에 없는 경우)화이트리스트만 두지 말고 블랙리스트도 같이 두는 게 핵심입니다. LLM은 "허용된 것 외엔 금지"보다 "이건 명시적으로 금지"라는 신호에 더 강하게 반응합니다.
6-3. 라운드별 변경량 모니터링
N+1 라운드의 변경 크기(diff)가 N 라운드보다 크면 발산으로 간주하고 즉시 종료합니다. 4번 절의 두 번째 패턴이 감지되는 순간 루프를 깹니다. 코드로 강제하기 쉬운 객관적 신호라서, 6-1의 절대 상한과 함께 두 겹의 안전장치가 됩니다.
6-4. 같은 지적이 2라운드 연속 살아남으면 사용자에게 위임
The Pair는 3라운드까지 권하지만, 실제로 해보면 2라운드가 더 안전합니다. 3라운드까지 가면 이미 본래 지적과 무관한 변경이 같이 섞여 들어와 있는 경우가 많습니다. "이 부분이 두 번 연속 지적됐다"는 신호는 AI가 자체 판단으로 닫지 말고 사람에게 넘기는 게 맞습니다.
6-5. 최종 검수는 새 세션에서 단발성으로
루프 내부에서 Codex의 컨텍스트(이전 대화 기억)가 계속 쌓이면, "이 정도면 됐다"는 편향이 자연스럽게 생깁니다. 종료 직전 한 번은 이전 대화 기록이 전혀 없는 새 세션으로 다시 검수합니다. SmartScope가 Level 1.5라고 부르는 패턴입니다.
요점은 이렇습니다 — 핑퐁에 참여한 리뷰어는 이미 그 코드와 정서적으로 얽혀 있습니다. 마지막 한 번은 그 정서가 없는 리뷰어에게 맡기는 게 안전합니다.
6-6. 버그픽스 모드와 설계 모드를 분리한다
같은 게이트로 모든 작업을 다루지 마세요. 버그픽스 모드는 디폴트 1라운드, 설계 모드는 3라운드로 분리해서 운영합니다. 한 가지 라운드 수로 모든 작업을 통과시키려고 하면, 반드시 한쪽(보통 작은 변경 쪽)에서 과설계가 일어납니다.
7. 후일의 나에게 남기는 메모
핑퐁 게이트 스킬을 만들기 전에 스스로에게 던질 질문 셋입니다.
- 종료 조건이 객관적인가? —
APPROVED가 리뷰어의 주관이면 발산합니다. "요구사항 X, Y, Z 충족됨"처럼 체크리스트로 바꿀 수 있는가. - 리뷰어의 지적 범위를 좁혔는가? — 좁히지 않은 리뷰어는 매 라운드마다 새 일을 만들어냅니다. "correctness 외엔 지적 금지"를 명시적으로 박았는가.
- 상한을 코드로 강제했는가? — 자연어 가이드는 안 지켜집니다. 카운터를 박았는가. 그리고 그 상한이 작업 유형에 맞게 1~5 범위에 있는가.
이 세 가지가 다 "예"가 아니면, 핑퐁 게이트는 덜 안전하지만 더 비대한 코드를 만들어내는 기계가 됩니다. CLAUDE.md에 무엇을 쓰든 그렇습니다.
참고
- SmartScope — Claude Code × Codex Review Loop Automation
- The Pair (timwuhaotian/the-pair)
- Adversarial Review (alecnielsen/adversarial-review)
- Self-Refine: Iterative Refinement with Self-Feedback (Madaan et al., 2023)
- Lessons Learned: A Multi-Agent Framework for Code LLMs (2025)
- Agent-to-agent pair programming — Axel Delafosse
- Best practices for Claude Code (공식)