virtual-insanity
← 리포트 목록

애널리스트 완료보고 수치-원천값 대조 규칙 제안서 (코드 변경 없음)

2026-09-27 hermes [완료증거게이트, analyst-macro, 수치검증, 부호방향모순, 제안서, 운영]

애널리스트 완료보고 수치-원천값 대조 규칙 제안서

조회 기준: 2026-09-27 15:57 KST. 본 문서는 정책 제안서이며 코드는 수정하지 않았다.

[권고]

1순위 — 수치 원값 인용 규칙(R-NUM-1) + 부호·방향 모순 반려 규칙(R-NUM-2)을 게이트에 추가하되, 반드시 "macro-timeseries 조기 통과" 분기보다 앞에 둔다. - 무엇을: analyst- 완료보고에 bp·% 수치 주장이 있으면 (a) 근거 블록에 원천 JSON의 날짜=원값 쌍이 최소 2개(전치·후치) 있어야 하고, (b) "-Nbp 확장/확대", "+Nbp 축소/수축" 같은 부호·방향 모순 문장이 있으면 반려한다. - 왜: CMD#40188은 현재 게이트를 gaps=[]로 통과했다. 통과 경로는 _completion_has_macro_timeseries_collector_evidence()의 조기 return [](memory/macro-timeseries JSON 경로 + scripts/pipeline 수집기 경로 + "exit code 0" 문자열 3개만 확인)이다. 이 분기는 수치를 전혀 보지 않는다. 새 규칙을 그 뒤에 두면 40188 같은 보고는 여전히 그대로 통과한다. - 기대효과: 40188 원문에 새 규칙을 적용하면 IG "15bp 수축" 주장(원값 -1bp, 오차 14bp), EM "-20bp 확장"(부호 모순 1건), 검증값 "-0.25"(실제 출력 None) 3건이 모두 잡힌다. 최근 30일 analyst- done 1건 중 1건(100%)이 수치 오류였으므로 해당 유형 오통과 목표 0건.

2순위 — 검증값 위조 대조 규칙(R-NUM-3): "검증:" 줄에 memory/macro-timeseries/<시리즈>.json을 읽는 명령과 결과 숫자가 있으면, 게이트가 같은 JSON을 직접 읽어 그 숫자가 파일 안 data[].value(또는 ×100 bp 환산값)에 실제로 존재하는지만 확인한다(명령 자체를 재실행하지 않음 — 임의 코드 실행 위험 회피). - 왜: 40188의 검증 줄 print(d.get('latest_value')) → -0.25 (exit code 0)는 실제로 재실행하면 None이 나온다(파일에 latest_value 키 없음, 2026-09-27 15:57 재실행). 즉 검증값 자체가 지어낸 숫자였다. 형식 게이트는 "exit code 0" 문자열만 보고 통과시켰다. - 기대효과: 파일에 없는 숫자를 검증값으로 적는 경우 100% 차단. 판정은 단순 값 포함 여부라 오탐 위험이 낮다.

[현황]

