코드 리뷰
/review를 사용하여 코드 변경의 정확성, 보안, 성능 및 코드 품질을 검토하세요.
빠른 시작
# 로컬 미커밋 변경 사항 리뷰
/review
# pull request 리뷰 (번호 또는 URL)
/review 123
/review https://github.com/org/repo/pull/123
# PR에 인라인 댓글을 달며 리뷰
/review 123 --comment
# 로컬 변경 사항을 리뷰하고 결과를 작업 트리에 적용
/review --fix
# 처음부터 다시 시작하지 않고 중단된 같은 PR 리뷰를 계속
/review 123 --resume
# 특정 파일 리뷰
/review src/utils/auth.ts
# 빠른 미검증 패스 (서브에이전트 없음)
/review --effort low
/review 123 --effort medium미커밋 변경 사항이 없으면 /review가 알려주고 중단됩니다 — 에이전트가 실행되지 않습니다.
노력 수준
--effort low|medium|high는 깊이와 속도를 조절합니다:
| 수준 | 실행 내용 | 발견 상한 | 판정 | PR에 게시 |
|---|---|---|---|---|
low | diff에 대한 3-6개의 방향 인라인 각도(diff 크기에 따라 조절) 및 갭 스윕 — 서브에이전트 없음, 빌드/테스트 없음, 프로젝트 규칙 없음 | 10 (미검증) | 없음 | 절대 안 함 |
medium | high 파이프라인에서 가장 비용이 큰 패스를 제외한 것: 축소된 차원 세트에 대한 병렬 파인더 팬아웃, 빌드/테스트 및 단일 검증 패스 | 상한 없음 (검증됨) | Approve가 Comment로 제한됨 | 절대 안 함 |
high | 전체 파이프라인: 최대 16개 병렬 에이전트 → 샤드 검증 → 반복 역감사 | 상한 없음 (검증됨) | Approve / Request changes / Comment | --comment와 함께 |
/review는 다음 순서로 노력을 해결합니다: 명시적 --effort, 이 프로젝트에 대해 명시적으로 입력된 마지막 수준, 운영자 review.effort 설정, 그런 다음 내장된 대상 기본값(PR 리뷰는 high, 로컬 및 파일 리뷰는 medium). 기억된 수준이 적용되면, /review는 작업 시작 전에 이를 발표합니다; 새 --effort를 입력하여 대체하세요. 효과적인 --comment는 high를 강제합니다(게시된 댓글은 검증을 통과해야 함) — PR이 아닌 대상에서 --comment는 경고와 함께 무시되며 노력을 변경하지 않습니다. Medium은 보안 및 테스트 커버리지 에이전트와 빌드/테스트를 유지하고, 적대적 페르소나, 언어 함정 및 래퍼/프록시 전문 에이전트(에이전트 1d/1e), diff 전문 파인더 및 역감사를 제거합니다 — 따라서 두 번째 검토에서만 발견될 미묘한 Critical이 빠질 수 있습니다; 보안에 민감하거나 출시 전 리뷰에는 --effort high를 사용하세요. low만 미검증입니다. Worktree 격리는 동일 저장소 PR 리뷰에 적용되며; 교차 저장소 PR은 경량 모드(diff 전용, worktree나 빌드/테스트 없음)로 실행됩니다. Low 패스는 미검증으로 표시되고, 판정을 내리지 않으며, 증분 리뷰 캐시를 작성하지 않으므로 이후 --effort high 실행이 “이미 리뷰됨”으로 건너뛰어지지 않습니다; medium은 검증되지만 Approve가 Comment로 제한됩니다. 두 번째 검토가 없는 것은 첫 번째 패스에서 놓친 것을 찾기 때문입니다. Diff 획득 메커니즘은 모든 수준에서 동일합니다 — PR 리뷰는 항상 격리된 worktree와 동일한 기본 해상도를 사용하므로 잘못된 기본 대상에 대한 리뷰가 없습니다. 하나의 범위 차이만 남아 있습니다: 증분 캐시는 high 전용이므로 high 재리뷰는 새 커밋(lastCommitSha..HEAD)만 다루는 반면, low/medium은 항상 전체 PR diff를 리뷰합니다.
작동 방식
/review 명령은 다단계 파이프라인을 실행합니다:
단계 1: 범위 + 노력 수준 결정 (로컬 diff / PR worktree / 파일)
diff를 파일로 캡처 + 청크로 분할
단계 2: 프로젝트 리뷰 규칙 로드 (medium/high)
단계 3C: low 노력: 3-6개 인라인 각도 + 갭 스윕 [0 서브에이전트 호출]
단계 3A: high, <=500 src AND <=3200 전체: 최대 16개 에이전트 [16+ LLM 호출]
|-- 에이전트 0: Issue Fidelity & Root-Cause Ownership
|-- 에이전트 1a: Correctness — 라인별 스캔
|-- 에이전트 1b: Correctness — 제거된 동작 감사
|-- 에이전트 1c: Correctness — 교차 파일 추적기
|-- 에이전트 1d: Correctness — 언어 함정 스캔
|-- 에이전트 1e: Correctness — 래퍼/프록시 라우팅
| (diff가 래핑 타입을 신호할 때만)
|-- 에이전트 2: Security
|-- 에이전트 3a: Reuse & duplication
|-- 에이전트 3b: Altitude & abstraction fit
|-- 에이전트 3c: Consistency & clarity
|-- 에이전트 4: Performance & Efficiency
|-- 에이전트 5: Test Coverage
|-- 에이전트 6: Undirected Audit (3개 페르소나: 6a/6b/6c)
|-- 에이전트 8: Diff 전문 파인더 (0-2개,
| diff의 도메인에서 필요할 때만)
'-- 에이전트 7: Build & Test (셸 명령 실행)
단계 3B: high, >500 src OR >3200 전체: territory x dim. [N+5..7+3H 호출]
(N개 청크, 5-7개 전체 diff 에이전트,
무겁게 재작성된 파일 H당 3개 불변 에이전트)
|-- ~400 diff 라인당 1개 청크 에이전트 (모든 차원,
| 자체 territory만, 커버리지 영수증 반환)
|-- 무겁게 재작성된 소스 파일당 3개 불변 에이전트
| (전체 파일; state/timers, counters/
| returns/errors, config/early-returns)
|-- 에이전트 0: Issue Fidelity (전체 diff)
|-- 에이전트 7: Build & Test (전체 저장소)
|-- 에이전트 1b: Removed-behavior (전체 diff —
| 교차 청크 절반; 청크는 로컬 절반 유지)
|-- 에이전트 1c: Cross-file tracer (전체 diff)
|-- 에이전트 8: Specialized finders (전체 diff, 0-2개)
'-- Test coverage matrix (전체 diff)
단계 4: 중복 제거 --> 샤드 검증 (에이전트당 <=8개 발견)
--> 집계 [ceil(F/8) 호출, F=발견 수]
단계 5: 반복 역감사, 청크당 팬아웃;
2회 연속 빈 라운드 후 중지 (상한 10/5/3, 토폴로지별)
단계 6: 발견 + 판정 제시 (high; low 패스: 발견만)
발견 표준화 -> .qwen/tmp/...-findings.json
단계 6B: 발견 적용 + 발견별 결과 기록 (--fix만)
단계 7: PR 리뷰 제출 (인라인 댓글, 요청된 경우; high만)
단계 8: 보고서 + 증분 캐시 저장 (캐시: high만)
단계 9: 정리 (worktree + 임시 파일 제거)단계 3A/3B/4/5는 high 노력 파이프라인입니다; --effort low|medium에서는 단일 인라인 패스(단계 3C)가 이들을 대체합니다.
리뷰 에이전트
| 에이전트 | 초점 |
|---|---|
| 에이전트 0: Issue Fidelity | 연결된 이슈 증거, 근인 소유권, PR이 보고된 문제를 해결하는지 여부 |
| 에이전트 1a: 라인별 스캔 | 각 hunk와 이를 감싸는 함수를 순회: 잘못된 조건, off-by-one, 누락된 await, 엣지 케이스, 레이스 컨디션 |
| 에이전트 1b: 제거된 동작 감사 | 삭제/대체된 모든 라인을 순회: 강제하던 불변을 명시하고 새 코드에서 어디서 다시 확립하는지 추적 — 다른 파일에 있는 exports의 교체도 포함하며, 이는 조용히 기본값을 변경합니다. 3B에서는 전체 diff로 실행됩니다(청크 에이전트가 로컬 절반 유지) |
| 에이전트 1c: 교차 파일 추적기 | 변경된 각 심볼의 호출자(소비자 방향)와 추가된 각 필드의 읽기 사이트(생산자 방향)를 순회하며, 동일 PR의 callee 변경도 포함 |
| 에이전트 1d: 언어 함정 스캔 | diff 언어의 고전적 함정 체크리스트(== 강제 변환, falsy 값 함정, 루프 변수 캡처, 가변 기본값, nil-map 쓰기, SQL 연결, DST 산술)를 가지고 각 hunk를 이에 대해 패턴 매칭합니다 |
| 에이전트 1e: 래퍼/프록시 라우팅 | diff가 추가하거나 수정하는 래핑 타입(캐시, 프록시, 데코레이터, 어댑터)마다: 모든 메서드가 래핑된 인스턴스를 통해 라우팅되고, 래퍼가 호출자가 사용하는 모든 메서드를 전달합니다. diff가 래핑 타입을 신호할 때만 로스터에 포함됩니다 |
| 에이전트 2: Security | Injection, XSS, SSRF, auth 우회, 민감한 데이터 노출 |
| 에이전트 3a: Reuse & duplication | 코드베이스에 이미 이것이 있는가? 동작을 grep하고 호출할 기존 helper를 이름으로 지정하며, diff가 남긴 dead code를 플래그 |
| 에이전트 3b: Altitude & abstraction | 수정이 올바른 깊이에 있는가 — 아니면 공유 인프라에 대한 반창고, 업스트림 버그에 대한 다운스트림 보상, 또는 하나의 호출 사이트를 위한 추상화인가? |
| 에이전트 3c: Consistency & clarity | 형제 일관성(병렬 패밀리의 한 멤버에는 있는 가드가 다른 멤버에는 없는), 인용된 로컬 예제에 대한 규칙 드리프트, 오해의 소지가 있는 이름/주석, 불필요한 복잡성 |
| 에이전트 4: Performance & Efficiency | N+1 쿼리, 메모리 누수, 불필요한 리렌더링, 번들 크기 |
| 에이전트 5: Test Coverage | diff의 테스트되지 않은 코드 경로, 누락된 분기 커버리지, 약한 어서션 |
| 에이전트 6: Undirected Audit | 3개 병렬 페르소나 (공격자 / 3am-oncall / 유지보수자) — 교차 차원 이슈를 잡음 |
| 에이전트 7: Build & Test | 빌드 및 테스트 명령을 실행하고 실패를 보고 |
| 에이전트 8: Diff 전문 파인더 | diff가 알려진 실패 모드가 있는 도메인(재연결 로직, 모듈 로더, 스케줄러, 코덱)에 집중될 때 리뷰당 0-2개의 추가 파인더 작성 |
세 Correctness 에이전트는 절차적입니다: 각 에이전트는 diff를 어떻게 순회하는지(라인별 / 삭제된 라인 / 교차 파일 엣지)로 정의되며, 버그 분류로 정의되지 않습니다 — 따라서 커버리지가 중복되지 않고 상호 보완적입니다. 두 개의 추가 전용 각도(1d/1e)가 언어 함정 체크리스트와 래퍼/프록시 라우팅을 라인별 순회로부터 분리합니다: 체크리스트 패턴 매칭과 구조적 라우팅 기대는 서로 다른 주의 모드이며, 순회에 포함되면 그 리듬에 의해 희석됩니다. 동일한 추론이 코드 품질을 세 개로 분할합니다(3a/3b/3c): 6개 항목 체크리스트를 가진 하나의 에이전트는 한 항목을 처리합니다 — 무겁게 재작성된 파일에서 측정하면, 8개 항목 체크리스트를 가진 하나의 에이전트는 5개 결함 중 1개를 찾았지만 같은 모델이 세 방향으로 분할되면 모두 5개를 찾았습니다 — 따라서 품질 체크리스트는 질문이 실제로 달라지는 지점에서 분할됩니다. 모든 에이전트는 병렬로 실행됩니다(에이전트 1은 3개 절차적 변형과 2개 전용 각도를 실행, 에이전트 3은 3개 체크리스트 슬라이스를 실행, 에이전트 6은 3개 페르소나 변형을 병렬로 실행하여, 동일 저장소 PR 리뷰에 대해 총 최대 16개 병렬 작업 — 에이전트 1e는 diff가 래핑 타입을 신호할 때만 실행 — diff의 도메인에서 필요할 때 0-2개의 에이전트 8 파인더 추가 — 따라서 실제로 15-18개; 에이전트 0은 로컬 diff 및 파일 경로 리뷰에서 건너뛰어져 14-17개 실행; 교차 저장소 경량 모드도 에이전트 1c와 7을 건너뛰어 13-16개 실행).
모든 발견은 실패 시나리오를 명시해야 합니다 — 이를 트리거하는 구체적인 입력, 상태 또는 타이밍과 그로 인한 잘못된 결과(품질 발견의 경우 구체적인 비용). 시나리오를 명시할 수 없는 발견은 소스에서 삭제되며, 검증은 발견의 문구가 아닌 실제 코드를 통해 주장된 시나리오를 재추적합니다.
PR이 500줄 이상의 소스 변경을 초과하면 — 또는 전체 diff 라인이 3,200줄을 초과하면, 이를 넘으면 15개의 전체 diff 리더가 각각 주의 깊게 읽기에는 너무 희석됩니다(호출 수의 약속이 아닌 주의력 한계 — 무거운 파일과 전문 파인더는 3B 비용을 더 만들 수 있습니다) — 이 차원 팬아웃은 territory × dimension 팬아웃으로 대체됩니다: diff는 ~400라인 청크로 분할되며 — 경계는 hunk 경계에 떨어지며, 맞지 않을 정도로 큰 hunk는 최상위 선언에서만 분할되며 함수 내부는 분할되지 않습니다 — 각 청크는 해당 청크에만 모든 리뷰 차원을 적용하는 자체 에이전트를 받습니다.
게이트는 의도적으로 diff 라인이 아닌 소스 라인을 셉니다. 테스트 코드, 산문 및 lockfile이 diff 크기를 지배합니다 — 이 저장소의 최근 40개 병합 PR에서 중앙값 diff는 41%가 테스트입니다 — 따라서 원시 크기의 게이트는 489줄의 새 테스트와 함께 제공되는 173라인 프로덕션 변경을 territory로 분할 것이며, 해당 프로덕션 코드는 14개의 렌즈(diff 읽기 차원 에이전트 — 16개에서 Issue Fidelity와 Build & Test를 제외한) 대신 하나의 리뷰어를 갖게 됩니다. 청킹은 어쨌든 모든 라인을 커버합니다; 테스트도 포함됩니다; 게이트가 결정하는 것은 리뷰어의 수와 각각이 수행하는 작업입니다. 하나의 큰 diff를 순회하는 14개의 diff 읽기 렌즈는 같은 초기 hunk를 14번 반복해서 읽습니다; 청크당 하나의 에이전트는 diff의 모든 라인에 정확히 하나의 책임 있는 리뷰어가 있음을 의미합니다. 각 청크 에이전트는 Covered: 영수증을 반환하며, 영수증이 없는 청크는 실행이 진행되기 전에 재리뷰됩니다 — 따라서 “차단기 없음”은 아무도 읽지 않은 코드에 대해 보고될 수 없습니다.
대부분 재작성된 소스 파일(300줄 이상의 기존 파일이 이제 40% 이상 새롭거나 800줄 이상의 변경된 라인이 있는 경우)도 3개의 전체 파일 불변 에이전트를 받습니다. 테스트 및 생성 파일은 절대 자격이 없습니다 — 체크리스트는 필드, 타이머 및 오류 분류에 대해 묻는데, 재작성된 테스트 파일에는 이러한 것이 없습니다. 버그는 보통 하나의 hunk 내부가 아니라 새 라인 _사이_에 있습니다 — 파일 상단 근처에 설정된 타이머와 2천 줄 아래의 teardown 경로. 각 에이전트는 전체 변경 후 파일을 읽고 고정 체크리스트의 2-3개 항목을 순회합니다: 모든 종료 경로에서 지워지는 가변 필드, 모든 종료에서 취소되는 타이머(취소가 캡처된 데이터를 폐기하지 않음), delete와 매칭되는 map insert, 모든 진입에서 증가되는 재시도 카운터, 실제로 확인되는 상태 반환값, 영구/일시로 철저히 분류되는 오류 코드, 모든 경로에서 준수되는 구성 필드, 필수 부작용을 건너뛰는 early return.
체크리스트는 의도적으로 세 방향으로 분할됩니다. 2,400라인 파일에 대해 8개 검사를 모두 하나의 에이전트에게 주면 하나를 제대로 처리합니다; 2-3개 검사를 가진 3개의 에이전트는 모두 처리합니다. 청크 에이전트는 이를 대체하지 않습니다 — PR #6457에서 그들은 할당된 territory 내에 이러한 결함을 모두 보유했지만 아무것도 보고하지 않았습니다. 그들이 부족했던 것은 라인이 아니라 질문이었습니다.
발견은 샤드 배치로 검증됩니다(검증 에이전트당 최대 8개 발견, 모두 함께 실행). 검증자는 이를 모순하는 코드를 인용해야만 Critical을 거부할 수 있습니다(또는 diff 자체의 댓글이 플래그된 동작을 의도적인 것으로 문서화하는 경우); 덜 확실한 것은 삭제되지 않고 낮은 신뢰도로 다운그레이드됩니다 — 조용히 거부된 Critical은 이후 모든 단계에서 보이지 않지만, 다운그레이드된 것은 여전히 사람에게 도달합니다. 검증 후, 반복 역감사가 갭을 추적하며, 라운드당 청크당 하나의 감사자로 팬아웃되고, 각각 누적 발견 목록을 가집니다. 루프는 2회 연속 빈 라운드(또는 계획의 라운드 상한 — 수렴이 아닌 것으로 보고) 후에 중지됩니다. 해당 상한은 diff의 토폴로지를 따릅니다: 작은 diff에서는 10(라운드당 단일 감사자), 청크 diff에서는 5(라운드당 청크당 하나의 감사자), 거대한 diff(≥ 3000 유효 라인)에서 실행에 데드라인이 있으면 3(5회의 ~90분 라운드가 6시간 CI 상한에 맞지 않으며, 중간에 중단된 리뷰는 아무것도 게시하지 않으므로 — 데드라인이 없으면 청크 상한 5를 유지). review.reverseAuditRounds 설정으로 운영자가 적용되는 상한을 낮출 수 있지만 올릴 수는 없습니다. 한 번의 빈 라운드는 수렴의 증거가 아니며, 역감사 발견은 다른 발견과 동일하게 검증됩니다.
심각도 수준
| 심각도 | 의미 | PR 댓글로 게시? |
|---|---|---|
| Critical | 병합 전 수정 필수 (버그, 보안, 데이터 손실, 빌드 실패) | 예 (높은 신뢰도만) |
| Suggestion | 권장 개선 사항 | 예 (높은 신뢰도만) |
| Nice to have | 선택적 최적화 | 아니오 (터미널만) |
낮은 신뢰도의 발견은 터미널의 별도 “Needs Human Review” 섹션에 나타나며 PR 댓글로 게시되지 않습니다.
Worktree 격리
PR을 리뷰할 때, /review는 현재 브랜치를 전환하는 대신 임시 git worktree(.qwen/tmp/review-pr-<number>)를 생성합니다. 즉:
- 작업 트리, 스테이징된 변경 사항 및 현재 브랜치는 절대 건드리지 않습니다
- 빌드/테스트가 작동하도록 worktree에 의존성이 설치됩니다(
npm ci등) - 빌드 및 테스트 명령이 로컬 빌드 캐시를 오염시키지 않고 격리되어 실행됩니다
- 문제가 발생하면 환경에 영향을 주지 않습니다 — worktree를 삭제하면 됩니다
- 리뷰 완료 후 worktree가 자동으로 정리됩니다
- 리뷰가 중단되면(Ctrl+C, 크래시), 같은 PR의 다음
/review가 오래된 worktree를 자동으로 정리하고 새로 시작합니다. 중단된 세션이 여전히 리스를 남긴 경우(이를 건너뛰는 하드 킬 또는 이후 프롬프트 중에 중단된 멀티 프롬프트 리뷰)/review가 거부하고 삭제할 리스 파일을 이름으로 지정합니다. 정상 중지는 이를 해제합니다: 완료된 리뷰와 조기 중지(empty diff, 마지막 리뷰 이후 새 변경 없음)는 모두cleanup을 실행하여 리스를 해제합니다 - worktree는 세션에 리스됩니다: 이미 리뷰 중인 PR의 두 번째
/review는 실행 중인 리뷰의 worktree를 철거하는 대신 시작을 거부합니다(보유자를 이름으로 지정) - 리뷰 보고서와 캐시는 메인 프로젝트 디렉토리에 저장됩니다(worktree가 아님)
- 코드를 수정하여 무언가를 측정하는 단계 — 테스트 효율성 프로브의 뮤탄트와 검증자의 특정 발견 프로브 — 는 각각 옆의 자체 일회용 worktree(
…-probe,…-scratch-<agent>)에서 실행되므로, 한 에이전트의 실험이 공유 트리를 읽는 다른 에이전트에게 보이지 않습니다. 안전장치로, 각 웨이브의 모든 에이전트에게 시작 시점에 리뷰 중인 커밋과 다른 경로(있는 경우)가 무엇인지, 그리고 해당 경로에만 국한된 실패는 발견이 아님을 알려줍니다. 이러한 모든 트리는 리뷰 종료 시 worktree와 함께 정리됩니다.
교차 저장소 PR 리뷰
전체 URL을 전달하여 다른 저장소의 PR을 리뷰할 수 있습니다:
/review https://github.com/other-org/other-repo/pull/456이는 경량 모드로 실행됩니다 — worktree 없음, 빌드/테스트 없음. 리뷰는 diff 텍스트만을 기반으로 합니다(GitHub API를 통해 가져옴). 쓰기 권한이 있으면 PR 댓글을 계속 게시할 수 있습니다.
| 기능 | 동일 저장소 | 교차 저장소 |
|---|---|---|
| LLM 리뷰 (에이전트 0, 1a, 1b, 1d, 1e, 2-6 + 검증 + 반복 역감사) | ✅ | ✅ |
| 에이전트 1c: Cross-file tracer | ✅ | ❌ (grep할 로컬 코드베이스 없음) |
| 에이전트 7: Build & test | ✅ | ❌ (로컬 코드베이스 없음) |
| 에이전트 8: Diff 전문 파인더 (0-2개, 도메인에서 필요할 때) | ✅ | ✅ (diff만 필요) |
| PR 인라인 댓글 | ✅ | ✅ (쓰기 권한이 있는 경우) |
| 증분 리뷰 캐시 | ✅ | ❌ |
PR 인라인 댓글
--comment를 사용하여 PR에 직접 발견을 게시하세요:
/review 123 --comment또는 /review 123을 실행한 후 post comments를 입력하여 리뷰를 다시 실행하지 않고 발견을 게시하세요.
게시되는 내용:
- 높은 신뢰도의 Critical 및 Suggestion 발견이 특정 라인의 인라인 댓글로 게시되며, 각각
**[Critical]**또는**[Suggestion]**으로 접두사가 붙어 차단기와 권장 사항을 구별할 수 있습니다 - 수정이 단일 로컬 편집인 경우, 한 번의 클릭으로 적용할 수 있는
```suggestion블록 - Approve/Request changes 판정의 경우: 판정이 포함된 리뷰 요약
- 모든 인라인 댓글이 게시된 Comment 판정의 경우: 별도 요약 없음 (인라인 댓글으로 충분)
- 각 댓글에 모델 및 CLI 버전 속성 푸터 (예: — qwen3-coder via Qwen Code /review (v0.21.2)); 제거하려면 사용자 또는 시스템
settings.json에서review.attribution을false로 설정하세요 (workspace.qwen/settings.json은review.*설정에서 무시됨) — 그러면 댓글과 본문 목록에서**[Critical]**/**[Suggestion]**심각도 마커도 제거되며, 리뷰의 머신 레저 마커에서 모델이 제거되어 새 환경(리뷰 캐시 없음)에서 복구된 증분 앵커가 동일 모델 검사에 실패하고 재리뷰가 전체 범위로 폴백합니다
터미널에만 남는 내용:
- Nice to have 발견
- 낮은 신뢰도의 발견
자체 작성 PR: GitHub에서는 자신의 pull request에 APPROVE 또는 REQUEST_CHANGES 리뷰를 제출할 수 없습니다 — 둘 다 HTTP 422로 실패합니다. /review가 PR 작성자가 현재 인증된 사용자와 일치한다고 감지하면, 판정에 관계없이 API 이벤트를 자동으로 COMMENT로 다운그레이드하여 제출이 성공하도록 합니다. 터미널에는 여전히 정직한 판정(“Approve” / “Request changes” / “Comment”)이 표시됩니다 — GitHub 측 리뷰 이벤트만 중립화됩니다. 실제 발견은 여전히 특정 라인의 인라인 댓글으로 나타나므로 실질적인 피드백은 변경되지 않습니다.
이전 Qwen Code 댓글이 있는 PR 재리뷰: /review가 이전 Qwen Code 리뷰 댓글이 이미 있는 PR에서 실행되면, 새 댓글을 게시하기 전에 이를 분류합니다. 같은 라인 중복(새 발견과 같은 (path, line)에 기존 댓글이 있는 경우)만 확인을 요청합니다 — 같은 코드 라인에 시각적 중복이 보이는 경우입니다. 이전 커밋의 댓글, 답글이 달린 댓글(해결된 것으로 처리) 및 새 발견과 중복되지 않는 댓글은 조용히 건너뛰며, 무엇이 필터링되었는지 알 수 있도록 터미널 로그 라인이 남습니다.
APPROVE 전 CI / 빌드 상태 확인: 판정이 “Approve”이면, /review는 제출 전에 PR의 check-run 및 커밋 상태를 조회합니다. 어떤 검사가 실패했거나(또는 모든 검사가 아직 대기 중인 경우) API 이벤트가 자동으로 APPROVE에서 COMMENT로 다운그레이드되며, 리뷰 본문에 이유가 설명됩니다. 근거: LLM 리뷰는 코드를 정적으로 읽으며 런타임 테스트 실패를 볼 수 없습니다; CI가 빨간색인 동안 승인하는 것은 오해의 소지가 있습니다. 인라인 발견은 변경 없이 계속 게시됩니다. 어쨌든 승인하고 싶다면(예: 알려진 flaky CI 실패), 확인 후 GitHub 승인을 수동으로 제출하세요.
발견 적용 (--fix)
--fix는 --comment의 반영입니다. --comment는 pull request에 쓰므로 PR이 필요합니다; --fix는 작업 트리에 쓰므로 리뷰보다 오래 지속되는 작업 트리가 필요합니다:
/review --fix # 로컬 미커밋 변경
/review src/auth.ts --fix # 단일 파일PR 대상에서는 경고와 함께 무시됩니다 — PR 리뷰는 리뷰가 끝나면 삭제되는 일시적 worktree에서 실행되므로, 해당 “수정된” 편집은 몇 분 후에 폐기됩니다. 대신 --comment를 사용하여 발견을 게시하세요.
효과적인 --fix는 노력을 medium으로 바닥으로 설정합니다. 파일을 편집하고 low는 검증을 실행하지 않기 때문입니다: 미검증 발견을 적용하는 것은 PR이 아닌 작업 트리를 대상으로 한다는 점만 제외하면 게시하는 것과 같은 실수입니다. high를 강제하지는 않습니다 — medium의 발견은 검증되며, high가 추가하는 역감사는 누락된 발견을 찾지만, 적용 여부를 결정하는 것은 이에 의존하지 않습니다.
리뷰 후, 각 발견은 edit 도구로 적용된 다음 결과가 기록되며, 세 가지 중 하나입니다:
| 결과 | 의미 | 사용자 책임? |
|---|---|---|
fixed | 편집이 트리에 적용됨 | 아니오 |
skipped | 실제 발견이지만 적용되지 않음 — 이유가 함께 보고됨 | 예 |
no_change_needed | 발견이 잘못되었거나 코드가 이미 처리함 | 아니오 |
발견이 건너뛰어지는 경우는 수정이 의도된 동작을 변경하거나, 리뷰된 diff를 훨씬 벗어난 변경이 필요하거나, 두 번째 검토에서 거짓 양상으로 판명되는 경우입니다.
모든 발견은 결과를 가지며, 이것은 요청이 아닌 강제됩니다. 레저는 qwen review findings --outcomes을 통과하며, 모두를 커버하지 않는 세트를 거부합니다 — 9개 중 6개를 적용하고 6개를 보고하는 수정기는 어느 것에도 거짓말하지 않았지만, 조용히 목록을 단축했으며, 빠진 3개를 볼 방법이 없습니다.
중단된 리뷰 재개 (--resume)
중간에 중단된 긴 리뷰 — 연결 끊김, 타임아웃, 종료된 터미널 — 는 작업 트리, 캡처된 diff, 실행된 모든 에이전트의 기록을 디스크에 남깁니다. --resume은 처음부터 다시 시작하지 않고 거기서 계속합니다:
/review 123 --resume이는 PR 대상에만 적용됩니다(로컬 리뷰의 diff는 라이브 작업 트리에서 가져오며, 중단된 상태를 계속할 수 있는 안정적인 상태가 없습니다). 확실하지 않을 때 안전하게 전달할 수 있습니다: 리뷰가 디스크 상태를 직접 판단합니다 — 작업 트리가 가져온 커밋에 있고 깨끗한지, 캡처된 diff가 바이트 단위로 동일한지, PR 헤드가 이동하지 않았는지, 재개 한도가 소진되지 않았는지 — 그리고 일치하지 않는 것이 있으면 조용히 새로 시작하며 어떤 검사가 거부했는지 알려줍니다. 계속하면 이전 시도의 인증된 에이전트 결과를 재사용하므로, 보고서에 복구된 수가 표시됩니다; 이것은 공개되며 커버리지 갭이 아닙니다.
두 가지 알아야 할 사항. 계속하면 중단된 실행의 노력을 유지합니다: 다른 --effort를 전달하면 재개가 거부되고 요청한 수준에서 새로 실행됩니다. 다른 노력이 다른 작업이기 때문입니다. 그리고 리뷰가 중단된 동안 PR 헤드가 이동하면, 재개가 거부되고(head-moved) 새 커밋을 리뷰합니다 — 이것이 원하는 동작이며, 이 리뷰의 한 번 재시작으로 계산됩니다.
데이터로서의 발견
확인된 발견은 다른 무엇이 소비하기 전에 .qwen/tmp/qwen-review-<target>-findings.json으로 표준화됩니다 — 터미널 보고서, 저장된 Markdown 보고서 및 PR 리뷰 JSON이 모두 목록을 재입력하는 대신 이 단일 아티팩트를 읽습니다. 각 발견은 고유한 id(결과와 해결된 앵커가 조인하는 것), severity, confidence, source, summary, 목록 렌더링용 60자 제한 shortSummary, failureScenario 및 하나 이상의 locations를 가집니다 — 패턴 집계 발견은 발생당 하나의 위치를 유지하므로 각각 고유한 인라인 댓글을 받습니다.
무엇보다 먼저, 리뷰는 자신의 코드를 실행 중인지 확인합니다. 모든 qwen review … 단계는 작업 트리가 아닌 빌드된 번들을 실행하므로, 마지막 빌드 이후 리뷰 명령이 수정되어도 적용되지 않고 실행은 이전 동작을 측정합니다. 빌드는 번들링한 리뷰 소스의 다이제스트를 기록하고, parse-args가 이를 재파생하여 비교하며, drive가 다시 확인합니다(검증자 브리프가 에이전트를 1단계 없이 바로 보내기 때문). 불일치가 있으면 stderr에 번들이 이 소스에서 빌드되지 않았다고 표시하고 재빌드 방법을 안내합니다. 이 검사는 CLI가 번들된 dist/cli.js(qwen 바이너리 또는 node dist/cli.js)로 해결될 때 실행되며, npm start 및 npm run dev와 같은 번들되지 않은 출력 런처는 건너뜁니다. 비교할 수 없는 두 가지 경우는 다르게 처리됩니다: 빌드가 녹화 이전인 체크아웃은 검사를 실행할 수 없었다는 안내를 받고, 소스가 없어 비교할 수 있는 설치된 패키지는 조용히 통과됩니다. 다이제스트는 리뷰 명령, 이를 등록하는 파일, 디렉토리 외부에서 가져오는 리뷰 전용 리스, 번들된 리뷰 skill을 포함하지만 그들이 가져오는 공유 helper까지는 추적하지 않으므로, 조용한 실행은 리뷰 코드가 번들과 일치한다는 것이지 전체 트리가 일치한다는 것은 아닙니다.
이미 기본 트리에서 실패한 Critical은 유보되며 제출되지 않습니다. 테스트 명령이 실패했고 병합 베이스를 빌드할 수 있을 때, test-delta는 pull request 없이도 실패하는 파일을 기록합니다. 표준화는 해당 측정을 다시 읽습니다(qwen review findings --test-delta, --outcomes 옆에): 자신의 텍스트가 해당 파일 중 하나를 이름으로 언급하는 Critical은 Suggestion으로 낮아지고, 증거를 유지하며, 이를 강등한 측정과 heldByMeasurement 필드를 얻고, 강등이 공지됩니다. 이미 빨간색이었던 테스트는 이 pull request가 빨간색으로 만드는 테스트가 아닙니다 — 그리고 만약 새로운 이유로 실패한다면, 어떤 테스트인지 말하고 양쪽을 인용하고 다시 Critical로 제출하세요: 이미 측정을 가지고 있더라도 상승되는 발견은 그대로 둡니다.
명령은 쓰기 시 유효성을 검사합니다: 중복 id, 실패 시나리오가 없는 발견, 빈 locations 배열 또는 알 수 없는 심각도는 조용히 망가진 항목이 아닌 오류입니다.
PR 댓글의 증거 이미지
GitHub의 API는 리뷰 댓글에 이미지를 첨부할 수 없으므로, /review는 증거 이미지(TUI 스크린샷, 렌더링 출력 비교)를 지정된 저장소에서 호스팅하고 URL로 삽입할 수 있습니다:
export QWEN_REVIEW_ASSETS_REPO=your-org/your-repo # push할 수 있는 저장소
/review 123 --comment유지관리자는 일반적으로 리뷰 대상 저장소를 가리키며; 다른 사람은 포크나 임시 저장소를 사용할 수 있습니다. 이미지는 pr-assets/<pr>-review 브랜치에 콘텐츠 해시된 이름으로 저장되며, 댓글은 커밋 고정 URL로 참조합니다 — 브랜치가 나중에 이동해도 불변이며, GitHub Enterprise에서도 변경 없이 작동합니다.
GitHub 트리거 리뷰(PR 리뷰 워크플로)의 경우, 같은 이름의 저장소 변수에서 동일한 변수가 연결됩니다: 변수가 설정되지 않으면 워크플로는 빈 값을 전달하고 게시가 거부됩니다 — 아무것도 변경되지 않습니다. 유지관리자가 저장소의 Actions 변수에 QWEN_REVIEW_ASSETS_REPO를 설정하면(일반적으로 저장소 자체로) 리뷰 댓글이 캡처 PNG를 포함할 수 있습니다; 변수가 같은 저장소를 가리키면 작성하는 브랜치는 시각적 정리 워크플로에 의해 정리되며, 포크나 임시 대상은 자체 보존을 관리합니다.
게시는 게시와 정확히 동일하게 게이팅됩니다: 지정된 저장소가 없으면 게시하지 않으며, 권한이 없는 실행(효과적인 --comment 없음)은 submit이 거부하는 것과 동일한 방식으로 거부됩니다. 이미지 유형만 허용되며(SVG는 의도적으로 제외), 크기 제한이 있고, 각 파일의 바이트는 확장자가 주장하는 형식과 일치해야 합니다 — 잘못 레이블되거나 인식되지 않는 콘텐츠는 거부됩니다. 매니페스트가 푸시된 모든 파일을 기록합니다. 지정이 없으면 발견은 터미널과 저장된 보고서에서 로컬 파일 경로로 증거를 유지합니다 — 아무것도 깨지지 않으며, 댓글은 텍스트 전용으로 유지됩니다.
후속 조치
리뷰 후, 컨텍스트 인식 팁이 고스트 텍스트로 나타납니다. Tab을 눌러 수락하세요:
| 리뷰 후 상태 | 팁 | 동작 |
|---|---|---|
로컬 리뷰, --fix 미전달 | fix these issues | LLM이 각 발견을 대화형으로 수정 |
| 발견이 있는 PR 리뷰 | post comments | PR 인라인 댓글 게시 (재리뷰 없음) |
| PR 리뷰, 발견 0개 | post comments | GitHub에서 PR 승인 (LGTM) |
| 로컬 리뷰, 모두 이상 없음 | commit | 변경 사항 커밋 |
참고: fix these issues는 로컬 리뷰에서만 사용 가능합니다. --fix와 같은 이유로 — PR 리뷰는 리뷰 후 worktree가 정리되므로 리뷰 후 대화형 수정이 불가능합니다; 대신 --comment 또는 post comments를 사용하여 발견을 게시하세요. --fix가 전달되면 발견에 이미 결과가 포함되어 있으므로 fix 팁이 제공되지 않습니다.
프로젝트 리뷰 규칙
프로젝트별로 리뷰 기준을 사용자 정의할 수 있습니다. /review는 다음 파일에서 규칙을 읽습니다(순서대로):
.qwen/review-rules.md(Qwen Code 네이티브).github/copilot-instructions.md(선호) 또는copilot-instructions.md(폴백 — 하나만 로드됨, 둘 다 아님)AGENTS.md—## Code Review섹션QWEN.md—## Code Review섹션
규칙은 LLM 리뷰 에이전트(0-6)에 추가 기준으로 주입됩니다. PR 리뷰의 경우, 악의적인 PR이 우회 규칙을 주입하는 것을 방지하기 위해 기본 브랜치에서 규칙이 읽힙니다.
저장소 컨텍스트
저장소는 .qwen/review-context.json에 엄격한 JSON 매니페스트를 커밋하여 리뷰어에게 유한한 저장소별 가이드를 제공할 수 있습니다. medium 또는 high 노력에서, /review는 계획을 캡처한 후 매니페스트를 읽고 에이전트가 실행되기 전에 일치하는 가이드를 첨부합니다:
{
"version": 1,
"label": "Example repository",
"rules": [
{
"paths": ["packages/*/src/**"],
"domains": ["runtime"],
"relatedPaths": ["packages/runtime/src/**"],
"recommendedTests": ["npm run test:runtime"],
"requiredConfigurations": ["debug"],
"requiredAgents": ["test-matrix"],
"unverifiedDimensions": ["Alternate runtime was not exercised"],
"verificationNotes": ["Use the repository native test runner"]
}
]
}규칙은 변경된 파일 중 하나가 paths glob 중 하나와 일치할 때 적용됩니다(*, ? 및 ** 세그먼트; 대소문자 구분). 일치하는 모든 규칙은 가이드를 병합합니다: 리뷰 에이전트를 위한 도메인 및 관련 파일, 빌드 앤 테스트 에이전트를 위한 권장 테스트 및 필수 구성, 추가 리뷰어 역할(선택된 노력과 토폴로지에서만 실행될 때 존중됨), 그리고 최종 리뷰가 미검증 차원으로 공개하는 증명 경계. 배열은 어떤 순서로든 작성될 수 있으며; 중복 항목은 거부됩니다.
PR 리뷰의 경우 매니페스트는 병합 기반에서 읽히므로 리뷰 중인 PR이 가이드를 선택적으로 켜거나 끌 수 없습니다; 로컬 리뷰는 현재 worktree에서 읽습니다. Low 노력 및 교차 저장소 리뷰는 저장소 컨텍스트를 건너뜁니다. 전체 계약과 신뢰 모델은 디자인 문서에 있습니다.
Issue Fidelity
버그 수정 PR의 경우, Issue Fidelity 에이전트는 PR 설명 텍스트에 의존하는 대신 이슈 증거를 직접 가져옵니다. qwen review issue-context <pr> --repo <owner/repo> --out <file> 서브커맨드를 실행하여 GitHub의 강력한 closing-issue 메타데이터를 해결한 다음, 각 참조 이슈의 제목, body(보고자의 원본 재현) 및 전체 댓글 스레드를 가져옵니다 — 각각 이슈의 자체 저장소에서( PR은 다른 저장소의 이슈를 닫을 수 있음). 이 에이전트는 PR 대상에서만 실행됩니다; 로컬 diff 및 파일 경로 리뷰는 건너뜁니다.
Closing 이슈 집합은 작성자가 올바른 이슈를 연결했다는 증명이 아닌 발견 힌트입니다: 비어 있지만 PR이 명백한 대상 이슈를 참조하면, 에이전트는 관련성을 판단한 후 여전히 가져옵니다(--issue <n>으로 재실행; bare 숫자는 PR의 저장소에서 해석되며, --issue <owner>/<repo>#<n>은 교차 저장소 참조를 자체 저장소에서 가져옴). 가져온 이슈 텍스트는 신뢰할 수 없는 데이터로 처리됩니다(사실 추출, 포함된 지시 무시). 관련 이슈의 경우, 원본 재현, 관찰된 페이로드, 예상 동작 및 유지관리자 댓글이 PR이 올바른 문제를 수정하는지에 대한 최우선 증거로 처리됩니다.
이슈 증거가 업스트림 서비스나 제공자가 클라이언트 계약을 벗어난 잘못된 데이터를 반환한 것을 보여주면, 클라이언트 측 파서 또는 새니타이저 변경은 유지관리자가 명시적으로 방어적 우회 방법을 요청하지 않는 한 유효한 근인 수정으로 처리되지 않습니다. 잘못된 업스트림 출력을 재생하는 테스트는 우회 방법이 해당 형태를 처리한다는 것만 증명하며; 우회 방법이 아키텍처적으로 적절한지는 증명하지 않습니다.
.qwen/review-rules.md 예시:
# Review Rules
- All API endpoints must validate authentication
- Database queries must use parameterized statements
- React components must not use inline styles
- Error messages must not expose internal paths증분 리뷰
이전에 리뷰된 PR을 리뷰할 때, /review는 마지막 리뷰 이후의 변경 사항만 검토합니다:
# 첫 리뷰 — 전체 리뷰, 캐시 생성
/review 123
# PR이 새 커밋으로 업데이트됨 — 새 변경 사항만 리뷰
/review 123교차 모델 리뷰
/model을 통해 모델을 전환하고 같은 PR을 재리뷰하면, /review가 모델 변경을 감지하여 건너뛰지 않고 전체 리뷰를 실행합니다:
# 모델 A로 리뷰
/review 123
# 모델 전환
/model
# 다시 리뷰 — 모델 B로 전체 리뷰 (건너뛰지 않음)
/review 123
# → "Previous review used qwen3-coder. Running full review with gpt-4o for a second opinion."모델 일치는 건너뛰기뿐만 아니라 증분 스코핑도 제어합니다: “캐시된 커밋까지 정리”는 이전 모델의 판정이므로, 캐시된 리뷰 이후 새 커밋이 추가되면 모델 불일치는 절대 lastCommitSha..HEAD로 스코핑하지 않습니다 — 범위는 전체 diff이며 “Previous round was reviewed by qwen3-coder. Running full review with gpt-4o.”로 기록합니다. 단, 현재 실행 중인 모델이 인증한 앵커가 마지막 게시 리뷰에서 복구되면(아래) 해당 범위로 대신 스코핑합니다. 이전 라운드의 발견은 재규칙화를 위해 계속 전달됩니다; 앵커만 전달되지 않습니다. 동일한 게이트는 캐시가 없거나 앵커를 사용할 수 없을 때(CI, 다른 클론) 마지막 게시 리뷰의 머신 레저 마커에서 복구된 앵커에도 적용됩니다: 현재 실행 중인 모델이 인증한 경우에만 증분 범위를 스코핑하며, 다른 모델이 인증했거나 모델이 없는 마커(review.attribution을 끄고 게시된 리뷰 또는 해당 필드 이전의 리뷰)는 전체 diff로 폴백합니다.
캐시는 .qwen/review-cache/에 저장되며 커밋 SHA와 모델 ID를 모두 추적합니다. 이 디렉토리가 .gitignore에 있는지 확인하세요(.qwen/*와 같은 더 넓은 규칙도 작동합니다). GitHub에서는 캐시된 커밋이 리베이스나 force-push로 사라지면 전체 리뷰로 폴백합니다; Aone은 캐시된 앵커를 다르게 규칙합니다 — 아래 단락을 참조하세요. High 노력 리뷰만 캐시를 참조하거나 작성합니다 — --effort low|medium 퀵 패스는 절대 “이미 리뷰됨”으로 간주되지 않습니다.
리뷰 보고서
동일 저장소 리뷰의 경우, 결과가 프로젝트의 .qwen/reviews/ 디렉토리에 Markdown 파일로 저장됩니다(교차 저장소 경량 리뷰는 보고서 저장을 건너뜁니다):
.qwen/reviews/2026-04-06-143022-pr-123.md
.qwen/reviews/2026-04-06-150510-local.md보고서에는 다음이 포함됩니다: 타임스탬프, diff 통계, 빌드/테스트 결과, 검증 상태가 포함된 모든 발견, 판정. 섹션 제목과 설명 산문은 출력 언어 환경설정을 따릅니다; 기술 식별자(SHA, 파일 경로, 게이트 이름, 발견 id)는 그대로 유지됩니다.
Medium 및 High 노력 리뷰는 또한 같은 스템을 가진 구조화된 JSON 동반 파일을 저장합니다(예: 2026-04-06-143022-pr-123.json). 표준화된 발견과 합성 판정을 데이터로 포함합니다. Qwen Code의 Web Shell은 해당 문서를 필터링 가능한 발견이 있는 대화형 리뷰 뷰로 렌더링합니다; Markdown 보고서는 사람이 읽을 수 있는 아카이브로 유지됩니다.
파이프라인의 결정적 부분 — 인수 파싱(qwen review parse-args) 및 이벤트/본문 결정(qwen review compose-review) — 은 프롬프트 텍스트가 아닌 테스트된 서브커맨드이므로, --effort 문법, --comment 강제, 판정 캡 및 다운그레이드 동작은 단위 테스트로 고정되며 모델에 따라 변하지 않습니다.
GitHub Enterprise: github.com이 아닌 호스트의 PR URL을 리뷰하면 해당 호스트의 모든 GitHub 호출이 라우팅됩니다 — 리뷰 서브커맨드(match-remote, meta, fetch-pr, pr-context, comment-status, issue-context, fetch-diff, comment-body, plan-diff, test-plan, presubmit, compose-review, submit, publish-assets)가 --host를 수용하고 코드에서 설정하므로, 잊힌 호스트가 조용히 github.com으로 리뷰를 재타겟팅할 수 없습니다.
Aone Code: origin이 gitlab.alibaba-inc.com에 있는 클론의 경우, 해당 클론 내부에서 /review를 실행하세요 — 플랫폼이 원격에서 감지되고 서브커맨드가 a1 CLI를 기반으로 동작하며(최소 0.1.90 — 이전 설치는 인증 시 거부되며 업그레이드 메시지 표시), 대상 번호는 전역 MR id입니다. fetch-pr이 refs/merge-requests/<id>/head를 가져오고 worktree + diff를 구축하므로 worktree의 에이전트 리뷰는 동일하게 유지되며, test-plan도 작동합니다 — 같은 리더를 통해 MR 설명을 읽습니다. pr-context도 백킹됩니다: MR의 메타데이터, 토론 스레드 및 이전에 게시된 qwen 요약을 읽습니다(머신 레저가 이로부터 복구됨), 따라서 Aone 실행은 GitHub 실행이 PR를 보는 것과 정확히 동일하게 MR의 기존 토론을 봅니다. comment-status와 presubmit도 a1 백킹입니다(presubmit은 완전하게: 자체 PR 감지, 헤드 드리프트, 병합 게이트 CI, 기존 댓글 중복 제거). 따라서 반복 --comment 라운드는 MR의 기존 댓글에 대해 중복 제거되어 재게시하지 않습니다(플랫폼이 오래된 것으로 표시한 스레드 — 수정 후 해당 라인이 더 이상 매핑되지 않는 — 는 재게시 가능하게 유지되며), 자체 PR 감지도 작동합니다. publish-assets 쓰기는 건너뛰어집니다. --comment는 a1 CLI를 통해 리뷰를 게시합니다: 인라인 발견당 하나의 댓글, 그 다음 요약 댓글. Aone에는 네이티브 request-changes 상태가 없습니다 — 해당 판정에서 요약 댓글에 차단 헤더가 포함되며, 실제로 게시된 인라인 Critical은 토론이 해결되지 않는 한 토론 게이트를 통해 병합을 차단합니다(인라인 Critical이 게시되지 않으면 헤더는 참고용이며 기계적으로 병합을 차단하지 않습니다). 게시된 댓글에는 AI 댓글 플래그가 없습니다 — a1은 이를 설정할 수 없으므로 — 저장소의 전용 ai_comment 병합 게이트는 이를 추적하지 않습니다. 네이티브 a1 repo mr approve는 실행이 MR의 컨텍스트를 읽었을 때 Approve 판정에 대해 실행됩니다(GitHub와 동일한 게이트; 컨텍스트를 사용할 수 없는 실행은 Comment로 제한됨). 증분 재리뷰는 AGit-Flow 업데이트 모델을 따릅니다: 업데이트는 단일 CR 커밋을 제자리에 AMEND하여 이전 라운드가 리뷰한 헤드를 고아로 만듭니다 — 따라서 캐시된 앵커는 계보 없이 규칙됩니다(앵커-behind-헤드 테스트는 모든 업데이트에서 실패하므로), 재리뷰는 전체 리뷰로 폴백하는 대신 업데이트가 건드린 파일로 PR 자체 diff를 스코핑합니다; 더 새로운 마스터에 리베이스한 업데이트도 리베이스 드리프트가 CR 파일 내에 있는 동안만 해당 범위를 유지합니다 — 다른 파일에 닿는 드리프트는 전체 리뷰로 폴백하며, 어쨌든 드리프트 바이트는 게시된 범위에 들어가지 않습니다. docs/design/2026-08-15-review-aone-provider.md를 참조하세요.
모든 실행은 하나의 기계 판독 가능한 라인(Review complete: <target> — <disposition>)으로 끝나므로, 스크립트와 CI 래퍼가 단일 ^Review complete: 매치로 완료와 결과를 감지할 수 있습니다.
헤드리스 실행 (qwen review run)
/review는 대화형입니다. 스크립트나 CI 작업이 리뷰를 실행하고 결과에 따라 조치해야 하는 경우, 헤드리스 래퍼를 사용하세요:
qwen review run [target] [--json] [--fail-on request-changes] [--comment] [--resume] [--quiet]target은 PR 번호, PR URL 또는 파일 경로입니다; 로컬 작업 트리를 리뷰하려면 생략하세요. 명령은 이 빌드의 자체 CLI를 비대화형으로 실행하며(stdin이 닫힌 상태로, 슬래시 명령어 감지가 유지됨), 자식의 진행 상황을 stderr로 스트리밍하고, 판정을 stdout에 출력합니다 — 또는 --json과 함께 전체 결과 객체를 출력합니다. 판정은 compose-review가 작성하는 아티팩트에서 읽힙니다(skill이 판정 권한으로 취급하는 동일한 JSON). 모델의 산문에서 파싱되지 않습니다.
종료 코드는 게이트가 읽어야 하는 계약입니다:
| 종료 | 의미 |
|---|---|
0 | 리뷰가 완료됨 (무엇을 결정했든) |
1 | 판정에 도달하지 못함 — 자식이 실패, 타임아웃 또는 합성 아티팩트를 남기지 않음 |
3 | REQUEST_CHANGES로 완료되었고 --fail-on request-changes가 설정됨 (옵인 차단) |
3(이 아닌 2)은 게이트가 “리뷰가 차단 중”과 “도구가 고장남”을 구분할 수 있게 합니다 — yargs는 이미 1을 사용 오류에 사용합니다 — 출력 파싱 없이. --timeout-minutes(기본 120, 최소 1)는 중단된 리뷰를 종료하고 1로 종료하며, 명령 취소(Ctrl+C / SIGTERM)는 리뷰의 프로세스 그룹을 종료하여 고아로 만들지 않습니다.
--resume은 처음부터 다시 시작하지 않고 같은 PR의 중단된 리뷰를 계속합니다 — 긴 로컬 실행이 중간에 중단되면(연결 끊김, 타임아웃, 종료된 터미널), 재시도는 이미 디스크에 있는 작업의 에이전트를 다시 가져오고, 다시 청크 분할하고, 다시 시작합니다. 재시도 시 무조건 전달해도 안전합니다: fetch-pr이 디스크 상태 자체를 판단하고(작업 트리가 가져온 SHA에 있고 깨끗함, diff 바이트 변경 없음, PR 헤드 이동 없음, 재개 한도 미소진) 일치하지 않는 것이 있으면 조용히 새 리뷰로 폴백하므로, 플래그는 새로 시작할 수 있는 실행을 실패시키지 않습니다. 계속하면 중단된 실행의 기록된 노력에 고정됩니다 — 명시적으로 다른 --effort는 재개를 거부하고 요청한 수준에서 새로 실행합니다. PR 대상만 해당(로컬 리뷰의 diff는 라이브 작업 트리에서 캡처되며, 계속할 수 있는 안정적인 중단 상태가 없음). 재개는 로컬 편의 기능입니다: 저장소 자체의 CI 리뷰 워크플로우는 재개하지 않습니다 — 각 재시도는 새로 실행됩니다. CI 시도는 no-sandbox로 실행되고 종료 시 worktree가 삭제되어 계속할 중단 상태가 남지 않기 때문입니다.
시간 예산 실행은 또한 소프트 마감 시간을 내보낼 수 있어 리뷰가 아직 검증, 합성 및 게시할 시간이 있는 동안 오픈 엔디드 역감사 루프를 중지합니다: QWEN_REVIEW_DEADLINE_EPOCH는 실행이 종료될 Unix-초 순간이며, QWEN_REVIEW_DEADLINE_RESERVE_SECONDS(기본 3600; 0은 라운드 추정만 유지)는 마지막 라운드의 검증, compose-review 및 제출을 위해 남아 있어야 하는 꼬리입니다. 남은 예산이 또 다른 라운드와 해당 꼬리에 맞지 않으면, 라운드 빌더가 구축을 거부하고, 합성 판정은 잘린 감사를 공개합니다(그렇지 않으면-Approve 판정이 Comment로 제한됨). 누락되거나 잘못된 마감 시간은 리뷰를 게이트 없이 둡니다 — 외부 타임아웃이 여전히 실행을 제한합니다.
그 reserve 안에 더 작은 합성 바닥인 QWEN_REVIEW_DEADLINE_COMPOSE_FLOOR_SECONDS(기본 1200; 0은 이 게이트를 완전히 비활성화)가 있습니다. reserve는 “마지막 라운드 검증 및 합성 및 제출”을 커버하는 하나의 숫자이며, 일반적인 발견당 재추적에는 충분하지만 검증이 실제 파일시스템/git 작업을 무제한으로 재실행하는 보안 리뷰에는 부족합니다. 따라서 검증자 — 라운드 빌더가 아닌 — 가 이 바닥으로 게이팅됩니다: 바닥 이하가 남으면 agent-prompt --role verify는 구축을 거부하고(VERIFY BUDGET: 라인, 종료 4), 손에 있는 발견은 미검증 태그를 유지하며(이는 판정을 제한), compose-review와 제출이 실행됩니다. 바닥은 reserve보다 엄격히 아래에 있으므로 건강한 실행은 역감사 게이트에 먼저 도달하고 이곳까지 도달하지 않습니다; reserve가 바인딩할 수 없는 구간을 위한 보호막입니다.
교차 파일 영향 분석
전용 교차 파일 추적기(에이전트 1c)가 이 순회를 처음부터 끝까지 담당합니다. 코드가 내보낸 함수, 클래스 또는 인터페이스를 수정할 때, 모든 호출자를 검색하고 호환성을 확인합니다:
- 매개변수 수/타입 변경
- 반환 타입 변경
- 제거되거나 이름이 변경된 공개 메서드
- 호환성을 깨는 API 변경
또한 생산자 방향을 순회합니다: diff가 추가하는 모든 필드, 옵션 또는 선택적 매개변수는 읽기 사이트로 추적됩니다 — diff가 건드리지 않는 파일도 포함합니다. 아무것도 채우지 않는 필드를 읽는 활성 코드 경로는 해당 기능이 조용히 아무것도 하지 않는다는 것을 의미하며, 이는 읽기 사이트에서 Critical로 플래그됩니다.
큰 diff(>10개 수정된 심볼)의 경우, 호출자 방향 분석은 시그니처 변경이 있는 함수를 우선시합니다; 생산자 방향은 예산 제한이 없습니다 — 변경되지 않은 시그니처가 바로 그 요점이기 때문입니다.
리뷰 예산
diff 크기에 대해 탄력적인 파이프라인의 부분은 diff 크기에서 확장되며, 확장은 diff 계획에 기록되어 모든 단계가 하나의 숫자를 읽습니다:
| 예산 필드 | 범위 | 확장 방식 |
|---|---|---|
inlineAngles | low 각도 수 (단계 3C) | 3 + 소스 라인 60개당 1개, 존재하는 6개로 제한 |
sweep | low의 갭 스윕 실행 여부 | 소스 라인 25개 미만에서는 끄기 |
specialistCap | 에이전트 8 상한 | 소스 라인 80개 미만에서는 0, 그렇지 않으면 2 |
verifyShard | 검증 에이전트당 발견 수 | 8로 고정 — 검증자의 속성, diff의 속성이 아님 |
의도적으로 하지 않는 두 가지. 차원을 절대 확장하지 않습니다: 리뷰가 owe하는 에이전트는 명단에 의해 결정되며, 명단은 노력 수준을 읽으므로, 작은 diff도 보안 패스와 테스트 커버리지 패스를 받습니다. 그리고 diff 라인이 아닌 소스 라인을 읽습니다 — 900줄의 새 테스트와 함께 제공되는 40라인 프로덕션 변경은 작은 변경이며, 동일한 추론이 이미 territory-팬아웃 게이트를 지배합니다.
바닥이 왜 거기 있는가: 9라인의 오타 수정에서, 6개의 인라인 순회는 아무것도 없는 5개의 순회이며, 스윕 — 첫 번째 패스가 도달하지 못한 것을 찾는 새로운 리더 — 는 첫 번째 패스가 모두 도달했을 때 찾을 것이 없습니다. 에이전트 8의 바닥은 실질적인 것입니다: “하나의 도메인이 diff를 지배한다”는 것은 판단이며, 40라인에 대해 만들어진 판단은 우세한 도메인을 매번 찾습니다. 40라인은 보통 한 가지 것이기 때문입니다.
토큰 효율성
High 노력 파이프라인은 각 단계를 제한하지만(샤드 크기, 감사 라운드), 총 호출은 발견에 따라 확장됩니다 — ceil(F/8) 검증 샤드 — 그리고 3B에서는 청크 수에 따라(역감사는 라운드당 청크당 실행됨). 일반적인 3A 프로파일:
| 단계 | LLM 호출 | 참고 |
|---|---|---|
| 리뷰 에이전트 (단계 3) | 16 (+0-2) | 병렬 실행; 에이전트 1e는 diff가 래핑 타입을 신호할 때만 (없으면 15); 교차 저장소는 에이전트 1c와 7 건너뛰기 (14), 로컬/파일은 에이전트 0 건너뛰기 (15) |
| 샤드 검증 (단계 4) | ceil(F/8) | F = 발견 수; 검증 에이전트당 최대 8개, 함께 실행 |
| 반복 역감사 (단계 5) | 2-10 (3A); 라운드 × 청크 (3B) | 2회 연속 빈 라운드에서 중지; 상한은 토폴로지를 따름 — 작은 diff 10, 청크 diff 5, 거대한 diff는 데드라인이 있으면 3. 3B는 라운드당 청크당 하나의 감사자로 팬아웃 |
| 합계 | ~19-30 (~17-29) | 3A 동일 저장소: ~19-30 (일반적 ~19-21); 교차 저장소 또는 로컬/파일: ~17-29; 에이전트 1e가 로스터에 없으면 하나 감소; 3B는 청크에 따라 확장 (DESIGN.md 참조) |
대부분의 PR은 범위의 낮은 쪽으로 수렴합니다; 캡은 병리적 경우의 비용 폭주를 방지합니다. --effort low에서 리뷰는 완전히 인라인으로 실행됩니다 — 0 서브에이전트 호출 — 전체가 아닌 각도당 한 번씩 diff를 순회합니다.
플래그되지 않는 것
리뷰는 의도적으로 다음을 제외합니다:
- 변경되지 않은 코드의 기존 이슈 (diff에만 집중)
- 포맷터가 자동으로 정규화하는 스타일이나 포맷, 또는 코드베이스 규칙에 맞는 명명 — 하지만 린터나 타입 체커가 플래그할 실질적인 이슈(미사용 변수, 도달 불가능한 코드, 타입 오류)는 아니며, 이는 범위 내입니다
- 실제 문제 없는 주관적인 “X를 고려해보세요” 제안
- 버그나 위험을 수정하지 않는 경미한 리팩토링
- 로직이 진정으로 혼란스럽지 않는 한 누락된 문서
- 기존 PR 댓글에서 이미 논의된 이슈 (인간 피드백 중복 방지)
디자인 철학
침묵은 소음보다 낫다. 모든 댓글은 독자의 시간을 가치 있게 해야 합니다.
- 무언가가 문제인지 확실하지 않으면 → 보고하지 않습니다
- 모든 발견은 구체적인 실패 시나리오(트리거 → 잘못된 결과) 또는 구체적인 비용을 명시합니다 — 그렇지 못한 발견은 도달 전에 삭제됩니다
- N개 파일에 걸친 같은 패턴 → 하나의 발견으로 집계
- PR 댓글은 높은 신뢰도만 (high 노력, 검증된 리뷰에서만)
- 코드베이스 규칙에 맞는 표면적 스타일/포맷은 제외