문서 목차
이 페이지에서목차

Bug Diagnosis — 공통 버그 재현·회귀 계약

`run`의 버그 모드와 `bugfix` 연결 명령이 사용하는 단일 원본입니다.

run의 버그 모드와 bugfix 연결 명령이 사용하는 단일 원본입니다. 구 bugfix Step 0 / 3.5 / 4.2 / 4.5 / 6의 계약을 이곳으로 옮겼습니다. 구현·PR·머지 사이클은 run, 점유/차단은 ZenHub 규칙, 루프 표기는 orchestration-graph를 따릅니다.

1. 적용과 영향 범위#

  • 버그 이슈 또는 --type fix에서 구현 전에 수행합니다. 문서/서버 등 기기 재현 대상이 아닌 변경은 실제 재현 수단(CLI·서버 테스트 등)을 사용하고 플랫폼 검사는 N/A 근거를 남깁니다.
  • 호출자/피호출자 조사 상한은 심볼 검색 총 40회입니다. 초과분은 blastRadiusDeferred에 파일·심볼별로 남깁니다. 잘린 조사 결과를 영향 없음으로 해석하지 않습니다.
  • 영향 파일 ≤5·레이어 ≤1: LOW, 그 외 파일 ≤15 또는 레이어 ≤2: MEDIUM, 나머지 HIGH. 미조회 심볼이 있으면 최소 MEDIUM입니다. MEDIUM 이상은 범위와 위험을 계획에 포함하고, 승인된 범위를 넘으면 호출자의 범위/드리프트 계약에 따라 확인 후 진행합니다.

2. 기기 선택과 준비#

  1. Flutter 대상은 도구 존재 확인 후 flutter devices --machine으로 후보를 조회합니다. 조회 실패(undetermined)와 빈 목록(none)을 구분합니다.
  2. 실행 가능한 실기기(데스크톱 포함) → 시뮬레이터/에뮬레이터 순서로 선택합니다. 이슈 플랫폼을 우선하되 단서가 불명확하다고 후보를 조용히 모두 버리지 않습니다.
  3. --device로 지정한 대상이 없으면 다른 대상으로 바꾸지 않고 중단합니다.
  4. 웹은 이 네이티브 VM 계측 경로의 대상이 아닙니다. 웹 검증은 브라우저 도구를 사용합니다.
  5. 기기 부재/--skip-device는 run의 무인·승인 표를 그대로 따릅니다. 승인된 생략은 status: waived, waivedGates: runtime-repro, 이유/probe와 원인 추정을 PR에 남깁니다. --skip-tests는 기기 진단 생략을 뜻하지 않습니다.
  6. 앱의 VM Service와 DTD URI를 구분해 연결합니다. 부팅/연결 실패는 재현 안 됨이 아닙니다. 조작 도구는 mcp-tool-selection을 따릅니다. 내가 기동한 프로세스/터미널 핸들을 기록해 종료할 때도 같은 핸들만 사용합니다.

3. 진단 루프 (L-bf3.5)#

