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