디버깅 습관 리셋
수동 추적에서 AI 협업 가설-검증 기반 디버깅으로
버그를 만나면 개발자는 본능적으로 추적을 시작한다. 누군가는 console.log를 심고, 누군가는 브레이크포인트를 걸고 스텝 실행을 돌린다. 도구는 다르지만 접근은 같다. "어디서 값이 이상한지"를 한 지점씩 좁혀가는 것이다.
이 방식이 수십 년간 살아남은 이유는 확실하기 때문이다. 하지만 확실한 것이 항상 효율적인 것은 아니다. AI 시대의 디버깅은 **"어디서"**가 아니라 **"왜"**에서 시작한다.
수동 추적의 두 축: console.log와 디버거
디버깅의 수동 추적 방식은 크게 두 가지로 나뉜다.
console.log 방식
가장 원시적이지만 가장 널리 쓰이는 방식이다.
// 1차: 의심 지점에 로그 삽입
console.log("user:", user);
console.log("items:", items);
// 2차: 범위 좁히기
console.log("before filter:", items.length);
console.log("after filter:", filtered.length);
// 3차: 더 깊이
console.log("item[0]:", JSON.stringify(items[0], null, 2));
// ... 5-6회 반복 후 원인 발견
// ... 그리고 심어둔 console.log 전부 제거디버거 방식
IDE나 DevTools의 디버거를 적극 활용하는 접근이다. console.log보다 분명히 강력하다.
1. 의심 지점에 브레이크포인트 설정
2. 실행 → 중단점에서 멈춤
3. 변수 패널에서 현재 상태 확인
4. 콜스택 추적 → 호출 경로 파악
5. 스텝 오버/스텝 인 → 한 줄씩 실행하며 상태 변화 관찰
6. 조건부 브레이크포인트로 특정 케이스만 포착
7. ... 반복하며 원인 좁히기공통된 한계
도구는 다르지만, 두 방식 모두 같은 패턴을 따른다.
| 특성 | console.log | 디버거 |
|---|---|---|
| 탐색 방식 | 로그 삽입 → 실행 → 관찰 → 반복 | 브레이크포인트 → 실행 → 관찰 → 반복 |
| 한 번에 확인하는 범위 | 삽입한 로그 지점만 | 중단된 지점의 스코프만 |
| 방향 결정 | 개발자의 직감 | 개발자의 직감 |
| 속도 제한 요인 | 로그 삽입/삭제/재실행 사이클 | 스텝 실행 속도, 스택 탐색 시간 |
| 핵심 병목 | 어디를 봐야 하는지 모른 채 한 지점씩 탐색 | 어디를 봐야 하는지 모른 채 한 지점씩 탐색 |
디버거가 console.log보다 우월한 건 맞다. 변수 상태를 즉시 볼 수 있고, 콜스택을 추적할 수 있고, 코드를 수정하지 않아도 된다. 하지만 근본적인 접근 방식은 동일하다. 둘 다 "의심 지점을 설정하고, 실행하고, 관찰하고, 다음 지점으로 이동"하는 루프를 반복한다.
문제는 이 루프의 방향을 정하는 것이 순전히 개발자의 직감에 의존한다는 점이다. 직감이 맞으면 빠르고, 틀리면 한참을 헤맨다.
디버거가 나쁘다는 것이 아니다
디버거는 훌륭한 도구다. 특히 상태 흐름을 정밀하게 추적해야 할 때는 여전히 최선이다. 문제는 디버거든 console.log든 "어디를 봐야 하는지"를 사람이 직감으로 결정해야 한다는 점이다. AI는 바로 이 "어디를 봐야 하는지"를 제안하는 데 강점이 있다.
AI 시대 디버깅: 가설-검증 기반 접근
수동 추적이 **"어디서 값이 이상한지"**로 시작한다면, 가설-검증 접근은 **"왜 이런 증상이 나타나는지"**로 시작한다.
핵심 차이는 탐색 방향을 AI가 제안한다는 것이다. 개발자의 직감 대신, AI가 코드 패턴과 에러 유형을 기반으로 "가장 가능성 높은 원인"을 확률 순으로 나열해준다. 개발자는 가장 유력한 가설부터 검증하면 된다.
세 접근법의 비교
| 항목 | console.log | 디버거 | 가설-검증 (AI) |
|---|---|---|---|
| 시작점 | 어디서 값이 이상한지 찍어보자 | 어디서 상태가 변하는지 걸어보자 | 왜 이런 증상이 나타나는지 추론하자 |
| 탐색 방향 | 직감 | 직감 + 콜스택 | AI가 확률 순 제안 |
| 한 사이클 비용 | 높음 (코드 수정 필요) | 중간 (실행 제어) | 낮음 (가설 확인만) |
| 범위 | 한 지점씩 | 한 스코프씩 | 여러 가설 동시 고려 |
| 속도 결정 요인 | 반복 횟수 | 스택 깊이, 재현 난이도 | 가설 품질 |
| 부산물 | 제거해야 할 로그 | 없음 | 문서화된 디버깅 과정 |
| 학습 효과 | 이번 버그에만 유효 | 도구 숙련도 향상 | 유사 버그 패턴 인식 축적 |
디버깅 컨텍스트의 구조
AI에게 에러 메시지만 던지는 것은 의사에게 "아파요"라고만 말하는 것과 같다. 효과적인 디버깅 요청에는 구조화된 컨텍스트가 필요한데, 경험적으로 네 가지 요소가 반복적으로 등장한다.
| 요소 | 포함할 내용 | 예시 |
|---|---|---|
| 증상 | 에러 메시지 전문, 기대 vs 실제 동작 | "TypeError: Cannot read property 'map' of undefined" |
| 재현 조건 | 환경, 빈도, 패턴 | "로그인 직후 /users 직접 접근 시에만 발생" |
| 시도한 것 | 이미 확인한 부분, 배제한 가설 | "users 초기값은 빈 배열, API 응답은 정상" |
| 의심 영역 | 원인 추정, 최근 변경, 관련 모듈 | "SSR/CSR 하이드레이션 타이밍 문제?" |
정보 전달 방식의 차이
## 정보가 부족한 경우
이 에러 좀 해결해줘:
TypeError: Cannot read property 'map' of undefined## 구조화된 정보 전달
### 증상
사용자 목록 페이지에서 TypeError: Cannot read property
'map' of undefined 발생.
페이지 첫 로딩 시에만 발생하고, 새로고침하면 정상 동작.
### 재현 조건
- 로그인 직후 /users 페이지로 직접 접근할 때
- 사이드바에서 네비게이션으로 이동하면 발생하지 않음
- 개발 환경에서만 확인 (프로덕션 미확인)
### 시도한 것
- users 상태의 초기값 확인: 빈 배열
- API 호출 시점 확인: useEffect에서 호출
- 네트워크 탭: API 응답은 정상 (200, 배열 데이터)
### 의심 영역
- SSR/CSR 하이드레이션 타이밍 문제?
- useEffect 실행 전 렌더링 시점에서 데이터가 undefined?구조화된 컨텍스트의 효과
위처럼 정보를 제공하면, AI는 5-10초 내에 가능한 원인 3-5개를 확률 순으로 제시하는 경향이 있다. 첫 번째 가설이 맞을 확률이 높으며, 아니더라도 어디를 확인해야 하는지 명확해진다.
실전 케이스 스터디 1: React 하이드레이션 버그
버그 상황: 서버와 클라이언트 렌더링 불일치
// UserDashboard.tsx - 문제의 코드
export default function UserDashboard() {
const [greeting, setGreeting] = useState(
`안녕하세요, 현재 시각은 ${new Date().toLocaleTimeString()}입니다`
);
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
return (
<div>
<h1>{greeting}</h1>
<p>화면 너비: {windowWidth}px</p>
</div>
);
}에러: window is not defined (SSR 시), 하이드레이션 불일치 경고
접근법 비교
// 1차: 렌더링 확인
console.log("렌더링 시작", typeof window);
// 2차: useEffect 타이밍
useEffect(() => {
console.log("useEffect 실행", window.innerWidth);
}, []);
// 3차: SSR vs CSR 구분
console.log("IS_SERVER:", typeof window === "undefined");
// ... 5-6번의 로그 삽입/삭제 반복
// 총 소요시간: 약 40분과정: 로그를 하나씩 심고, 실행하고, 출력을 읽고, 다시 심는 반복. 매번 코드를 수정하고 앱을 재시작해야 한다.
1. useState(window.innerWidth) 라인에 브레이크포인트 설정
2. SSR 환경에서 실행 → 중단
3. 스코프 확인: window === undefined 확인
4. 콜스택 추적: 서버 렌더링 경로 확인
5. CSR 경로에서 다시 브레이크포인트 → 정상 동작 확인
6. 차이 분석 → SSR에서 window 접근이 문제임을 파악과정: console.log보다 빠르지만(약 15-20분), SSR/CSR 두 환경을 오가며 브레이크포인트를 걸고 상태를 비교해야 한다. 디버거가 서버 사이드 렌더링 경로를 잡아주지 않는 경우 설정에 시간을 쓰게 된다.
개발자가 AI에게 전달한 정보:
증상: UserDashboard에서 window is not defined 에러
+ 하이드레이션 불일치 경고
환경: Next.js 15, App Router, SSR 활성화
코드: [위 컴포넌트 코드 첨부]AI가 제시한 가설:
| 순위 | 가설 | 확인 소요 |
|---|---|---|
| 1 | useState 초기값에서 window 직접 참조 → SSR에서 불가 | 즉시 확인 |
| 2 | Date 객체가 서버/클라이언트에서 다른 시간 반환 | 즉시 확인 |
| 3 | useEffect 없이 브라우저 API 사용 | 코드 검토 |
AI가 제안한 수정:
export default function UserDashboard() {
const [greeting, setGreeting] = useState("");
const [windowWidth, setWindowWidth] = useState(0);
useEffect(() => {
setGreeting(
`안녕하세요, 현재 시각은 ${new Date().toLocaleTimeString()}입니다`
);
setWindowWidth(window.innerWidth);
}, []);
return (
<div>
<h1>{greeting || "로딩 중..."}</h1>
{windowWidth > 0 && <p>화면 너비: {windowWidth}px</p>}
</div>
);
}과정: 증상 정리 30초 + AI 응답 10초 + 코드 적용 2분 = 약 3분.
결과 비교:
| 항목 | console.log | 디버거 | AI 가설-검증 |
|---|---|---|---|
| 소요 시간 | 약 40분 | 약 15-20분 | 약 3분 |
| 코드 수정 횟수 | 6회 (로그 삽입/삭제) | 0회 (설정만) | 1회 (최종 수정) |
| 방향 결정 | 직감 | 직감 + 스택 | AI 가설 |
| 학습 효과 | 이 케이스만 | SSR 디버깅 경험 | SSR 패턴 전반 |
핵심은 시간 차이가 아니다. "어디를 봐야 하는지"를 직감으로 찾느냐, AI가 제안하느냐의 차이다. 숙련된 개발자는 디버거로도 빠르게 찾겠지만, AI는 그 숙련도와 무관하게 일정한 속도를 보장한다.
실전 케이스 스터디 2: 간헐적 검색 실패
상황: 검색 결과가 때때로 빈 배열을 반환
// searchService.ts
export async function searchDocuments(query: string) {
const index = getSearchIndex(); // Orama 인덱스
const results = await search(index, { term: query });
return results.hits;
}같은 검색어로 3번 요청하면 2번은 정상, 1번은 빈 배열 반환. 서버 로그에 에러 없음.
이런 비결정적 버그는 디버거로도 잡기 어렵다. 브레이크포인트를 걸어도 "실패하는 순간"을 포착하려면 여러 번 실행해야 하고, 타이밍 자체가 원인일 경우 디버거가 실행을 멈추는 것 자체가 재현 조건을 바꿔버린다.
AI에게 전달: 증상 + 코드 + 비결정적 재현 패턴
AI가 생성한 가설 목록:
| 순위 | 가설 | 확인 방법 | 소요 |
|---|---|---|---|
| 1 | 인덱스 빌드가 비동기 완료 전 요청 도달 | 빌드 상태 로깅 1줄 | 2분 |
| 2 | 캐시 만료 시 빈 결과 반환 | 캐시 비활성화 테스트 | 3분 |
| 3 | 커넥션 풀 소진으로 타임아웃 | 커넥션 풀 모니터링 | 5분 |
| 4 | 토크나이저의 비결정적 동작 | 동일 입력 반복 테스트 | 5분 |
가설 1 검증 결과: 원인 확인
// 수정 전: 인덱스 준비 여부 확인 없음
export async function searchDocuments(query: string) {
const index = getSearchIndex();
const results = await search(index, { term: query });
return results.hits;
}
// 수정 후: 인덱스 준비 완료 대기
let indexReady = false;
let indexPromise: Promise<void>;
export async function searchDocuments(query: string) {
if (!indexReady) {
await indexPromise; // 인덱스 빌드 완료 대기
}
const index = getSearchIndex();
const results = await search(index, { term: query });
return results.hits;
}console.log를 10군데 심거나, 브레이크포인트를 걸고 실패를 기다리는 대신, 1개의 가설 검증으로 문제를 해결한 사례다.
AI 협업 디버깅의 흐름
효과적인 AI 디버깅에는 일정한 흐름이 있다.
증상 공유 — 개발자가 사실 기반으로 보고
- 에러 메시지 전달, 관련 코드 첨부, 재현 조건 설명
- 핵심: 추측 배제, 관찰한 사실만 전달
가설 수립 — AI가 패턴 매칭 기반으로 가설 생성
- AI가 가능한 원인을 확률 순으로 나열
- 개발자가 도메인 지식으로 가설을 필터링하고 우선순위 조정
검증 — 개발자가 유력한 가설부터 확인
- 한 번에 하나씩 검증, 결과를 AI에게 피드백
- AI가 검증 방법과 수정안 제안
해결 — 수정 적용 + 회귀 확인
- 수정 적용, 부작용 확인, 테스트
- 디버깅 과정을 기록으로 남기기
각 단계에서 개발자와 AI의 역할이 자연스럽게 나뉜다.
| 단계 | 개발자의 역할 | AI의 역할 |
|---|---|---|
| 증상 공유 | 사실 기반 보고 | 경청 및 분류 |
| 가설 수립 | 도메인 지식으로 필터링 | 패턴 매칭 기반 가설 생성 |
| 검증 | 실제 코드 확인, 실행 | 검증 방법 및 수정안 제안 |
| 해결 | 수정 적용, 부작용 확인 | 엣지 케이스 점검, 테스트 생성 |
AI가 잘 못하는 디버깅, 잘하는 디버깅
AI가 만능은 아니다. 유형에 따라 AI의 효과가 크게 달라진다.
AI에게 맡기기 어려운 영역
아래 유형은 AI에게 가설을 요청하되, 최종 판단은 사람이 하는 것이 낫다. AI의 가설을 출발점으로 삼되, 환경과 맥락에 대한 사람의 판단이 결정적이다.
| 디버깅 유형 | AI가 어려운 이유 | 보완 방법 |
|---|---|---|
| 환경 의존적 버그 | AI는 로컬 환경을 직접 볼 수 없음 | 환경 변수, OS 버전, 메모리 등 상세 제공 |
| 타이밍/동시성 버그 | 비결정적이라 가설 검증이 어려움 | 사람이 시나리오 좁히고 AI가 분석 |
| 레거시 코드 버그 | 역사적 맥락을 모름 | git blame 결과 + 당시 배경 설명 |
| 인프라/네트워크 버그 | 코드 레벨이 아닌 환경 문제 | 구성 파일과 로그를 AI에게 제공 |
| 데이터 오염 버그 | DB 상태를 직접 조회 불가 | 쿼리 결과를 텍스트로 전달 |
| UI 레이아웃 버그 | 시각적 렌더링 결과 판단 어려움 | 스크린샷 + DOM 구조 함께 제공 |
반면, AI가 압도적 우위를 보이는 영역도 분명히 존재한다.
| 디버깅 유형 | AI의 강점 | 활용 팁 |
|---|---|---|
| 타입 에러 / 인터페이스 불일치 | 코드 전체를 빠르게 스캔 | 관련 타입 정의 파일 함께 제공 |
| 라이브러리 API 오용 | 방대한 문서 지식 | 사용 중인 버전 명시 |
| 정규식 버그 | 패턴 분석과 반례 생성 우수 | 의도하는 매칭 예시 제공 |
| 비동기 코드 로직 오류 | Promise 체인 흐름 추적 | 전체 비동기 흐름 코드 제공 |
| 알고리즘 로직 오류 | 반례 빠르게 생성 | 기대 입출력 쌍 제공 |
| CSS 스타일 충돌 | 우선순위 규칙 정확히 적용 | 관련 CSS 파일 모두 제공 |
이런 분포를 보면, AI 디버깅의 핵심은 "무엇이든 AI에게 맡기는 것"이 아니라 어떤 종류의 문제에 AI를 투입할지 판단하는 것이라는 점이 드러난다.
기존 도구와 AI의 조합
기존 디버깅 도구들이 AI와 조합되면서 사용 방식 자체가 달라지고 있다. 도구를 직접 원인을 찾는 용도로 쓰는 대신, AI에게 줄 증거를 수집하는 용도로 쓰는 것이다.
| 도구 | 기존 사용법 | AI와 조합한 사용법 |
|---|---|---|
| 브라우저 DevTools | 네트워크 탭에서 직접 원인 추적 | 응답 헤더/페이로드를 AI에게 분석 요청 |
| 디버거 (브레이크포인트) | 한 줄씩 스텝 실행하며 상태 변화 관찰 | 중단 시점의 변수 스냅샷을 AI에게 전달 |
| 프로파일러 | flame chart를 직접 읽고 병목 판단 | 프로파일링 결과를 AI에게 병목 분석 요청 |
| git bisect | 수동으로 이진 탐색 | AI에게 의심 커밋 범위를 먼저 좁히게 한 후 실행 |
| React DevTools | 리렌더링 횟수를 직접 세고 원인 추적 | 리렌더링 패턴을 AI에게 전달해 원인 분석 |
| 구조적 로깅 | JSON 로그를 직접 읽고 패턴 파악 | 로그 뭉치를 AI에게 패턴 분석 요청 |
예시: 프로파일러 결과를 AI에게 전달
아래는 Node.js 프로파일러 출력 중 상위 5개 함수입니다.
| 함수 | 자체 시간 | 총 시간 | 호출 횟수 |
|------|----------|---------|----------|
| processOrder | 2.3ms | 450ms | 1 |
| validateItems | 1.1ms | 380ms | 1 |
| checkInventory | 350ms | 350ms | 47 |
| formatResponse | 0.5ms | 0.5ms | 1 |
| logMetrics | 0.2ms | 0.2ms | 1 |
checkInventory가 47번 호출되는 것이 의심됩니다.
상품 목록은 최대 10개인데 왜 47번 호출되는지 분석해주세요.디버거로 checkInventory에 브레이크포인트를 걸고 47번 스텝 실행하는 것보다, 호출 패턴을 AI에게 던지는 것이 훨씬 빠르다.
디버깅 과정의 기록
팀 전체의 디버깅 효율을 높이는 데 의외로 큰 역할을 하는 것이 디버깅 과정 자체의 기록이다.
## 버그 #1234: 결제 금액 불일치
### 증상
- 할인 쿠폰 적용 시 최종 결제 금액이 예상보다 높음
- 100원 단위에서 차이 발생
### 가설 (AI 생성)
1. [검증 완료] 반올림 방식 차이 (Math.round vs Math.floor)
결과: 원인 아님
2. [검증 완료] 할인율 적용 순서 (쿠폰 vs 포인트)
결과: 원인 확인
3. [미검증] 세금 계산 타이밍
### 원인
할인 적용 순서가 기획 의도와 다름.
기획: 쿠폰 먼저, 포인트 차감
구현: 포인트 먼저, 쿠폰 적용
### 수정
applyDiscount 함수의 적용 순서를 기획 의도에 맞게 수정.
### 교훈
할인 적용 순서는 비즈니스 규칙이므로 CLAUDE.md에 명시 필요.디버깅 로그의 가치
디버깅 로그를 남기면 3가지 효과가 관찰된다.
- 같은 버그 재발 시 즉시 원인을 파악할 수 있음
- AI에게 과거 사례를 제공하면 유사 버그 진단 정확도가 올라감
- 팀원 온보딩 시 시스템의 함정을 사전에 공유할 수 있음
상황별 디버깅 프롬프트
에러 분석
다음 에러의 가능한 원인을 확률 순으로 3-5개 나열해줘.
에러: [에러 메시지]
발생 위치: [파일명:라인번호]
재현 빈도: [항상/간헐적/특정 조건]
환경: [Node 버전, OS, 프레임워크 버전]
각 가설에 대해:
- 왜 이 에러가 발생하는지 메커니즘 설명
- 확인 방법 1줄 요약
- 예상 수정 방향성능 병목 분석
아래 프로파일링 결과를 분석하고 최적화 방안을 제안해줘.
[프로파일링 결과 붙여넣기]
현재 응답 시간: [현재값]
목표 응답 시간: [목표값]
제약 조건: [변경 불가능한 부분]코드 리뷰 기반 잠재 버그 탐지
이 코드에서 버그가 될 수 있는 부분을 찾아줘.
특히 다음 관점에서 검토:
- null/undefined 처리 누락
- 비동기 에러 처리
- 엣지 케이스 (빈 배열, 빈 문자열, 큰 숫자)
- 타입 안전성
[코드 붙여넣기]| 프롬프트 유형 | 적합한 상황 | 예상 효과 |
|---|---|---|
| 에러 분석 | 명확한 에러 메시지가 있을 때 | 원인 특정 시간 80% 단축 |
| 성능 병목 | 프로파일링 데이터가 있을 때 | 최적화 포인트 즉시 식별 |
| 잠재 버그 탐지 | 코드 리뷰 또는 배포 전 | 프로덕션 버그 사전 예방 |
디버깅 역량의 진화 과정
디버깅 역량이 어떻게 발전하는지 관찰하면, 흥미로운 패턴이 보인다. 레벨 1과 2는 도구가 다를 뿐 본질적으로 같은 접근이고, 레벨 3에서 접근 방식 자체가 전환된다.
레벨 1 — console.log 추적
console.log로 값 확인 → 로그 삽입/삭제 반복- 에러 메시지 구글 검색 → Stack Overflow 답변 참고
- 도구: 텍스트 에디터 + 터미널
레벨 2 — 디버거 활용
- 브레이크포인트, 콜스택 추적, 워치 표현식, 조건부 중단
- 프로파일러, DevTools 네트워크 탭 등 전문 도구 사용
- console.log보다 빠르고 정밀하지만, 탐색 방향은 여전히 직감에 의존
레벨 3 — 가설-검증 전환 ← 접근 방식이 바뀌는 지점
- "어디를 볼까"가 아니라 "왜 이런 증상이 나타나는가"로 시작
- AI에게 가설 목록을 요청하고 확률 순으로 검증
- 기존 도구들은 가설을 검증하는 수단으로 역할이 재정의됨
레벨 4 — 체계화
- 디버깅 과정을 로그로 기록 → 팀 지식 자산화
- 예방적 디버깅 → AI로 잠재 버그 사전 탐지
- CLAUDE.md에 반복 패턴 등록 → 같은 유형의 버그 재발 방지
여기서 흥미로운 점은, 레벨 1→2 전환은 도구의 업그레이드지만, 레벨 2→3 전환은 접근 방식의 전환이라는 것이다. 디버거를 아무리 능숙하게 다뤄도, "어디를 봐야 하는지"를 직감으로 결정하는 한 수동 추적의 한계를 벗어나지 못한다.
레벨 4에 도달한 개발자도 때로는 console.log를 쓰고, 때로는 브레이크포인트를 건다. 다만 그것이 유일한 선택지가 아니라는 것을 알고 있을 뿐이다.
이 챕터의 핵심
기억할 한 문장
디버깅의 핵심 변화는 더 좋은 도구를 쓰는 것이 아니라, "어디를 볼까"에서 "왜 이런 증상이 나타나는가"로 출발점을 바꾸는 것이다.
다음 장 미리보기
디버깅에서 AI에게 좋은 컨텍스트를 제공하는 것이 핵심이었습니다. 다음 장에서는 이 "컨텍스트 제공" 능력을 더 넓게 확장합니다. AI에게 무엇을 알려주고 무엇을 생략할지 판단하는 컨텍스트 관리는 AI 시대 개발자의 새로운 핵심 역량입니다.
참고 자료
참고 자료 안내
이 장의 관점과 프레임워크를 뒷받침하는 참고 자료입니다. 본문의 모든 주장이 아래 자료에서 직접 인용된 것은 아니며, 실무 경험과 커뮤니티 사례를 종합한 해석이 포함되어 있습니다.
- Microsoft. "Debug JavaScript in Chrome DevTools." https://code.visualstudio.com/docs/nodejs/browser-debugging
- Anthropic (2025). "Troubleshooting and Debugging with Claude Code." https://docs.anthropic.com/en/docs/claude-code/common-workflows