Analyst 크론 장애 조사 — 커널 패닉 3회 + LLM 호출 42,858건 전량 실패
Analyst 크론 장애 조사 — 260414
1. 한 줄 요약
오늘 analyst 크론 모두 실패. 커널 패닉 3회 + LLM 호출 42,858건 중 성공 7건 (해리 수동 테스트 + ETF 프리워밍). 표면 증상 여러 개 잡았지만 진짜 남은 문제는 openclaw:main 게이트웨이 경로의 400 Bad Request. Codex 세션(pane 8)에 심층 수정 핸드오프.
2. 타임라인 (2026-04-13 밤 ~ 2026-04-14 오전)
| 시각 | 이벤트 |
|---|---|
| 04-10 11:29 | 첫 번째 kernel panic (watchdog timeout) |
| 04-11 10:29 | 두 번째 panic |
| 04-13 19:16 | 세 번째 panic |
| 04-13 19:30 | 네 번째 panic (부팅 후 14분) |
| 04-13 22:09 | 다섯 번째 panic |
| 04-13 22:11 | 해리 "근본해결 못 한다" 지적 → Claude 조사 시작 |
| 04-13 22:27 | chroma-mcp hook 1차 차단 (불완전 — 세션 내 런타임 재로드 안 됨) |
| 04-13 23~ 04-14 00~03시 | 42,310건 401 폭탄 (Copilot scope 누락) |
| 04-14 04:07 | Hermes 저장소 통째로 재-clone (누군가 복구 시도, Codex 아님) |
| 04-14 09:10 | 해리가 shared/llm.py line 327 max_tokens → max_completion_tokens + ollama routing 버그 수정 |
| 04-14 09:30 | 해리가 agent-queue 8개 재가동 (Claude가 bootout 한 것 원복) |
| 04-14 09:42 | Claude가 llm_chat_direct line 530 동일 수정 적용 |
| 04-14 10:10 | analyst 크론 여전히 400 실패 확인, Codex(pane 8)에 핸드오프 |
3. 진짜 근본 원인 (조사로 확정)
3.1 1차 원인 — Copilot 토큰 scope 누락
$ gh auth status
Token scopes: 'delete_repo', 'gist', 'read:org', 'repo', 'workflow'
copilot scope 없음. 그래서 모든 github-copilot/gpt-5-mini 호출이 401 Unauthorized. shared/llm.py:llm_chat_with_fallback()의 폴백 체인이 끝까지 밀려서 결국 ollama/qwen3.5:9b-nothinker(6.6GB) 로드 → 메모리 폭주 → watchdog 90초 응답 실패 → 커널 자폭.
실측: 00~03시 42,310건 중 99.5%가 401. 새벽 어느 시점(04~07시 사이)에 scope가 추가되면서 401은 사라졌지만 곧바로 400 Bad Request 문제가 드러남.
3.2 2차 원인 — max_tokens vs max_completion_tokens
GPT-5 reasoning models (gpt-5-mini 등)는 OpenAI 신규 필드 max_completion_tokens만 받음. 기존 max_tokens 넣으면 400 Bad Request.
shared/llm.py의 3개 함수가 이 payload를 만드는데:
- line 327 llm_chat_with_fallback() Copilot/OpenAI 경로 → 해리가 09:10 수정 ✓
- line 530 llm_chat_direct() non-ollama 경로 → Claude가 10:00 수정 ✓ (백업: llm.py.bak-2026-04-14-max-completion-fix)
- line 170 llm_chat() 게이트웨이 경유 → 아직 미수정, 가장 유력한 남은 범인
3.3 3차 원인 — OpenClaw 잔존 launchd 에이전트 무더기
해리가 "2026-04-12에 Hermes로 이전 완료"라고 기억했지만 실제로는:
- OpenClaw launchd 에이전트 44개 등록, 22개 활성
- agent-queue-codex, agent-queue-ron: 1.8초 간격 (fast 0.7초) 루프
- 나머지 6개 agent-queue (macro/fundamental/technical/pm/cowork/guardian): 6초 간격
- 하루 42,776건 LLM 호출 / 분당 284회 / caller는 전부 llm_chat_with_fallback
이 workers가 401/400 에러에도 불구하고 지속적으로 retry하면서 메모리/CPU 압박 가중.
3.4 진짜 남은 문제 — openclaw:main 경로의 400
07시 이후 모든 실패 호출의 로그 model 필드가 openclaw:main. 이건 github-copilot/gpt-5-mini 같은 구체 모델명이 아니라 OpenClaw 게이트웨이의 추상 라벨. 즉:
- Workers가
llm_chat_with_fallback(["github-copilot/gpt-5-mini", ...])로 호출한 게 아님 - 또는
llm_chat()(line 170) 게이트웨이 경유 경로를 타는데, 게이트웨이가 내부에서 fallback chain을 처리하면서openclaw:main이라는 alias를 로깅 - 게이트웨이 → 상류 모델 pass-through 단계에서
max_tokens그대로 전달 → 400 Bad Request - Claude가 수정한 line 327, 530은 이 경로를 안 탐 → 수정 효과 없음
4. 조사로 확정된 기기 메모리 예산 (Mac mini 16GB)
| 카테고리 | RSS 합계 | 프로세스 수 |
|---|---|---|
| Ollama runner (qwen3.5:9b 로드 시) | 8,079 MB | 1~3 |
| 기타 시스템 | 2,119 MB | 426 |
| Claude CLI 세션 | 938 MB | 4 |
| 파이프라인 Python | 321 MB | 59 |
| claude-mem plugin | 69 MB | 2 |
| cmux | 95 MB | 2 |
| 나머지 | ~2 GB | — |
판정: 16GB에 위 워크로드 + ollama 9b 로드 시 구조적으로 불가능. Swap 2.7GB 사용 중. Ollama 로드가 panic 트리거.
5. 이번 세션에서 적용한 수정 (Claude 작업)
5.1 chroma-mcp 완전 차단
- 파일:
~/.claude/plugins/cache/thedotmack/claude-mem/10.6.2/scripts/worker-service.cjs - 파일:
~/.claude/plugins/marketplaces/thedotmack/plugin/scripts/worker-service.cjs - 변경:
spawn("uvx", ...)→spawn("uvx-cm-disabled", ...)(4곳 × 2파일) - 백업: 각
.bak-2026-04-13 - 검증: kill 후 60초+ 재확인 → chroma-mcp 0건. smart-explore/mem-search는 SQLite 경로라 기능 유지.
5.2 vault_watcher 폭주 방지 가드 3종
- 파일:
/Users/ron/.openclaw/workspace/scripts/vault_watcher.py - 변경:
threading.BoundedSemaphore(3)— 동시 ingest_linker 최대 3개DEBOUNCE_SECS = 2.0— 같은 파일 2초 내 중복 무시WARMUP_SECS = 45— 기동 후 45초 flush 차단 (catch-up 폭주 방지)- 검증: launchctl 재기동 후 고아 linker 114개 → 0개. test 3/3 passed.
5.3 vault_ingest_linker 다이어트 (-36%)
- 파일:
/Users/ron/.openclaw/workspace/scripts/pipeline/vault_ingest_linker.py - 범인 top 3:
cycle_baseimport가 pykrx/FinanceDataReader/pandas 끌어옴 → +123MBvault-search-index.json27MB → dict 파싱 시 ~210MB 팽창 (768차원 임베딩 벡터 포함)_build_tag_catalog+_load_search_index다중 로드 → +175MB- 변경:
cycle_base제거, 로컬load_json_safe/save_json_atomic복제_LINKER_INDEX_CACHE전역 캐시 추가note['embedding']드롭 +gc.collect()- 실측: 435.9 → 278.0 MB (-36%). 3 concurrent 기준 1308 → 834 MB (-474 MB).
- 백업:
vault_ingest_linker.py.bak-20260413 - 테스트 3/3 passed.
5.4 Hermes scheduler.py 부팅 유예 + catch-up 동시성 제한
- 파일:
/Users/ron/.hermes/hermes-agent/cron/scheduler.py - 주의: 해리가 "OpenClaw timer.ts"를 지목했지만 실제로 돌고 있는 건 Hermes Python scheduler. OpenClaw timer.ts는 비활성 경로.
- 변경:
_BOOT_GRACE_SEC = 60,_get_system_uptime_sec()(macOS sysctl kern.boottime + Linux /proc/uptime 폴백)tick()진입 즉시 uptime<60s면return 0+ 로그for job in due_jobs:순차 루프 →ThreadPoolExecutor(max_workers=min(3, len(due_jobs)))- 백업:
scheduler.py.bak-2026-04-13-panic-fix+jobs.json.bak-2026-04-13-panic-fix(양쪽) - 검증:
launchctl kickstart -k gui/501/ai.hermes.gateway→ boot catch-up guard active 로그 찍힘.executed: 0.
5.5 Ollama fallback 모델 교체 (panic의 즉시 트리거 제거)
- Hermes:
~/.hermes/config.yamlline 10qwen3.5:9b→qwen2.5:3b - OpenClaw:
~/.openclaw/workspace/scripts/shared/llm.py라인 45, 46, 60, 69, 77, 84 (6곳)qwen3.5:9b-nothinker→qwen2.5:3b - 추가 매핑:
kimi-k2.5:cloud→qwen2.5:3balias - 결과: 폴백 로드 시 6.6GB → 1.9GB (-4.7GB)
- 기존 9b 모델 파일 보존 (해리 미래 사용 대비)
- 메모리 언로드 완료 (
keep_alive:0)
5.6 agent-queue 8개 bootout → 해리가 원복
- 8개 라벨:
com.openclaw.agent-queue-{codex,ron,macro,fundamental,technical,pm,cowork,guardian} launchctl bootout+ plist.disabled-2026-04-13-panic-fixsuffix- 해리가 09:30 원복해서 다시 돌고 있음. 즉 이 조치는 무효가 됐고, 404 에러 폭탄의 원천은 그대로.
- 원복 후 새 PID: 19662, 19666, 19670, 19674, 19678, 19683, 19688, 19692
5.7 llm_chat_direct line 530 max_tokens 조건부 수정
- 파일:
/Users/ron/.openclaw/workspace/scripts/shared/llm.pyline 525~539 - 해리의 line 327 패턴을 같은 함수 다른 경로에 복제:
python is_gateway_gpt5 = (url == GATEWAY_URL and payload_model.startswith("gpt-5")) if is_gateway_gpt5: payload["max_completion_tokens"] = max_tokens if temperature == 1: payload["temperature"] = temperature else: payload["max_tokens"] = max_tokens payload["temperature"] = temperature - 백업:
llm.py.bak-2026-04-14-max-completion-fix - 검증:
llm_chat_direct('github-copilot/gpt-5-mini')→ 400 → 429 Too Many Requests (payload schema는 수용됨, 단순 쿼터)llm_chat_direct('openrouter/nemotron')→ 401 (local key 부재, 무관)- py_compile / import 모두 통과
6. 해리가 09:10에 먼저 수정한 것 (참고)
shared/llm.pyline 327max_tokens → max_completion_tokens(Copilot/OpenAI gpt-5 계열)- Ollama routing 버그 수정 (상세 미확인)
- Copilot scope 추가 (추정 — 새벽 어느 시점.
gh auth refresh -s copilot브라우저 OAuth) - agent-queue 8개 원복 (Claude가 disabled 시킨 plist 복구)
7. 실측 수치 (2026-04-14 기준, 10:10 시점)
LLM 호출 시간대별 분포
| 시각 | 총 | OK | 401 | 400 | 기타 |
|---|---|---|---|---|---|
| 00시 | 8,780 | 0 | 8,665 | 115 | 0 |
| 01시 | 11,342 | 0 | 11,292 | 50 | 0 |
| 02시 | 13,088 | 0 | 12,983 | 105 | 0 |
| 03시 | 9,100 | 0 | 9,055 | 45 | 0 |
| 04시 | 105 | 0 | 10 | 95 | 0 |
| 05시 | 45 | 0 | 0 | 45 | 0 |
| 06시 | 70 | 0 | 5 | 65 | 0 |
| 07시 | 110 | 0 | 5 | 105 | 0 |
| 08시 | 151 | 1 | 0 | 145 | 5 |
| 09시 | 49 | 3 | 0 | 45 | 1 |
| 10시 | 18 | 3 | 0 | 15 | 0 |
| 계 | 42,858 | 7 | 42,015 | 830 | 6 |
analyst 프롬프트로 성공한 건 0건. 성공 7건은 전부 해리 수동 테스트 + ETF 프리워밍.
모델별 분포 (caller는 전부 llm_chat_with_fallback)
| 모델 | 총 | OK |
|---|---|---|
| github-copilot/gpt-5-mini | 8,468 | 6 |
| openai-codex/gpt-5.4 | 8,443 | 0 |
| openrouter/minimax-m2.5 | 8,443 | 0 |
| ollama/qwen3.5:9b-nothinker | 8,442 | 1 |
| openrouter/nvidia/nemotron-3 | 8,432 | 0 |
| openclaw:main (← 07시 이후 통합) | 615 | 0 |
| anthropic/claude-opus-4-6 | 15 | 0 |
analyst 스케줄 vs 400 클러스터 (일치)
| 스케줄 | 크론 | 400 클러스터 |
|---|---|---|
| 07:05 | 매크로 애널리스트 v2.0 | 07:00 정각 400 × 10 |
| 07:28 | 펀더멘탈 애널리스트 v3.0 | 07:15~07:17 클러스터 |
| 07:32 | 테크니컬 애널리스트 v4.0 | 07:35~07:37 클러스터 |
| 07:55 | 투자 PM + 애널리스트 추론 에이전트 | 07:47~07:58 클러스터 |
| 08:00 | 딥다이브 converge + 데일리 마켓 | 08:03~08:09 클러스터 |
| 08:05 | 할일 브리핑 아침 | 08:03~08:09 (겹침) |
| 08:10 | 애널리스트 발전 추적기 | 08:17~08:29 클러스터 |
| 08:15 | DM 애널리스트 프롬프트 갱신 | 08:17~08:29 (겹침) |
모든 analyst 스케줄에서 호출 발생 → 전부 400 실패.
현재 기기 상태 (10:10 시점)
- Load Average: 1.74 / 1.83 / 1.90
- Unused 메모리: ~3,000 MB (아침 초기 100~250MB → 대폭 개선, panic-fix 효과)
- Python 프로세스: 5 (이전 244개 → vault_watcher 가드 효과)
- Zombie: 0
- Stuck: 0
- chroma-mcp: 0건 (차단됨)
- Ollama: idle listener 56MB (9b 언로드됨)
- Swap: 2.7GB/4GB (여전히 압박, 자연 해소 대기)
8. Codex에 핸드오프할 핵심 문제
openclaw:main 모델 라우팅 경로의 400 Bad Request
조사할 것
openclaw:main모델명이 어디서 정의되는가 —shared/llm.py또는 gateway 코드llm_chat()(line 170) 또는 gateway가 이 라벨을 받아 상류 모델로 변환할 때 payload schema 어떻게 만드는가- 변환 단계에서
max_tokens그대로 전달 여부 (가설: Yes) - gateway 코드 위치:
~/.openclaw/workspace/gateway/, 또는hermes-agent/gateway/, 또는 별도 프로세스 - agent_queue_worker가 실제로 어느 함수를 호출하는지 (
llm_chatvsllm_chat_with_fallbackvsllm_chat_direct) — 07시 이후 모든 호출이openclaw:main으로 찍히는 이유
수정 방향 후보
llm_chat()(line 170)에도 gpt-5 감지 +max_completion_tokens변환 추가- 게이트웨이 자체에서 상류 pass-through 전에 payload schema 번역 (더 근본적)
- agent_queue_worker가
llm_chat_with_fallback(이미 수정됨)을 쓰도록 경로 변경
검증 방법
- 400 에러 body 원본 확보 (agent-queue-*.err.log 에 있을 것)
- 워커 로그에서 실제 호출 payload 캡처
- 수정 후
openclaw:main경로 직접 재현 테스트
9. 남은 미정리 이슈 (별건)
vault-search-index.jsonUTF-8 깨짐 (0xaa @ 26995206).vault_indexer.py --full로 재생성 필요. 이게 해결되면 vault_ingest_linker 추가 -108MB 절감 가능.- Hermes
~/.hermes.failed/,.hermes.backup.v0.6/,.hermes.backup.pre-migration/백업 디렉토리 정리 여부 ~/.cache9.5GB,~/Library/Caches6.8GB — 스왑 압박 해소용 정리 후보- claude-mem plugin 업데이트(10.6.3+) 시 worker-service.cjs 패치 덮어쓰임 → 업그레이드 감지 시 재패치 필요
- OpenClaw 루프 데몬 9개 (orchestrator-loop, cowork-daemon 등) 종료 여부 — 해리 판단 대기
10. 관련 파일 / 로그 / 서브에이전트
수정한 파일
/Users/ron/.openclaw/workspace/scripts/shared/llm.py(line 525~539 + 기존 수정)/Users/ron/.openclaw/workspace/scripts/vault_watcher.py(동시성 + debounce + 부팅 유예)/Users/ron/.openclaw/workspace/scripts/pipeline/vault_ingest_linker.py(다이어트)/Users/ron/.hermes/hermes-agent/cron/scheduler.py(부팅 유예 + catch-up 동시성)/Users/ron/.hermes/config.yaml(fallback 모델)/Users/ron/.claude/plugins/cache/thedotmack/claude-mem/10.6.2/scripts/worker-service.cjs/Users/ron/.claude/plugins/marketplaces/thedotmack/plugin/scripts/worker-service.cjs/Users/ron/.claude/plugins/marketplaces/thedotmack/plugin/hooks/hooks.json(worker 훅 제거)
핵심 로그 / DB
/Users/ron/.openclaw/logs/llm/20260414.jsonl(21MB, 42,858 라인)/Users/ron/.openclaw/logs/agent-queue-*.log(워커별 수십 MB 누적)/Users/ron/.openclaw/logs/agent-queue-*.err.log(에러 샘플 — 400 body 원본 있을 것)/Users/ron/.openclaw/workspace/data/ops_multiagent.db(59MB)/Library/Logs/DiagnosticReports/panic-full-2026-04-{10,11,13}-*.panic(panic 로그 5개)/Users/ron/.ollama/logs/server.log
서브에이전트 ID (SendMessage로 재개 가능)
- chroma-mcp 1차 차단:
a1ae2469a303174eb - chroma-mcp 2차 완전 차단:
a8f2c01e195cdc832 - vault_watcher 가드:
ae2f2672e4f7e15a9 - Hermes scheduler 가드:
a6a59dea269e7e14a - vault_ingest_linker 다이어트:
aed2752d12992efbe - 메모리 전수 진단:
ac45ea467ddac683b - Hermes ↔ Ollama 연결 조사:
ace7777e8f8311f2a - Codex 전환 작업 추적:
a5b84fcbb2c63b187 - Hermes copilot 인증 + fallback 추적:
a1fdc979d79e1108e - Hermes 04:07 재-clone 분석:
aec8b04e14fe3d27a - Ollama fallback 교체:
a8fee9b0526c56b79 - OpenClaw 잔존 에이전트 전수:
a518d79c5b3eae268 - llm_chat_direct line 530 수정:
a88a1674d38a8c97a - analyst 크론 LLM 로그 집계:
a468d9061d823ba4d
11. 해리가 기억해야 할 것
- "Hermes로 이전 완료"는 사실이 아니었음. OpenClaw launchd 에이전트 44개 중 22개 여전히 활성. 에이전트 큐 워커들이 하루 42,000+건 LLM 호출 폭탄의 주범.
- agent-queue 8개를 내가 bootout했는데 해리가 원복함. 진짜 범인이라 원복한 이유 확인 필요 (실제 필요한 워크로드가 있어서?).
- Copilot scope 추가는 해리가 09시경 직접 해야 했음 —
gh auth refresh -s coplot실행됐는지 재확인 (새벽 42,000건 401의 회복 시점과 일치). - 내가 만든 bak 파일이 여러 개 있음.
find ~ -name "*.bak-2026-04-*"로 찾을 수 있음. Codex 수정 결과 안정되면 정리.
12. 핸드오프 메모
→ Codex session on pane:8
Claude 세션에서 panic 즉시 원인(chroma-mcp + vault_watcher + Ollama 9b 로드)은 잠재웠고, 메모리 여유 3GB 회복. 하지만 실제 analyst 프롬프트는 0건 성공. 남은 작업은 openclaw:main 경로 심층 수정이고 이건 게이트웨이/llm_chat 코드 분석이 필요해서 Codex가 맡는 게 적합.
Claude 쪽은 standby. 필요하면 이 문서의 서브에이전트 ID로 재개하거나 새 세션으로 지원 가능.
작성: Claude Opus 4.6 (1M context) — 2026-04-14 10:15 KST 세션: d8a3e766-b42c-4e2e-bd0f-fc92c9a7aec5