# BAT-046 Design - Status: confirmed - Batch: BAT-046 ## Architecture Summary - P0 로깅 기반(BAT-045) 위에 분류·조회·문서를 얹는다. 청산 로그는 기존 reason·actor를 함께 노출(신규 필드 없음). 운영 조회는 순수 집계 모듈(`operator_report.py`) + CLI direct-DB 리더로 구성해 집계 로직을 테스트 가능하게 분리. ## Changed Areas - Docs: docs/operations.md(신규), docs/interface-contract.md(reason+actor 어휘 + report 매핑), docs/runtime-flows.md·docs/project-structure.md(정합) - Modules: trex_core/application/safety_sell.py(actor 로그), trex_core/application/operator_report.py(신규), trex_core/runtime/cli.py(report) - Interfaces: 운영자 CLI `report` 추가(direct-DB, RPC 없음). reason+actor는 로그/계약 노출(메시지 계약 불변). ## Key Decisions 1. **REQ-086 = Option A**: 기존 `reason`(조건) + `actor`(주체)를 함께 노출. safety_sell fire 로그에 `actor=trex-safety-sell` 추가, interface-contract에 어휘 명문화. 신규 reason 값·분류 필드 없음. `slot_transition_log`는 이미 actor 기록 → 추가 스키마 변경 불요. 2. **REQ-088 실현 PnL = net 매매 현금흐름**: `ledger_outbox`에 매도별 cost basis가 없어, 운영자가 수기 계산하던 당일 net(Σ매도 대금−수수료−세금 − Σ매수 대금−수수료)을 정의로 채택. 일중 진입·청산에서 net ≈ 실현손익. 미청산 평가손익 제외(런북·계약에 명시). 3. **REQ-088 표면 = CLI direct-DB**(OQ-1): 신규 RPC 없음. 집계는 순수 함수(`operator_report.py`)로 분리해 단위 테스트, DB 와이어링은 `cli._cmd_report`(psycopg) 얇은 리더. 4. **"오늘" 경계 = trading_date KST**: `kst_day_bounds_utc()`로 KST 자정 경계를 UTC 범위로 변환해 `ledger_outbox.executed_at` 필터. ## Edge Cases - ledger_outbox executed_at NULL → `COALESCE(executed_at, created_at)`로 폴백. - 체결 0건 → realized PnL 0, 빈 섹션. - report는 인스턴스 필터 없이 DB 전체 집계(pause/resume 선례) — 멀티인스턴스 분리는 후속(런북에 명시). ## Architecture Impact - both (project-structure: operator_report·logging_setup·operations.md / runtime-flows: 로깅·관측성·report 흐름) — REQ-090에서 정합 완료. ## Reference Doc Update Plan - project-structure.md: `application/operator_report.py`·`runtime/logging_setup.py`·`docs/operations.md`·cli report — 완료. - runtime-flows.md: 구조화 로깅/관측성 flow + 운영 조회 리포트 flow — 완료.