runtime-evidence-debugger
Runtime Evidence Debugger
When to Use
- 코드 읽기만으로 원인 추측이 어려울 때
- 이전 수정 시도가 런타임 데이터 없이 실패했을 때
- 비동기·이벤트·타이밍 버그일 때
서버 전제조건
POST http://127.0.0.1:7827 서버가 실행 중이어야 한다.
body JSON의 logFile 절대경로에 NDJSON 한 줄 append + CORS 허용.
서버 구현 방식(Docker 등)은 무관하며, skill 내에서 서버를 시작하지 않는다.
서버 실행 방법은 이 스킬의 server/README.md 참조.
브라우저가 connect-src CSP 때문에 localhost/127.0.0.1로 직접 fetch하지 못하는 앱이라면,
브라우저에서 디버그 서버를 직접 호출하지 말고 same-origin 앱 API 프록시를 둔다.
- 예: Next.js
pages/api/agentRuntimeDebug.ts - 브라우저 계측은
/api/agentRuntimeDebug만 호출 - API route가 서버에서
http://127.0.0.1:7827로 프록시 - CSP 에러가 보이면 포트/호스트를 계속 바꿔보지 말고 이 모드로 즉시 전환
Step 0: 서버 확인 (실패 시 즉시 중단)
curl -s -o /dev/null -w "%{http_code}" \
-X POST http://127.0.0.1:7827 \
-H 'Content-Type: application/json' \
-d '{}' \
--max-time 2
200이 아니면 사용자에게 서버 미실행 안내 후 즉시 중단.
세션 상태 확정 (이후 모든 단계에서 고정):
- SESSION_ID:
Date.now().toString(36).slice(-6)(예:a3f9c1) - LOG_FILE:
{projectRoot}/.cursor/debug-{SESSION_ID}.log
Step 1: 가설 수립
코드를 먼저 읽는다. 3–5개 가설, 각각 hypothesisId 부여 (A, B, C…).
단 한 번의 재현으로 모든 가설을 동시에 검증할 수 있도록 로그 배치 설계.
Step 2: 계측 삽입
로그 개수: 최소 1개 필수 · 최대 10개 · 일반 2–6개
각 로그는 반드시 하나 이상의 hypothesisId에 매핑.
배치 우선순위:
- 의심 함수 진입 (파라미터 포함)
- 의심 함수 종료 (반환값 포함)
- 핵심 연산 전후 값
- 분기 실행 경로
- 예상치 못한 이벤트 핸들러
- 상태 변경 전후
모든 로그를 #region agent log / #endregion으로 감싼다.
JS/TS — 브라우저·Node.js (fetch):
// #region agent log
fetch('http://127.0.0.1:7827',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({logFile:'LOG_FILE',sessionId:'SESSION_ID',runId:'debug',hypothesisId:'A',location:'file.ts:LINE',message:'설명',data:{key:val,stack:new Error().stack?.split('\n').slice(1,5)},timestamp:Date.now()})}).catch(()=>{});
// #endregion
JS/TS — 브라우저가 CSP로 localhost 호출을 막는 경우 (권장 프록시 모드):
// #region agent log
fetch('/api/agentRuntimeDebug',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({sessionId:'SESSION_ID',runId:'debug',hypothesisId:'A',location:'file.ts:LINE',message:'설명',data:{key:val,stack:new Error().stack?.split('\n').slice(1,5)},timestamp:Date.now()})}).catch(()=>{});
// #endregion
Next.js Pages Router 프록시 예시:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ success: false })
}
const body = req.body ?? {}
const sessionId = String(body.sessionId ?? '')
if (!sessionId) {
return res.status(400).json({ success: false, message: 'sessionId is required' })
}
const proxyResponse = await fetch('http://127.0.0.1:7827', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...body,
logFile: `${process.cwd()}/.cursor/debug-${sessionId}.log`,
}),
})
if (!proxyResponse.ok) {
return res.status(502).json({ success: false, message: 'debug proxy failed' })
}
return res.status(200).json({ success: true })
}
Transport 선택 규칙:
- 브라우저 외부 origin 호출이 가능한 환경이면 direct fetch 사용
- 브라우저 콘솔에
Content Security Policy또는connect-src위반이 보이면 same-origin 프록시 사용 - Node/server-side 계측은 계속 디버그 서버 직접 호출 가능
Python·Go 등 서버사이드 (직접 파일 append, 서버 불필요):
# #region agent log
import json,time,traceback
with open('LOG_FILE','a') as f: f.write(json.dumps({'logFile':'LOG_FILE','sessionId':'SESSION_ID','runId':'debug','hypothesisId':'A','location':'file.py:LINE','message':'설명','data':{'key':val,'stack':traceback.format_stack()[-3:]},'timestamp':int(time.time()*1000)})+'\n')
# #endregion
페이로드 필수 필드:
| 필드 | 값 |
|---|---|
logFile |
LOG_FILE 절대경로. 단, same-origin 프록시가 서버에서 주입하면 브라우저 payload에서는 생략 가능 |
sessionId |
SESSION_ID |
runId |
"debug" (초기) / "post-fix" (검증) |
hypothesisId |
"A" ~ "E" |
location |
"파일명:줄번호" |
stack |
콜 스택 슬라이스 |
timestamp |
ms |
Step 3: 로그 파일 삭제 → 재현 요청
delete_file도구로 LOG_FILE 삭제 — shell rm/touch 금지- 다른 세션의 로그 파일은 건드리지 않는다
- 응답 마지막에
<reproduction_steps>블록 필수:
<reproduction_steps>
1. [인터페이스 무관한 재현 지침]
...
N. Press Proceed/Mark as fixed when done.
</reproduction_steps>
규칙: "click" 금지 · "done이라고 답해주세요" 금지 · 인터페이스 분기 금지 · 앱 재시작 필요 시 명시
Step 4: 로그 분석
LOG_FILE 읽기. 각 가설 판정:
| 가설 | 판정 | 근거 (로그 라인 인용) |
|---|---|---|
| A | CONFIRMED | … |
| B | REJECTED | … |
타임스탬프로 인과 관계 타임라인 재구성.
LOG_FILE이 비어있거나 없으면: 재현 실패 가능성 안내 후 재시도 요청.
모든 가설이 REJECTED이면: 수정 금지. 다른 서브시스템에서 새 가설 생성 + 추가 계측.
Step 5: 수정
- CONFIRMED 가설에 대해서만, 최소 범위로 수정
- 계측 코드 유지 (검증 전 제거 금지)
- REJECTED 가설 코드 변경 즉시 되돌림
- 프록시 모드를 썼다면 디버그용 API route/helper도 계측의 일부로 간주하고 검증 완료 전 제거하지 않는다
Step 6: 수정 검증
delete_file로 LOG_FILE 삭제- 모든 계측
runId→"post-fix" <reproduction_steps>블록과 함께 재현 요청- LOG_FILE 읽기 — 특정 로그 라인 인용으로 성공 근거 제시 (인용 없는 성공 선언 금지)
실패 시: 해당 가설 코드 변경 되돌림 → 다른 서브시스템에서 새 가설 생성.
Step 7: 정리
사용자 확인 후에만:
- 모든
#region agent log/#endregion블록 제거 - 프록시 모드를 썼다면 디버그용 API route/helper 제거
delete_file로 LOG_FILE 삭제
Critical Constraints
- 런타임 증거 없이 수정 금지
- REJECTED 가설 코드 변경 즉시 되돌림 (방어적 가드 누적 금지)
- 계측은 검증 완료 전까지 절대 제거 금지
setTimeout/sleep을 픽스로 사용 금지- shell rm/touch 금지 — 로그 파일 조작은
delete_file도구만 - 성공 선언 시 특정 로그 라인 인용 필수
- CSP 에러가 보이면 브라우저 direct fetch를 고집하지 말고 same-origin 프록시로 전환