---
type: note
kind: Recipe
tags: ['claude-code', 'subagent', 'code-review', 'llm']
status: release
ctime: 2026-09-01
mtime: 2026-09-01
parent: '581'
verified: { by: claude/opus-5, at: 2026-09-01T00:00:00Z }
sources:
  - id: bun-in-rust
    resource: https://bun.com/blog/bun-in-rust
    title: "How we rewrote Bun in Rust — Bun"
  - id: bun-v1-4
    resource: https://bun.com/blog/bun-v1.4
    title: "Bun v1.4 (릴리스 노트 — 방법론은 위 글에)"
---

**64개 병렬은 결과지 원인이 아니다.** 일을 성립시킨 건 셋이다 — 컨텍스트 비대칭, 기계적으로 생성되는 큐, **언어 독립 오라클**.

**언제**: 실패를 기계적으로 열거할 수 있고, 그걸 반복해서 고쳐야 할 때.

> [!IMPORTANT]
> **오라클이 없으면 여기서 멈춘다.** [그 포팅](https://bun.com/blog/bun-in-rust)에는 4,174개 파일 6만여 개 `expect()` 짜리 TypeScript 테스트 스위트가 있었고 **스킵·삭제 0개**였다. 언어를 바꿔도 "테스트 통과"가 진짜 신호였다는 뜻이다. 그게 없으면 리뷰어를 둘 붙여도 **검증되지 않은 코드를 빠르게 생산할 뿐**이다. 순서를 뒤집는다 — 실패를 열거 가능한 상태(타입 에러 목록·스냅샷·시각 회귀)를 **먼저** 만들고 그다음에 에이전트를 붙인다.

**절차** — 한꺼번에 세우지 않는다. 리뷰어 하나부터.

1. `adversarial-reviewer` 하나만 만들어 `memory: project`로 몇 주 돌린다.

   ```markdown
   ---
   name: adversarial-reviewer
   description: diff 하나를 받아 틀린 이유만 찾는다. 수정하지 않는다.
   tools: Read, Grep, Glob
   memory: project
   ---
   이 diff는 틀렸다. 어디가 왜 틀렸는지 찾는 것이 유일한 임무다.
   "괜찮아 보인다"는 결론은 허용되지 않는다. 최소 3개의 실패 시나리오를 제시하라.
   구현자의 근거를 요청하지 마라. 주어진 diff와 원본 파일만 본다.

   거절 규칙:
   - 한 문단짜리 주석으로 우회를 정당화해야 한다면 코드가 틀린 것이다.
   - 스텁·TODO·조건부 비활성화로 컴파일을 통과시킨 것은 미완성이다.
   - 테스트를 수정해서 통과시킨 변경은 무조건 거절이다.

   반복해서 나오는 패턴은 메모리에 기록하라.
   ---
   ```

2. 쌓인 지적 패턴이 **거절 규칙 목록**이 된다. 그 목록이 생긴 뒤에야 나머지를 붙이는 게 의미가 있다.
3. `porter`(구현, `isolation: worktree`)와 `fixer`(지적만 반영, 새 기능 금지)를 붙인다. 큐를 도는 건 세션 밖이다 — 실패 목록을 파일로 만들고 `claude -p`를 반복한다.

**확인**: 리뷰어가 **`tsc`·`eslint`가 통과시키는 지점**을 잡고 있는가. 그게 이 역할의 존재 가치 전부다 — effect 의존성의 의미 변화, 이벤트 핸들러의 eager/lazy, `??`와 `||`의 단축평가 차이, 리렌더 타이밍, 정리 함수 누락. 린터가 잡을 걸 잡고 있으면 프롬프트가 헐거운 것이다.

**함정**

- **컨텍스트 비대칭은 저절로 유지되지 않는다.** 위임 프롬프트를 부모가 쓰기 때문에, 그냥 두면 구현 근거를 요약해서 리뷰어에게 넘겨버린다. `.work/<id>.diff`를 경유시키고 **"리뷰어에게는 diff 경로와 원본 경로만 전달한다"를 CLAUDE.md에 규약으로** 박는다.
- **역할 분리를 프롬프트로 하면 무너진다.** 리뷰어 `tools`에 `Edit`/`Write`가 없는 것이 그 강제다 — 권한으로 막는다.
- **같은 모델 둘은 실패 상관관계가 높다.** 리뷰어를 둘 둘 거면 하나는 `model`을 다르게 준다.
- **`-p`(비대화형)에서는 fork mode가 꺼져 subagent가 포그라운드로 도는 경우가 있다.** 병렬은 셸 레벨에서 잡는 편이 예측 가능하다.
- 병목은 모델이 아니라 **디스크 IOPS**였다 — *"One slow `grep` command was all it took to freeze disk reads & writes for minutes."*

**왜 되는가** — 같은 모델인데 **입력이 다르면 목적함수가 갈린다.** 구현자는 원본과 자기 추론을 갖고 **머지되기를 원하고**, 리뷰어는 diff만 받고 "이 코드는 틀렸다고 가정하라"는 지시를 받아 **버그를 찾기를 원한다.** 그래서 입력 자체를 잘라야 한다.

실패가 나오면 **코드가 아니라 프롬프트를 고친다.** 스텁으로 때우기·변명 주석 붙이기는 *"한 문단짜리 주석이 필요하면 코드가 틀린 것"* 이라는 거절 규칙 하나로 사라졌다.
