PABCD Initiative Documentation Hub pabcd_initiative codexclaw cli-jaw

dev-debugging

Source: skills/dev-debugging/SKILL.md

5-phase systematic root-cause debugging method for real failures in any language.

왜 별도 모듈인가
에이전트가 버그를 만나면 증상을 보고 바로 패치하는 경향이 있다. 타임아웃이면 타임아웃 값을 늘리고, OOM이면 메모리를 올린다. 이런 증상 패치는 다음 버그를 만들어낸다. 이 스킬은 '이건 설계 문제인가 코드 버그인가?'부터 시작하는 5단계 근본 원인 분석을 강제한다.
LLM 단독 사용 시 발생하는 문제

LLM의 디버깅 방식은 '에러 메시지를 보고 가장 가능성 높은 수정을 즉시 제안'하는 것이다. 이건 통계적으로 가장 흔한 원인을 먼저 시도하는 것이므로 간단한 버그에는 효과적이지만, 근본 원인이 다른 곳에 있으면 증상 패치를 반복하게 된다. 특히 LLM은 '지금까지 시도한 것들이 왜 실패했는지'의 기록을 유지하지 않기 때문에, 같은 수정을 반복 제안하거나, 이미 기각된 가설을 다시 시도한다. Phase 3의 '기각 기록 보존'은 이 LLM 특유의 기억 없는 디버깅을 방지한다.

이 스킬이 해결하는 실제 문제

증상 패치의 악순환

요청 타임아웃 -> 타임아웃 30초로 증가 -> N+1 쿼리가 원인인데 감춰짐 -> 부하 증가 시 DB 커넥션 고갈. Phase 0의 Symptom vs Root Cause Fix 테이블은 이런 흔한 잘못된 패치와 올바른 수정을 대비시킨다.

3번째 같은 종류의 버그는 설계 문제

같은 모듈에서 비슷한 버그가 3번 발생하면, 그건 코드 버그가 아니라 구조적 문제다. Phase 0의 Decision Tree는 이 신호를 감지하여 dev-architecture 리뷰로 에스컬레이트한다.

비동기 코드의 숨겨진 레이스 컨디션

에이전트가 async/await를 쓰면서 floating promise, 공유 상태 경쟁, deadlock을 만드는 경우가 많다. async-debugging.md는 이 특수한 디버깅 영역을 별도로 다룬다.

Triggers: debug this, why is X failing, flaky test, fix the crash, root cause, error, stack trace

Key Concepts

  • Phase 0: Bug vs Design Problem
  • Phase 1: Investigation (trace-first)
  • Phase 2: Analysis (pattern recognition)
  • Phase 3: Hypothesis (falsifiable claims)
  • Phase 4: Implementation (failing test first)
  • Symptom vs Root Cause Fix

Reference Documents

DocumentDescription
Async Debugging Reference비동기 코드의 Race condition, deadlock, floating promise 디버깅
Debugging Methodologies Reference이분 탐색(git bisect), 구조화된 로깅, 재현 환경 구성 방법론
Blameless Postmortem Template사후 분석(blameless postmortem) 작성 템플릿
Debugging Tool Referencelldb, Chrome DevTools, strace, perf 등 디버깅 도구 가이드

Sections Overview

SectionSummary
Phase 0: Bug vs Design Problem반복되는 같은 류의 버그는 설계 문제다. 아키텍처 리뷰로 에스컬레이트.
Phase 1: Investigation에러 메시지, 스택 트레이스, 로그를 먼저 수집한다. 추측 전에 증거.
Phase 2: Analysis수집한 증거에서 패턴을 찾는다. 변수 하나만 변경, 실패 시 되돌리기.
Phase 3: Hypothesis반증 가능한 가설을 세우고 기각 기록을 보존한다.
Phase 4: Implementation실패하는 테스트를 먼저 작성하고, 수정 후 테스트 통과를 확인한다.

Academic References

PaperYearRelevance
Yesterday, My Program Worked. Today, It Does Not. Why? (Zeller, Delta Debugging)
DOI:10.1145/318774.318946
1999자동화된 RCA의 기초 — 실패를 유발하는 입력 변경을 체계적으로 좁히는 방법론.
A Survey on Software Fault Localization (Wong et al.)
IEEE TSE 42(8)
2016스펙트럼 기반, 돌연변이 기반, 통계적 결함 위치 추정의 포괄적 서베이.

Official Guides

Full Specification

Show full SKILL.md content

Dev-Debugging — Systematic Root Cause Analysis

This skill is the thinking process for fixing bugs. It activates by change surface for errors and diagnoses, and enforces a structured

5-phase methodology for every technical issue — test failures, runtime errors,

build failures, performance regressions, integration bugs.

Boundary: This skill covers how to reason about bugs. For test harness,

reproduction frameworks, and verification tooling, see dev-testing. For

