카테고리 없음

Gerrit 코드 리뷰에서 반복되는 지적을 Claude Code Skill 로 자동화한 회고 (반복 코멘트 → TSV → Skill)

임마누엘한 2026. 5. 14. 15:44

들어가며

3개월 분량의 사내 Gerrit 코드 리뷰 코멘트를 모아 보니, 같은 지적이 자꾸 반복되고 있었다. 신규 합류자가 같은 사이클을 한 번 더 돌고, 리뷰어 시간이 매번 깎인다. 그래서 다음 파이프라인을 만들어 봤다.

  1. 리뷰 코멘트 전체를 한 곳에 모으기 (Gerrit REST API → TSV → Excel).
  2. 카테고리로 클러스터링.
  3. 상위 N개 패턴을 Claude Code Skill 한 개로 코드화.
  4. 신규 코드 작성 시 Claude 가 자동으로 사전 차단.

결과적으로, 작성 단계에서 자동 차단되는 항목이 생겨서 같은 PR 의 같은 리뷰 코멘트가 줄어드는 게 확인됐다. 회고 + 만든 사람용 가이드 + 같은 파이프라인을 다른 저장소에 복제하는 방법까지 정리.

핵심 키워드: Claude Code, Skill, code review automation, Gerrit, repository skill, SKILL.md, 코드 리뷰 자동화.

시스템 컨텍스트

  • 사내 코드 호스팅: Gerrit (CL 단위 리뷰, +1/+2 system).
  • 리뷰 코멘트가 Gerrit 곳곳에 흩어져 있어서 패턴화·통계 어려움.
  • 신규 합류자 / 다른 팀이 모르고 같은 실수 반복.
  • 리뷰어가 매번 같은 지적을 손으로 다는 게 비효율.

목표: 반복 코멘트 → 일관된 규칙 문서 → 에디터 단계에서 사전 차단 (Claude Code 가 파일 편집 시 자동 적용).

[Gerrit REST API]          [데이터]            [지식]                [실행]
   285 CLs    ──extract──> raw TSV  ──curate──> categorized ──skill──> SKILL.md
   4400+ 리뷰 라인                              top-5 패턴            ↓
                                                                  Claude Code 가
                                                                  편집 시 자동 발동

시도한 것들

시도 1 — 리뷰 전체를 TSV 로 끌어모으기

Gerrit REST API 로 최근 N개월 모든 CL 의 리뷰 thread 를 긁어왔다. 핵심 endpoint:

# CL 목록
GET /a/changes/?q=project:myrepo+after:2026-02-14&o=ALL_REVISIONS&o=ALL_COMMITS

# 각 CL 의 리뷰 코멘트
GET /a/changes/{change-id}/revisions/current/comments

스크립트 의사 코드:

import requests, csv, base64
from urllib.parse import quote

AUTH = ("user", "http-password")  # Gerrit HTTP password 발급 필요
BASE = "https://gerrit.example.com/a"

def fetch_changes(query):
    r = requests.get(f"{BASE}/changes/?q={quote(query)}&o=DETAILED_ACCOUNTS",
                     auth=AUTH)
    # Gerrit 응답은 XSS 방지용 prefix ")]}'\n" 가 붙어 있다.
    return json.loads(r.text[5:])

def fetch_comments(change_id):
    r = requests.get(f"{BASE}/changes/{change_id}/revisions/current/comments",
                     auth=AUTH)
    return json.loads(r.text[5:])

with open("raw-reviews.tsv", "w") as fh:
    w = csv.writer(fh, delimiter="\t")
    w.writerow(["datetime", "author", "repo", "cl_id", "file", "line", "comment"])
    for cl in fetch_changes("project:myrepo after:2026-02-14"):
        comments = fetch_comments(cl["id"])
        for path, items in comments.items():
            for c in items:
                w.writerow([
                    c["updated"], c["author"]["name"], cl["project"],
                    cl["_number"], path, c.get("line", ""), c["message"]
                ])

함정 두 가지:

  • Gerrit 응답 JSON 앞에 )]}'\n 5바이트 prefix 가 붙는다 (XSS 방지용). 파싱 전에 제거.
  • HTTP basic auth 는 일반 password 가 아니라 Gerrit HTTP password (Settings 페이지에서 발급) 를 써야 한다.

처음에 컬럼 순서를 막 잡았다가, 분석하면서 두 번 재정리. 최종 순서 (분석 용도로 읽기 좋게):

  1. datetime — 정렬·시계열 분석용
  2. author — 누가 코멘트 했는지 (리뷰어 패턴 분석)
  3. repo — 어느 저장소
  4. cl_id — 추적용
  5. file / line — 위치
  6. comment — 본문

raw / curated 분리. raw TSV 는 API 결과 그대로. 사람이 본문을 읽으면서 category 컬럼을 손으로 채운 curated TSV 를 별도 유지. 분석 도중 카테고리가 바뀌어도 raw 가 남아 있어 재분류 가능.

