Skip to content

feat: 사이클 관측성 — 결측 원인 추적 + 당일 결측 경보#430

Merged
easygap merged 1 commit into
mainfrom
feat/cycle-observability
Jul 2, 2026
Merged

feat: 사이클 관측성 — 결측 원인 추적 + 당일 결측 경보#430
easygap merged 1 commit into
mainfrom
feat/cycle-observability

Conversation

@easygap

@easygap easygap commented Jul 2, 2026

Copy link
Copy Markdown
Owner

무엇

한 달 운영 리뷰(docs/PAPER_MONTH1_REVIEW_AND_PLAN.md P0-1)의 사이클 관측성을 구현합니다. 트랙레코드 재시작 전에 머지해야 하는 항목(새 60일은 결측 예산이 3일뿐).

2026-06-26 스냅샷 결측은 operation_events에 사이클 이벤트가 하나도 없어 "왜 빠졌는지" 사후 추적조차 불가능했습니다. 커버리지 94%로 게이트(95%)를 위협하는데도 원인을 알 수 없던 게 핵심 문제였습니다.

무엇을 했나

  • core/cycle_observability.py 신설
    • 순수 함수 find_snapshot_gaps(trading_days, snapshot_dates) / format_gap_alert(basket, gaps, today) — 테스트 용이.
    • best-effort record_cycle_event(...) — 기록 실패가 사이클을 절대 막지 않음.
    • detect_snapshot_gaps_for_account(...) — DB 스냅샷 + 영업일을 엮어 결측일 산출, 운영 시작 이전 영업일은 제외.
  • main.py run_rebalance 배선
    • CYCLE_START / CYCLE_END(저장 n/N) / CYCLE_ERROR — START만 있고 END 없으면 중도 사망으로 판별 가능.
    • 바스켓별 SNAPSHOT_SAVED / SNAPSHOT_SKIPPED.
    • 최근 영업일 결측 감지 → SNAPSHOT_GAP + Discord 경보. 오늘 결측만 critical, 과거 결측은 warning(복구 불가한 과거 결측을 매일 critical로 울리는 피로 방지).
  • 재시도(스케줄링): 사이클은 멱등((account_key, date) upsert + 드리프트 재평가)이라 같은 날 재실행이 안전. 11:00·14:00 크론 추가로 당일 복구(문서 §4에 절차). PC가 하루 종일 꺼진 경우는 구조적으로 당일 복구 불가 — 다음 실행의 결측 경보로 인지.

적대적 리뷰 반영

다중 에이전트로 검토(8건 제기 → 7건 확정). 코드 확정 항목 반영:

  • [medium] KST vs 로컬 시각 불일치 — 스냅샷 귀속은 KST인데 결측 판정 '오늘'은 naive 로컬이라, 비KST 호스트(클라우드/CI)에서 당일 critical 경보가 안 울릴 수 있었음 → datetime.now(ZoneInfo("Asia/Seoul"))로 통일.
  • [low] 룩백 7일 → 14일(명절 연휴 클러스터 커버). 그보다 오래된 결측은 승격 게이트·헬스 점검이 담당.
  • [low] live 동기화 실패 sys.exit가 CYCLE_END 우회 → 그 앞에 CYCLE_ERROR 기록.
  • [low] 배선 무커버리지 → run_rebalance 통합 테스트 추가(스킵 분기, 오늘/과거 결측 criticality).

테스트

  • 신규: tests/test_cycle_observability.py(순수 함수 + DB 수집), tests/test_rebalance_snapshot.py에 관측성 배선 통합 테스트 4건.
  • 전체 스위트 통과. 실데이터 스모크로 실제 6/26 결측 감지 + 경보 문구 생성 확인, 드라이런 CLI 정상.

한 달 운영 리뷰(docs/PAPER_MONTH1_REVIEW_AND_PLAN.md P0-1) 처방. 6/26 스냅샷
결측이 operation_events에 사이클 이벤트가 없어 원인 추적조차 불가능했던 문제를
해결한다. 트랙레코드 재시작 전에 머지해야 하는 항목(새 60일은 결측 예산 3일뿐).

core/cycle_observability.py 신설:
- find_snapshot_gaps / format_gap_alert: 순수 함수(테스트 용이)
- record_cycle_event: best-effort 기록(실패해도 사이클 불변)
- detect_snapshot_gaps_for_account: DB 스냅샷+영업일로 결측일 산출
  (운영 시작 이전 영업일 제외)

main.py run_rebalance 배선:
- CYCLE_START/END(저장 n/N)/ERROR로 '언제 어디서 멈췄는지' 추적 가능
- 바스켓별 SNAPSHOT_SAVED/SKIPPED
- 최근 영업일 결측 → SNAPSHOT_GAP + Discord 경보
  (오늘 결측만 critical, 과거 결측은 warning — 알림 피로 방지)

재시도는 스케줄링 영역: 사이클이 멱등이라 11:00·14:00 재실행이 안전하다
(문서에 절차). PC가 하루 종일 꺼진 경우는 당일 복구 구조적 불가 — 다음 실행
결측 경보로 인지.

적대적 리뷰 반영:
- 결측 판정 '오늘'을 스냅샷 귀속과 같은 KST로 통일(비KST 호스트 오탐 방지)
- 룩백 14일로 확대(명절 연휴 클러스터 커버)
- live 동기화 실패 sys.exit 전에 CYCLE_ERROR 기록(중도 사망 breadcrumb)
- run_rebalance 배선 통합 테스트 보강(스킵/오늘·과거 결측 criticality)

전체 스위트 1565 통과, 실데이터로 6/26 결측 감지 확인.
@easygap easygap merged commit 1c215a1 into main Jul 2, 2026
1 check passed
@easygap easygap deleted the feat/cycle-observability branch July 2, 2026 04:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant