대부분의 에이전트가 생성한 Pull Request(PR)가 리뷰가 잘못되는 것은 리뷰어들이 게을러서가 아닙니다. 리뷰어들이 순서를 잘못 읽기 때문에 잘못됩니다. 즉, 요약본을 먼저 보고, 그 다음 hunk를 위에서 아래로 읽고, 마지막에 이미 주의력이 떨어진 상태인 diff의 manifest나 CI 변경 사항을 보는 식입니다.
순서를 고치면 리뷰 비용이 절감됩니다. 파일 목록은 에이전트가 자신에 대해 작성한 요약본보다 작고 더 진실된 아티팩트(artifact)이기 때문에, 리뷰를 파일 목록부터 시작해야 합니다.
실패 지점은 파일 목록에 있다
제가 에이전트 PR을 분류하는 경험상, 위험한 변경 사항들은 몇몇 경로에 집중되는 경향이 있으며, 이는 에이전트가 강조하는 부분이 거의 아닙니다:
- Lockfile 및 빌드 출력물: 에이전트가 수동으로 해결 오류를 '수정'했기 때문에 직접 편집된 경우.
- CI 워크플로우 파일: 권한(permission), 트리거(trigger) 또는 시크릿 참조가 한 줄만 변경되어도 문제가 될 수 있는 경우.
- 설정 및 환경 기본값 (Config and env defaults): 새로운 키(key)가 런타임 동작을 조용히 변경하는 경우.
- 테스트 자체: 오라클(oracle)이 코드를 따라 이동한 경우.
- 일반 소스 코드 (Ordinary source): 보통 가장 안전한 부분이며, 리뷰어들이 시간의 80%를 할애하는 부분이기도 합니다.
마지막 항목이 문제입니다. 리뷰 노력은 위험도와 역의 상관관계를 가집니다.
한 명령어로 실행할 수 있는 분류 스크립트
아래 스크립트는 두 참조(ref) 사이의 git diff --name-status를 읽고, 각 경로를 순서가 지정된 규칙 목록과 비교하여, PR이 반드시 지녀야 할 버킷과 증거를 담은 Markdown 테이블을 출력합니다. 첫 번째 일치하는 패턴이 우선하므로, 구체적인 패턴이 일반적인 패턴보다 위에 위치해야 합니다.
#!/usr/bin/env python3
"""triage.py - PR diff의 모든 파일을 누군가 hunk를 읽기 전에 버킷화합니다.
...
PR 헤드에 대해 실행해 보세요:
git fetch origin pull/4123/head:pr-4123
python triage.py origin/main pr-4123 --fail-on REVERT
예시 출력 형태 (특정 레포지토리의 측정치가 아닌 예시입니다):
결정 테이블
| Bucket | 신뢰할 것 (What to trust) | 테스트할 것 (What to test) | 되돌리기 트리거 (Revert trigger) |
|---|
| REVERT | 아무것도. 생성기가 만들지 않은 파일은 검토 불가로 간주합니다. | 매니페스트에서 재생성 (npm ci, poetry lock --no-update)하고 그 결과를 PR과 비교(diff)합니다. | 수동으로 편집된 모든 lockfile, 커밋된 빌드 출력물, 또는 출처가 없는 vendored blob. |
| ... | | | |
읽는 순서: REVERT → TEST → TRUST
- 먼저 REVERT를 명확히 합니다. 이것들은 이진 결과(binary outcomes)를 가지는 5분짜리 결정입니다. 수동으로 편집된 lockfile은 논의 대상이 아닙니다. 재생성 커밋을 요청하세요.
- 실제 시간은 TEST에 할애합니다. 에이전트 PR이 실제로 문제가 발생하는 곳입니다: 워크플로우 파일의 한 줄, 설정 로더의 기본값 하나가 문제입니다.
- TRUST는 훑어봅니다(Skim). 테스트가 성공적이고 파일이 평범한 애플리케이션 코드라면, 줄 단위로 읽는 추가적인 가치는 낮습니다. 모든 hunk를 읽기보다는 함수 시그니처와 삭제된 라인을 읽으세요.
이는 기본 동작을 역전시킵니다. 검토자들이 보통 알파벳순으로 정렬되어 있고 src/에서 지치게 된 후에야 .github/에 도달하는 diff의 맨 위부터 시작하는 경향이 있기 때문입니다.
hunk 텍스트를 읽기 전에 세 가지 확인 사항
BASE=origin/main; HEAD=pr-4123
# 1. 매니페스트 없이 lockfile을 이동했거나, 그 반대
...
만약 확인 2가 +로 시작하는 라인을 출력하면, 다른 어떤 것보다도 먼저 해당 hunk를 읽고 멈추세요. 단 하나의 추가된 permissions: write-all은 PR의 모든 코드 개선 사항보다 우선합니다.
무료 모델 접근 및 무료 서버가 실제로 들어가는 곳
트리아지(Triage)는 결정론적 작업이므로, 유료 모델 호출을 낭비할 만한 장소가 아닙니다. 하지만 무료 모델을 사용할 만한 합리적인 장소입니다.
두 가지 좁은 용도 모두 모델을 승인 경로에서 제외합니다:
- 버킷 테이블만으로 검토 의견 초안 작성. 스크립트의 출력물(경로, 버킷, 이유, 소스 코드 없음)만 전달하고, REVERT 항목당 하나의 의견 작성을 요청합니다. 모델은 diff를 절대 보지 못하므로 승인을 환각할 수 없습니다.
- 스크립트 자체 실행. 분류 작업(Triage)은 대화형 도구가 아니라 cron job 또는 webhook 핸들러입니다. 이는 항상 작동하는 작은 장치가 잘 처리하는 정확한 워크로드입니다.
MonkeyCode 오픈 소스 프로젝트는 무료 모델 접근과 무료 서버 옵션을 광고합니다. 작성 시점을 기준으로 운영자는 무료 할당량이 10M 토큰에 무료 서버라고 명시했습니다. 이 조건은 시간이 민감하므로, 파이프라인을 설계하기 전에 저장소에서 확인해야 합니다. 이 워크플로우의 경우 모델이 이미 triage.py가 생성한 테이블을 포맷하는 것만 요청받기 때문에 무료 모델로 충분합니다. PR을 판단하도록 요청받는 것이 아닙니다.
공개 정보: 본 기사는 MonkeyCode의 제품 홍보의 일환으로 작성되었습니다.
스크립트를 실행하고 테이블을 PR 댓글로 게시하는 최소한의 webhook 핸들러는 약 30줄이며, 흥미로운 부분은 전송(transport)이 아니라 셸 호출입니다:
python triage.py "$BASE" "$HEAD" --fail-on REVERT > triage.md || echo "BLOCKED" >> triage.md
gh pr comment "$PR" --body-file triage.md
REVERT에서 검사를 실패시키면, 사람이 잠금 파일(lockfile)을 재생성할 때까지 PR은 병합될 수 없습니다. 이것은 모델의 판단이 아니라 검토 게이트입니다.
제한 사항 및 건너뛰어야 할 경우
- 코드 생성 코드가 많은 저장소(Generated-code-heavy repos). 트리의 절반이 코드 생성 출력물이라면, 규칙 목록은 노이즈로 가득 차고 모든 PR이 REVERT에 걸립니다. 출력 경로 대신 생성기 설정(generator config)을 기준으로 일치시키세요.
- 소유권 경계가 없는 모노레포(Monorepos without ownership boundaries). 이 스크립트는 어떤 팀이 어떤 경로를 소유하는지 알지 못합니다. TRUST 버킷을 신뢰하기 전에
CODEOWNERS 파싱을 추가하세요.
- 녹색 테스트 스위트가 없는 팀(Teams without a green test suite). TRUST 버킷은 테스트가 사용 가능한 오라클이라고 가정합니다. 그렇지 않다면, 모든 것이 TEST가 되며 분류 작업은 아무런 도움이 되지 않습니다.
- 진정으로 아키텍처적인 PR(PRs that are genuinely architectural). 40개 파일의 리팩토링은 버케팅이 필요하지 않습니다. 방에 사람이 있는 디자인 리뷰가 필요합니다.
무료 모델 및 무료 서버 경로를 시도하고 싶다면, 마지막 10개의 병합된 에이전트 PR에 대해 triage.py를 실행하여 REVERT 버킷이 무언가를 잡아냈을지 확인해 보세요. 그 답변은 이 체크리스트를 포함한 어떤 리뷰보다 더 유용합니다.