Executive Summary
- 원인:
pm_context_filter.py가 입력 freshness 판정에source_date()를 썼고, 이 함수가as_of/date를generated_at보다 먼저 읽었다. 오늘 07:10에 생성된analyst-fundamental/latest.json도as_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
주요 변경:
source_date()는 그대로 “원천 데이터 기준일”로 유지.- 신규
input_freshness_date(data, path)추가. generated_at,executed_at,run_at,updated_at우선- 없으면 파일 mtime
- 마지막 fallback만
source_date - 신규
read_analyst_input(name, today, wait_seconds)추가. - 오늘 dated JSON이 있으면 우선 사용
- 없으면
latest.json사용 - fundamental은 오늘 freshness가 확인될 때까지 최대 600초 대기
- PM stale 판정은
source_date가 아니라freshness_date기준으로 변경. - 투명성을 위해
source_data_dates와methodology_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.json의generated_at/executed_at/mtime확인 - 오늘 완료본이 아니면 최대 600초 대기
- 그래도 오늘 완료본이 없으면 그때만
[구 데이터: fundamental=...]stale 마커 기록
6. 자체평가
- 정확성: 4.5/5 — 실제 원인은
as_of/date와generated_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