domain-specific context (API errors, hydration issues, query performance),

consult dev-backend or dev-frontend.

> C0/C1 work (small local patches): See dev §0.0 Work Classifier + §0.1 Patch Fast-Path before reading references.

dev-debugging = root cause methodology (the thinking)
dev-testing   = test harness for reproducing/verifying (the tooling)
dev §2        = summary pointer to this skill (the overview)

---

Core Principle

Check if the problem is structural before debugging code.

Complete root cause investigation before proposing any fix.

If Phase 1 is not done, keep investigating.

---

When to Activate

  • Test failures, runtime errors, build failures, performance regressions
  • Integration issues (API, database, third-party), CI pipeline failures
  • Especially: when under time pressure or when "just one quick fix" seems obvious — that's when methodology matters most

---

The Phases

Phase 0: Is This a Bug or a Design Problem?

Before debugging code, ask: "Could this be a structural/design issue rather

than a code bug?" Patching symptoms of architectural debt creates an endless

stream of "bugs" that are really design consequences.

Decision Tree — escalate to architecture review if any apply:

SignalInterpretation
Same class of bug recurring (3rd time fixing similar issue)Design problem — add a constraint at the architecture level
Bug spans multiple modules / crosses 2+ boundariesBoundary/coupling issue — see dev-architecture
Fix would require changing 3+ files simultaneouslyLikely structural — single-responsibility violation
Symptom appears far from cause (error in UI, root in DB layer)Tracing/observability gap — instrument boundaries first

If structural: escalate to architecture review. Do not patch the symptom —

the patch creates the next bug.

Symptom vs Root Cause Fix:

SymptomLikely Patch (wrong)Root Cause Fix (right)
Request timeoutIncrease timeout to 30sAdd circuit breaker + fallback
OOM crashIncrease container memoryFind and fix the memory leak
N+1 query performanceAdd a cache layer in frontFix the query (eager load / join)
Duplicate recordsAdd unique constraint + rescueFix the race condition that creates duplicates
Flaky testAdd retry/skip annotationFix shared mutable state between tests

If none of the above apply — proceed to Phase 1 (it's a code bug, not a

design problem).

---

Phase 1: Root Cause Investigation

Feedback loop gate: For UI, browser, TUI, visual, streaming, or agent-output bugs,

first create a red-capable loop that can fail before the fix: screenshot/assertion,

recorded terminal bytes, Playwright visual check, log fixture, or a manual repro script

with explicit pass/fail evidence. Do not patch from screenshots alone when a repeatable

probe can be built in reasonable time.

Complete these before attempting any fix:

  1. Read the full error — stack trace, line numbers, error code, surrounding

context. Do not skim. The answer is often in the error message itself.

  1. Reproduce consistently — exact steps to trigger the bug. If intermittent,

document frequency, conditions, and environment state. A bug you cannot

reproduce is a bug you cannot verify as fixed.

  1. Check recent changes — run git log --oneline -10 and git diff. Check

new dependencies, config changes, environment variables. Bugs correlate with

recent changes most of the time.

  1. Trace data flow — where does the bad value originate? Trace backward from

the failure point through the call stack until you find the source. Follow the

full causal chain from trigger → boundary → bad state → failure. Removing the

visible symptom is not a fix unless the defect that creates the bad state is gone.

  1. Instrument component boundaries — for multi-layer systems (API → service →

database, CI → build → deploy), log input/output at each boundary BEFORE

proposing fixes.

  1. Trace-first for distributed/async/agent failures (DEFAULT) — capture the

evidence trail before hypothesizing: request IDs, OpenTelemetry spans/logs,

Playwright traces/videos, and exact agent tool transcripts. For order-dependent,

native, concurrency, or intermittent failures that logs cannot explain, use

time-travel/replay debugging (Microsoft TTD on Windows, rr on Linux) — see

references/tool-guides.md.

For EACH component boundary:
  - Log what data enters the component
  - Log what data exits the component
  - Verify environment/config propagation
Run once → analyze evidence → identify failing layer → investigate THAT layer

Work through these steps; skip only if clearly irrelevant to the problem at hand.

Phase 2: Pattern Analysis

  1. Find working examples — similar working code in the same codebase. If it

worked before, use git bisect to find the breaking commit (see

references/tool-guides.md).

  1. Compare systematically — list every difference between working and broken

code. No matter how small. Resist assuming "that can't matter."

  1. Read reference docs completely — official documentation for the library,

API, or framework involved. Don't skim — read the full relevant section.

  1. Check known issues — GitHub Issues, changelogs, migration guides. Someone

may have hit the same bug. Search with the exact error message.

When the bug depends on third-party library/API/framework behavior, current

error workarounds, upstream issues, changelogs, or migration guides, read the

active search skill and follow its source-fetch and evidence-status rules

