재현 없이 가설 없다 — 배포 6섹션 65항목과 디버깅 4 Phase

배포 전·중·후·롤백·보안·성능 여섯 섹션을 65개 항목으로 펼치고, 섹션마다 다른 점검 주기를 한 장의 흐름도로 그린다. 롤백 섹션은 표가 둘이라 14로 세기 쉬운데 항목은 여덟이며, 합계가 65가 되는지로 검산한다. 뒤쪽은 디버깅 — 재현·가설·검증·회귀방지 4 Phase와 13행 함정 카탈로그, 프롬프트 10패턴이다. 이 카테고리의 다른 글이 쓰는 「증상→원인→해결→예방」 4단과 이름이 같은데 카탈로그가 겹치는지 행 단위로 세어 본 결과도 함께 적는다.

체크리스트가 65개라는 사실보다 중요한 것은 그 65개를 매번 다 하지 않는다는 것이다. 여섯 섹션의 점검 주기가 각각 다르고, 그 주기를 모르면 체크리스트는 첫 배포에 한 번 쓰이고 버려진다.

이 글은 3계층 통제로 시작한 시리즈의 마지막 편이다. 앞 편이 하나를 만들어 한 번 내보내는 데까지였다면, 이 글은 그 뒤 — 매번 내보낼 때 무엇을 확인하고, 터졌을 때 무엇부터 하는가다.

이 글에서 가장 오래 남는 규율은 원 자료가 "The Iron Law"라 이름 붙인 한 줄이다. 재현 없이 가설 없다. 가설 없이 수정 없다. 수정 후 회귀 테스트 없이 완료 없다.

이 글이 옮긴 원 자료의 작성 기준일은 2026-07-26이다. 성능 지표 이름과 기준값, 플랜별 타임아웃은 그 시점의 것이다.

아래의 65항목·13행 함정 카탈로그·10패턴·MCP 6종은 원 자료가 제시한 예제이며, 이 글이 운영해 얻은 실적이 아니다. 특히 디버깅 절의 시간·성공률 비교는 예시 값이다 — 해당 표 아래에 원 자료의 고지를 옮겨 두었다.

용어 정리

시리즈 첫 편의 용어표 31행 중 이 글이 쓰는 행만 추렸다.

용어풀이
Rules에이전트가 매 세션 자동으로 읽는 정적 지침서(.md). 강제력 없음, 규범 역할
Hooks특정 이벤트 발생 시 자동 실행되는 스크립트. 도구 호출 자체를 차단할 수 있음
MREMinimum Reproducible Example. 버그를 재현하는 가장 작은 코드
5-Why"왜?"를 5번 물어 표면 증상이 아닌 근본 원인에 도달하는 분석 기법
git bisect이진 탐색으로 회귀 버그를 만든 커밋을 찾는 Git 명령
회귀 테스트고친 버그가 다시 나오지 않는지 자동으로 검사하는 테스트
RLSRow Level Security. DB 행 단위 접근 제어. 애플리케이션이 아니라 DB가 막는다
auth.uid()현재 요청의 JWT에서 추출된 사용자 UUID를 반환하는 Supabase 함수
service_role 키RLS를 우회하는 관리자 키. 서버 사이드 전용, 클라이언트 노출 시 전체 데이터 유출
anon 키클라이언트에 노출해도 되는 공개 키. RLS의 통제를 받는다
Smoke Test배포 직후 핵심 경로가 살아 있는지 5분 내로 확인하는 최소 검증
Core Web VitalsLCP·FID(INP)·CLS. 사용자 체감 성능을 측정하는 표준 지표
MCPModel Context Protocol. 외부 도구·데이터 소스를 에이전트에 연결하는 규약
Seed 데이터개발·테스트용으로 미리 넣어두는 샘플 데이터

git bisect·auth.uid()·service_role·anon 은 아래 본문이 영문 이름 대신 「이진 탐색」·「인증 함수」·「관리자 키」·「공개 키」라는 한국어로만 쓴다. 그래도 행을 남겼다 — 다른 자료에서는 영문 이름으로 나오기 때문이다.

배포 체크리스트 6섹션 65항목

섹션시점항목 수점검 빈도
1. Pre-Deploy배포 전15매 배포
2. Deploy배포 중10매 배포
3. Post-Deploy배포 후12매 배포
4. Rollback비상 상황8사고 발생 시
5. 보안출시 전 + 정기10출시 전 1회 + 분기 1회
6. 성능출시 전 + 정기10출시 전 1회 + 월 1회

15 + 10 + 12 + 8 + 10 + 10 = 65. 여섯 행의 항목 수를 더하면 제목의 숫자와 맞는다.

체크리스트를 대하는 태도: "모든 항목을 매 배포마다 한다"는 뜻이 아니다.

13섹션은 매 배포, 4섹션은 사고 시, 56섹션은 정기 점검이다.

자료의 조언은 "외우려 하지 말고 첫 배포 때 출력해 옆에 두고 따라가라. 두세 번 반복하면 몸이 외운다"이다.

