codebase-review

전체 코드베이스를 다축(아키텍처, 리팩토링, 가독성, 성능, 견고성, 보안, 테스트, 일관성)으로 훑어 "고칠 가치가 있는 문제"를 근거(file:line)와 심각도로 정리하는 read-only 리뷰. "코드베이스 전체 리뷰해줘", "전체 코드 점검해줘", "리팩토링 관점에서 봐줘", "코드 개선점 찾아줘", "코드 품질 다각도로 리뷰", "이 프로젝트 전

SKILL.md

GitHub

Codebase Review

전체 코드베이스를 여러 각도에서 점검해, 근거와 우선순위를 갖춘 발견 목록을 만든다. diff/PR 단위 리뷰가 아니라 코드베이스 전반을 대상으로 한다.

모드 선언

이 스킬이 활성되면 아래 모드로 전환한다:

  • read-only 리뷰다. 리뷰 단계에서 코드를 수정하지 않는다. Edit/Write 금지.
  • 근거 없는 지적을 만들지 않는다. 모든 발견은 file:line으로 실제 코드를 가리킨다. 코드를 확인하지 않은 일반론("테스트를 추가하세요")은 발견이 아니다.
  • 오탐보다 신뢰가 먼저다. "거짓 양성보다 누락이 낫다"는 착각을 버린다. 그럴듯하지만 틀린 발견이 리뷰 전체의 신뢰를 깎는다. Zero findings는 정당한 결과다.
  • 취향이 아니라 비용을 본다. 스타일 논쟁·린터가 잡을 것 대신 결함·리스크·유지보수 비용에 집중한다.
  • 전부 읽으려 하지 않는다. 구조를 먼저 그리고 위험도 높은 영역부터 깊게 본다. 대형 레포에서 전수 읽기는 컨텍스트만 태우고 리뷰 깊이를 떨어뜨린다.
  • 개선은 위임한다. 리뷰 확정 후 수정으로 이어가라는 지시가 오면 self-feedback-loop로 넘긴다(아래 "개선으로 잇기").

진행 방식

1. 맵핑 (Survey)

코드베이스 구조를 먼저 파악하고 위험도 높은 영역(핫스팟)을 식별한다. 정찰 항목·핫스팟 신호·규모 기반 깊이 조절은 references/survey-checklist.md 참조.

  • 언어/프레임워크, 빌드·의존성 매니페스트, 디렉토리 레이아웃, 진입점, 핵심 모듈을 결정적 명령으로 한 번에 수집한다.
  • 스택 감지 후 비파괴 분석 도구(타입체커·린터·audit·dead-code 검출기)를 돌려 근거를 확보하고, 도구가 이미 잡는 것은 발견에서 뺀다. 명령·축 매핑은 references/survey-checklist.md.
  • 감지한 스택으로 무관한 축을 뺀다(frontend 없으면 UI, DB 없으면 쿼리 성능). 뺀 축은 Coverage에 "해당 없음"으로 명시.
  • 핫스팟 신호: 변경 빈도(git churn), 파일 크기·복잡도, 의존성이 몰리는 지점, 진입점·신뢰 경계.
  • 리뷰 범위를 좁히라는 지시(특정 디렉토리·축·언어)가 있으면 그 범위로 한정한다.
  • churn·소유권 공백 정량 진단이 더 필요하면 git-diagnosis 스킬로 넘긴다(그건 "어디를 볼지" 진단, 이 스킬은 발견 목록 생성).

2. 다축 리뷰 (Review)

아래 축별로 점검한다. 각 발견은 반드시 file:line 근거를 단다. 모든 축을 기계적으로 채우지 말고, 코드에 실제 신호가 있는 축에 집중한다.

축 무엇을 보나 이 축이 안 보는 것
아키텍처/구조 모듈 경계, 의존성 방향, 순환 의존, 레이어 위반, bounded context, 결합도 라인 단위 로직
리팩토링 여지 중복 코드, 죽은 코드, 과도한 복잡도, 잘못된/누락된/조급한 추상화 동작 변경
가독성/유지보수성 네이밍, 응집도, 매직 넘버, 주석-코드 불일치, 타입 설계(불변식을 타입으로 강제하나·외부에서 깨지나·any/cast escape hatch) 포맷·린트(린터 몫)
성능 불필요한 반복·할당, N+1, 비효율 자료구조, 동기 블로킹, 캐싱 부재 — 근거 있는 것만 마이크로 최적화
견고성/에러 처리 silent failure, 삼켜진 예외, 위험한 fallback(.catch(()=>[])), 경계·null, 동시성(lock 없는 read-modify-write→TOCTOU), 외부 호출 timeout·rollback 부재, unbounded/SELECT * 쿼리 정상 경로
보안 입력 검증, injection, 하드코딩 시크릿, 권한·인증, prompt injection — references/security-rulesets.md 비암호 난수 등 theater
테스트 커버리지 공백, 핵심 로직·엣지 케이스 미검증, happy-path-only, 취약한 테스트(no-throw·tautological assert, behavior 대신 mock만 검증) 커버리지 % 목표치
일관성 프로젝트 컨벤션 위반 — 단, 기존 스타일이 표준인지 결함인지 구분 개인 취향