before treating external material as proof.

Phase 3: Hypothesis and Testing

  1. List competing hypotheses first — write at least three plausible root-cause

hypotheses before investigating any single one. Include the evidence that would

support or reject each hypothesis. If fewer than three are plausible, state why.

  1. State the leading hypothesis explicitly — "X is the root cause because

evidence Y shows Z." If you can't articulate it clearly, you don't understand

it yet.

  1. Design a test to disprove — falsification is stronger than confirmation.

What would you expect to see if your hypothesis is wrong?

  1. Test one variable — smallest possible change, one variable at a time.

Never fix multiple things at once.

  1. If it fails → move to another listed hypothesis. Revert the failed change and

start from clean state. Stacking fixes obscures the root cause.

  1. Keep the rejection record — preserve rejected hypotheses and the evidence

that rejected them. The final report must include them, not just the winning cause.

  1. Admit ignorance — "I don't understand X" is a valid finding. Research

further rather than guessing. Record the open question explicitly.

Phase 4: Implementation

  1. Write a failing test first — the test reproduces the bug. It should fail

before the fix. Use dev-testing for TDD patterns and test harness setup.

  1. Make the minimal fix — address the root cause, not symptoms. One logical

change only.

  1. Verify: the test passes, no regressions (run the full test suite:

npm test / pytest / equivalent).

  1. Check for similar patterns — does the same bug class exist elsewhere in

the codebase? Search for it. Fix all instances, not just the one you found.

  1. Document — final report and commit message explain root cause AND fix,

including rejected hypotheses and rejection evidence. Not "fixed bug"

but "fix: race condition in session middleware caused by missing await on

Redis write."

---

Red Flags — Return to Phase 1

If you catch yourself doing any of these, pause — root cause investigation

was likely skipped.

Red FlagWhy It Fails
"Quick fix for now, investigate later"First fix sets the pattern. Tech debt compounds. You won't investigate later.
"Just try changing X and see"Guessing guarantees rework. You'll be back here within the hour.
"Add multiple changes, run tests"Can't isolate cause if multiple variables changed. Revert, change ONE thing.
"It's probably X, let me fix that""Probably" without evidence = Phase 1 not done. Go back and trace it.
"I don't fully understand but this might work"Seeing symptoms ≠ understanding root cause. Your "fix" hides the real bug.
"One more fix attempt" (after repeated failures)After repeated failures, pause and reassess architecture/assumptions. See escalation below.
"It works on my machine"Reproduce in the SAME environment as the failure. Local success proves nothing.
"Let me add a try/catch around it"Suppressing errors is not fixing them. Find WHY it throws.

Repeated Failure Rule: After repeated failed fix attempts, pause entirely.

Each fix revealing a new problem in a different place is a sign of

architectural issues, not simple bugs. Discuss with the user before

attempting more fixes.

---

Slop Debugging Patterns

Slop debugging is spray-and-pray: guess, patch, pray, repeat.

Instead of…Use…
Proposing fixes before investigationComplete Phase 1 checklist first
"Might be X" without evidence"Evidence shows X because [log/trace/diff]"
Multiple simultaneous changesOne change at a time, revert between attempts
Skimming stack tracesRead every line of stack trace, note line numbers
Silent catch blocks that suppress errorsLog with context ([module] error.message), re-throw or handle
Modifying failing tests to passFix the code, not the test — a failing test is evidence
Claiming "fixed" without running verificationRun full test suite, show green output, verify the original symptom
Copy-pasting a fix without understandingUnderstand why the fix works, then adapt to your codebase
Suppressive try/catch (catch-and-ignore, catch-and-return-null)Fix at the source. Boundary catch with logging/re-throw is fine — see dev-architecture §4.
Guessing at types, nulls, or undefined valuesAdd diagnostic logging, inspect actual runtime values
"It works now" after changing something unrelatedCorrelation ≠ causation — revert the change and test again
Letting an AI auto-repair loop (test healer, auto-fix) mask the defectAgentic repair aids run only AFTER root cause is understood; keep the failing repro as evidence

---

Concrete Debugging Scenarios

Scenario A: API Returns 500

Root cause pattern: Missing input validation lets undefined values propagate into business logic. Instrument controller/service/repository boundaries to find where the bad value enters. Compare with a working endpoint that validates input with a schema. Fix: add schema validation at the entry point, write a test that sends invalid input and expects 400.

Worked example:

curl -i -X POST http://localhost:3000/api/orders \
  -H 'content-type: application/json' \
  -d '{"sku":"book-1"}'

Observed failure:

HTTP/1.1 500 Internal Server Error
TypeError: Cannot read properties of undefined (reading 'toFixed')
    at calculateTotal (src/orders/service.ts:42:21)
    at createOrder (src/orders/controller.ts:27:18)

