본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 05. 26. 10:47

AI가 작성한 코드는 AI가 본다 ── 리뷰가 정체되지 않고, 오히려 품질이 올라간다 (연재 Part 3)

요약

AI가 작성한 코드를 AI가 직접 리뷰하고 수정하여 머지까지 완료하는 자동화 파이프라인 구축 사례를 소개합니다. 리뷰 병목 현상을 해결하기 위해 인간은 개별 의사결정 대신 시스템 가이드라인을 조정하는 'human-on-the-loop' 역할을 수행합니다.

핵심 포인트

  • AI 작성 코드를 AI가 리뷰하는 자동화 루프 구축
  • 리뷰 병목을 방지하기 위한 human-on-the-loop 모델 도입
  • 평균 31분 이내의 빠른 PR 머지 및 높은 자동화율 달성
  • Claude Code 활용 시 발생하는 리뷰 부하 문제 해결 전략

여러분 안녕하세요! 에어클로젯(airCloset)에서 CTO를 맡고 있는 츠지(辻)입니다.

Part 1(총론)에서는 AI가 PR 리뷰나 장애 대응을 수행하고 있는 이야기를, Part 2(Product Graph)에서는 코드·docs·DB·인프라를 하나의 지식 그래프(Knowledge Graph)로 통합한 cpg에 관한 이야기를 썼습니다.

이번에는 자동 리뷰 (Automatic Review) ── PR을 AI가 보고, AI가 수정하고, AI가 머지(Merge)하는 파이프라인의 전체 플로우입니다. AI 개발에서 반드시 화제가 되는 "리뷰가 정체된다", "품질이 떨어진다"라는 문제에 대해, cortex 내부에서는 그러한 일들이 구조적으로 일어나기 어려운 파이프라인이 구축되어 있습니다. 그 메커니즘을 차례대로 살펴보겠습니다.

연재 목록

#테마주요 장면기사
1총론: cortex의 하네스 (Harness)PR 무인 머지 / 장애를 인지하기 전에 수정됨ai-harness-intro
...

갑자기 한 달 치 수치부터

머지된 PR: 769개.

머지 시간 중앙값: 31분.

개별 PR에 대한 사람의 리뷰: 거의 0%.

이것이 최근 30일(4/21~5/21) 동안의 cortex의 "전형적인 한 달"입니다.

그 769개 모두에 AI 리뷰어가 가장 먼저 투입되어, review-fix loop가 평균 10.8회 / 최대 56회 돌아가고 있습니다. 5개 중 1개는 10분 이내, 약 절반은 30분 이내에 머지됩니다. 사람이 하고 있는 일은 리뷰 결과를 보고 리뷰 프롬프트(Prompt)나 가이드라인 자체를 조정하는 것 ── 말하자면 human-in-the-loop가 아니라, human-on-the-loop입니다. "개별적인 의사결정 속에 사람이 섞이는" 것이 아니라, "시스템 전체를 위에서 내려다보는 역할"로 역할이 바뀌었습니다.

최근 30일의 수치
머지된 PR769개
...
이것이 지금 cortex의 "전형적인 한 달"입니다.

세상에서 흔히 듣는 "AI로 개발 속도를 높여도 결국 리뷰가 정체된다", "AI가 작성한 코드는 품질이 떨어진다"라는 목소리는, cortex 내부에서는 구조적으로 일어나기 어려운 파이프라인으로 받아내고 있습니다. 여기서부터 차례대로 분해해 보겠습니다.

"AI가 작성하면 리뷰가 정체된다"를 구조적으로 방지하기

통설: 리뷰가 새로운 병목(Bottleneck)이 된다

AI로 작성하는 속도가 올라갈수록, 작성된 코드를 보는 쪽(리뷰어)의 부하가 비례해서 늘어납니다. Anthropic의 사내 블로그(How Anthropic teams use Claude Code)에서도, 작성하는 쪽보다 보는 쪽에 병목이 옮겨가고 있다는 점, 시니어 엔지니어의 업무가 코드를 작성하는 것보다 AI 출력을 통합하고 리뷰하는 쪽으로 치우치고 있다는 점이 보고되었습니다.