시도 2 — 카테고리 클러스터링

전체 코멘트 4,400+ 라인을 한 번 훑으면서 의미 단위로 묶었다.

  • 처음엔 50개 정도로 잘게 쪼개고
  • 비슷한 것들끼리 통합해서 30개
  • 빈도순으로 정렬해서 상위 5개가 전체의 약 28% 차지하는 걸 확인

상위 5개 (실 예시):

#패턴빈도영향

1 plaintext secret 가 manifest 에 들어감 18건 보안 risk
2 환경별 config 가 base 에 들어가 모든 env 영향 21건 운영 사고
3 commit message convention 위반 (대소문자 / prefix / ticket) 11건 release note 자동화 깨짐
4 Python import 가 함수 안에 / 파일 끝에 11건 가독성·테스트 어려움
5 한 CL 에 source + build + deploy + third-party 가 섞임 13건 리뷰 부담·롤백 곤란

이 5개를 Skill 1개로 코드화하기로 결정.

시도 3 — 출력 포맷 선택 (Confluence vs Lint vs Skill)

세 가지 옵션을 비교했다.

옵션강제력작성 비용신규 합류자 효과유지 비용

Confluence/README 약함 (사람이 안 봄) 낮음 낮음 (읽어야 효과) 낮음
Lint/CI rule 강함 (PR 차단) 높음 (각 규칙 구현) 자동 적용 중간
Claude Code Skill 중간 (편집 단계) 낮음 (SKILL.md 1개) 높음 (Claude 가 사전 차단) 낮음

CI lint 까지 만들면 가장 강력하지만 초기 비용이 크다. Claude Code Skill 은 SKILL.md 1개로 끝나고, 사람이 잊어버려도 Claude 가 옆에서 잡아주는 형태. ROI 가 가장 좋아 보였다.

장기적으로는 Skill + Lint 병용이 정답. Skill 로 작성 단계에서 잡고, Lint 로 PR merge 단계에서 잡는 다층 방어. 일단은 Skill 부터.

시도 4 — SKILL.md 작성 가이드라인

만들면서 굳어진 작성 패턴.

1. frontmatter 의 description 이 트리거 매칭 핵심. Claude 가 이 description 을 보고 발동 여부를 결정. "어떤 파일·언어·상황에서 켜져야 하는지" 를 구체적으로 명시.

---
name: code-review-<repo>
description: "Apply learned code-review patterns from <repo>. Use when (1) editing kube/ manifests, (2) authoring BUILD/Dockerfile, (3) writing Python in service modules, (4) drafting commit message, (5) splitting a CL. Enforces 5 recurring rule-clusters distilled from <N>-day review feedback. Do NOT trigger for unrelated work or generic Python style questions."
version: "v1.0"
---

핵심:

  • 발동 조건 (When this skill applies) 을 번호 매겨서 5개 이내로.
  • 비발동 조건 (Do NOT trigger) 을 명시. 노이즈가 크게 줄어든다.
  • 출처 (N개 CL / M개 코멘트 분석) 명시. Claude 가 정당성을 판단할 때 도움.

2. 상위 N개 규칙만, 도메인 분리. 모든 규칙을 한 파일에 넣으면 description 모호해지고 트리거 정확도 떨어진다. 다른 도메인 (예: 일반 Python style) 은 다른 Skill 로.

3. Quick Reference 표 를 본문 맨 앞에. 규칙 번호 / 발동 조건 / 출처 카테고리. Claude 가 빠르게 정책 매핑을 잡는 데 결정적.

#RuleTriggerSource Cluster

1 plaintext secret 금지 *credentials*.yaml, *.env 편집 C1 (18 comments)
2 env config 는 overlay 에 kube/{just,overlays}/ 새 파일 C2 (21 comments)
3 commit message convention /COMMIT_MSG 작성 C7 (11 comments)
4 Python imports top-of-file *.py 새 파일 C5 (11 comments)
5 single-purpose CL source+build+kube 동시 변경 C11 (13 comments)

4. 각 규칙은 5 섹션으로.

  • When this applies (구체 trigger)
  • The rule (한 줄)
  • Before / After 코드 예시
  • Why (왜 이게 문제인지, 사례 인용)

5. NOT trigger 섹션. 잘못된 컨텍스트에서 발동하면 노이즈가 심하므로 반드시 명시.

시도 5 — 트리거 정확도 검증

Skill 을 추가하고 일부러 다음 상황들로 테스트.

  • (a) plaintext secret 가 있는 yaml 편집 → ✅ Claude 가 SealedSecret 으로 감쌀 것 제안.
  • (b) 일반 Python 코드 리팩터링 (스킬 외 영역) → ✅ 발동 안 됨 (트리거 scope 잘 좁혀짐).
  • (c) 다른 저장소의 비슷한 yaml 편집 → ✅ 발동 안 됨 (description 에 저장소 명시 효과).

description 의 trigger / not-trigger 명시 비중이 정확도의 거의 전부였다.

