← /geode/portfolioGEODE . 문서
GitHub
가이드
How-to

멈춘 실행 디버깅

트랜스크립트와 runlog를 읽어 실행이 멈춘 지점을 찾고 복구하는 방법입니다.

실행이 멈추는 양상은 두 가지입니다. 같은 도구를 같은 인자로 무한히 도는 경우와, 이벤트 발화가 끊긴 채 매달려 있는 경우입니다. 둘 다 디스크에 남는 두 개의 append-only JSONL이 증거를 줍니다. 턴 단위 대화는 transcript, 파이프라인 이벤트는 runlog입니다. 멈춘 실행 디버깅은 이 둘을 찾아 마지막 이벤트를 읽고, 원인을 분류해 복구하는 순서로 진행합니다.

1. transcript와 runlog를 찾습니다

세션 transcript는 SessionTranscript(core/observability/transcript.py)가 ~/.geode/transcripts/<project-slug>/<session_id>.jsonl 또는 run_dir에 묶인 경우 dialogue.jsonl에 기록합니다. user/assistant 메시지, 도구 호출과 결과, 비용, 오류, 라이프사이클 이벤트가 한 줄씩 들어갑니다. runlog는 RunLog(core/orchestration/run_log.py)가 ~/.geode/runs/<session_key>.jsonl에 기록하며, 각 줄은 event, node, status, duration_ms를 가진 RunLogEntry입니다.

ls -t ~/.geode/transcripts/*/            # most recent session jsonl
ls -t ~/.geode/runs/                     # most recent run_key jsonl

2. 마지막 이벤트를 읽습니다

어디서 멈췄는지는 마지막 줄들이 알려줍니다. transcript는 read_events(limit=N)로 최근 이벤트를 읽고, runlog는 read(limit=N, ...)로 newest-first로 읽으며 event_filter / node_filter / status_filter로 좁힐 수 있습니다.

uv run python -c "
from core.observability.transcript import SessionTranscript
tx = SessionTranscript('<session_id>')
for e in tx.read_events(limit=10):
    print(e.get('event'), e.get('tool', ''), e.get('status', ''))
"

마지막이 tool_call인데 짝이 되는 tool_result가 없으면 도구 실행에서 매달린 것이고, 같은 tool_call이 같은 인자로 반복되면 진전 없는 루프입니다.

3. 원인을 분류합니다

두 가지 정지 양상을 구분합니다.

  • 매달림(이벤트 끊김). SessionTranscript.is_stale(threshold_s)는 파일 mtime을 보고 일정 시간 이벤트가 안 붙었는지 알려줍니다. last_touched_at()가 한참 전이면 PIPELINE_TIMEOUT / PIPELINE_ERROR를 발화하지 못한 채 멈춘 것입니다.
  • 노드 stuck. StuckDetector(core/orchestration/stuck_detection.py)가 NODE_ENTERED / NODE_EXITED / NODE_ERROR 훅으로 실행 중인 노드를 추적합니다. get_running()은 현재 실행 중인 세션 키와 경과 시간을 돌려주고, 타임아웃(timeout_s, 기본 2시간)을 넘으면 check_stuck()이 그 작업을 자동 release하고 PIPELINE_ERROR를 발화합니다.
uv run python -c "
from core.orchestration.stuck_detection import StuckDetector
d = StuckDetector()
print(d.get_running())   # {session_key: elapsed_seconds}
print(d.check_stuck())   # released keys past timeout
"

4. 복구합니다

루프가 진전 없이 도는 경우는 ConvergenceDetector가 동일 도구·동일 인자 반복을 감지해 끊습니다. 매달림이 확인되면 StuckDetector.check_stuck()이 작업을 release하고 PIPELINE_ERROR를 발화해 세션을 정리합니다. transcript와 runlog가 가리키는 마지막 도구·노드를 보고 근본 원인(외부 호출 타임아웃, 자격증명 오류, 입력 오류)을 고친 뒤 다시 실행합니다. transcript와 runlog는 30일 자동 정리되므로 진단 근거가 사라지기 전에 보존하세요.

확인

복구 후 새 실행의 transcript가 session_end까지 도달하는지, runlog의 마지막 이벤트가 pipeline_end(status: ok)인지 확인합니다.

tail -n 3 ~/.geode/runs/<session_key>.jsonl   # last events, expect pipeline_end ok

참조: Long-running runs, Observability.