← 리포트 목록
bond_daily_report Telegram message_id 로깅 보강
2026-04-15
bond
[bond, telegram, observability, message-id, phase17-followup]
결론
bond_daily_report.py의 Telegram 그룹/PDF 발송 경로에 message_id 관측 로그를 추가했다.
- 신규 TSV:
/Users/ron/.hermes/logs/bond_daily_last_telegram.tsv - 그룹 텍스트 폴백:
send_group_chunked_result()로 각 chunk별message_id/status/error확보 - PDF 발송:
send_document_result()로sendDocumentAPI 응답의message_id확보 - 기존 bool API(
send_group_chunked,send_document)는 유지해서 다른 호출자 호환성 보존
단, 1회 실제 --notify 실행은 LLM 단계에서 네트워크/DNS 실패로 중단되어 bond 본문 그룹 발송까지 도달하지 못했다. 이 실패도 TSV에 남도록 보강했다.
1단계 — 소스 분석
대상 파일:
/Users/ron/.hermes/workspace/scripts/pipeline/bond_daily_report.py/Users/ron/.hermes/workspace/scripts/shared/telegram.py
확인한 기존 발송 경로:
bond_daily_report.py --notify- LLM 생성 성공
- PDF 생성 성공 시:
send_document(GROUP_CHAT_ID, pdf, topic_id=DAILY_REPORT_TOPIC_ID)send_document(492860021, pdf)- PDF 생성 실패 시:
send_group_chunked(report_md, topic_id=DAILY_REPORT_TOPIC_ID, parse_mode="")
기존 문제:
shared.telegram._send_raw()는 이미 Telegram API 응답에서message_id를 읽고 있었음.- 하지만
send_group_chunked()가 bool만 반환해서 각 chunk의message_id가 호출부로 전달되지 않았음. send_document()도sendDocument응답 전체를 버리고 bool만 반환했음.bond_daily_report.py는 성공/실패 문자열만 로그에 남기고message_id를 저장하지 않았음.
2단계 — 수정 diff 요약
/Users/ron/.hermes/workspace/scripts/shared/telegram.py
+ def send_group_chunked_result(... ) -> list[dict]:
+ # dedupe면 status=skipped_dedupe 반환
+ # 각 chunk마다 _send_raw() 결과의 message_id/status/error 반환
+
def send_group_chunked(... ) -> bool:
- # 직접 _send() 반복, bool만 반환
+ return all(r["ok"] for r in send_group_chunked_result(...))
+ def send_document_result(... ) -> dict:
+ # sendDocument API 응답에서 result.message_id 추출
+ # 실패 시 {ok: False, message_id: None, error: ...}
+
def send_document(... ) -> bool:
- # API 응답에서 ok만 반환
+ return bool(send_document_result(...)["ok"])
핵심 라인:
send_group_chunked_result:telegram.py:592-630send_group_chunked호환 래퍼:telegram.py:633-638send_document_result:telegram.py:838-881send_document호환 래퍼:telegram.py:884-889
/Users/ron/.hermes/workspace/scripts/pipeline/bond_daily_report.py
+ TELEGRAM_TSV = Path.home() / ".hermes" / "logs" / "bond_daily_last_telegram.tsv"
+
+ def _append_telegram_tsv(chat_id, topic_id, message_id, status, error=None):
+ # timestamp/chat_id/topic_id/message_id/status/error append
+
- send_document(...)
+ group_result = send_document_result(...)
+ _append_telegram_tsv(GROUP_CHAT_ID, DAILY_REPORT_TOPIC_ID,
+ group_result["message_id"], status, error)
+
- send_group_chunked(...)
+ chunk_results = send_group_chunked_result(...)
+ for r in chunk_results:
+ _append_telegram_tsv(r["chat_id"], r["topic_id"],
+ r["message_id"], r["status"], r["error"])
+
+ # LLM 실패/노트 없음처럼 본문 발송 전 실패한 notify도 TSV에 실패 상태 기록
핵심 라인:
- TSV 상수/append 함수:
bond_daily_report.py:37-70 - 노트 없음 알림 결과 기록:
bond_daily_report.py:823-832 - LLM 실패 알림 결과 기록:
bond_daily_report.py:859-868 - PDF 그룹/DM 결과 기록:
bond_daily_report.py:914-951 - 텍스트 폴백 chunk 결과 기록:
bond_daily_report.py:952-966
3단계 — 검증
구문 검사
python3 -m py_compile \
/Users/ron/.hermes/workspace/scripts/shared/telegram.py \
/Users/ron/.hermes/workspace/scripts/pipeline/bond_daily_report.py
결과: 통과.
result API 단위 검증
PYTHONPATH=/Users/ron/.hermes/workspace/scripts python3 - <<'PY'
from shared import telegram
calls=[]
def fake_send_raw(chat_id, text, parse_mode='HTML', topic_id=None, **kwargs):
calls.append((chat_id, text, topic_id))
return {'ok': True, 'message_id': 12345 + len(calls), 'error': None}
telegram._send_raw = fake_send_raw
telegram._is_duplicate = lambda chat_id, text: False
res = telegram.send_group_chunked_result('hello', topic_id=39439, parse_mode='')
print(res)
assert res[0]['message_id'] == 12346
assert telegram.send_group_chunked('hello2', topic_id=39439, parse_mode='') is True
print('OK')
PY
출력:
[{'ok': True, 'chat_id': -1003076685086, 'topic_id': 39439, 'message_id': 12346, 'status': 'success', 'error': None, 'chunk_index': 1, 'chunk_count': 1}]
OK
TSV append 형식 검증
PYTHONPATH=/Users/ron/.hermes/workspace/scripts:/Users/ron/.hermes/workspace/scripts/pipeline python3 - <<'PY'
from pathlib import Path
import bond_daily_report as b
p = Path('/tmp/bond_daily_last_telegram_unit.tsv')
if p.exists():
p.unlink()
b.TELEGRAM_TSV = p
b._append_telegram_tsv(-1003076685086, 39439, 987654321, 'success', None)
b._append_telegram_tsv(-1003076685086, 39439, None, 'skipped_dedupe', None)
print(p.read_text())
PY
출력:
timestamp chat_id topic_id message_id status error
2026-04-15T19:31:40+09:00 -1003076685086 39439 987654321 success
2026-04-15T19:31:40+09:00 -1003076685086 39439 skipped_dedupe
4단계 — --notify 1회 실행 결과
실행 명령:
cd /Users/ron/.hermes/workspace/scripts/pipeline
python3 bond_daily_report.py --notify
출력 요약:
[2026-04-15 19:30:38] bond_daily_report 시작
[2026-04-15 19:30:38] 노트: 260414_황대진_전달-일일-414-화-마감-및-채권시장-정리-DS증권-황대진.md
[2026-04-15 19:30:38] 파싱 완료 — 타입: 낙찰정리, 날짜: 2026-04-14, 낙찰: 0건
[2026-04-15 19:31:28] [ERROR] LLM 실패: github-copilot/gpt-5-mini: <urlopen error [Errno 8] nodename nor servname provided, or not known>
실제 본문/PDF 발송 전 LLM 단계에서 실패했다. 따라서 이번 실행에서는 그룹 토픽 message_id가 생성되지 않았다.
그래도 실패 상태는 TSV에 기록됨:
timestamp chat_id topic_id message_id status error
2026-04-15T19:31:28+09:00 -1003522748967 llm_failed_alert_ok_or_dedupe github-copilot/gpt-5-mini: <urlopen error [Errno 8] nodename nor servname provided, or not known>
TSV 경로:
/Users/ron/.hermes/logs/bond_daily_last_telegram.tsv
5단계 — 남은 리스크
- 현재 세션에서는 LLM/Gateway/Telegram 네트워크가 불안정해 실제 그룹 발송 message_id를 확보하지 못했다.
- 16:00 이전 실행 기록에는 텍스트 폴백 성공이 있었지만, 그 시점은 패치 전이라 message_id가 남아있지 않다.
- 다음번 LLM이 성공하고 PDF 또는 텍스트 폴백 발송까지 도달하면 TSV에 실제
message_id가 남는다. send_group_chunked_result()는 dedupe 발생 시status=skipped_dedupe를 반환하게 했으므로, 중복 skip도 관측 가능하다.
변경 파일 목록
/Users/ron/.hermes/workspace/scripts/shared/telegram.py/Users/ron/.hermes/workspace/scripts/pipeline/bond_daily_report.py/Users/ron/knowledge-agent/400-reports/260415_bond_msgid_logging.md
자체평가
- 정확성: 4.4/5 — message_id 전달/저장 경로는 구현. 실제 message_id는 LLM 선행 실패로 미확보.
- 완성도: 4.5/5 — PDF, 텍스트 chunk, dedupe, 실패 상태를 모두 TSV에 기록.
- 검증: 4.0/5 — 구문검사/단위검증/실제
--notify실행 완료. 운영 message_id 검증은 네트워크/LLM 실패로 보류. - 최소 변경: 4.7/5 — 기존 bool API 유지, bond 비즈니스 로직 변경 없음.
- 종합: 4.4/5
재개 후 실제 도달 검증 — 2026-04-15 19:40~19:48 KST
원인 재진단
재개 후 네트워크가 열리자 상태가 바뀌었다.
확인 결과:
Gateway 18789: LISTEN, /health = {"status":"ok","platform":"hermes-agent"}
Ollama 11434: LISTEN, qwen2.5:3b / qwen3.5:4b 사용 가능
Telegram getMe: ok=True, username=RONforMAC_Bot
OpenRouter: DNS/API 접근 가능하지만 OPENROUTER API key 없음
openai-codex/gpt-5.4: Hermes gateway 500, Codex token refresh 401
github-copilot/gpt-5-mini: empty_response 또는 기존 sandbox DNS 실패
직전 실패의 직접 원인:
- 이전 sandbox 상태에서 로컬/외부 HTTP가 막혀
openai-codex, Ollama 모두Operation not permitted로 실패했다. - OpenRouter는 API key가 없어 스킵됐다.
- 마지막 Copilot까지 떨어졌고 DNS/empty response로 실패했다.
회피 방법:
- 네트워크가 열린 상태에서 재실행.
- 불필요한 장시간 재시도를 줄이기 위해 실행 시
OPENCLAW_MAX_RETRY_PER_MODEL=1만 적용. - 실제 LLM 생성은 fallback인
ollama/qwen3.5:4b가 수행했다. - bond 비즈니스 로직 추가 변경은 하지 않았다.
실제 실행 명령
cd /Users/ron/.hermes/workspace/scripts/pipeline
OPENCLAW_MAX_RETRY_PER_MODEL=1 OPENCLAW_PER_MODEL_TIMEOUT_SEC=60 \
python3 bond_daily_report.py --notify
실행 로그 증거
START=2026-04-15 19:41:30 KST
[2026-04-15 19:41:30] bond_daily_report 시작
[2026-04-15 19:41:30] 노트: 260414_황대진_전달-일일-414-화-마감-및-채권시장-정리-DS증권-황대진.md
[2026-04-15 19:41:30] 파싱 완료 — 타입: 낙찰정리, 날짜: 2026-04-14, 낙찰: 0건
[2026-04-15 19:44:42] LLM 완료 (모델: ollama/qwen3.5:4b, 5794자)
[2026-04-15 19:47:54] [WARN] NanumGothic 폰트 없음 — PDF 생성 스킵
[2026-04-15 19:47:54] 메모리 저장 완료. 볼트: None
[2026-04-15 19:47:58] 텔레그램 그룹 텍스트 폴백: 성공 message_ids=[51803, 51804] statuses=['success', 'success']
PDF는 기존 환경과 동일하게 NanumGothic 폰트 부재로 스킵됐고, 텍스트 폴백으로 그룹 토픽에 2 chunk 발송됐다.
TSV 실제 message_id 기록
경로:
/Users/ron/.hermes/logs/bond_daily_last_telegram.tsv
기록:
timestamp chat_id topic_id message_id status error
2026-04-15T19:31:28+09:00 -1003522748967 llm_failed_alert_ok_or_dedupe github-copilot/gpt-5-mini: <urlopen error [Errno 8] nodename nor servname provided, or not known>
2026-04-15T19:47:58+09:00 -1003076685086 39439 51803 success
2026-04-15T19:47:58+09:00 -1003076685086 39439 51804 success
도달 증거:
- Telegram Bot API
sendMessage응답에서message_id=51803,message_id=51804를 수신했다. - 대상은 그룹
chat_id=-1003076685086, 토픽topic_id=39439. - TSV와 bond 로그 양쪽에 동일한 성공 기록이 남았다.
최종 상태 갱신
- message_id 로깅 기능: 동작 확인 완료.
- 실제 그룹 발송: 성공.
- 실제 message_id TSV 기록: 성공.
- LLM 선행 실패: sandbox 네트워크 해제 후 Ollama fallback으로 회피 확인.
자체평가 갱신
- 정확성: 4.9/5 — 실제 Telegram 그룹 발송 및 message_id 2건 확보.
- 완성도: 4.8/5 — 성공/실패/dedupe/LLM 실패 모두 TSV 관측 가능.
- 검증: 4.9/5 — 실제
--notify운영 실행, LLM 완료, Telegram API message_id 기록 확인. - 최소 변경: 4.7/5 — 기존 bool API 유지, bond 비즈니스 로직 변경 없음.
- 종합: 4.8/5