이는 cortex에서도 실제로 동일한 현상이 일어났습니다. Claude Code를 풀 가동시킨 순간, 작성 속도는 자릿수가 바뀔 정도의 기세로 뛰어오릅니다. 반면, PR을 읽고 승인하는 인간의 시간은 선형적으로만 늘어납니다. 리뷰어(=나)가 쉬면 전체가 멈추는, 고전적인 단일 장애점(Single Point of Failure)이 됩니다.

cortex의 해답: 보는 쪽도 AI에게 맡긴다

Part 1 / Part 2에서 반복해서 썼던 "하네스(Harness)를 어디까지 확장할 것인가"라는 문제에서, cortex는 망설임 없이 "AI가 작성한 코드는 AI가 본다"로 방향을 틀었습니다. 인간이 손에 남겨둔 역할은 "프롬프트나 가이드라인 자체를 고치는" 역할입니다. 개별 PR 안에서 의사결정을 하는 것이 아니라, 시스템 전체를 위에서 보고 조정하는 위치입니다.

이것이 성립하기 위해서는 세 가지 조건이 필요했습니다.

--
AI에게 전달하는 컨텍스트(Context)가 충분할 것
일반적인 AI 리뷰는 PR의 diff(차이점)만 봅니다. 코드 본체만 봐서는 비즈니스적인 의미, 상류/하류의 의존성, 과거의 장애 이력을 볼 수 없습니다. cortex에서는 Part 2에서 썼던 Product Graph (cpg) ── 코드·문서·DB·인프라를 하나의 그래프로 통합하고, 노드마다 비즈니스적인 역할과 상류/하류의 의존성을 부여한 지식 기반 ── 을 AI 리뷰어에게 전달하고 있기 때문에, PR에서 건드리지 않은 관련 부분까지 포함하여 영향 범위를 추적할 수 있습니다. 결과적으로 다음과 같은 사항들이 구조적으로 검출됩니다:

  • 상류/하류의 수정 누락
  • 문서 업데이트 누락
  • 관련 테스트 미추적

이는 AI를 사용한 리뷰라 할지라도, PR diff만 보는 방식으로는 절대로 도달할 수 없는 범위입니다.

지적의 품질이 "떠오른 대로(思いつきベース)" 되지 않도록 하는 것 리뷰가 매번 달라지면 팀은 혼란에 빠지고, AI에 대해서도 "정답"을 정의할 수 없습니다. 이는

**명문화된 리뷰 가이드라인 (Review Guidelines)**을 AI가 반드시 인용하도록 판정 기준으로 전달함으로써 보장합니다 (후술하며, 이는 별도의 리포지토리(Repository)로 공개했습니다). -

오지적으로 인한 머지 블록(Merge Block)이 연발되지 않도록 하는 것 False Positive(오탐)를 전부 Critical로 설정하면 현장이 마비됩니다. 이는

중요도의 계층화 (Critical / Major / Minor / Nit) 및 강등 금지 규칙으로 억제하고 있습니다.

요컨대, Part 2에서 작성한 cpg가 "AI에게 전달할 컨텍스트(Context)"라면, 리뷰 가이드라인은 Guides (사전 제어)로서 "AI에게 무엇을 시킬 것인가"를, 중요도 계층과 강등 금지 규칙은 Sensors (사후 제어)로서 "AI가 하지 말아야 할 것"을 각각 담당합니다. Martin Fowler가 제창한 Guides / Sensors 분류(Part 1에서 언급)를 그대로 따르는 구조입니다.

한 가지 더 보충하자면, 이 3개 층의 앞단에 **파일당 500행까지라는 린트 (Lint)**를 적용하여, PR에 포함된 파일이 반드시 AI의 1개 세션(Session) 내에서 다 읽을 수 있는 크기로 유지되도록 하고 있습니다. 이것만으로도 자동 리뷰가 파괴되는 것을 방지하기 쉬우며, 사람의 리뷰와 달리 간과하는 일도 적습니다. 이 외에도 다수의 린트를 배치하고 있지만, 전체적인 모습은 Part 4 (Alert-Fix + Observability + 자동 린트 추가)에서 다룹니다.

자동 리뷰의 시스템 배치

구현은 각 개발자의 PC에서 동작하는 스크립트입니다. GitHub webhook은 사내에서 운용 중인 Event Relay 서버가 수신하여 Firestore에 영속화(Persistence)하고, 각 PC의 스크립트는 SSE 클라이언트로서 Event Relay에 연결하여 이벤트를 받는 구성입니다. 재연결 시에는 Last-Event-ID를 통해 전송되지 않은 부분이 재전송되므로 누락이 제로(0)이며, GitHub admin 권한도 단 한 번의 webhook 등록만으로 충분합니다. 전달은 Event Relay가 집약하고, 리뷰 판정 및 수정 처리는 각 PC에서 실행하는 것이 기본 루트입니다.