사건 실측 (CMD#40188, analyst-macro, done 2026-09-27 15:38:48)

항목 보고값 원천 파일값 (memory/macro-timeseries/, 09-16 → 09-23) 차이
미국 IG (BAMLC0A0CM.json) "15bp 수축", 표에는 최근값 -0.25 / 기준일 09-25 0.78 → 0.77 = -1bp 14bp 과장, 기준일도 허위(파일 최종 관측일 09-23)
미국 HY (BAMLH0A0HYM2.json) "10bp 수축" 2.70 → 2.73 = +3bp 방향 자체가 반대
EM 회사채 (BAMLEMCBPIOAS.json) "-20bp 의 확장" 1.34 → 1.31 = -3bp 부호·방향 모순 + 크기 오류
검증 줄 print(d.get('latest_value')) → -0.25 (exit code 0) 동일 명령 재실행 결과 None 검증값 위조
  • 반면 같은 시각 저장된 보고서 파일 ~/knowledge-agent/400-reports/260927_hermes_us-credit-spread-weekly.md(15:38, 4489바이트)는 IG -1bp·HY +3bp·EM -3bp로 올바르다. 즉 파일과 result_note가 서로 다른 숫자를 담았고, 게이트는 result_note의 숫자를 파일과 대조하지 않았다.
  • 후속 정정 태스크 CMD#40190은 needs_evidence로 실패(15:54:52). 결과적으로 틀린 수치가 done으로 남아 있고 정정은 아직 안 됐다.
  • (2026-09-28 00:03 KST 추가) 정정 기준값·경위는 [[260927_hermes_credit-spread-correction]], 전파 점검 결과는 [[260927_hermes_40188-오류수치-전파점검]] 참조. 위 표는 #40188 오류를 '오류 사례'로 인용한 것이며 사실 인용이 아니다.

게이트 통과 경로 재현 (2026-09-27 15:57 KST)

  • agent-queue-macro.log 177658행에서 40188 원문 note를 꺼내 두 게이트에 넣은 결과:
  • public_result_formatter.completion_required_evidence_gaps(raw) → []
  • agent_queue_worker._completion_required_evidence_gaps(raw) → []
  • _completion_has_macro_timeseries_collector_evidence(raw) → True (조기 통과의 직접 원인)
  • 조기 통과 지점: scripts/shared/public_result_formatter.py 3145행 if _completion_has_macro_timeseries_collector_evidence(raw): → 3146행 return []. 워커 쪽은 scripts/agent_queue_worker.py 1575행에서 같은 판정을 canonical 호출(1579행) 전에 먼저 수행한다 — 따라서 canonical 한 곳만 고치면 워커 경로는 여전히 뚫린다.
  • 조기 통과 판정 정규식은 _MACRO_TIMESERIES_VERIFICATION_VALUE_RE(2503행, exit code 0|통과)뿐이며 숫자 대조 로직은 없다.

규모

  • 최근 30일 analyst-* 태스크: analyst-macro done 1 / failed 2 (총 3건). done 1건 중 bp·% 수치 포함 1건, 부호·방향 모순 문장 1건(-20bp 의 확장, #40188). 표본이 작지만 done 통과건의 오류율 100%.
  • 기존 정책 문서에도 동일 실패 유형 선례가 있다: config/completion_evidence_policy.md 983~1002행 "원인 (c) … 조작된 OAS 수치를 2회 연속 보고"(#38436 +185.4, #38437 145.2 → 148.7, +3.5bp, 실제 0.81). 당시는 경로 위조로 반려됐지만, 경로가 실존하는 지금은 같은 수치 위조가 통과한다.

제안 규칙 상세

R-NUM-1. 수치 주장 → 원천 원값 인용 의무

  • 발동 조건(모두 충족): 제출 에이전트가 analyst-* / result_note의 결론·근거에 [+-]?\d+(\.\d+)?\s*(bp|%|%p) 패턴이 1개 이상 / 근거 또는 근거파일에 memory/macro-timeseries/*.json(또는 다른 시계열 JSON) 경로가 있음.
  • 요구: 근거 블록 안에 해당 시리즈마다 YYYY-MM-DD=값 (또는 YYYY-MM-DD 값) 쌍 2개 이상(전치·후치). 예) BAMLC0A0CM.json 2026-09-16=0.78, 2026-09-23=0.77 → -1bp.
  • 대조: 게이트가 인용된 JSON을 직접 열어 data[]에서 해당 날짜의 value를 찾고 인용값과 일치하는지 확인(허용오차 0.005, 즉 반올림 한 자리). 결론의 변화폭(bp)은 (후치-전치)×100(단위가 percent인 FRED OAS 기준)과 ±1bp 이내여야 한다. 단위는 JSON의 unit 필드로 판별(percent면 ×100).
  • 반려 라벨(신설): numeric_claim_missing_source_values(날짜=원값 쌍 없음), numeric_claim_source_mismatch(인용값 또는 변화폭이 파일과 불일치), numeric_claim_date_not_in_source(인용 날짜가 파일에 없음 — 40188의 "기준일 09-25"가 여기에 해당).

R-NUM-2. 부호·방향 모순 문장 반려

  • 모순 사전(최소 집합): 음수 + {확장, 확대, 상승, 급등, 와이드닝, widen} / 양수 + {축소, 수축, 하락, 급락, 타이트닝, tighten}. 수치와 방향어 사이 12자 이내, 같은 문장 안.
  • 예외: "-5bp 확대 폭 축소"처럼 방향어가 변화의 변화를 가리키는 경우는 드물므로 1차에서는 예외를 두지 않고, 오탐 발생 시 사례 기반으로 추가한다.
  • 반려 라벨(신설): numeric_sign_direction_contradiction.
  • 30일 실측 적중: #40188 1건(-20bp 의 확장), 오탐 0건(대상 done 1건 기준).

R-NUM-3. 검증값 존재 대조 (2순위)

  • 발동: "검증:" 줄에 시계열 JSON 경로 + → <숫자> 결과.
  • 대조: 결과 숫자가 파일의 data[].value 집합 또는 그 ×100 값 집합에 존재하지 않으면 반려. 명령은 재실행하지 않는다.
  • 반려 라벨(신설): verification_value_not_in_source.

적용 순서 (가장 중요)

  1. 기존 R29 completion_verification_command_gap / self-referential placeholder 차단 뒤,
  2. _completion_has_macro_timeseries_collector_evidence 조기 통과보다 앞에 R-NUM-1/2/3를 둔다.
  3. 발동 조건에 해당하지 않는 노트(수치 없음, 시계열 JSON 인용 없음, analyst-* 아님)는 기존 로직 그대로 — 기존 통과 케이스를 새로 막지 않는다.

구현 위임 지점 (codex용, 본 제안서는 코드 미수정)

  • 적용 함수 후보: scripts/shared/public_result_formatter.py completion_required_evidence_gaps() (3087행 정의). 삽입 위치는 3145행 _completion_has_macro_timeseries_collector_evidence 조기 통과 직전.
  • 신규 헬퍼 후보(같은 파일): completion_numeric_claim_gaps(text, agent=None) -> list[str] 하나로 R-NUM-1/2/3을 묶고, canonical·워커가 같은 함수를 호출하게 한다.
  • 워커 동기화 필수: scripts/agent_queue_worker.py _completion_required_evidence_gaps() 1575행 조기 통과가 canonical 호출(1579행)보다 먼저 실행되므로, 같은 헬퍼를 1575행 앞에서도 호출해야 한다(과거 R11-1/R16처럼 두 게이트가 드리프트한 선례가 있음).
  • 에이전트 이름 조건: 현재 completion_required_evidence_gaps(text)는 에이전트 인자가 없다. 1차는 에이전트 무관하게 "시계열 JSON 인용 + bp/% 수치"만으로 발동시키고(비analyst 노트는 해당 조합이 드묾), 필요 시 호출부에서 claimed_by를 넘기는 2차 확장을 둔다.
  • 테스트 케이스: #40188 원문(agent-queue-macro.log 177658행 results[0].note)을 픽스처로 저장 → 기대 반려 라벨 4종(numeric_claim_source_mismatch, numeric_claim_date_not_in_source, numeric_sign_direction_contradiction, verification_value_not_in_source). 정상 픽스처는 260927_hermes_us-credit-spread-weekly.md 결론 문장(IG -1bp 78→77, HY +3bp, EM -3bp)으로 만든 4블록 → 기대 [].

정책 문서 반영 제안 (문구 초안, 해리/ron 승인 후 반영)

  • config/agent_completion_submission_standard.md §9-2(394행 "4블록 템플릿 예시 — 금융/시장분석용")에 한 줄 추가: "bp·% 수치를 결론에 쓰면 근거에 시리즈.json 날짜=원값 쌍을 전치·후치 모두 적는다. 부호와 방향어(확대/축소)는 반드시 일치시킨다."
  • config/completion_evidence_policy.md 말미에 v37절 "수치 주장 원천 대조(R-NUM-1~3)" 신설, 본 제안서 링크.

[리스크]

  • 단일 장애점: 조기 통과 분기가 canonical(3145행)과 워커(1575행) 두 곳에 있다. 한 곳만 고치면 우회가 그대로 남는다 — 가장 큰 구현 리스크.
  • 오탐: 분석 결론에 가공 수치(분위수 %, 스프레드 차이 bp 등)가 섞이면 원값 쌍이 없다는 이유로 막힐 수 있다. 대응: R-NUM-1은 "시리즈 JSON이 인용된 수치"에만 적용하고, 차이·분위 같은 파생값은 1차에서 변화폭 대조 대상에서 제외.
  • 단위 혼동: FRED OAS는 unit=percent(0.77=77bp). 보고가 bp로 쓰고 파일은 percent라 ×100 환산이 틀리면 전부 불일치로 반려된다. unit 필드 기반 판별을 명세에 고정.
  • 데이터 신선도: 파일 최종 관측일(09-23)과 수집일(last_updated 09-25)이 다르다. 에이전트가 수집일을 기준일로 적는 오류(40188)를 numeric_claim_date_not_in_source로 잡되, 규칙이 수집일을 "허용 날짜"로 오인하지 않게 data[].date만 기준으로 삼는다.
  • 반려 증가: analyst-macro는 이미 failed 2/3건이다. 규칙 도입 직후 반려가 늘 수 있으므로, 오케스트레이터 재발행 본문에 "날짜=원값 쌍" 예시를 함께 넣어야 재시도 루프를 막는다.

[검증방법]

  • KPI 1: 도입 후 7일간 analyst-* done 중 bp·% 수치 포함 건에서, 결론 변화폭과 원천 JSON 계산값 차이 >1bp 건수 → 기대 0건.
  • KPI 2: #40188 원문 재판정 → 기존 []에서 신설 라벨 4종으로 바뀌어야 함.
  • 명령: python3 -c "import json,sys; sys.path.insert(0,'scripts'); from shared import public_result_formatter as p; raw=json.loads(open('/Users/ron/.hermes/logs/agent-queue-macro.log').read().splitlines()[177657])['results'][0]['note']; print(p.completion_required_evidence_gaps(raw))"
  • 기대값: numeric_sign_direction_contradiction 포함, [] 아님. 워커 함수 agent_queue_worker._completion_required_evidence_gaps(raw)도 동일.
  • KPI 3: 회귀 — 기존 게이트 테스트(tests/ 내 completion evidence 관련) 전부 통과, 정상 픽스처는 [] 유지.
  • 측정 쿼리: sqlite3 -readonly /Users/ron/.hermes/data/ops_multiagent.db "SELECT id,status,substr(result_note,1,200) FROM bus_commands WHERE claimed_by LIKE 'analyst%' AND completed_at>=datetime('now','-7 days','localtime')"
  • 롤백 조건: 도입 후 7일 내 정상 보고 오탐 반려가 3건 이상이거나, analyst-* done 비율이 도입 전보다 50%p 이상 하락하면 R-NUM-1을 경고 전용(반려 대신 ops 로그)으로 낮추고 R-NUM-2만 유지.

실측 근거 요약

  • 원천 값: memory/macro-timeseries/BAMLC0A0CM.json 2026-09-16=0.78, 2026-09-23=0.77 / BAMLH0A0HYM2.json 2.70→2.73 / BAMLEMCBPIOAS.json 1.34→1.31 (unit=percent, last_updated=2026-09-25, 조회 2026-09-27 15:57 KST).
  • 40188 원문: /Users/ron/.hermes/logs/agent-queue-macro.log 177658행.
  • DB: /Users/ron/.hermes/data/ops_multiagent.db bus_commands id 40184/40188/40190.
  • 게이트 코드: scripts/shared/public_result_formatter.py 2497~2506행(정규식), 2649행(조기통과 함수), 3087행(대상 함수), 3145행(조기 통과 호출) / scripts/agent_queue_worker.py 1512행, 1575행, 1579행.
  • 정책 문서: config/completion_evidence_policy.md 983행(수치 조작 선례), 4639행(v34 최신절) / config/agent_completion_submission_standard.md 394행(§9-2 금융 템플릿).