각 축은 자기 영역만 본다("이 축이 안 보는 것" 열). 영역을 지켜 축 간 중복 발견을 줄인다. 축이 많아 병렬이 유리하면 subagent/Agent 도구가 있는 환경에서 축별 병렬 dispatch, 없으면 순차 점검한다.

병렬 dispatch 시 각 축 에이전트에 계약을 명시한다: 전달 = 축 정의 + "이 축이 안 보는 것" + 대상 파일 집합, 반환 = 출력 포맷의 발견 스키마(severity·file:line·근거 라인·실패 모드·effort/autofix) 그대로, 범위 밖 = 다른 축. 계약이 없으면 산출물 포맷이 어긋나 병합이 깨진다.

3. 반증 (Verify)

발견을 목록에 올리기 전에 각 발견을 독립적으로 반증한다. 이 단계가 오탐을 거른다. 상세 규율(Pre-Report Gate 4문항, Quote-the-line gate, 오탐 블랙리스트, 심각도 앵커)은 references/false-positives.md 참조.

핵심 규칙:

  • Pre-Report Gate: file:line 인용 가능? 구체적 실패 모드 명명 가능? 주변 컨텍스트 읽었나? 심각도 방어 가능? — 하나라도 아니오면 강등/삭제.
  • Quote-the-line: High/Critical은 verbatim 근거 라인 인용 필수. 못 하면 Medium 이하로 강등.
  • 실제 결함 vs 의도된 설계: "이게 버그인가, 아니면 프로젝트의 의도적 선택인가"를 구분한다.
  • 근본 원인에 앵커한다: 견고성·로직 발견은 나쁜 값이 유입되는 origin에 file:line을 단다. 증상이 드러나는 위치에 달면 위임(self-feedback-loop)이 증상만 고치고 근본 원인은 남는다.
  • 불확실성은 발견을 조용히 지우지 않는다: Critical 후보가 저확신이면 버리지 말고 추정으로 표시해 남긴다(fail-closed).
  • 서브에이전트를 쓸 수 있으면 살아남은 High+ 발견을 per-finding 독립 verifier로 검증한다. verifier는 반증을 목표로 프레이밍한다("진짜 결함인가 / 의도된 설계 아닌가 / 다른 곳에서 이미 처리되지 않나", 불확실하면 기각) — 같은 모델 self-review의 확증 편향을 상쇄한다. 검증 실패·모호는 강등.

심각도 & 확신도

Severity 기준 예시
Critical 런타임 에러, 데이터 손실, 보안 결함 injection, 미검증 입력, race condition
High 기능 오동작, 계약 불일치, 심각한 구조 결함 순환 의존 결합, 잘못된 상태 전이
Medium edge case 누락, 유지보수 비용 큰 복잡도 중복 로직, 경계값 미검증
Low docs 불일치, 사소한 불일관성 네이밍 흔들림, 주석-코드 괴리

앵커: 외부 악용 가능 보안=항상 High+, 핫패스 성능=최소 Medium, cosmetic=Low 상한. 두 독립 축이 같은 발견을 내면 한 단계 승격한다.

확신도는 심각도와 분리해 판단한다 (심각도 = 진짜일 때 얼마나 나쁜가, 확신도 = 진짜일 확률). low/med/high 3단계로 매기고 — 숫자 점수는 false precision이라 쓰지 않는다 — 확신도 낮음은 보고하지 않는다. 단 저확신 Critical 후보는 버리지 말고 추정으로 남긴다(fail-closed). run/repro가 있어야 확정되는 발견은 미검증을 달고 단정하지 않는다.

출력 포맷

먼저 요약 헤더 — 코드베이스 개요(스택·구조·규모) + 통계 한 줄: 축 N개 점검 / 발견 원본 X → 병합 후 Y / Critical a · High b · Medium c · Low d

