| name | aidlc-systematic-debugging |
| description | 버그 신고, 테스트 실패, 예상 밖 동작, 에러 발생, 수정 시도 실패 등 코드 변경 전 진단이 필요한 모든 증상에 사용.
Use when a bug is reported, a test is failing, behavior is unexpected, an error is thrown, a fix attempt is not working, or any symptom requires diagnosis before a code change is made.
|
| metadata | {"version":"0.2.0","author":"Jay","category":"ai-dlc-workflow","invoke_mode":"user-invocable","return_behavior":"stop-no-gate","skill_nature":"compensation","lifecycle":"active","model_dependency":"모델이 원인 미확정 상태로 수정을 시도함"} |
aidlc-systematic-debugging
철의 법칙
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
수정 코드를 작성하기 전에 반드시 근본 원인을 확인해야 한다.
"아마도 이 문제일 것이다"는 근거가 될 수 없다. 재현 가능한 증거가 필요하다.
Trigger
다음 상황 중 하나라도 해당하면 이 스킬을 실행한다:
- 버그 신고 또는 예상치 못한 동작 발생
- 테스트 실패 (CI 포함)
- 에러 메시지 또는 예외 발생
- "왜 이게 안 되지?" 또는 "이상하게 동작한다"는 질문
- 수정 후에도 같은 증상이 지속될 때
- 이전 수정이 다른 곳을 망가뜨렸을 때 (회귀)
Purpose
증상을 빠르게 수정하는 것이 아니라, 올바른 원인을 찾아 올바른 위치에 올바른 수정을 적용하는 것.
합리화 방지
아래 생각이 들면 즉시 멈추고 4단계 프로세스를 따른다:
| 합리화 패턴 | 올바른 행동 |
|---|
| "빠르게 고치면 될 것 같아" | 1단계 Root Cause 조사부터 |
| "이전에 비슷한 버그 봤어" | 현재 케이스를 독립적으로 재현 |
| "에러 메시지가 명확해" | 상위 호출 스택까지 추적 |
| "테스트만 고치면 되겠다" | 테스트가 틀린 이유를 먼저 증명 |
| "시도해보고 안 되면 다른 거" | 단일 가설 → 단일 수정 → 검증 |
4단계 디버깅 프로세스
1단계: Root Cause 조사
절대 수정 코드를 작성하지 말 것. 먼저 다음을 수행한다:
-
에러 메시지 정독
- 에러 유형, 메시지, 스택 트레이스 전체를 읽는다
- 에러가 발생한 파일, 줄 번호, 함수명을 기록한다
- 단순히 마지막 줄만 보지 않는다 — 상위 호출 스택도 확인한다
-
재현
- 에러를 직접 재현한다 (가능하면 최소 재현 케이스로 축소)
- 재현 불가능하면 수정 불가 — 재현 방법 확보를 우선한다
- 재현 명령어 또는 절차를 기록한다
-
최근 변경사항 확인
git log --oneline -10
git diff HEAD~1
git log --oneline --follow -- <파일경로>
- 증상이 처음 발생한 커밋을 특정할 수 있다면
git bisect 활용
-
진단 계측 추가 (필요시)
- 재현은 되지만 원인이 불명확할 때만 추가
print / log / debug 구문으로 실제 값 확인
- 계측 코드는 수정 완료 후 반드시 제거
2단계: 패턴 분석
DO NOT proceed to 3단계 until a difference table between success/failure cases is documented. 차이점 없이 가설을 세우면 추측 수정이 된다.
-
작동하는 케이스 찾기
- 같은 코드 경로에서 성공하는 케이스를 찾는다
- "A는 되는데 B는 안 된다"는 패턴이 나오면 A와 B의 차이를 비교한다
-
차이점 표로 정리
| 항목 | 성공 케이스 | 실패 케이스 |
|--------------|-----------|-----------|
| 입력값 | | |
| 환경 | | |
| 의존성 버전 | | |
| 실행 순서 | | |
-
공통점 제거법
- 둘 다 같은 조건이면 그 조건이 원인일 수 없다
- 차이점 목록을 줄여가며 범위를 좁힌다
3단계: 가설 및 테스트
DO NOT proceed to 4단계 until the hypothesis is verified or falsified. 가설이 틀리면 2단계로 돌아간다.
-
단일 가설 수립
- 한 번에 하나의 가설만 세운다
- 가설은 구체적이어야 한다: "X 함수의 Y 파라미터가 None일 때 Z 경로로 분기되어 오류 발생"
- 막연한 가설 금지: "어디선가 값이 잘못 전달되는 것 같다"
-
최소 변경으로 가설 검증
- 가설을 반증하거나 증명하는 최소 변경 또는 임시 계측을 적용한다
- 여러 변경을 동시에 가하지 않는다
-
검증
- 재현 케이스를 다시 실행하여 가설이 맞는지 확인한다
- 가설이 틀렸으면 계측 코드를 되돌리고 2단계로 돌아간다
- 가설이 맞으면 4단계로 진행한다
4단계: 구현
-
실패 테스트 작성 (TDD RED)
- 버그를 재현하는 테스트를 먼저 작성한다
- 이 테스트는 현재 코드에서 실패해야 한다
- 테스트가 실패하지 않으면 테스트 자체가 잘못된 것
-
단일 수정 적용
- 근본 원인을 해결하는 최소한의 코드 변경만 한다
- 이 기회에 "다른 것도 고쳐야지"를 하지 않는다 (별도 브랜치에서 처리)
-
검증 (TDD GREEN)
- 작성한 테스트가 통과하는지 확인한다
- 기존 테스트가 모두 통과하는지 확인한다 (회귀 방지)
-
3회 이상 수정 실패 시 → 멈추고 실패 이력 분석
즉시 수정 시도를 중단한다. 먼저 왜 3번 실패했는지 분석한다:
실패 이력 요약
공통 패턴 식별
- 3번의 가설이 모두 같은 영역을 겨냥했는가? → 다른 영역 탐색 필요
- 수정이 매번 다른 테스트를 깨뜨렸는가? → 설계 결합도 문제
- 근본 원인을 찾지 못한 채 증상만 수정했는가? → 1단계 재현으로 복귀
분석 후 선택지 제시
- A) 더 상위 레벨에서 설계를 재검토한다
- B)
aidlc-receiving-code-review 스킬로 피드백을 구한다
- C) 문제를 최소 재현 케이스로 격리하여 다시 1단계부터 시작한다
Examples
Example 1: pytest 테스트 실패
증상: test_user_creation 테스트가 갑자기 실패함
1단계 조사:
FAILED tests/test_user.py::test_user_creation
AssertionError: assert 422 == 201
스택 트레이스에서 POST /users 엔드포인트 → validate_email() 호출 실패 확인
최근 변경:
git log --oneline -5
a1b2c3d 커밋에서 이메일 검증 정규식을 변경한 것을 발견.
2단계 패턴 분석:
| 이메일 | 결과 |
|--------------|--------|
| user@a.com | 성공 |
| user@a.io | 실패 |
→ 2글자 TLD는 통과, 특정 TLD가 새 정규식에서 거부됨
3단계 가설: 새 정규식이 .io TLD를 허용하지 않음
→ 정규식 직접 테스트로 확인 → 가설 맞음
4단계 구현:
def test_validate_email_with_io_tld():
assert validate_email("user@example.io") is True
EMAIL_PATTERN = r'^[\w.+-]+@[\w-]+\.[a-z]{2,}$'
Example 2: 간헐적 타임아웃
증상: API가 간헐적으로 504 반환
1단계: 에러 로그 → upstream timed out 확인. 재현: locust로 50 RPS
2단계: DB 쿼리 있는 엔드포인트에서만 발생 (10 RPS 정상, 50 RPS 실패)
3단계: DB 연결 풀 고갈 가설 → SHOW PROCESSLIST로 풀 상한(10) 도달 확인
4단계: RED(풀 고갈 시뮬레이션 테스트) → GREEN(POOL_SIZE=20)
Troubleshooting
재현이 불가능할 때
증상: 직접 실행하면 에러가 나지 않는데 CI 또는 프로덕션에서만 발생
처리 방법:
- 환경 차이를 목록화한다: OS, Python/Node 버전, 환경변수, 데이터 상태
- CI 환경을 로컬에서 재현한다 (
docker run 또는 .env.ci 파일 활용)
- 로그 레벨을 높여서 다음 발생 시 더 많은 정보를 수집한다
- 재현 없이는 수정하지 않는다 — "아마도" 수정은 다른 버그를 유발한다
수정 후 다른 테스트가 실패할 때
증상: 버그를 고쳤는데 관련 없어 보이는 테스트 5개가 새로 실패
처리 방법:
- 수정을 즉시 되돌린다 (
git stash)
- 실패한 테스트 5개를 수정 없이 실행한다 → 통과하는지 확인
- 통과한다면 내 수정이 공유 상태(DB, 파일, 전역 변수)를 오염시킨 것
- 수정의 사이드 이펙트 범위를 다시 분석하고 더 좁은 수정을 시도한다
- 격리가 필요하다면 테스트 픽스처 또는 mock을 추가한다
Return to Orchestrator
conventions 표준 형식. 반환 필드:
- 근본 원인: [1줄 요약]
- 수정 내용: [1줄 요약]
- 테스트: [회귀 테스트명] 추가됨
- 전체 테스트: [N]개 통과, 0 실패
audit emit (호출 추적)
skill 호출 시 devflow-docs/audit.md에 다음 prefix 두 개를 emit한다. memory-sync 패턴과 동일한 한 줄 형식.
Prefix 명세
| Prefix | 시점 | required fields |
|---|
systematic-debugging-invoked | skill 진입 (1단계 시작 직전) | trigger, symptom |
systematic-debugging-completed | 4단계 완료 (root_cause 확정 + fix 검증) | root_cause, fix_test |
형식
devflow-docs/audit.md에 한 줄 append (BL-092 memory-sync와 동일):
[<ISO timestamp>] systematic-debugging-invoked | trigger=<source> | symptom=<short>
[<ISO timestamp>] systematic-debugging-completed | root_cause=<one-line> | fix_test=<test-name>
emit 절차 (인라인)
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo "[${TS}] systematic-debugging-invoked | trigger=<source> | symptom=<short>" >> devflow-docs/audit.md
또는 Edit tool 호출:
- Read
devflow-docs/audit.md
- Edit append (마지막 줄 뒤에 신규 줄 추가)
- 절대 Write tool로 전체 재작성 금지 (devflow-audit utility critical rule 준수)
호출 경로별 emit
세 경로 모두 동일 emit (skill 본인 책임, caller 별도 emit 안 함):
- Orchestrator 경로: construction-orchestrator K-gate → 진입 직전
invoked + 4단계 완료 후 completed
- User-invocable 경로:
/aidlc:aidlc-systematic-debugging 직접 호출 → 동일
- Debugging chain 경로: 다른 skill이 인라인 호출 → 동일
중단/abort 케이스: 4단계 미완료 시 completed emit 안 함. invoked만 audit에 남고 STORE도 호출 안 함 (조건 미충족 — 아래 §STORE 호출 참조).
Why
T2 진단(2026-04-28)에서 systematic-debugging 호출 자체가 audit에 흔적 안 남는 사용 경험 결함 발견 (다른 skill — memory-sync, finishing 등 — 은 emit하는데 본 skill만 누락). BL-098 (#191)로 일관성 fix.
STORE 호출 (완료 시 guaranteed)
root_cause 확정 + 수정 검증 완료 상태에서 무조건 devflow-solutions STORE 호출.
호출 조건
다음 모두 만족 시에만 STORE 호출:
- root_cause가 명확히 확정됨 (가설이 아닌 확증)
- fix가 적용되고 회귀 테스트가 PASS됨
- debugging이 inconclusive / aborted 상태 아님
위 조건 미충족 시 STORE 호출하지 않음.
호출 형식
devflow-solutions STORE(
root_cause="[확정된 근본 원인 한 줄]",
fix_summary="[적용된 수정 내용 한 줄]",
regression_test="[추가/수정된 회귀 테스트명 또는 경로]",
test_result="[수정 후 전체 테스트 결과, 예: '139 passed, 0 failed']",
error_message="[원본 에러 메시지 — build-and-test 경로 또는 caller가 전달]"
)
Return 필드 (caller 소비용)
STORE Return값을 systematic-debugging 자체 Return에 포함:
solution_verdict: "SAVE" | "DUPLICATE" | "REJECT"
solution_saved_path: string | null
solution_similar_to: string | null
solution_reject_reason: string | null
caller (construction-orchestrator, user-invocable, chain)는 이 값을 audit에 로그만 남김 (STORE 재호출 금지).
호출 경로 (3가지 모두 동일)
- Orchestrator 경로: construction-orchestrator K-gate → systematic-debugging 호출 → 내부 STORE
- User-invocable 경로:
/aidlc:aidlc-systematic-debugging 직접 호출 → 내부 STORE
- Debugging chain 경로: 다른 skill이 인라인 호출 → 내부 STORE
세 경로 모두 guaranteed trigger. writer ownership = systematic-debugging 단독.
Noise 관리 (Sprint 1 정책)
- Phase 1 목표: Solution layer가 비어있지 않음. 깨끗함은 Phase 2+.
- 중복 판정은
error_signature 기반 duplicate check에 위임 (utility 책임).
- 유사 문제 반복 저장 허용. promotion_filter는 Sprint 2+ 주제.
- 첫 2주 noise 관측 후 실제 데이터로 필터 기준 수립.