위치를 보충하자면, 리뷰어 모드(Reviewer mode)의 스크립트를 실행하는 PC는 상시 기동 (리뷰가 언제 오더라도 즉시 반응할 수 있는 체제), 작성자 모드(Author mode)의 스크립트는 PR 작성자가 직접 작업하는 백그라운드에서 동작 (PR 작성자는 평소 개발을 위해 PC를 켜두므로, 그 프로세스의 일부로 공존)하는 운용 방식입니다. 장시간 오프라인 상태였더라도 Event Relay가 Firestore에 보류하고 있으므로, 연결이 복구되는 시점에 재전달됩니다.

리뷰어의 PC에서 동작하는 스크립트가 이벤트를 받으면, claude -p를 spawn하여 9가지 관점 (Graph / Architecture / Security / Test / Doc / Impact / Observability / AI-Antipattern / Recurrence)을 순차적으로 체크하고, AI가 말미에 작성한 최종 판정 마커를 읽어 gh pr reviewAPPROVE / REQUEST_CHANGES를 게시합니다.

自動レビュー全フロー — PR起票から自動デプロイまで人なしで完結

포인트를 조금만 보충하겠습니다.

모드로 역할 분리── 동일한 스크립트를 --mode reviewer로 실행하면 리뷰어가 되고, --mode author로 실행하면 PR 작성자의 대응 요원이 됩니다. 리뷰어를 할당받은 사람의 PC가 reviewer 모드로 동작하고, PR을 올린 사람의 PC가 author 모드로 동작합니다 ── Event Relay가 집약하여 전달하고, 각자의 PC가 분산되어 이벤트에 반응하는 구성입니다. -
worktree로 PR마다 분리── author 모드에서는 origin/main을 worktree에 머지(Merge)한 후 AI를 spawn합니다. 여러 PR을 병렬로 대응해도 파일 상태가 섞이지 않습니다. -
1개 세션에서 9가지 관점을 순차적으로 체크── 병렬 sub-agent가 아니라, 하나의 claude -p

세션에서 9가지 관점을 순차적으로 체크합니다. 컨텍스트 (Context)를 공유한 상태로 관점을 전환하기 때문에, 관점 간의 정합성 (Consistency)도 동시에 포착할 수 있는 설계입니다. -
리뷰 가이드라인의 스냅샷을 공개── air-closet/cortex-review-guidelines (JP/EN). 실제 운용 중인 가이드라인은 cortex (비공개) 내에서 매일 업데이트되고 있으며, 외부 참고용으로 일부를 추출하여 스냅샷 형태로 공개하고 있습니다.

병렬 sub-agent가 아니라, 1세션 순차 리뷰로 구성한 이유

처음에는 9가지 관점을 병렬 sub-agent로 나누는 안을 시도했으나, 실제 운용에 적용했을 때 다음과 같은 문제가 발생했습니다:

동일한 컨텍스트를 sub-agent 수만큼 중복 주입하게 됨── cpg, 가이드라인, PR diff를 9번 전송하게 되어 토큰 (Token) 비용이 그대로 늘어납니다. -
관점 간에 findings (발견 사항)를 상호 참조할 수 없음── [Test]의 지적이 [Graph] 위반 (@graph-connects 불일치)과 관련되어 있는 경우처럼, 별도의 sub-agent라면 "Test 단독으로는 문제 없음"이라며 통과시켜 버리는 경우가 발생합니다. -
집계 로직이 복잡해짐── 9개의 출력을 병합 (Merge)하고, 중복을 제거하며, 최종 판정을 내리는 로직을 별도로 갖춰야 합니다.

1세션 순차 방식으로 전환하면 cpg / 가이드라인 읽기는 단 1회로 충분하며, 이전 관점의 findings를 유지한 채 다음 관점으로 넘어갈 수 있어 관점 간의 정합성도 자연스럽게 포착할 수 있습니다. 출력 또한 1개 스트림 (Stream)이므로, 마지막에 최종 판정 마커를 하나 작성하는 것만으로 집계가 완료됩니다.