「점검 빈도」 열을 흐름으로 옮기면 이렇게 된다.

도식을 탭하면 확대해서 볼 수 있습니다

이 흐름도는 이 글이 새로 그린 것이다. 세 갈래의 근거는 전부 위 표와 아래 롤백 판단 기준 표에 있다 — 1~3섹션의 순서는 「시점」 열의 배포 전·중·후이고, 3에서 4로 가는 조건과 옆으로 빠지는 조건은 롤백 판단 기준 표의 「즉시」 네 행과 「시간 두고 핫픽스」 두 행이며, 5·6섹션이 별도 줄기인 것은 원 자료가 "13섹션은 매 배포, 4섹션은 사고 시, 56섹션은 정기 점검" 이라고 직접 적은 문장이다.

Pre-Deploy 15항목

#항목확인 방법통과 기준
1.1타입 체크 통과타입체크 스크립트 실행에러 0건
1.2린트 통과린트 스크립트 실행경고·에러 0건
1.3단위 테스트 통과테스트 스위트 실행전부 통과, 커버리지 80% 이상 권장
1.4로컬 프로덕션 빌드 성공빌드 명령 실행산출물 생성, 에러 없음
1.5환경변수 키 누락 없음예제 파일과 실제 파일의 키 목록 비교차이 없음
1.6운영 환경변수 등록 확인호스팅 콘솔의 production 스코프 조회로컬의 모든 키가 존재
1.7시크릿 노출 검사저장소 전체에 키 패턴 정규식 검색결과 없음
1.8마이그레이션 파일 순서 확인마이그레이션 디렉터리 정렬 확인타임스탬프 순서가 올바름
1.9마이그레이션 로컬 적용 성공로컬 DB 리셋 후 재적용에러 없이 완료
1.10RLS 활성화 확인RLS 미적용 테이블 조회 쿼리결과 없음
1.11작업 디렉터리 깨끗함상태 조회미커밋 변경 없음
1.12기본 브랜치 최신화원격 fetch 후 상태 비교원격과 동기화됨
1.13잠금 파일 커밋됨마지막 커밋의 잠금 파일 변경 이력누락 없음
1.14변경 이력 갱신변경 이력 문서 확인이번 배포 내용이 기록됨
1.15자동 검증 스크립트 통과통합 사전 점검 스크립트 실행종료코드 0

열다섯 항목 중 열넷은 「통과 기준」이 온전히 판정 가능한 값이다 — 0건 · 차이 없음 · 결과 없음 · 종료코드 0. "확인했다"로 끝나는 칸이 없다는 것이 이 표가 체크리스트로 기능하는 이유다. 예외는 1.3 하나다 — "전부 통과, 커버리지 80% 이상 권장" 에서 앞은 판정 가능하지만 뒤의 「권장」은 통과·실패를 가르지 않는다. 한 칸에 기준과 권고가 함께 들어간 자리는 열다섯 중 이것뿐이다.

Deploy 10항목

#항목통과 기준
2.1기본 브랜치에 pushCI 파이프라인이 자동 트리거됨
2.2빌드 시작 확인최신 배포가 빌드 상태로 표시
2.3빌드 로그 실시간 모니터링에러 로그 없음
2.4빌드 시간 확인5분 미만. 평소의 2배 이상이면 캐시 문제 의심
2.5빌드 성공배포가 준비 완료 상태
2.6운영 DB 마이그레이션 적용적용 성공
2.7마이그레이션 후 스키마 검증새 테이블·컬럼이 운영에 반영됨
2.8운영 도메인 연결도메인의 최신 배포가 방금 배포한 버전
2.9HTTPS 인증서 활성HSTS 헤더 응답 확인
2.10CDN 캐시 무효화필요 시에만. 외부 CDN 사용 시 수동 처리

2.4가 유일하게 상대 기준을 든다 — "평소의 2배 이상이면 캐시 문제 의심". 절대값(5분)과 추세 비교를 한 칸에 함께 둔 항목은 이 열 개 중 이것뿐이다.

Post-Deploy 12항목

#분류항목통과 기준
3.1Smoke홈페이지 응답200
3.2Smoke헬스체크 API 응답정상 상태 반환
3.3Smoke로그인 플로우 동작로그인 → 대시보드 진입 성공
3.4SmokeDB 조회 성공로그인 후 본인 데이터 표시 (RLS 정상)
3.5Smoke자동 smoke test 통과종료코드 0
3.6모니터링트래픽·에러율첫 1시간 5xx 에러율 1% 미만
3.7모니터링에러 트래킹배포 직후 신규 에러 알림 없음
3.8모니터링DB 로그401/403/500 비율이 평소 수준
3.9공지팀 알림 발송버전·URL·커밋 수·빌드 시간·변경 이력 링크 포함
3.10공지릴리스 태그 생성태그 push + 릴리스 노트 작성
3.1124h핵심 KPI 비교전일 대비 20% 이상 하락 시 롤백 검토
3.1224h고객 문의 모니터링"안 된다" 류 문의가 평소보다 많으면 핫픽스 또는 롤백

