virtual-insanity
← 리포트 목록

analyst/pipeline NO_SEND dry-run 표준화

2026-04-24 no [no-send, dry-run, analyst, telegram, hermes]

analyst sender NO_SEND/dry-run 모드 표준화

결론

6개 대상 모두 NO_SEND=1 / DRY_RUN=1 / ANALYST_COMMON_NO_SEND=1 / --dry-run / --no-send 계열을 표준 인식하도록 맞췄다.

대상 적용 결과 NO_SEND=1 검증 일반 모드 검증
macro 표준 가드 적용 sender 호출 0 fake sender 1회
fundamental 표준 가드 적용 sender 호출 0 fake sender 1회
technical analyst_common_sender.py 표준화 sender 호출 0 fake sender 1회
pm analyst_common_sender.py 표준화 sender 호출 0 fake sender 1회
market_indicator main + dedup wrapper 가드 적용 sender 호출 0 fake sender text/photo 각각 1회
oil_supply main + dedup wrapper 가드 적용 sender 호출 0 fake sender text/photo 각각 1회

실제 외부 Telegram 발송은 하지 않았다. “일반 실행 → 정상 발송”은 fake sender monkeypatch로 정상 호출 경로가 살아있는지 검증했다.

변경 파일

공통 가드 추가:

/Users/ron/.hermes/workspace/scripts/shared/no_send_guard.py
/Users/ron/.hermes/workspace/shared/no_send_guard.py

적용 파일:

/Users/ron/.hermes/workspace/scripts/macro_redesign_report.py
/Users/ron/.hermes/workspace/scripts/fundamental_redesign_report.py
/Users/ron/.hermes/workspace/scripts/analyst_common_sender.py
/Users/ron/.hermes/workspace/scripts/pipeline/market_indicator_tracker.py
/Users/ron/.hermes/workspace/scripts/pipeline/oil_supply_monitor.py

백업:

*.bak-no-send-standard-20260424

공통 가드

shared/no_send_guard.py가 인식하는 값:

NO_SEND=1
DRY_RUN=1
ANALYST_COMMON_NO_SEND=1
--dry-run
--no-send

제공 함수:

env_truthy(name)
env_no_send()
flags_no_send(argv)
no_send_requested(argv=None, *extra)
dry_run_result(sector="market")
no_send_log_line(component, body_len=None)

패치 내용

macro

  • 기존: --no-send, ANALYST_COMMON_NO_SEND=1만 인식
  • 변경: NO_SEND=1, DRY_RUN=1, ANALYST_COMMON_NO_SEND=1, --dry-run, --no-send 인식
  • 발송 직전 dry_run_result() 반환
  • stderr에 macro_redesign: NO_SEND active — send skipped body_len=... 기록

fundamental

  • 기존 자체 가드가 있었으나 공통 가드로 표준화
  • NO_SEND=1 실행 시 tg.send_sector_result() 미호출
  • stderr에 fundamental_redesign: NO_SEND active — send skipped body_len=... 기록

technical / pm

  • 두 analyst는 analyst_common_sender.py를 통해 발송
  • 기존: ANALYST_COMMON_NO_SEND=1만 인식
  • 변경: NO_SEND=1, DRY_RUN=1, ANALYST_COMMON_NO_SEND=1, --dry-run, --no-send 인식
  • CLI 사용법도 [--dry-run|--no-send] <analyst> <latest.json> <tsv> <wrapper.log>로 확장

market_indicator

  • NO_SEND=1이면 수집 후 저장/발송 없이 dry-run 결과로 반환
  • _dedup_send_sector, _dedup_send_sector_photo, _dedup_send_photo, _dedup_send_sector_album, _dedup_send_notification_center_chunked에도 NO_SEND 가드 삽입
  • 즉 main 레벨과 발송 wrapper 레벨 이중 차단