이와 함께 CLAUDE.md를 리뷰 전용으로 교체하는 설계를 적용했습니다. cortex의 기본 CLAUDE.md에는 개발 작업용 컨텍스트 (Product Graph 조작 방법, 운영 데이터 보호 규칙, 각종 MCP 사용 순서 등)가 방대하게 적혀 있어, 리뷰어 AI에게는 거의 노이즈 (Noise)에 가깝습니다. 실행 시 리뷰 전용 CLAUDE.md (심각도 (Severity) 계층 / 강등 금지 규칙 / 최종 판정 마커 사양 등을 핵심으로 구성한 것)로 교체하면, AI의 주의가 리뷰 목적에 집중되어 탈선이 줄어듭니다.

불필요한 컨텍스트 주입을 줄임으로써 판정 정밀도와 토큰 비용을 동시에 개선한다 ── 이것이 이 설계의 기본 베이스입니다.

세부적인 운용 제어

실제 운용에서는 몇 가지 "필터링"을 적용하고 있습니다:

Draft (WIP) PR은 리뷰 대상에서 제외── GitHub의 Draft 상태인 PR은 웹훅 (Webhook)을 받아도 스킵 (Skip)합니다. 작성 중인 코드에 매번 리뷰가 돌아가면 노이즈가 되므로, PR 작성자가 Ready for Review로 전환한 시점에 비로소 리뷰가 시작되는 운용 방식입니다. -
특정 PR을 수동으로 리뷰 대상으로 지정 가능── 통상적으로는 웹훅을 기점으로 동작하지만, CLI에서 PR 번호를 지정하여 개별적으로 리뷰를 실행할 수도 있습니다. CI가 실패한 후의 재확인이나, "이 PR만 한 번 더 보고 싶다"는 경우에 사용합니다. -
자동 머지 (Merge) 여부는 PR 작성자가 선택── 자동 리뷰 APPROVE + CI green 이후에 자동 머지까지 실행할지는 PR 작성자의 의사에 따라 결정할 수 있는 설계입니다. 기본값은 자동 머지 ON이지만, 운영 환경에 직결되는 중요 변경이나 신중하게 반영해야 하는 PR의 경우 작성자가 OFF로 설정하여 "마지막에는 직접 머지 버튼을 누르는" 방식으로 전환할 수 있습니다.

지적의 구조 ── 태그와 중요도

자동 리뷰의 출력은 태그 (Tag) + 심각도 (Severity) + 구체적 사례의 3종 세트로 구조화되어 있습니다.

태그 (관점)

태그 (Tag)관점 (Perspective)주요 대상
[Graph]Product Graph 정합성@graph-* JSDoc, 의존 노드, 문서 정합성
[Doc]문서 정합성코드 변경에 따른 문서 추종 및 배치
[Impact]영향 범위 분석상류/하류 수정 누락, via: 필드 불일치
[Security]보안 (Security)인증·인가·입력 검증·기밀 정보
[Architecture]Composable Architectureapp/package 경계, 의존 방향
[Test]테스트 품질커버리지(Coverage)·matcher·명명 규칙
[Observability]관측성 (Observability)로그·알림의 구조화·truncate 금지
[AI-Antipattern]AI 생성 코드의 함정환각(Hallucination) API, 폴백(Fallback) 남용, 데드 코드(Dead code)
[Recurrence]재발 방지장애 수정 시의 판정 (lint화 / 수평 전개 / 가이드라인 추가)

중요도 (Severity)

severity기준액션
Critical보안, 데이터 파괴, 운영 장애, 문서 불일치, @graph-* 누락, 품질 기준 완화REQUEST_CHANGES
Major사양 이탈, Composable Arch 위반, 테스트 결여REQUEST_CHANGES
Minor명명 개선, 유지보수성, 경미한 리팩토링REQUEST_CHANGES (resolve 필수)
Nit스타일 선호도, 표기 불일치APPROVE (코멘트만 남김)

최우선 규칙은 "강등 금지"입니다:

  • "기존 패턴을 따른 추가"를 이유로 강등해서는 안 됩니다 (기존 위반 사항은 별도의 수정 대상이지, 신규 추가를 허용하는 근거가 될 수 없습니다).
  • "다른 PR에서 대응", "단계적으로 진행"을 이유로 Critical/Major를 Nit로 낮춰서는 안 됩니다.
  • "TODO/FIXME 남겨둠"을 이유로 미뤄서는 안 됩니다.