3.11이 이 체크리스트에서 가장 중요한 항목이다. 기술 지표(에러율·응답시간)가 정상인데 전환율만 떨어지는 배포가 존재한다. 원 자료는 여기에 "에러 없이 실패하는 배포를 잡는 유일한 항목이 KPI 비교다" 라고 적는데, 같은 표의 3.12(고객 문의 모니터링)도 에러 없이 걸린다 — "안 된다" 류 문의가 늘었다는 신호에 에러 로그가 필요하지 않기 때문이다. 에러 없이 실패하는 배포를 잡는 항목은 둘이고, 3.11이 그중 자동으로 재는 쪽이다.

열두 항목이 「분류」 열에서 Smoke 5 · 모니터링 3 · 공지 2 · 24h 2로 갈린다. 앞의 여덟은 배포 직후에 끝나고, 뒤의 넷 중 둘(3.11·3.12)만 다음 날까지 열려 있다.

Rollback — 판단 기준과 절차

상황즉시 롤백?
5xx 에러율 5% 초과즉시
로그인 불가즉시
결제 실패즉시
데이터 손실 위험즉시
UI 깨짐 (기능은 정상)시간 두고 핫픽스
일부 사용자만 영향시간 두고 핫픽스

원칙: 고치는 것보다 되돌리는 게 빠르다. 목표는 5분 내 롤백이다.

장애 중에 원인을 찾겠다는 판단이 장애 시간을 몇 배로 늘린다.

#절차내용
4.1이전 배포 식별직전 정상 배포 URL 확인
4.2프로덕션 승격이전 배포를 프로덕션으로 승격 (수초 내)
4.3도메인 복원 확인버전 엔드포인트가 이전 버전을 응답
4.4문제 커밋 revert되돌리는 새 커밋 생성. 강제 푸시 금지
4.5롤백 헬퍼 실행호스팅·Git 동시 롤백 가이드
4.6마이그레이션 호환성 점검컬럼 추가는 안전 / 삭제·이름 변경은 위험
4.7다운 마이그레이션반드시 백업 후 진행. 데이터 손실 가능
4.8인시던트 리포트 작성발생·영향·근본원인·해결·재발방지 5블록

⚠️ 이 섹션은 표가 둘인데 항목 수는 여덟이다

롤백 섹션에는 표가 두 개 있다 — 판단 기준 6행절차 8행. 6 + 8 = 14로 세면 안 된다.

위 6섹션 표가 Rollback의 항목 수를 8로 적었고, 번호도 절차 표에만 4.1~4.8로 붙어 있다. 판단 기준 표의 여섯 행에는 번호가 없다 — 그것은 체크할 항목이 아니라 절차에 들어갈지 말지를 가르는 문이다.

검산이 가능하다. 14로 세면 15 + 10 + 12 + 14 + 10 + 10 = 71이 되어 65와 맞지 않는다. 이 검산은 이 글의 정리이며, 원 자료는 6섹션 표에 8을 적어 둘 뿐 두 표의 관계를 따로 설명하지 않는다.

4.4의 「강제 푸시 금지」는 이 시리즈 첫 편의 차단 규칙 7종 중 5번(git push --force + main|master)과 같은 것을 막는다. 한쪽은 사람이 지킬 절차로, 다른 쪽은 훅이 강제하는 규칙으로 적혀 있다.

보안 10항목

#분류항목통과 기준
5.1시크릿클라이언트 번들에 시크릿 미노출공개 접두사 변수에 SECRET·PRIVATE·SERVICE 키워드 없음
5.2시크릿로컬 환경파일이 무시 목록에 포함무시 확인 명령이 해당 파일을 출력
5.3시크릿CI 시크릿 저장소에 운영 키 저장배포 토큰·관리자 키가 등록됨
5.4RLS모든 사용자 대상 테이블 RLS 활성미적용 테이블 조회 결과 없음
5.5RLS작업별 정책 분리테이블마다 SELECT/INSERT/UPDATE/DELETE 정책 확인
5.6RLS관리자 키는 서버에서만 사용클라이언트는 공개 키만 사용
5.7전송HTTPS 강제 (HSTS)HSTS 헤더 설정
5.8전송CORS 허용 도메인 제한와일드카드 금지, 실제 도메인만 허용
5.9전송CSP 헤더 설정스크립트·이미지 소스 제한
5.10인가관리자 라우트 보호미인증 접근 시 리다이렉트 또는 401

시크릿 3 · RLS 3 · 전송 3 · 인가 1로 갈린다. 「인가」 분류에만 항목이 하나인 것은 나머지 인가 판정이 RLS 세 항목으로 DB 쪽에 내려가 있기 때문이다 — 5.4~5.6이 「누가 무엇을 읽을 수 있는가」를 이미 맡고 있고, 5.10은 그것으로 덮이지 않는 화면 단위 접근을 맡는다. 이렇게 갈라 읽는 것은 이 글의 정리이며, 원 자료는 「분류」 열에 네 이름을 붙일 뿐 항목 수가 왜 3·3·3·1인지 적지 않는다.