Competing hypotheses before narrowing:

  1. Request validation allows missing quantity.
  2. Controller mapping drops quantity before service call.
  3. Repository returns an order row with quantity = null.

Boundary instrumentation:

DEBUG=orders:* npm run dev
curl -s -X POST http://localhost:3000/api/orders \
  -H 'content-type: application/json' \
  -d '{"sku":"book-1"}' | jq .

Sample log output:

orders:controller input {"sku":"book-1"}
orders:controller mapped {"sku":"book-1"}
orders:service input {"sku":"book-1"}
orders:repository skipped insert due service error

Rejections: repository-null is rejected because the repository is never reached.

Controller-drop is rejected because controller input already lacks quantity.

Root cause: entry validation accepts a payload missing a required domain field.

Fix at the entry boundary: schema rejects missing quantity; regression test posts

the same payload and expects HTTP 400 with a stable error.code.

Scenario B: React Hydration Mismatch

Root cause pattern: Server renders a value (e.g., date, locale string) that differs from client-side rendering due to environment differences (UTC vs. local timezone). Compare with components that defer environment-dependent rendering to useEffect. Fix: move environment-dependent formatting into a client component.

Scenario C: N+1 Query Performance

Root cause pattern: List endpoint lazy-loads related records per item (1 query + N queries). Enable query logging to count queries, then compare with an endpoint that uses eager loading. Fix: add include/joinedload, write a test asserting bounded query count.

Scenario D: Flaky Test (Intermittent Failure)

Root cause pattern: Test passes in isolation but fails in suite due to shared mutable state (database rows, global variables, uncleared mocks). Compare with stable tests that use transaction rollback in beforeEach/afterEach. Fix: add proper test isolation, then search for other tests missing cleanup.

---

When to Escalate vs When to Keep Digging

Keep Digging When:

  • You have untested hypotheses from Phase 2
  • You haven't read the full error message or stack trace
  • You haven't checked recent changes (git log, git diff)
  • You haven't found working comparison code yet
  • The bug is in YOUR code (not a third-party library)
  • You still have untested approaches to try

Escalate When:

  • Repeated fix attempts failed — likely architectural; needs human judgment
  • Undocumented library behavior — file an issue upstream, work around it
  • Environment-specific — requires access you don't have (prod DB, cloud IAM)
  • Security-sensitive — don't debug auth/crypto/payment alone; flag for human review
  • Multi-team dependency — bug is in another team's service or API contract
  • Stalled: if investigation stalls, reassess approach

How to Escalate Well

Don't just say "I'm stuck." Provide: symptom (exact error), **reproduction

steps, evidence gathered (logs, traces, bisect results), hypotheses

tested (including rejected hypotheses and rejection evidence), remaining hypotheses** (untested),

and a recommendation for next steps.

---

Post-Mortem Discipline

After resolving any bug that:

  • Was user/customer-impacting
  • Took >1 hour to diagnose
  • Involved 3+ failed fix attempts (per postmortem-template.md)
  • Revealed a systemic issue (same bug class exists elsewhere)

Fill out references/postmortem-template.md and include it in the PR or commit.

The goal is learning, not blame. Every postmortem must produce at least one

action item that prevents the same class of bug from recurring.

---

Modular References

FileWhen to ReadWhat It Covers
references/methodologies.mdWhen choosing a debugging approachFive Whys, bisection, differential diagnosis, subtraction, rubber duck, systematic logging
references/async-debugging.mdWhen debugging concurrency issuesRace conditions, deadlocks, event loop blocking, promise/callback issues
references/tool-guides.mdWhen you need stack-specific debugger commandsNode.js inspector, Python pdb/debugpy, Chrome DevTools, git bisect, database EXPLAIN
references/postmortem-template.mdAfter resolving a significant incidentBlameless postmortem template with filled example

---

Integration with Other Skills

SkillRelationship
dev §2Summary of this methodology. This skill is the full version.
dev-testingPhase 4 "write failing test first" → use dev-testing for test patterns and harness. dev-testing provides the tooling; this skill provides the thinking.
dev-backendServer-side debugging context: API errors, database issues, middleware chains.
dev-frontendClient-side debugging context: hydration, rendering, DevTools, layout shifts.
dev-code-reviewerCode review catches bugs before they ship — prevention beats debugging.

---

Security-Sensitive Bugs

For security-sensitive bugs (auth bypass, data leak, injection), follow the incident response in dev-security/SKILL.md before applying a fix.

---

Compact Summary

When context is limited, preserve: (1) Phase 0 — is it a bug or a design problem?,

(2) Core principle — no fixes without root cause,

(3) phases 0-4 — architecture check → investigate → analyze → hypothesize → implement,

(4) Repeated Failure Rule — after repeated failures, reassess, (5) one variable at a time,

(6) evidence over intuition, (7) failing test first.