이는 severity.md에 명시되어 있으며, AI가 이를 인용하며 REQUEST_CHANGES를 반환합니다.

실례: embedding 모델을 gemini-embedding-001에서 gemini-embedding-2로 이관하는 PR

실제 자동 리뷰 코멘트를 보는 것이 빠르므로, 전형적인 사례를 하나 첨부합니다. 이는 2026-05-19에 머지된 feature PR (feat(meet): dual-write embeddings to new 'embedding' column (v2))로, 생성부터 머지까지 **1.5시간 동안 6회 반복(Iterate)**한 기록입니다.

첫 번째 리뷰 (07:35:25):

dual-write 구현 방침, 멱등한 (Idempotent) migration script, Promise.all 병렬화 모두 타당합니다. 아래 3점의 Critical과 2점의 Minor를 수정한 후 merge를 부탁드립니다.

Critical

[Graph]

@graph-business 태그 누락 (×3)

graph-integrity.md는 앱 계층의 최상위 선언에 @graph-business를 필수 사항으로 규정하고 있습니다 (severity: Critical).

이번에 추가된 아래 3가지 선언 모두에서 누락되었습니다 (별도 스레드에 상세 코멘트 있음).

기존 코드도 마찬가지로 누락되어 있으나, "기존 패턴을 따른 추가"는 강등 사유가 되지 않습니다 (severity.md).

  • generateEmbeddingV2 (v2 embedding 생성 함수)
  • EMBEDDING_MODEL_V2 (모델명 config)
  • EMBEDDING_LOCATION_V2 (리전 config)

[Graph]

embedMeetContent@graph-connectsgenerateEmbeddingV2를 반영하지 않음

embedMeetContent의 JSDoc에 @graph-connects generateEmbedding [calls] Embedding 생성은 있으나, generateEmbeddingV2

generateEmbeddingV2 호출이 추가되었음에도 불구하고, 그에 대응하는 @graph-connects가 추가되지 않았습니다.

그래프 노드(Graph Node)에서 generateEmbeddingV2로 향하는 엣지(Edge)가 보이지 않는 상태가 됩니다.

* @graph-connects generateEmbedding [calls] Embedding 생성 + * @graph-connects generateEmbeddingV2 [calls] v2 Embedding 생성 (dual-write) * @graph-connects insertMeetChunks [calls] BQ에 청크 데이터 삽입

[Doc] 대응하는 BigQuery 스키마 문서가 업데이트되지 않음

대응하는 문서의 「BigQuery 스키마」 섹션에 신규 embedding 컬럼이 기재되어 있지 않습니다.

graph-integrity.mdseverity.md는 문서 불일치를 Critical로 정의하고 있습니다.

| created_at| TIMESTAMP | 생성 일시 | +|embedding | FLOAT64[] | Embedding 벡터 (v2: gemini-embedding-2)|

Minor

[Test]

textEmbeddingV2 값이 테스트에서 검증되지 않음

objectContaining은 여분의 필드를 허용하기 때문에, v2 값이 전달되지 않더라도 테스트는 통과합니다.

textEmbedding: [0.1, 0.2, 0.3], + textEmbeddingV2: [0.1, 0.2, 0.3],

[Test] v2만 null을 반환하는 시나리오가 미테스트됨

generateEmbeddingV2: mockGenerateEmbedding으로 v1과 동일한 모의 객체(Mock)를 사용하고 있기 때문에, 「v2가 null을 반환하고 v1은 성공하는」 케이스가 독립적으로 검증되지 않고 있습니다.

<!-- VERDICT:REQUEST_CHANGES -->

포인트는 세부적인 정밀도입니다.

  • 파일 + 행 번호까지 구체적으로 명시
  • 수정안을 diff 형식으로 제시 (복사 붙여넣기로 반영 가능)
  • 인용 가이드라인 (graph-integrity.md / severity.md)을 명시
  • 전형적인 변명 ("기존 코드도 마찬가지로 누락되어 있다")을 사전에 차단
  • 말미의 <!-- VERDICT:REQUEST_CHANGES -->기계 처리가 가능한 최종 판정 마커이며, PR을 REQUEST_CHANGES 상태로 전이시키는 트리거 역할을 함