성능 10항목

#분류항목기준
6.1Vitals성능 점수90 이상
6.2VitalsLCP2.5초 미만
6.3VitalsFID100ms 미만
6.4VitalsCLS0.1 미만
6.5이미지최적화 컴포넌트 사용원시 이미지 태그 잔존 없음
6.6이미지이미지 용량200KB 미만 (대형 히어로 제외)
6.7캐시정적 자산 캐시 헤더장기 캐시 적용
6.8번들번들 크기 분석500KB 초과 라이브러리는 동적 임포트로 분할
6.9DB자주 조회되는 컬럼 인덱스조건절에 쓰는 컬럼에 인덱스 존재
6.10DBN+1 쿼리 점검평균 100ms 초과 쿼리는 인덱스 추가 또는 컬럼 제한

⚠️ 6.3의 지표 이름이 이 글 안의 다른 자리와 다르다

이 글 맨 앞의 용어 정리는 Core Web Vitals를 LCP·FID(INP)·CLS 로 적어 INP를 괄호로 병기한다. 위 6.3행은 FID 만 적는다. 같은 원 자료 안의 두 자리다.

Core Web Vitals는 원 자료가 만든 것이 아니라 공개된 웹 표준 지표이므로 지표 이름을 그대로 옮긴다 — 병기된 쪽의 이름이 INP다.

이 글이 확인할 수 있는 것은 원 자료가 용어 풀이에서는 FID(INP)로 병기하고 체크리스트에서는 FID만 적는다는 사실과, 그것이 2026-07-26 기준이라는 것까지다. 어느 이름이 현재 표준의 것인지는 표준 문서를 직접 확인해야 한다.

6.9와 6.10만 분류가 「DB」다. 나머지 여덟이 브라우저에 도착한 뒤의 문제인 반면 이 둘은 응답을 만들기 전의 문제다.

자주 만나는 배포 실패

증상원인해결
빌드 실패: 모듈을 찾을 수 없음의존성 설치 누락의존성·빌드 캐시 삭제 후 재설치·재빌드
환경변수 누락 경고호스팅 콘솔에 미등록콘솔에서 변수 추가 후 재배포
RLS 정책 위반정책이 사용자 ID를 매칭하지 못함정책의 사용자 비교 조건 확인
배포 후 502서버리스 함수 타임아웃긴 작업을 백그라운드 잡으로 분리
콜드 스타트 5초 이상큰 SDK를 통째로 임포트필요한 모듈만 개별 임포트

같은 증상이 클러스터 위에서 나면 원인이 하나 더 붙는다 — 생존 프로브와 준비 프로브를 혼동하면 무한 재시작이나 5xx가 된다.

디버깅 — 절대 원칙과 4 Phase

The Iron Law

재현 없이 가설 없다. 가설 없이 수정 없다. 수정 후 회귀 테스트 없이 완료 없다.

도식을 탭하면 확대해서 볼 수 있습니다

원 자료는 감에 의존한 디버깅과 체계적 디버깅을 다음과 같이 대조한다.

항목감으로 디버깅체계적 디버깅
평균 해결 시간2~3시간15~30분
첫 시도 성공률40%95%
새 버그 유발 빈도흔함거의 없음
토큰 비용5만~15만8천~2만

위 표에 대한 원 자료의 고지 — 원 자료는 이 표를 소개하는 문장에 이어 이 수치가 예시 값이며 실측 벤치마크가 아니라고 못 박는다.

이 표는 4행 × 2열 = 여덟 칸이고, 그중 여섯이 그 수치다. 나머지 둘(「흔함」·「거의 없음」)은 수치가 아니라 빈도 서술이다. 여섯 수치 어느 것도 어느 팀이 측정한 결과가 아니라 두 방식을 대조하기 위해 제시된 예시이며, 이 글도 이 수치를 측정한 적이 없다.

Phase 1 — 재현

"재현하지 못하면 고치지 못한다." 가장 흔한 함정은 "가끔 나오는 거라서"라며 추측으로 수정하는 것이다. 결과는 항상 같다 — 수정 후에도 가끔 나온다.

재현이 어려울 때의 4가지 무기확인 대상
로그 빈도·깊이 늘리기단순 출력 대신 스택까지 남기는 추적 출력
시간·순서 의존성 검사타이머, 이펙트 실행 순서, 경쟁 상태
환경 차이 확인로컬은 되고 배포만 안 되면 운영 환경변수부터
데이터 상태 차이특정 레코드가 있어야 재현되는가. Seed로 고정

에러 메시지 읽는 법

에러 메시지의 90%는 답을 들고 있는데, 대부분 마지막 줄만 본다. 첫 4줄에서 얻을 수 있는 정보는 다음과 같다.

첫 4줄의 구성요소알 수 있는 것
에러 타입런타임 오류인가 컴파일 오류인가
에러 문구무엇에 무엇을 했다가 실패했는가
접근하려던 속성·메서드기대한 타입이 무엇이었는가
파일:라인:컬럼정확한 발생 위치