이슈의 재현 절차 → 에러/스택/상태 관찰 → 필요한 임시 계측 → 반영 → 재현/관찰을 반복합니다. 남은 불확실성은 {repro, failing-point, root-cause} 집합으로 추적합니다.

  • 계측은 관측 전용입니다. 앱의 조건·분기·상태를 바꾸거나 테스트에 계측을 심지 않습니다.
  • 모든 임시 줄/블록과 로그 문자열에 BUGFIX-DEBUG(#N)을 넣고 instrumentation에 블록 시작 위치를 기록합니다. 다음 단계가 그 목록을 전량 회수합니다.
  • 일반 메서드 로그는 hot reload, 필드/클로저 캡처/listen·타이머 등록/main·전역·상태 shape 변경은 hot restart합니다. 계측 모양이 불명확하면 restart합니다. 증상 문구는 보조 신호입니다.
  • 로그가 안 찍히면 미반영 여부를 먼저 확인합니다. 새 계측의 로그는 다음 관찰에서 읽습니다.
  • 원인 확정에는 file, line, 실제 로그 evidence가 필요합니다.
  • 가상 기기의 카메라·푸시·결제·생체·권한·딥링크·백그라운드·블루투스·위치 한계를 기록합니다. 그 환경에서 미재현됐다는 사실을 버그 없음으로 승격하지 않습니다.
inv: 관측 전용 · 태그와 계측 대장 필수
prog: unknowns.size 강한 감소; no-prog면 같은 계측 반복 대신 다른 관측 위치/리프레임
term: 재현 판정·실패 지점·근거 있는 원인 특정
budget: 3 iterations (구 bugfix L-bf3.5 예산 유지)
exhaust: status=inconclusive로 구현 단계에 반환; 원인 확정 주장 금지
resume: .claude/docs/bugfix/{N}/runtime/ 산출물 + 계측 잔여 재조회, 예산 초기화 금지
log: 라운드·unknown 전후·계측 위치·로그/스크린샷 경로

진단 반환: status(confirmed|inconclusive|waived), deviceTier, device, probe, reproduced(true|false|null), rootCause, artifacts, instrumentation, limits, rounds. 진단 산출물은 소스 커밋에 포함하지 않고 PR에는 경로와 요약을 남깁니다. 커밋되는 PR 작업내역 HTML(pr-work-artifact)에도 원본 로그·스크린샷을 옮겨 싣지 않고 요약과 로컬 경로만 적습니다 — 저장소 이력은 영구이고, 기기 로그에는 토큰·개인 데이터가 섞이기 쉽습니다(rules/artifact-publishing.md §1).

구독 좀비 계측 레시피#

  • 구독별 ID, 등록 시 overwriting, emit 시 등록 맵과 해당 구독의 identical 여부를 함께 기록합니다.
  • 상태의 onChange에서 범위 밖 항목의 스택을 관찰하고 super.onChange를 호출합니다. 이름이 충돌하면 계측용 bloc_signals.Change를 prefix로 구분합니다.
  • 필드/import/override/listen 캡처까지 BUGFIX-DEBUG(#N) begin/end로 감싸 블록 전체를 회수합니다.
  • 이 계측은 restart가 필요합니다. restart가 누적 좀비도 지우므로 재현 절차가 다시 만드는지 확인합니다.
  • 세대 가드가 있으면 registered=false 부재만으로 정상이라 하지 않습니다. listen 수 - cancel 수 - 현재 등록 구독 수 원장과 상태 범위 이탈을 함께 봅니다.
  • 간헐 문제는 한 번 미재현으로 판정하지 않습니다. 동일 경합을 반복해 양성 지표 0건을 확인하고, 회귀 테스트가 수정 전 코드에서 실패하는지 확인합니다.
  • 수정 정본은 swr-pattern의 키별 세대 카운터입니다. restartable이나 덮기 직전 취소만으로 낡은 호출의 재등록을 막았다고 가정하지 않습니다.

4. 수정 후 검증과 계측 회수 (구 Step 4.2)#

  1. 같은 대상에서 hot restart 후 같은 재현 절차를 실행합니다.
  2. true(재현 잔존)이면 진단→수정으로 1회만 돌아갑니다. 두 번째도 재현되면 blockIssue(..., runtime_fix_unverified)로 보드 반영·점유 해제 후 중단합니다.
  3. null(판정 불가)은 fixVerified: unverified, false만 verified입니다. 진단의 inconclusive를 수정 검증의 통과로 읽지 않습니다.
  4. 대장의 계측을 전량 회수합니다. 영구 로그로 승격할 때는 프로젝트 로깅 규칙에 맞춰 다시 쓰고 기록합니다.
  5. 추적/미추적 소스와 커밋에서 BUGFIX-DEBUG 잔여를 검색합니다. 진단 산출물 폴더만 제외합니다. 검색 오류를 잔여 0건으로 읽지 않습니다. 잔여 0건은 생략할 수 없는 pre-push 조건입니다.
  6. 회수 후 다시 restart·재현합니다. 재현되거나 판정 불가면 통과시키지 않습니다.
  7. 기록한 자기 프로세스를 종료합니다. 오류/중단에서도 임시 계측과 프로세스 정리 결과를 남깁니다.

fixVerified=verified 또는 승인 기록이 있는 status=waived만 다음 게이트로 이동합니다. 미검증 결과를 검증 완료로 표시하지 않습니다.

5. 기존 테스트 기준선과 회귀 (L-bf4.5 / L-bf6)#

프로젝트의 실제 테스트 명령을 확인합니다. melos가 없으면 제공된 대체 명령을 사용하고, 도구/테스트가 없다는 사실을 0개 통과로 바꾸지 않습니다.

  • 변경 전 기준선을 확보하고, 새 회귀 테스트 추가 전 기존 테스트 결과도 비교합니다. {passed, failed, skipped, total}과 명령/종료 코드를 기록합니다.
  • 요약 해석 실패·수집 0건은 unverified입니다. 테스트가 원래 없는 범위는 N/A 근거를 적습니다.
  • skip 신규 추가·기존 테스트 삭제·통과 수 감소로 실패를 숨기지 않습니다. 수정된 테스트의 동등한 검증 근거를 남깁니다.
  • 기준선 복구는 2 iterations, 실패 수가 줄지 않으면 같은 수정을 반복하지 않습니다. 소진 시 baseline_repair_exhausted로 보드 반영·중단하며 사후 --skip-tests로 우회하지 않습니다.
  • 회귀 테스트 작성 후 수정은 3 iterations, 실패 수가 감소해야 합니다. 기존 통과 수를 유지하고 회귀 테스트의 수정 전 실패/수정 후 통과를 확인합니다. 재시도 상태는 내구 기록에서 이어갑니다.
  • 최초 승인된 --skip-tests는 기준선/회귀 검사를 함께 생략한 것으로 PR에 기록하며, 기준선 없음은 회귀 없음이 아닙니다. CI·리뷰·머지 게이트는 run이 계속 소유합니다.

L-bf4.5: inv=테스트 약화 금지, prog=failed 감소, term=실측 가능한 기존 테스트 통과, budget=2, exhaust=baseline_repair_exhausted, resume=실측/내구 예산 재조회, log=전후 개수·수정 근거. L-bf6: inv=동일 불변식, prog=실패 집합 감소, term=회귀 포함 통과, budget=3, exhaust=Stall Budget, resume=기록된 실측/예산, log=기존/신규 결과와 생략 사유. run의 재작업이 이 예산을 새로 초기화하지 않습니다.

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기