oil_supply

  • NO_SEND=1이면 리포트/차트 생성 후 Telegram 발송 블록 스킵
  • _dedup_send_sector, _dedup_send_photo, _dedup_send_sector_photo, _dedup_send_sector_album, _dedup_send_notification_center_chunked에도 NO_SEND 가드 삽입

검증 1 — 4개 analyst NO_SEND=1 실제 실행

실행:

NO_SEND=1 python3 macro_redesign_report.py ...
NO_SEND=1 python3 fundamental_redesign_report.py ...
NO_SEND=1 python3 analyst_common_sender.py technical ...
NO_SEND=1 python3 analyst_common_sender.py pm ...

notification_center_log 변화:

notification_log_before=223 after=223 delta=0

출력:

macro:       status=dry_run, message_id=null, no_send=true, body_len=2183
fundamental: message_id=null, body_len=2291, blacklist_hits=[]
technical:   status=dry_run, message_id=null, no_send=true, body_len=2484
pm:          status=dry_run, message_id=null, no_send=true, body_len=2455

stderr:

macro_redesign: NO_SEND active — send skipped body_len=2183
fundamental_redesign: NO_SEND active — send skipped body_len=2291
analyst_common_sender:technical: NO_SEND active — send skipped body_len=2484
analyst_common_sender:pm: NO_SEND active — send skipped body_len=2455

검증 2 — market/oil NO_SEND=1 sender-level 실행

외부 발송 없이 fake sender로 계측했다.

[
  {
    "module": "market",
    "no_send_results": [true, true, true],
    "no_send_underlying": {"sector": 0, "photo": 0, "sector_photo": 0, "nc": 0},
    "normal_results": [true, true, true],
    "normal_underlying_total": {"sector": 1, "photo": 1, "sector_photo": 1, "nc": 0}
  },
  {
    "module": "oil",
    "no_send_results": [true, true, true],
    "no_send_underlying": {"sector": 0, "photo": 0, "sector_photo": 0, "nc": 0},
    "normal_results": [true, true, true],
    "normal_underlying_total": {"sector": 1, "photo": 1, "sector_photo": 1, "nc": 0}
  }
]

판정:

  • NO_SEND=1에서는 text/photo/sector_photo 발송 함수가 실제 sender를 호출하지 않음
  • 일반 모드에서는 동일 경로가 fake sender를 호출함
  • 따라서 차단은 작동하고, 정상 발송 경로도 깨지지 않음

검증 3 — py_compile

python3 -m py_compile \
  macro_redesign_report.py \
  fundamental_redesign_report.py \
  analyst_common_sender.py \
  pipeline/market_indicator_tracker.py \
  pipeline/oil_supply_monitor.py \
  shared/no_send_guard.py

OK

CLAUDE.md 운영 규칙 추가 권고

실제 파일은 수정하지 않고 권고로 남긴다.

강제 재실행/수동 재검증은 기본적으로 NO_SEND=1 ANALYST_COMMON_PRINT_BODY=1로 먼저 실행한다. 실제 발송은 렌더링·길이·HTML·중복 체크 통과 후에만 수행한다.

남은 리스크

  • market/oil은 전체 main을 네트워크 수집까지 돌리는 방식 대신 sender-level로 검증했다. 이유는 실제 외부 발송/수집 부하와 노이즈를 피하기 위해서다.
  • 이번 범위는 요청된 6개에 한정했다. 다른 pipeline도 이미 dedup은 적용됐지만 NO_SEND 표준화까지 모두 적용된 것은 아니다.

자체평가

기준 점수 근거
정확성 4.4/5 6개 대상 모두 공통 env/flag 인식 및 sender 미호출 검증
완성도 4.3/5 공통 가드 추가, analyst/main/wrapper 경로 반영
검증 4.3/5 4 analyst 실제 NO_SEND 실행, market/oil fake sender 계측, py_compile 통과
최소 변경 4.4/5 발송 직전 가드와 공통 유틸만 추가, 실제 발송 로직 구조는 유지

종합: 4.35/5

DONE