스택 트레이스는 위에서 아래로 읽되, 본인 코드가 처음 나오는 지점에서 멈춘다. 프레임워크·라이브러리 내부 스택은 건너뛴다. 원인은 거의 항상 그 첫 지점에 있다.

증상·원인·해결·예방 카탈로그

네 개의 스택 구간으로 나뉜 13행이다.

TypeScript

증상원인해결예방
컴파일은 통과하는데 런타임에 속성 접근 실패any 로 타입을 무력화실제 타입을 선언해 오타를 컴파일 단계에서 잡는다any 사용 시 사유를 주석으로 강제하는 린트 규칙
값이 null인데 타입은 객체라고 주장as 강제 캐스팅으로 컴파일러를 속임타입 가드로 좁힌 뒤 사용캐스팅 대신 런타임 검증 라이브러리를 경계에 배치
사용자가 0을 입력했는데 기본값이 적용됨|| 는 0·빈 문자열도 falsy로 처리?? 로 교체 (null·undefined만 대체)0·빈 문자열이 유효값인 필드 목록을 리뷰 체크리스트에

React

증상원인해결예방
무한 리렌더 / 최대 업데이트 깊이 초과이펙트에 의존성 배열 누락의존성 배열 명시의존성 검사 린트 규칙 활성화
상태를 바꿨는데 화면이 안 바뀜원본 배열·객체를 직접 변형새 배열·객체를 만들어 교체불변성 규칙을 코딩 표준에 명문화
타이머 안의 값이 초기값에 고정됨오래된 클로저가 캡처한 값을 계속 사용함수형 업데이트로 최신 값을 받아 계산타이머·구독 안에서 상태를 직접 읽지 않는 관례

프레임워크 (SSR)

증상원인해결예방
Hydration 불일치 경고서버와 클라이언트의 렌더 결과가 다름 (시각·랜덤 등)클라이언트 전용 값은 마운트 후 설정서버 렌더 대상에 비결정적 값 금지
서버 컴포넌트에서 상태 훅 사용 실패기본이 서버 컴포넌트임클라이언트 지시자를 파일 최상단에 명시컴포넌트 구분 규칙을 파일 배치로 강제
비동기 API를 동기로 호출해 실패버전 업 후 API가 비동기로 변경대기 처리 추가메이저 업그레이드 시 변경 목록을 먼저 훑는다

DB / 인증

증상원인해결예방
에러는 없는데 빈 배열이 반환됨RLS 정책이 없어 전부 차단해당 작업에 대한 정책 추가테이블 생성 시 정책 생성을 같은 마이그레이션에 포함
모든 사용자의 데이터가 다 보임관리자 키가 클라이언트에 노출공개 키로 교체하고 노출 키 즉시 폐기공개 접두사 변수 스캔을 배포 전 점검에 포함
일정 시간 후 모든 요청 실패세션 토큰 만료, 갱신이 안 됨미들웨어에서 세션 갱신 호출세션 갱신 누락을 회귀 테스트로 고정
대량 행에서 정책 평가가 느림행마다 인증 함수가 재호출됨함수 호출을 서브쿼리로 감싸 1회 평가정책 작성 규칙에 래핑 패턴을 명문화

3 + 3 + 3 + 4 = 13행이다. DB / 인증만 네 행이고 나머지 셋은 세 행씩이다.

마지막 행(정책 평가가 느림)이 앞 편의 「정책 작성에서 놓치기 쉬운 4가지」 마지막 행과 같은 문제다. 거기서는 정책을 처음 쓸 때 피하는 방법으로, 여기서는 이미 느려진 뒤 찾는 증상으로 적혀 있다.

⚠️ 이 카테고리의 다른 글이 같은 이름의 4단을 쓴다 — 행을 하나씩 대조했다

3계층으로 좁히고 4단으로 분해한다 편은 "모든 장애를 증상 → 원인 → 해결 → 예방 4단으로 분해한다" 고 쓴다. 네 축의 이름이 위 네 표의 열 이름과 정확히 같다. 이름이 같으니 카탈로그도 겹치는지 세어 봐야 한다.

그 글에는 같은 네 열을 가진 표가 둘 있다 — **공통 문제 10선(10행)**과 현장 장애 5건(5행), 합 15행이다. 위 13행과 대조한 결과를 적는다.

그 글의 4단 표 행 수10 + 5 = 15
이 글의 카탈로그 행 수3 + 3 + 3 + 4 = 13
양쪽에서 같은 증상을 다루는 행0

겹치지 않는 이유는 다루는 대상이 다르기 때문이다. 그 글의 15행은 에이전트를 운영할 때 나는 장애다 — 도구 연동 실패, 컨텍스트 한도 초과, 훅 무한 루프, 권한 거부, 인증 충돌, 경로 확장 오류, 비용 폭주, 검토 없는 자동 커밋, 응답 품질 저하 같은 것들이다. 위 13행은 애플리케이션 코드의 버그다 — 타입 무력화, 리렌더, 하이드레이션 불일치, 정책 오설정.

