Hermes 시스템 대규모 리팩토링 총정리
- 수행: 2026-04-17 07:04 → 11:01 (약 4시간)
- 체제: Claude Code 메인 세션 + 6 Codex(cmux) + 1 Claude Opus(cmux) 병렬
- 해리 Auto Mode 활성
- 전체 진단 출발점: "PM만 전송됐고 그것도 과거치"
1. 발견된 핵심 문제
1-1. 아침 브리핑 착시
로그상 4개 애널리스트(macro 07:04 msg 2419, fundamental 07:15 msg 2420, technical 07:20 msg 2421, PM 07:35 msg 2422) 전부 chat=-1003522748967 topic=5로 정상 전송됨. 해리 관점 "PM만"은 텔레그램 포럼 UI에서 topic 5 미열람 + 최신 메시지(PM) 알림만 체감한 결과로 판정.
1-2. "과거치" 실체
- Fundamental
latest.jsonas_of=2026-04-16(어제) — Claude 직접 기록 - PM이 stale 감지 없이 합성 → 해리 눈에 "오늘 아침인데 어제 리포트"
- 구조적 stale:
market-indicators/2026-04-15.json내부 WTIdata_date=2026-04-14,oil-supply-monitor/state.jsonlast_run=2026-04-14,context-fundamental.jsonmtime2026-04-14,context-technical.jsonmtime2026-04-14
1-3. 데일리 브리프 중복·과거치
07:50 analyst_daily_brief.py가 폴백 조건(positioning/summary/regime/key_signal) 맞지 않아 과거 날짜 파일로 폴백. fundamental redesign 이후 top-level summary가 없어져 발생.
1-4. 크론 패키지 누락
Hermes 이전 시 venv 누락:
- yfinance → SPY price-history 5회 연속 실패
- beautifulsoup4 → blog_monitor 실패
- google-auth/* → gmail-newsletter 실패
1-5. 웹앱 500 에러 (375+12회 반복)
webapp/blueprints/market.py::_parse_scenarios()가action_triggers를list[dict]기대, 실제는list[str]templates/analyst/log.html이pm.narrative를 string 기대, 실제는listvirtual-insanity.net/과/analyst500
1-6. 100번대 수집이 제대로 쌓이지 않음
- 25개 활성 크론 중 100-inbox 단일 소스 원칙 일치는 5개뿐
~/knowledge-agent/안에 "100 수신함/"(공백)과 "100-inbox/"(하이픈) 두 개 동시 존재- 120 지식사랑방 1986파일인데 크론 연결 없음(수동만)
1-7. 평가 루프 반쯤 끊김
analyst_quality_tracker.py가 예전 필드명(summary/earnings/trend 등) 기대 → fund 50/tech 48 허위 저평가analyst_evolution_tracker.py크론 미등록 (루프 휴면)- 평가 결과가 다음날 프롬프트 개선으로 반영되는 경로 없음
1-8. OpenClaw fallback 10곳
openclaw gateway restart, openclaw message send, /var/lib/openclaw/ops_multiagent.db 등이 코드에 잔존. Hermes gateway 장애 시 잘못된 복구 경로.
1-9. 200 아토믹 쓰기/읽기 경로 이원화
- 쓰기:
~/knowledge-agent/200-atomic/(하이픈) - 읽기:
~/knowledge-agent/200 아토믹/(공백·한글) - note_atomizer 3주 미실행 상태. 재가동 시 데이터 단절 즉시 재발생
2. 해결한 21건
즉시 해결 (긴급)
- 웹앱 500 (M): market.py list[str] 허용 + log.html is string 분기 + 운영 재시작. 4/4 경로 200
- pip 패키지 3 (N): Hermes venv에 yfinance 1.3.0, beautifulsoup4 4.14.3, google-auth 2.49.2 등 설치. 3 크론 수동 재실행 exit 0
- Stale 데이터 4 (O): market_indicator_tracker, oil_supply_monitor, fundamental/technical context builder 수동 재생성
- popular_posts upstream (P): migration archive에서 channels.json(188채널) 복구. analyst_channel_collector가 263건 수집 재개
구조 개선 (중요)
- DART API key Hermes 이전 (해리 직접 제공)
- Vault bridge 3 + popular-posts upstream 크론 등록 (R)
- price-history-universe 크론 등록 (Y): 58/58, 13:00/18:00 스케줄
- 데일리 브리프 (G): 폴백 조건에 headline/one_liner/narrative/body/interpretation/top3_themes 추가 + fundamental_redesign_report에 top-level summary 필드 강제
- PM stale gate (A):
pm_context_filter.py에source_date()추가, 오늘≠source면[구 데이터: ...]프리픽스 + methodology_audit.stale_inputs 기록 + data_dates.fundamental이 as_of 우선 참조 - quality_tracker 스키마 드리프트 (S): REQUIRED_KEYS/EVIDENCE_FIELDS 새 redesign 스키마로 교체. 점수 58→94 (macro 97, fund 86, tech 95, pm 97)
- evolution tracker (T):
--memory-only옵션,collect_repeated_quality_feedback()추가. methodology-feedback/pending.json 누적 시작 - sector-compass 17/17
_date+ attractiveness 복구 (U): fundamental.industries 의존 제거, sector-research/sector-signals 1차 소스 전환 - partial exit 승격 (V): macro 10% 이상 실패 exit 1, twitter 20% 이상 exit 1, 429 rate limit은 제외
- OpenClaw fallback 10곳 → Hermes (W): gateway restart, telegram send, DB 경로, 모델 alias, 포트 18789→8642
Phase 1 — 5 수집 크론 → 100-inbox
- blog_monitor → 110 blog-insights
- twitter_collector → 112 twitter-reports
- popular-posts → 113 popular-posts (report + 개별 post)
- gmail-newsletter → 121 뉴스레터 (완전 이전)
- DART/EDGAR → 124 dart-edgar (JSON 사본 + _summary.md)
Phase 2 — 소비자 읽기 경로 전환
- macro/fundamental/technical context filter + knowledge_context_builder + morning_briefing 전부 100-inbox 우선 + memory fallback.
data_sources_read,data_vintage_by_source필드 표준화
Phase 3 — 나머지 수집 크론 이관
- macro-series → 117, fed-liquidity → 123, sector-news → 125, filtered-ideas → 114, hypotheses → 126, price-history → 122 (SPY + universe 58개)
추가 정리 (AB)
- α: evolution cron 등록 +
analyst_runner.sh --prompt-only(pending.json 내용을 프롬프트 끝에 "오늘 반드시 고칠 점"으로 주입) - β: 심볼릭 링크 11개 →
100-inbox/타겟으로 재연결. 기존은.symlink-backup-20260417-103744보존 - γ: nepcon → 120 지식사랑방/nepcon, bond-briefing → 119 크레딧메일
- δ: vault_analyst_feedback 해리 볼트 직접 쓰기 제거 →
~/knowledge-agent/400-reports/vault-analyst-feedback/+500-signals/510 매크로/로 전환. channel_collector → 118 텔레그램
200번대 (T200)
- T200-1: 경로 통일 (공백·한글 canonical 확정, 하이픈 버전 머지 + 호환 symlink)
- T200-2: note_atomizer 크론 등록 (enabled=false, 해리 dry-run 후 활성화)
- T200-8: frontmatter 린터 추가,
--lint-only모드
C급 자동검증
inbox_health_auditor.py신규 작성 + 크론 등록 (매일 00:30)- 10개 100-inbox 폴더 × 크론 로그 대사 + silent_fail/no_inbox_files 감지
3. 등록된 신규 크론 8개
| ID | 스케줄 | 다음 실행 | 상태 |
|---|---|---|---|
| ocRESTORE-popular-posts-collect | 20 7,13 * * 1-5 |
오늘 13:20 | active |
| ocRESTORE-price-history-universe | 0 7,13,18 * * 1-5 |
오늘 13:00 | active |
| ocRESTORE-vault-macro-bridge | 50 6 * * 1-5 |
월 06:50 | active |
| ocRESTORE-vault-fundamental-bridge | 0 7 * * 1-5 |
월 07:00 | active |
| ocRESTORE-vault-technical-bridge | 10 7 * * * |
내일 07:10 | active |
| ocRESTORE-analyst-evolution-tracker | 15 8 * * * |
내일 08:15 | active |
| ocRESTORE-inbox-health-auditor | 30 0 * * * |
내일 00:30 | active |
| ocRESTORE-note-atomizer | 37 2,14 * * * |
해리 활성화 대기 | paused |
4. 100-inbox 현재 적재량 (오늘 11:01 기준)
| 폴더 | 파일 수 | 담당 크론 |
|---|---|---|
| 110 blog-insights | 12 | blog_monitor |
| 112 twitter-reports | 1 | twitter_collector |
| 113 popular-posts | 51 | telegram_popular_posts |
| 114 filtered-ideas | 2 | discovery_enricher |
| 117 macro-series | 46 | macro_series_collector |
| 122 price-history | 58 | price_history_collector |
| 123 fed-liquidity | 3 | fed_liquidity_aggregator |
| 124 dart-edgar | 3 | dart_edgar_disclosure_collector |
| 125 sector-news | 1 | sector_news_scorer |
| 126 hypotheses | 7 | hypothesis_lifecycle |
총 184 파일 오늘 쌓임. 이관 이전에는 5개 크론만 100-inbox 기록, 이제 25개 대부분 기록.
5. 내일 아침 06:50~08:30 자연 검증 타임라인
| 시각 | 크론 | 기대 산출물 |
|---|---|---|
| 06:50 | vault-macro-bridge | analyst-context/context-macro.json 오늘자 갱신 |
| 07:00 | vault-fundamental-bridge | context-fundamental.json as_of=2026-04-18 |
| 07:00 | popular-posts-collect | 113 popular-posts/2026-04-18/ 채움 |
| 07:04 | macro analyst | 오늘자 매크로 리포트 |
| 07:10 | vault-technical-bridge | context-technical.json 갱신 |
| 07:15 | fundamental analyst | stale 해소 예상 |
| 07:20 | technical analyst | 오늘자 테크니컬 |
| 07:35 | PM analyst | stale 없으면 프리픽스 없음 (정상), 있으면 [구 데이터: ...] |
| 07:50 | vault-analyst-feedback + daily_brief | 오늘자 요약 + 분석환류 |
| 08:10 | analyst-quality-tracker | 점수 90+ 예상 |
| 08:15 | analyst-evolution-tracker | pending.json 갱신 |
6. 해리가 확인해야 할 1건
텔레그램 앱 "론 알림센터" → topic 5 스크롤해서 오늘 07:04~07:35 4개 메시지(msg_id 2419~2422) 존재 여부 직접 확인. Bot API는 서버 실존 검증 불가. 4개 다 보이면 "PM만 보였다"는 UI 착시 확정.
7. 남은 과제 (D급 이상)
- Phase 4 memory deprecation (1주 운영 후 판단)
- T200-3/4/5/6/7 (200번대 데이터 정리: 원자성 위반, 대형 파일, popular-posts 분리, 중복 제목, Phase 5 MOC)
- 120 지식사랑방 1986 고아파일 정리 방침
- note_atomizer 수동 dry-run 후 활성화
8. 제약·리스크
- Fundamental
as_of=2026-04-161건은 Claude가 07:10 직접 쓴 값. runner 덮어쓰기 아님. 내일 vault-fundamental-bridge가 오늘자 context 만들면 해소. channel-collector와analyst-feedsmemory 디렉터리는 여전히 비어 있음. 실제 산출물은100-inbox/116 croned_data에 저장되는 구조로 확인.- note_atomizer 재가동 시 3주치 + 새 유입 한 번에 enrich하면 LLM 호출 수천 건. 초기 batch-size=5, 야간에만 권장.
- 해리 볼트
~/knowledge/200 아토믹/은 심볼릭 링크. 타겟이 공백 버전으로 맞춰져 있어 자연 반영.