이후 PR 작성자(=대부분 작성자의 PC에서 동작하는 또 다른 AI)가 수정을 push → 재리뷰. Critical 3건의 본질적인 문제가 모두 해결되었는지 다음 리뷰에서 확인하고, 새롭게 다음 Major / Critical을 1개 지적 → 수정 → 확인 → ... 을 6회 반복(Iteration), 총 1.5시간 만에 수행하여, 최종적으로 APPROVE → 자동 머지(Merge)됩니다.

이 이터레이션 흐름을 시계열로 나타내면 다음과 같습니다.

review-fix loopの実例 — embeddingモデル移行PR / 1.5時間で6イテレーション

사람이 리뷰어였다면, Critical 3건을 지적하고 다음 날 대응을 기다린 뒤, 재리뷰를 또 다음 날 진행하여 ── 하나의 PR에 2~3일이 걸릴 일을, cortex는 90분 만에 완결시킵니다.

사람 리뷰와 자동 리뷰의 차이는 단순히 "빠르다"는 것만이 아닙니다. 하나의 AI 세션이 9가지 관점을 순차적으로 포착하고, 가이드라인을 반드시 인용하며 판정하기 때문에, 사람이 집중력 문제로 놓치기 쉬운 "깊은 지적" (문서 정합성 / 재발 방지 판단 / weak matcher 등)이 빠질 확률이 낮습니다. 이를 Before / After로 비교하면 다음과 같습니다.

Before / After — 人レビュー時代 vs cortexの自動レビュー時代

이것이 「리뷰 정체」가 구조적으로 발생하지 않는 이유입니다.

가이드라인을 육성한다 ── AI가 실수하는 순간을 포착하여 규칙을 수정한다

지금까지 몇 번 언급해 온 리뷰 가이드라인이지만, 그 가이드라인 자체는 정적인 문서가 아닙니다. 자동 리뷰를 운용하다 보면 정기적으로 "AI가 이 종류의 판단에서 실수한다"는 패턴이 보이기 시작합니다. 그때마다 개별 PR에 코멘트를 달아 덮어쓰는 것이 아니라, 가이드라인을 새로 써서 다음번 이후의 AI가 올바르게 행동하도록 만드는 것 ── 이것이 바로 human-on-the-loop의 실체입니다.

실제로 cortex에서 발생했던 실패 사례와, 각각을 구조적으로 어떻게 해결했는지 몇 가지 나열해 보겠습니다.

1. AI가 "기존 코드도 마찬가지니까"라며 등급을 낮추었던 경우

초기에는 AI가 지적을 내놓은 직후에 "단, 기존 코드도 동일하게 위반하고 있으므로, 본 PR에서는 Nit(사소한 의견)로 처리합니다"라며 스스로 등급을 낮추었습니다. 결과적으로 신규 추가 코드에 대한 위반 지적이 차례차례 Nit로 격하되었고, Approve(승인)가 양산되는 상태가 되었습니다.

severity.md에 "등급 강등 금지 규칙"을 명시하여 이를 차단했습니다:

"기존 패턴을 따른 추가"를 이유로 한 등급 강등 금지: 기존 코드가 가이드라인을 위반하고 있는 경우, 이를 따른 신규 코드도 동일한 중요도로 지적할 것. "다음 리팩터링(Refactoring) 시 검토"와 같은 미루기식 코멘트는 허용하지 않음.

이것만으로는 부족하여, 운영을 하다 보니 "별도 PR에서 대응", "다음 세션에서 대응", "범위 외(Out of scope)", "단계적으로 진행"과 같은 또 다른 변명 패턴들이 나타났기에, 이 역시 등급 강등 금지 카테고리로 추가했습니다. 나아가 "코드 내에 TODO/FIXME를 남겨두는 것"으로 미루는 케이스도 명문화하여 금지했습니다. "전형적인 회피 방법을 미리 파악하여 전부 차단한다"는 발상입니다.

2. AI의 최종 판정이 3가지 선택지여서, "코멘트만" 남긴 채 PR이 공중에 붕 떠 있던 경우

AI가 리뷰 말미에 출력하는 최종 판정은 원래 APPROVE (승인) / REQUEST_CHANGES (수정 요청) / COMMENT (코멘트만)의 3가지 선택지였습니다. Minor(경미한 사항)만 있는 경우 등에 AI가 COMMENT를 선택하면, 스크립트는 아무런 액션도 취하지 않아 PR은 리뷰 대기 상태로 방치되었습니다 ── 결국 나중에 사람이 직접 챙기지 않으면 움직이지 않는다는 안티 패턴(Anti-pattern)이 빈번하게 발생했습니다.