가장 가까이 붙는 한 쌍이 RLS다. 그런데 그 한 쌍조차 증상이 정반대다. 그 글의 사례는 "행 단위 보안을 켰는데 모든 인증 사용자가 전체 행 접근 가능, 30분간 노출" 이고 원인은 조건식을 USING (true)로 쓴 것이다. 위 표의 첫 DB 행은 "에러는 없는데 빈 배열이 반환됨" 이고 원인은 정책이 아예 없어 전부 차단된 것이다. 전부 열린 것과 전부 막힌 것이라 해결도 반대 방향으로 간다.

따라서 두 자료가 공유하는 것은 「증상→원인→해결→예방」이라는 분해 틀이고, 그 틀에 넣은 목록은 서로 다른 집합이다. 이 대조는 이 글의 정리이며, 두 카탈로그를 행 단위로 맞춰 보고 센 결과다.

MRE — 최소 재현 케이스

단계내용
1현재 코드를 별도 브랜치·복사본으로 분리
2버그와 무관해 보이는 코드를 절반씩 삭제
3삭제 후에도 재현되면 → 더 삭제
4삭제했더니 사라지면 → 그 부분이 원인 영역
550줄 이하가 될 때까지 반복

MRE의 부가 효과가 본래 효과보다 크다.

  • 만드는 도중에 원인을 찾는 경우가 약 60%. 절반씩 지우는 과정 자체가 이진 탐색이다.
  • 외부에 질문할 때 그대로 재사용 가능하다.
  • Phase 4의 회귀 테스트 기반 코드로 그대로 전환된다.

세 효과 중 마지막 하나 때문에 MRE는 만든 구간에서 끝나지 않고 Phase 4의 입력이 된다. 다만 MRE가 어느 Phase의 것인지는 원 자료가 한 곳에만 적어 두었다 — 뒤에 싣는 디버깅 체크리스트가 「MRE를 50줄 이하로 만들었다」를 Phase 3(검증) 에 배정하고, 위의 4 Phase 흐름도에는 MRE 노드가 아예 없다. 앞뒤를 잇는 산출물도 MRE 하나가 아니다 — Phase 1의 재현 시나리오 역시 Phase 4에서 "재현 시나리오를 테스트로 고정한 뒤 종료" 로 다시 쓰인다. MRE를 Phase 3 → Phase 4의 다리로 읽는 것은 이 글의 정리다.

5-Why — 근본 원인까지

3-Why까지만 가면 표면 수정, 5-Why까지 가야 재발 방지다. 자료의 예시를 구조만 남기면 다음과 같다.

단계질문답변 성격
Q1왜 화면이 비었나변수가 undefined여서 메서드 호출 실패 (증상)
Q2왜 undefined인가함수가 반환값 없이 끝남 (코드)
Q3왜 반환값이 없나쿼리가 정책에 막혀 에러를 반환했는데 에러를 무시함 (로직)
Q4왜 에러를 무시했나에러 핸들링 코드 자체가 없음 (관행)
Q5왜 핸들링이 없나팀 컨벤션에 규칙이 없고 린트 규칙도 미설정 (시스템)
조치 유형내용
즉시 조치해당 파일에 에러 핸들링 추가
근본 조치린트 규칙 추가 + 팀 컨벤션 명문화 + 회귀 테스트

「답변 성격」 열이 증상 → 코드 → 로직 → 관행 → 시스템으로 올라간다. 다섯 단계 중 앞의 셋은 그 파일 안에서 답이 나오고, Q4부터 답이 파일 밖으로 나간다.

Q5에 도달하면 답이 코드가 아니라 규칙·게이트로 바뀐다. 이 전환이 5-Why의 목적이며, 이 시리즈 첫 편의 Rules·Hooks 계층이 존재하는 이유이기도 하다.

회귀 버그 — 이진 탐색

"어제까지 됐는데 오늘 안 된다"에는 이진 탐색이 정답이다. 100개 커밋을 하나씩 확인하면 100회, 절반씩 좁히면 7회다.

방식절차
수동탐색 시작 → 현재를 bad로, 정상이던 커밋을 good으로 표시 → 이동한 커밋에서 테스트 → good/bad 응답 반복
자동판정 스크립트를 지정하면 종료코드로 good/bad를 자동 판정하며 끝까지 진행

범인 커밋을 찾은 뒤에는 "이 커밋의 어느 변경이 원인인가 / 최소 수정은 무엇인가 / 같은 패턴이 다른 곳에도 잠복해 있는가" 세 가지를 함께 확인한다. 세 번째 질문이 재발을 막는다.

디버거 사용 — console.log를 대체하는 3가지

기법언제이점
브레이크포인트변수 변화·호출 순서 추적모든 스코프 변수를 한 번에 확인. 코드 수정 불필요
조건부 브레이크포인트루프 안 특정 조건에서만 멈추고 싶을 때조건 판정용 임시 코드를 코드베이스에 넣지 않아도 됨
로그 포인트특정 줄 통과 시 값만 찍고 싶을 때코드 수정·재빌드 없이 로그 추가. 가장 저평가된 기능