시도 6 — 출력 자산 정리

code-review-learning/
├── raw-reviews.tsv          # API 로 긁은 원본
├── curated-reviews.tsv      # 사람이 카테고리 단 버전
├── curated-reviews.xlsx     # 동료 공유용 (필터·정렬 편함)
├── confluence-report.md     # 상위 패턴 + 통계 리포트 (Confluence 업로드용)
└── skills/
    └── code-review-<repo>/
        └── SKILL.md         # Claude Code Skill 본체

신규 합류자에게는 이 디렉토리 하나만 알려주면 됨. confluence-report 로 큰 그림 → SKILL 로 자동 차단.

Gerrit 사용 흐름 정리 (다른 분 참고용)

Gerrit 처음 쓰는 분들에게 정리: Gerrit 의 CL (Change List) 은 GitHub 의 PR 과 유사하지만 단위가 약간 다르다.

  • CL = 1 commit 이 원칙. push 시 Change-Id footer 로 식별.
  • 같은 CL 을 여러 patchset 으로 업데이트하면 동일 Change-Id 가 유지되어 한 CL 안에서 revision 이 쌓인다.
  • 리뷰 코멘트는 file / line 단위로 달리고, "전체 코드 리뷰 vs 파일별 마킹" 두 layer 가 있다.

신규 합류자가 자주 헷갈리는 부분:

  • CL 하나에 여러 commit 묶으면 안 된다. 묶으면 single-purpose CL 원칙 위반.
  • 여러 파일 / 여러 모듈을 한 CL 에 같이 수정하지 말 것. 리뷰 부담이 폭증. (이게 위 패턴 #5)
  • patch set 업데이트는 git push -o submit 또는 git push HEAD:refs/for/<branch> 같은 형태.

해결 — 최종 자산과 운영

code-review-learning/ 디렉토리 하나로 묶고, SKILL 은 ~/.claude/skills/code-review-<repo>/SKILL.md 위치에 둠. 신규 합류자에게 알려줄 것은 두 가지.

  1. "리뷰 받기 전에 SKILL 이 자동으로 잡는지 확인."
  2. "그래도 모르겠으면 confluence-report 의 Quick Reference 표 한 번 훑기."

운영 절차:

  • 매월 raw-reviews.tsv 를 갱신 (지난달 추가된 코멘트 fetch).
  • curated 재분류 (한 시간 정도). 새 패턴이 상위로 올라오면 SKILL 에 규칙 추가.
  • SKILL version 을 bump 하고 changelog 한 줄 (v1.0 → v1.1 (added Rule 6)).

검증 방법

Skill 발동이 의도대로인지는 다음으로 확인.

# Claude Code 가 현재 컨텍스트에서 어떤 skill 을 인지하는지
# (Claude Code CLI 안에서)
/help

# 또는 SKILL.md 의 description 을 일부러 모호하게 만들어보고
# 의도하지 않은 컨텍스트에서 발동되는지 확인

또한 신규 합류자 1명 onboarding 시 같은 패턴의 리뷰 코멘트가 몇 번 나오는지를 metric 으로 추적. 도입 전/후 비교가 가능.

배운 점

  • 반복 리뷰 코멘트는 자동화 가능한 신호다. 같은 지적이 N번 반복되면 그건 Skill / lint / 템플릿으로 옮길 시점. 데이터 수집부터 시작하자.
  • raw / curated TSV 를 분리해두자. 분석 도중 카테고리가 바뀌어도 raw 가 남아 있어 재분류 가능. 카테고리 변경은 흔하다.
  • SKILL.md 의 description 이 트리거 정확도의 거의 전부. 발동 조건 / 비발동 조건을 둘 다 적자. 발동만 적으면 노이즈가 커진다.
  • Skill 하나에 너무 많은 규칙을 넣지 말자. 도메인 분리 → 트리거 정확도 ↑. 사내에 저장소 A / B / C 가 있으면 Skill 도 A / B / C 셋으로.
  • 장기 best practice 는 Skill + Lint 병용. Skill 은 작성 단계, Lint 는 merge 단계. 다층 방어.
  • Gerrit 응답의 )]}' prefix 같은 작은 함정도 한 번 알면 끝. 모르고 처음 만나면 30분 잡아먹는다.
  • 한 번 만들어 두면 사내 다른 저장소에도 같은 파이프라인(REST API → curated TSV → Skill)으로 복제 가능. 회수 시점이 빠르다.

다음 단계

  • CI Lint 추가. Skill 로 잡힌 후에도 통과한 케이스를 PR 단계에서 한 번 더 차단.
  • 리뷰어별 패턴 분석. 특정 리뷰어가 자주 잡는 항목이 있다면 그 자체가 다음 Skill 후보.
  • 시계열 추적. "도입 후 같은 패턴 코멘트가 몇 % 줄었는지" 를 dashboard 로.
  • 다른 저장소로 파이프라인 복제 (raw fetch script 만 약간 손보면 됨).

참고