판정 로직을 2가지 선택지로 통일했습니다. Minor 이상은 전부 REQUEST_CHANGES로 처리하고, 최종 판정이 누락된 경우에도 안전 측면에서 REQUEST_CHANGES를 선택하며, Nit만 있거나 지적이 없는 경우(CI pass 시)에만 APPROVE를 하도록 했습니다. "판정이 모호하다면 fail-safe하게 작동하여 멈추는 쪽(REQUEST_CHANGES)으로 기울인다"라는 설계로 과감하게 전환한 것이 효과적이었습니다.

3. 체크 항목에 중요도가 적혀 있지 않아, AI가 매번 다른 판정을 내리던 경우

graph-integrity.mdtesting.md 등의 각 가이드라인은 당초 불렛 포인트 기반의 체크리스트였습니다. "테스트 명명이 설명적인가", "Mock은 최소한인가"와 같은 항목들이 나열되어 있을 뿐, 항목별 중요도가 적혀 있지 않았습니다. 결과적으로 동일한 위반이라도 PR이나 구동 세션에 따라 Major(주요 사항)로 취급되기도 하고 Nit로 취급되기도 하는 등 판정이 흔들렸습니다.

모든 가이드라인의 체크리스트를 severity (중요도) / scope (범위) / 관점의 표 형식으로 통일했습니다:

severityscope관점
Critical모든 PR@graph-business 누락
Major앱 계층(App layer)만테스트 결여
Minor공통 패키지(Common package)만인자(Argument) 3개 초과
Nit모든 PR명명 규칙의 표기 불일치

scope 열은 해당 체크가 어느 경로(Path)에 적용되는지를 기계적으로 판정하기 위한 것이며, AI 리뷰어는 scope에 해당하지 않는 PR에서는 해당 항목을 발생시키지 않습니다. 표로 정리했을 뿐이지만, 판정의 재현성(Reproducibility)이 크게 향상되었습니다.

4. 기존 가이드라인이 AI 특유의 함정을 잡아내지 못했던 경우

한동안 운영을 해보니 AI 생성 코드 특유의 안티 패턴 ── 존재하지 않는 API를 호출함 (환각(Hallucination) API. user.findOrCreate()와 같이 그럴듯해 보이지만 정의되지 않은 메서드 호출), 에러를 묵인하고 폴백(Fallback) 값을 반환함 (상위 API가 다운되면 아무 말 없이 빈 배열을 반환하는 등), 사용되지 않는 함수를 남겨둠 (refactor 과정에서 구 구현이 dead code가 됨), 요구 범위를 넘어 멋대로 수정을 확장함 (함수 1개의 수정 요청에 파일 전체를 reformat 함), 불필요한 하위 호환성 코드를 추가함 (내부 함수임에도 deprecated alias를 새로 생성함) ── 이들이 security.mdtesting.md에서는 다 포착할 수 없다는 것을 깨달았습니다. "AI이기에 저지르는 실수"라는 클러스터(Cluster)가 존재합니다.

이에 대응하여 ai-antipattern.md를 신설했습니다. 리뷰에서도

[AI-Antipattern]

이라는 태그로 명시적으로 포착하도록 되어 있습니다. AI에 대한 리뷰는 AI 특유의 함정을 알고 있는 상태에서 설계할 필요가 있다── 이는 인간의 리뷰 관점을 그대로 AI에 이식하는 것만으로는 나올 수 없는 발상입니다.

5. AI가 「기준 그 자체」를 완화하려 한다

마지막이자 가장 중요한 패턴. AI가 수정 PR (Pull Request)을 작성할 때, 가이드라인 위반을 고치는 대신 드물게 가이드라인 측을 완화하는 PR을 작성해 왔습니다. 예를 들어:

  • 테스트 커버리지 (Test Coverage) 임계값을 낮추어 테스트 추가를 회피
  • 자체 제작한 lint 규칙의 대상을 좁혀 위반 사항을 제거
  • 가이드라인 문서의 문구를 「권장」에서 「바람직함」으로 고쳐 구속력을 낮춤

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0