세 기법의 「이점」 열이 공통으로 말하는 것은 코드를 건드리지 않는다는 것이다. 출력문을 박아넣는 방식은 디버깅 흔적이 코드에 남고, 그 흔적을 지우다가 다른 것이 지워진다.

DevTools 패널디버깅에서의 용도
ElementsDOM·CSS 실시간 검사, 가상 상태 강제 활성화
Console선택 요소 참조, 직전 결과 참조, 객체 복사, 표 형식 출력
Sources브레이크포인트·전체 검색·로컬 폴더 연결
Network실패 요청 식별, 요청을 그대로 재현 가능한 형태로 복사, 속도 제한 시뮬레이션
Performance프레임 드랍 구간과 원인 함수 식별
Memory스냅샷 비교로 메모리 누수 추적 (정리 누락·리스너 미해제)
Application스토리지·쿠키·서비스 워커 확인. 인증 쿠키 디버깅
Lighthouse성능·접근성·SEO 자동 진단
Recorder사용자 동작 녹화 → 자동화 테스트 스크립트로 내보내기

디버깅 프롬프트 10패턴

#패턴쓰는 상황요청에 반드시 넣을 것
1재현 시나리오 요청가끔만 재현될 때환경·증상·시도한 단계·현재 재현율
2가설 수립 요청재현은 되는데 원인을 모를 때가설마다 검증 방법 + "가능성 70%, 근거는 Y" 형태 요구
3MRE 만들기코드가 길어 어디가 문제인지 모를 때50줄 이하, 외부 의존성 대체, 재현 검증 단계
45-Why 분석같은 버그가 반복될 때각 단계 답변에 코드 근거 요구, 즉시조치·근본조치 분리
5타입 에러 해결타입 오류의 의미를 모를 때우회 캐스팅 금지, 불가피하면 사유 명시, 동일 패턴 검색
6빌드 에러 해결빌드가 실패할 때최근 커밋 목록 첨부, 임시방편 플래그 사용 금지 명시
7런타임 에러 해결브라우저 에러발생 시점·사용자 상태·관련 컴포넌트 + 회귀 테스트 요구
8네트워크 실패요청이 실패할 때상태코드·헤더·페이로드 + 클라이언트/서버/인프라 레이어 분류 요구
9DB 쿼리 실패빈 결과 또는 에러정책 내용·인증 상태 + 권한/문법/데이터부재 중 분류 요구
10배포 실패로컬은 되는데 배포만 실패로컬·배포 환경 차이 표 + 환경변수는 개수만 (값 노출 금지)

공통 설계: 10패턴 중 이 "무엇을 하지 말 것"을 함께 지시한다 — 5번(우회 캐스팅 금지) · 6번(임시방편 플래그 사용 금지 명시) · 10번(환경변수 값 노출 금지)이다. 급할 때 가장 손이 가는 선택지를 프롬프트 단계에서 미리 봉쇄하는 자리이며, 나머지 일곱 칸은 금지가 아니라 무엇을 함께 넣을 것인가를 요구한다.

그 마지막 금지(환경변수 값 노출)는 이 시리즈 첫 편의 차단 규칙 7번(echo/cat/printf + 시크릿 환경변수명)이 훅으로 강제하는 것과 같은 사고를 막는다. 한쪽은 프롬프트에 적는 지시이고 다른 쪽은 프로세스가 거부하는 게이트다.

디버깅 체크리스트

Phase소요체크 항목
1. 재현5분에러 메시지 첫 4줄을 읽었다 / 스택에서 내 코드 첫 줄을 찾았다 / 100% 재현 단계를 적었다 / 환경 버전을 기록했다 / "어제까지 됐다면" 최근 커밋을 확인했다
2. 가설10분가설 3개를 가능성 순으로 적었다 / 가설마다 검증 방법이 있다 / 한 번에 한 변수만 바꾸기로 했다 / 프롬프트 4요소를 채웠다
3. 검증15분MRE를 50줄 이하로 만들었다 / 1번 가설부터 검증했다 / 결과를 기록했다 / 수정 시도 횟수를 세고 있다
4. 회귀 방지10분원래 재현 단계가 더 이상 재현되지 않는다 / 회귀 테스트를 작성했다 / 전체 테스트를 돌렸다 / 5-Why로 근본 원인까지 갔다 / 같은 패턴을 다른 곳에서 검색했다

네 Phase의 소요가 5 + 10 + 15 + 10 = 40분이다. 가장 긴 구간이 Phase 3(검증)이고, Phase 1(재현)이 가장 짧다. 2단계의 「프롬프트 4요소를 채웠다」는 목적·맥락·제약·형식을 말하며, 그 정의는 .claude 디렉터리와 프롬프트 7패턴 편에 있다.

절대 금지 6가지

