virtual-insanity
← 리포트 목록

PM analyst 캐시 의존 수정

2026-04-24 pm [pm-analyst, freshness, cache, hermes]

Executive Summary

  • 원인: pm_context_filter.py가 입력 freshness 판정에 source_date()를 썼고, 이 함수가 as_of/dategenerated_at보다 먼저 읽었다. 오늘 07:10에 생성된 analyst-fundamental/latest.jsonas_of=2026-04-23을 보존해서 PM이 이를 어제 데이터로 오판했다.
  • 수정: PM 입력 판정에 input_freshness_date()를 추가해 generated_at/executed_at/mtime 기준으로 오늘 생성 여부를 확인한다. fundamental은 오늘 결과가 없으면 최대 600초 대기한다.
  • 검증: PM 직접 재생성 후 summary[구 데이터: ...] 마커 제거, data_dates.fundamental=2026-04-24 확인.

1. 증거

기존 PM latest

/Users/ron/.hermes/workspace/memory/analyst-pm/latest.json 샘플에 아래 마커가 있었다.

[구 데이터: fundamental=2026-04-23]

마커 생성 위치:

# scripts/pm_context_filter.py
if stale_inputs:
    stale_prefix = "[구 데이터: " + ", ".join(
        f"{item['analyst']}={item['source_date']}" for item in stale_inputs
    ) + "] "

fundamental latest 실제 상태

오늘 파일은 존재했고 07:10에 생성되었다.

/Users/ron/.hermes/workspace/memory/analyst-fundamental/latest.json
mtime: 2026-04-24 07:10

하지만 JSON 내부는 아래처럼 source vintage와 run completion date가 섞여 있었다.

{
  "date": "2026-04-23",
  "as_of": "2026-04-23",
  "generated_at": "2026-04-24T07:10:14+09:00"
}

즉 PM이 읽은 파일 자체는 오늘 fundamental 결과가 맞지만, as_of/date 우선 판정 때문에 stale로 표시됐다.

2. 크론/실행 경로

PM 실행은 launchd가 담당한다.

Label: com.openclaw.analyst-pm
Program: /Users/ron/.hermes/workspace/scripts/analyst_common_wrapper.sh pm
Schedule: 07:35 KST

analyst_common_wrapper.sh의 PM 경로:

PM_FILTER="$SCRIPTS_DIR/pm_context_filter.py"
"$PM_FILTER" --write-latest

따라서 수정 대상은 pm_context_filter.py가 맞다. 실행 시각 07:35는 변경하지 않았다.

3. 수정 내역

백업:

/Users/ron/.hermes/workspace/scripts/pm_context_filter.py.bak-pm-freshness-20260424

수정 파일:

/Users/ron/.hermes/workspace/scripts/pm_context_filter.py

주요 변경:

  1. source_date()는 그대로 “원천 데이터 기준일”로 유지.
  2. 신규 input_freshness_date(data, path) 추가.
  3. generated_at, executed_at, run_at, updated_at 우선
  4. 없으면 파일 mtime
  5. 마지막 fallback만 source_date
  6. 신규 read_analyst_input(name, today, wait_seconds) 추가.
  7. 오늘 dated JSON이 있으면 우선 사용
  8. 없으면 latest.json 사용
  9. fundamental은 오늘 freshness가 확인될 때까지 최대 600초 대기
  10. PM stale 판정은 source_date가 아니라 freshness_date 기준으로 변경.
  11. 투명성을 위해 source_data_datesmethodology_audit.analyst_input_meta를 latest에 기록.

핵심 diff 요약:

- fundamental = read_json(MEMORY / "analyst-fundamental" / "latest.json")
- analyst_dates["fundamental"] = source_date(fundamental)
+ fundamental, fundamental_meta = read_analyst_input("fundamental", today, wait_seconds=600, interval_seconds=30)
+ analyst_dates["fundamental"] = fundamental_meta.get("freshness_date")
+ source_dates["fundamental"] = fundamental_meta.get("source_date")

4. 검증 결과

컴파일

/usr/bin/python3 -m py_compile /Users/ron/.hermes/workspace/scripts/pm_context_filter.py

결과: 통과.

PM 강제 재실행

중복 텔레그램 발송을 피하기 위해 wrapper 전체가 아니라 PM filter만 직접 재실행했다.

/usr/bin/python3 /Users/ron/.hermes/workspace/scripts/pm_context_filter.py --write-latest

결과:

{"ok": true, "path": "/Users/ron/.hermes/workspace/memory/analyst-pm/latest.json", "positioning": "선별 적극", "confidence": 76, "context_items": 6}

latest 검증

summary_has_stale: False
구 데이터 count: 0

data_dates:

{
  "macro": "2026-04-24",
  "fundamental": "2026-04-24",
  "technical": "2026-04-24",
  "pm_generated": "2026-04-24 12:38:55 KST"
}

source_data_dates:

{
  "macro": "2026-04-24",
  "fundamental": "2026-04-23",
  "technical": "2026-04-24"
}

해석: PM은 오늘 07:10에 완료된 fundamental 결과를 사용한다. 다만 fundamental 내부 원천 데이터 vintage는 2026-04-23이므로 별도 필드로 보존했다.

5. 내일 07:35 자동 점검 방식

별도 실행 시각은 바꾸지 않았다. 내일 07:35 PM 자동 실행 때 pm_context_filter.py가 자체적으로 아래를 점검한다.

  • analyst-fundamental/YYYY-MM-DD.json 있으면 우선 사용
  • 없으면 analyst-fundamental/latest.jsongenerated_at/executed_at/mtime 확인
  • 오늘 완료본이 아니면 최대 600초 대기
  • 그래도 오늘 완료본이 없으면 그때만 [구 데이터: fundamental=...] stale 마커 기록

6. 자체평가

  • 정확성: 4.5/5 — 실제 원인은 as_of/dategenerated_at 혼동으로 확인했고 PM stale 판정을 고쳤다.
  • 완성도: 4.3/5 — PM 경로는 수정 완료. fundamental producer가 dated 2026-04-24.json을 만들지 않는 문제는 별도 개선 여지가 있다.
  • 검증: 4.5/5 — py_compile, PM 재실행, latest JSON 필드 검증 완료.
  • 최소 변경: 4.5/5 — PM 실행 시각과 발송 경로는 유지, 필터 입력 freshness 판정만 변경.

종합: 4.45/5