이어서 심각도별 발견 목록 (축이 아니라 심각도로 그룹핑, 안정적 # 번호 부여):

#3 [High · conf:high] 견고성 — path/to/file.ext:42
근거: `const data = await fetch(url).catch(() => [])`
문제: fetch 실패를 빈 배열로 삼켜 하위 로직이 오작동. (구체적 실패 모드)
개선: 에러를 전파하거나 명시적 fallback. | effort: easy | autofix: manual

각 발견에 확신도(conf:low/med/high, 저확신 Critical은 추정, 미확정은 미검증), effort(trivial/easy/medium/hard), autofix(auto/manual/advisory)를 달아 위임 시 우선순위 신호로 쓴다.

Dedup: 같은 file:line의 같은 이슈는 1개로 병합(축 라벨은 견고성+성능으로 유지, 심각도는 높은 쪽). 같은 이슈 다른 위치는 분리하되 교차 참조.

Triage Groups: 여러 발견이 한 근본 원인에서 나오면 묶어 "선호 해결 순서 + why"로 제시한다.

Coverage: 안 본 영역, 버린(강등·제외한) 발견 수, 잔여 리스크를 명시해 투명화한다. 한 축이라도 실행 못 했으면 "완전 리뷰 아님"을 밝힌다.

마지막으로 개선 로드맵: 무엇부터 손대야 파급효과가 큰지 순서.

개선으로 잇기

리뷰 결과에서 다룰 항목을 사용자가 고르거나 "상위 N개 진행" 지시가 오면, 직접 고치지 말고 self-feedback-loop로 넘긴다. 그 스킬이 review-fix-verify-commit 루프로 수정·검증·커밋을 관리한다.

넘길 때: 선택된 발견을 안정 # 번호 + severity + file:line + 개선 방향으로 전달하고, 이를 fix 대상 범위로 명시한다. self-feedback-loop는 그 범위를 plan처럼 취급해 surgical fix만 수행한다.

작은 수정 한두 건이라 루프가 과하면 그 사실을 밝히고 이 세션에서 바로 고쳐도 된다. 단 수정 후 관련 빌드·테스트로 검증하고, 검증 전에는 완료라고 하지 않는다.

학습 자산화 (선택)

반복 리뷰의 가치를 누적하려면 compound 스킬과 연계한다:

  • 리뷰에서 반복 발견되는 패턴·근본 원인·해결책을 compound로 docs/solutions/에 frontmatter(module/tags/problem_type) 붙여 적재한다.
  • 다음 리뷰의 맵핑 단계에서 대상 모듈 관련 과거 솔루션을 먼저 소환해 "이미 아는 문제/결정"을 리뷰 컨텍스트로 삼는다.
  • 이러면 회를 거듭할수록 같은 오탐·같은 지적을 반복하지 않고 프로젝트 고유 지식이 쌓인다.

인접 스킬과의 경계

이 스킬은 전체 코드베이스를 다축으로 훑는 read-only 리뷰가 고유 영역이다. 나머지는 상호보완:

  • git-diagnosis — git 이력으로 핫스팟·소유권 공백 진단. "어디를 볼지" 단계. 맵핑에서 활용.
  • self-feedback-loop — plan 기준 최근 변경을 review-fix-verify-commit. 이 스킬의 개선 위임처.
  • test-code-guide — 테스트 스위트 심층 리뷰(구현 미러링·flaky·격리)와 작성 규범. 테스트 축 발견을 깊게 팔 때의 위임처.
  • compound — 리뷰 학습을 docs/solutions/에 자산화. 위 "학습 자산화" 연계처.
  • diff-review — 변경 집합(diff·staged·PR) 대상 read-only 리뷰. 이 스킬이 핫스팟을 찾으면 그 파일 집합을 diff-review로 넘기는 dispatch도 가능.

Gotchas

  • 전수 읽기 유혹: 대형 레포에서 모든 파일을 열면 컨텍스트가 고갈돼 핫스팟을 얕게 본다. 맵핑 → 핫스팟 → 심층 순서를 지킨다.
  • 축 채우기 강박: 8개 축을 전부 채우려다 신호 없는 축에서 억지 발견을 만든다. 신호 있는 축만 보고한다.
  • 오탐이 신뢰를 죽인다: 확인 안 한 코드에 대한 추측 하나가 전체 리뷰를 불신하게 만든다. Pre-Report Gate·Quote-the-line을 건너뛰지 않는다.
  • read-only 이탈: 리뷰 중 "이건 지금 고치면 되잖아"로 수정에 손대면 목적을 벗어난다. 수정은 승인 후 self-feedback-loop로.
  • 컨벤션 오판: 프로젝트의 의도적 선택을 "결함"으로 지적한다. 기존 스타일이 표준인지 결함인지 먼저 판단한다.
  • dead code 오탐: 동적 import·문자열 참조(라우트·DI·리플렉션)로만 쓰이는 심볼을 "죽은 코드"로 지적한다. 검출기 결과라도 unused로 올리기 전 실제 참조를 grep으로 확인한다(references/false-positives.md).
  • 불확실성으로 Critical을 조용히 버림: 저확신 Critical을 목록에서 빼면 진짜 위험을 놓친다. 버리지 말고 추정으로 남긴다.
  • 트리거 오인: "리뷰하고 고쳐줘"처럼 수정 의도가 명확하면 이 스킬(read-only)이 아니라 self-feedback-loop, 단순 변경 집합(diff/PR) 리뷰면 diff-review가 맞다.