금지대안
출력문 10개 박아넣기디버거 브레이크포인트 또는 로그 포인트
타입을 무력화해 회피타입 가드 또는 경계 검증
에러를 빈 catch로 삼키기로깅 후 재throw 또는 명시적 fallback
가설 없는 "일단 해보자" 수정가설을 문장으로 적고 검증 방법을 정한 뒤 착수
회귀 테스트 없이 "끝났다" 선언재현 시나리오를 테스트로 고정한 뒤 종료
3번 실패한 방향으로 4번째 시도설계 문제로 재정의하고 구조를 검토

"수정 3번 실패 = 아키텍처 문제"

같은 가설로 세 번 고쳤는데 다른 곳에서 계속 터진다면, 그것은 버그가 아니라 설계 문제다.

징후는 셋이다. 한 곳을 고치면 다른 곳이 깨진다 / 매번 범위가 커진다 / "대대적인 리팩토링이 필요하겠는데" 생각이 든다.

여섯 금지 중 「에러를 빈 catch로 삼키기」는 이 시리즈 첫 편의 Rules 5종에도 같은 조항으로 있다 — logging.md"에러를 잡고 삼키지 말 것. 로깅 후 재throw 또는 명시적 fallback" 이 그것이다. 첫 편의 Rules 두 표에는 타입 무력화를 금하는 조항도, 디버그 출력문을 금하는 조항도 없다.

도구 확장 계층 — MCP 6종

에이전트가 다룰 수 있는 범위를 넓히는 것이 MCP다. 원 자료는 6종을 한 번에 등록하는 설치 스크립트를 두고 있으나 그 코드를 본문에 싣지 않고, 어떤 축으로 6종을 골랐는가만 남긴다. 이 글이 옮기는 것도 그 선정 축이다.

아래 6종과 선정 이유는 원 자료가 제시한 구성이며, 이 글이 6종을 연동해 운영한 기록이 아니다.

MCP연결 대상인증 방식선정 이유
Notion문서·위키OAuth 브라우저 인증 (토큰 입력 불가)페이지 단위 권한 부여가 가능해 최소 권한 원칙에 맞음
Supabase운영 DBPersonal Access Token스키마·데이터를 직접 조회. 기본 --read-only로 등록
Context7라이브러리 공식 문서익명 사용 가능, 키는 rate limit 상향용모델이 최신 API를 환각하는 문제를 문서 실시간 조회로 차단
Playwright브라우저 자동화불필요UI 검증·스크린샷을 사람 없이 수행
YouTube Transcript영상 자막불필요영상 자료를 텍스트 컨텍스트로 전환
Google Workspace메일·드라이브·시트CLI OAuth (스코프 지정)업무 데이터 접근. 스코프를 명시적으로 좁혀 발급

운영 관점의 관전 포인트 3가지

  • 읽기 전용 기본값: DB MCP를 --read-only로 등록하고, 쓰기가 필요할 때만 옵션을 푼다. 기본값이 안전한 쪽이어야 한다.
  • 권한 스코프 최소화: OAuth 스코프를 필요한 것만 나열해 발급한다. 나중에 필요해지면 재인증으로 늘린다.
  • 설정 변경 전 자동 백업: 설치 스크립트가 설정 파일을 타임스탬프 백업(권한 600)한 뒤에만 수정한다. 롤백 경로를 먼저 만든다.

여섯 종의 「인증 방식」 열이 OAuth 2 · 토큰 1 · 불필요 2 · 선택적 키 1로 갈린다. 인증 없이 붙는 셋(Context7·Playwright·YouTube Transcript)은 연결 대상이 우리 데이터가 아니라는 공통점이 있고, 그중 Context7만 키가 선택 사항으로 붙는다 — 원 자료가 "익명 사용 가능, 키는 rate limit 상향용" 이라 적었기 때문이다.

MCP를 도구 하나가 점유하는 토큰 예산의 문제로 보는 관점은 이 카테고리의 MCP 도입은 기능 추가가 아니라 예산 배분이다 편이 따로 다뤘다. 그 글은 같은 6종을 다루면서 스코프 계층과 마켓플레이스 선별 기준까지 내려간다.

시리즈를 닫으며

네 편이 다룬 것을 한 줄씩 적으면 이렇게 된다.

다룬 것
Rules·Hooks·Skills 3계층규범·강제·절차. 강제력이 있는 계층은 하나뿐이다
업종별 CLAUDE.md 템플릿업종이 바뀌어도 7원칙·데이터 분류·권한 모델의 자리는 남는다
빈 폴더에서 배포까지자물쇠를 먼저 달고 출입증을 발급한다
이 글재현 없이 가설 없다. 그리고 5-Why의 끝은 다시 첫 편이다

마지막 행이 시리즈를 닫는 자리다. 5-Why를 Q5까지 밀면 답이 코드가 아니라 규칙과 게이트로 바뀌고, 그 규칙과 게이트가 첫 편의 Rules와 Hooks다. 디버깅에서 시작한 질문이 통제 계층으로 돌아온다.