REQ-095(슬롯 평단·원장 price 지정가 백필, 0 오염 방지) + REQ-096(백필/미해결 WARN 로깅) 구현. 지정가 부재 시 skip+강WARN. application 단일화(_resolve_fill_price), wire/LedgerTrade 스키마 불변. 575 passed/0 fail, opus QC PASS. REQ-097 알람=스파이크 산출물만(impl 후속). - _resolve_fill_price 헬퍼 추가: avg_price 검증, limit_price 백필, 미해결 WARN - _on_filled/_on_partial_cancel 통합: 백필 적용, 슬롯/원장 일관성 - _record_ledger 시그니처: resolved_price 파라미터 (backward compat) - test_execution_fill_price_backfill.py: 21 시나리오 (avg=None/0, limit=있음/없음 등) - docs: dcy-032, req-095/096/097, bat-048 설계/검증 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
18 KiB
18 KiB
0. 문서 상태
이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다.
- 상태: confirmed
- 문서 ID: dcy-032_20260621_fill-missing-price-cost-basis-backfill
- 이슈명: 체결가 누락(브로커 평균가 0/None) 시 슬롯 평단·원장 cost basis 0 오염(무경고·영구) — 지정가 백필 + 로깅 + 알람 검토
- 작성 시각(KST): 2026-06-21 (KST)
- 마지막 갱신 시각(KST): 2026-06-21 (KST)
- 대체됨: 없음
- 후속 Discovery 참조: 없음
- 생성된 REQ 참조: REQ-095, REQ-096, REQ-097
1. 계획 상태 요약
현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다.
- 연계 문서 현황:
- 관련 점수 파일: 미생성
- 관련 TODO/메모: 팀장 워크스페이스 백로그
trex-backlog.md("avg_price=None → 무경고 고정 2% 폴백" finding에서 상류 원인으로 추적)
- 해석:
- tsl tier 폴백(avg_price=None) finding을 상류로 추적한 결과, 진짜 원인은 trex-core 체결 처리에서 브로커 평균체결가가 0/None으로 올 때 슬롯 평단과 원장 cost basis가 동시에 0으로, 무경고·영구히 오염되는 데이터 무결성 갭이었다.
- 사장님 방향은 "지정가(주문 limit_price) 백필 + 로깅 + (이 기회에) 알람 기능 검토"이며 본 건은 M2 포함으로 확정되었다. 본 Discovery는 그 방향을 trex-core 변경 단위로 정식화한다.
2. 요구사항 판정 결과
이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다.
- 판정: 신규
- 근거
- dcy-026(매도 세금/수수료 정책), dcy-029(운영 관측성·PnL 뷰)는 체결 기록과 인접하나, "체결가 자체가 0/None일 때의 무결성 방어"는 어디서도 다루지 않았다. 기존 코드의
if avg else 0.0/fs.avg_price if not None else 0.0은 방어가 아니라 0 통과 경로다. - 신규 알람(alert) 능력 검토가 포함되어, 기존 Discovery의 미세 조정이 아니라 독립 주기로 추적하는 편이 명확하다.
- dcy-026(매도 세금/수수료 정책), dcy-029(운영 관측성·PnL 뷰)는 체결 기록과 인접하나, "체결가 자체가 0/None일 때의 무결성 방어"는 어디서도 다루지 않았다. 기존 코드의
3. 문제점의 요약
문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다.
- 현재 상태
- KIS 체결조회(
inquire-daily-ccld)가 체결수량(ccld_qty)은 보고하나 평균체결가(avg)가 없거나 0으로 오는 순간 스냅샷이 있을 수 있다.adapters/broker/kis.py:209,219(완전체결)·:232,238(부분체결+취소)·:243(부분체결)에서fill_price = float(avg) if avg else 0.0→avg_price = fill_price or None로, 체결인데 가격이 None/0인 FillStatus가 생성된다. - 이 값이 두 곳을 동시에 오염시킨다. (1) 슬롯 평단: 초기 매수 시
application/execution.py:242-251에서old_avg=0, fill_price=0 → new_avg=0로 HOLDING 전이 →slot.avg_price=0저장. (2) 원장:application/execution.py:424price = float(fs.avg_price) if fs.avg_price is not None else 0.0→ 매수가 price=0으로 ledger_outbox에 기록. - 무경고: 원장 skip 가드는
portfolio_id부재(:405)·execution_id부재(:415) 두 가지뿐이고 둘 다 WARN한다. "체결됐는데 price≤0"은 어느 가드에도 안 걸려 조용히 통과한다. - 영구성: 완전체결(
ccld_qty >= ord_qty)이면 즉시 HOLDING 전이 +clear_dispatch(execution.py:248-285)라 다음 폴링을 하지 않는다. KIS가 다음 틱에 올바른 평균가를 줘도 다시 읽지 않아 0이 영구히 박힌다. - 하류 영향 확인됨: 슬롯 평단 0 → slots RPC가 0.0 전송(
messaging_handlers.py:561) → tsl이≤0 → None(tsl_strategy.py:213)로 보고 tier 무시 2% 폴백 매도(무탐지). 원장 price=0 → 실현손익이 cost basis가 아닌 당일 net 현금흐름으로 계산되므로(operator_report.py) 매수 대금 과소 → 실현손익 과대 표시. - trex-core에는 구조화된 알람(alert) 채널이 없다. 운영자 표면은 CLI
trex-core report+ 구조화 로그가 전부이며, 이상 징후를 푸시로 알리는 메커니즘은 부재(daemon.py:248에 alert 주석 1건뿐).
- KIS 체결조회(
- 기대 상태
- 체결됐는데 브로커 평균체결가가 없거나 0이면, 슬롯 평단과 원장 price를 주문 지정가(limit_price)로 백필해 cost basis가 0으로 오염되지 않는다.
- 백필이 발생하면 반드시 식별 가능한 WARN 로그(슬롯·심볼·주문·대체가)를 남겨 사후 탐지·정합화가 가능하다.
- (검토 대상) 이런 무결성 이상을 운영자에게 즉시 알리는 알람 채널의 도입 가치/범위를 평가한다.
- 이해관계자
- 팀장(Claude) — Discovery/게이트 관리, 본 finding 추적자
- 사장님 — M2 범위·알람 채널·비가역 운영 결정 승인자
- trex-core-dev — delivery 담당
- 운영자 — 백필/이상 알림의 최종 소비자, 첫 거래일 매도 모니터링 주체
- 제약사항
- trex-core wire 계약(slots RPC 필드 등) 변경은 blast radius가 커 본 건 범위에서 가급적 피한다(slot.avg_price 값 정정은 wire 스키마 변경이 아님).
- 백필 가격은 추정치다 — 실제 체결가와 다를 수 있으므로 "정확값"이 아니라 "0보다 합리적인 근사 + 추적 가능"이 목표다.
- orb 매수는 지정가 주문이라 limit_price가 존재한다는 전제에 의존한다(시장가/지정가 부재 케이스는 별도 폴백 필요).
주요 사용자 시나리오
사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다.
- 운영자: 장중 매수 체결 직후 KIS 체결조회가 일시적으로 평균가 빈 행을 반환 → 현재는 슬롯 평단 0 + 원장 매수 price 0이 영구히 남아 그날 실현손익 리포트가 부풀려진다. 백필 후엔 지정가 근사로 기록되고 WARN으로 추적된다.
- tsl 매도 데몬: 평단 0인 holding 슬롯을 받아 tier 무시 2% 폴백으로 매도(정책 위반)하고 아무도 모른다. 백필 후엔 정상 tier로 평가된다.
- 운영자(알람 검토 시나리오): 무결성 이상(백필 발생, 0가격 체결)이 즉시 푸시 알람으로 도달해 당일 수기 점검 없이도 인지한다.
4. 이번에 정의할 변경
이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다.
- 변경 1 — 체결가 무결성 가드 + 지정가 백필: 체결(완전/부분) 처리에서 브로커 평균체결가가 None/0이면, 슬롯 평단과 원장 price를 주문 지정가(
slot.limit_price/주문 컨텍스트)로 백필한다. 지정가도 없으면 최종 폴백 정책을 적용한다(범위 경계 참조). - 변경 2 — 백필/0가격 체결 로깅: 백필 또는 price≤0 체결 통과 시 식별 가능한 WARN 로그를 남긴다(슬롯·심볼·주문·원가격·대체가격·사유). 원장 skip 가드와 동일한 운영 가시성 수준으로 맞춘다.
- 변경 3 — 알람(alert) 능력 검토(스파이크): trex-core 무결성 이상(백필 발생 등)을 운영자에게 푸시로 알리는 알람 채널의 도입 가치·범위·채널을 평가하고, M2 포함 여부와 최소 구현 범위를 결정한다.
영향 범위
변경이 미칠 코드/문서/운영 범위를 명시한다.
- 코드 영향:
trex_core/application/execution.py—_on_filled/_on_partial_cancel의 평단 계산(:242-251,:305-314)과_record_ledger의 price 결정(:424)에 백필 분기 추가.trex_core/adapters/broker/kis.py— 평균가 None/0 표면화 지점(:209,219,232,238,243)의 의미 정합성 검토(어디서 백필할지 결정: adapter vs application).- (알람 채택 시) 신규 alert 포트/어댑터 모듈 + 호출 지점. 본 Discovery에서는 검토만, 구현 범위는 OQ로 둔다.
- 문서 영향:
docs/discovery/index.md신규 행 추가.- (알람 채택 시)
docs/runtime-flows.md에 알람 흐름 추가 가능 — 채택 결정 후 반영.
- 운영 영향:
- 백필 발생 시 원장에 지정가 근사가 들어가므로, 운영자 PnL 리포트의 정확도가 개선되되 "근사"임을 런북에 명시 필요.
- (알람 채택 시) 운영자 알림 수신 채널·임계 설정이 신규 운영 절차로 추가됨.
5. 요구사항 목록
실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다.
기능 요구사항
- FR-1: 체결(완전·부분) 처리에서 브로커 평균체결가가 None 또는 ≤0이면, 슬롯 평단(
slot.avg_price)을 주문 지정가로 백필해 0으로 저장되지 않게 한다. - FR-2: 동일 조건에서 원장 기록 price(
_record_ledger)도 동일한 백필 가격을 사용해 매수/매도가 price=0으로 기록되지 않게 한다. - FR-3: 백필이 발생하거나 price≤0 체결이 통과할 때, 슬롯·심볼·주문ID·원가격·대체가격·사유를 포함한 WARN 로그를 남긴다(원장 skip 가드와 동일한 가시성 수준).
- FR-4: 알람(alert) 능력을 검토해 (a) 도입 여부, (b) 채널(로그 기반/AMQP 이벤트/외부 푸시), (c) M2 최소 범위를 산출물로 제시한다.
비기능 요구사항
- NFR-1: 백필은 trex-core wire 스키마(slots RPC 필드)를 변경하지 않는다(값 정정만, 계약 불변).
- NFR-2: 백필 분기는 happy path(정상 평균가 수신) 성능·동작에 영향이 없어야 하며, 정상 경로에서는 기존과 동일하게 동작한다.
- NFR-3: 백필 가격은 추적 가능해야 한다 — 어떤 체결이 실제 평균가가 아니라 백필 근사로 기록됐는지 로그/플래그로 구분 가능해야 한다.
범위 경계
이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다.
- In Scope
- 체결가 None/0 → 지정가 백필(슬롯 평단 + 원장 price) + WARN 로깅 (FR-1~3).
- 알람 능력 검토 산출물(FR-4) — 검토/결정까지 In Scope.
- Out of Scope
- slots RPC 등 wire 계약 스키마 변경.
- 과거에 이미 0으로 기록된 원장/슬롯의 소급 정정(별도 데이터 보정 작업).
- {{DECIDE_ALARM_IMPL_SCOPE}} — 알람의 실제 구현 범위(검토 결과 M2 포함으로 결정되면 In Scope로 승격, 아니면 후속 이월).
6. 리스크/가정 목록
불확실성과 전제 조건을 분리해서 적는다.
리스크
- R-1 (Medium): 지정가 백필도 추정치라, 실제 체결가와 차이가 나면 원장 cost basis가 부정확해진다(0보다는 낫지만 정확하진 않음).
- 완화 방안: 백필을 WARN+플래그로 추적 가능하게 남기고, 런북에 "백필 항목은 근사" 명시. 필요 시 후속 정합화(잔고/주문 대조) 검토.
- R-2 (Medium): 백필 시점을 adapter(kis.py)로 둘지 application(execution.py)로 둘지에 따라 paper 브로커·재구성(dcy-021) 경로와의 일관성이 달라질 수 있다.
- 완화 방안: 백필 결정 지점을 단일화(application 권장 — 주문 컨텍스트/limit_price 접근 용이)하고 design에서 paper/재구성 경로 회귀 테스트.
- R-3 (Low): 알람 채널 도입이 범위를 키워 M2 일정을 압박할 수 있다.
- 완화 방안: FR-4를 "검토 산출물"로 제한하고, 구현은 검토 결과에 따라 별도 결정(OQ-1).
가정
아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다.
- A-1: orb 매수는 지정가 주문이라 대다수 케이스에서
slot.limit_price(또는 주문 지정가)가 존재한다. - A-2: KIS 평균가 누락은 드문 순간 레이스이며, 정상 happy path에서는 평균가가 정상 수신된다(저빈도·고영향 특성).
- A-3: trex-core 기존 watchdog/원장 outbox/이벤트 발행 인프라는 그대로 재사용 가능하며, 본 변경은 그 위의 값 무결성 가드다.
오픈 질문
답을 아직 모르는 항목을 적는다.
- OQ-1: 알람(alert) 능력을 M2에 실제 구현까지 포함할지, 검토 산출물만 내고 구현은 후속으로 이월할지. 채널은 무엇으로 할지(구조화 로그 + 로그 기반 알람 / AMQP 이벤트 / 외부 푸시).
- 상태: Deferred (→ design)
- 처리 방안: design 단계에서 trex-core-dev가 채널별 장단점·최소 범위 분석 산출물 작성. 그 분석을 근거로 알람의 M2 구현 포함 여부는 design review에서 사장님이 최종 결정(범위·일정 결재 사안). FR-3 WARN 로깅은 채택 여부와 무관하게 M2 필수.
- 종료 조건: design review에서 알람 구현이 In Scope/후속 이월 중 하나로 확정되면 Answered (사장님 2026-06-21: design 분석 후 확정 합의).
- OQ-2: 주문 지정가(limit_price)마저 부재하거나 ≤0인 경우의 최종 백필 폴백 정책(예: 직전 종가/현재가 조회 / 해당 체결 보류·재폴링 / 기록 skip+강한 알림 중 무엇).
- 상태: Deferred (→ design)
- 처리 방안: design 단계에서 trex-core-dev가 후보별 영향 분석, 팀장 승인.
- 종료 조건: 폴백 우선순위가 단일 정책으로 확정되면 Answered (사장님 2026-06-21: design 분석 후 확정 합의).
7. 초기 성공 기준
이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다.
- S-1: 평균가 None/0 체결 입력에 대해 슬롯 평단과 원장 price가 0이 아닌 지정가 백필 값으로 기록된다.
- S-2: 백필/0가격 체결 통과 시 식별 가능한 WARN 로그가 100% 남는다(무경고 통과 0건).
- S-3: 정상 평균가 수신 경로는 기존과 동일하게 동작한다(회귀 0건). 알람 능력 검토 산출물이 confirm-discovery에 제출된다.
측정 방식 및 데이터 출처
- S-1 측정 방식: 평균가 None/0을 주입한 단위/통합 테스트로 슬롯 평단·ledger_outbox price 검증 / 데이터 출처: 신규 테스트 + ledger_outbox 레코드.
- S-2 측정 방식: 백필 경로 테스트에서 WARN 로그 발생 단언 / 데이터 출처: 구조화 로그.
- S-3 측정 방식: 기존 execution/ledger 테스트 스위트 회귀 + 검토 문서 제출 여부 / 데이터 출처: 테스트 결과 + Discovery 첨부 산출물.
8. REQ로 넘기기 전 확인 체크
REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다.
- 범위(In Scope/Out of Scope) 확정
- 기준: 알람 구현 범위(OQ-1)가 In Scope/이월 중 하나로 확정 — FR-1~3는 M2 In Scope 확정, 알람 구현 범위는 design review로 Deferred(설계 분석 후 사장님 결정)
- 성공 지표의 측정 방식/데이터 출처 확정
- 기준: S-1~S-3 측정안에 사장님/팀장 이견 없음
- High 영향 리스크 우선순위 및 해소 책임자 지정
- 기준: 현재 High 리스크 없음(R-1/R-2 Medium) — design에서 R-2 결정 지점 단일화 책임자(trex-core-dev) 지정
- 모든 오픈 질문(OQ)
Open상태 없음 확인- 기준: OQ 목록에
Open상태 항목이 0개이거나, 잔여 항목 전부Deferred처리 완료 — OQ-1/OQ-2 모두 design Deferred(사장님 2026-06-21)
- 기준: OQ 목록에
- Freeze 확정 담당자(CONFIRMED_BY) 지정
- 기준: confirm-discovery 시 팀장이 CONFIRMED_BY로 기록 — 팀장(Claude)
9. 파일 처리 결과
이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다.
- 처리 결과: 생성
- 생성 경로: docs/discovery/dcy-032_20260621_fill-missing-price-cost-basis-backfill.md
- 참조 문서:
- docs/discovery/dcy-026_20260612_sell-transaction-tax-and-fee-policy.md (체결 기록·세금/수수료 인접 정책)
- docs/discovery/dcy-029_20260616_operational-observability-logging-and-pnl-view.md (운영 관측성·실현 PnL 정의)
- trex_core/application/execution.py, trex_core/adapters/broker/kis.py, trex_core/application/operator_report.py (현재 구현 근거)
10. 사용자 결정 필요 항목 요약
사용자나 승인자가 결정해야 하는 항목만 모아 정리한다.
DECIDE
- (해소→design) 알람 능력 M2 구현 포함 여부 + 채널 선택(OQ-1) — design 분석 산출물 근거로 design review에서 사장님 결정(사장님 2026-06-21).
- (해소→design) 지정가 부재 시 최종 백필 폴백 정책(OQ-2) — design 단계 trex-core-dev 분석 후 팀장 확정(사장님 2026-06-21).
CONFIRM
- (확정) 본 건 FR-1~3(무결성 가드: 지정가 백필 + 로깅)의 M2 포함 — 사장님 결정(2026-06-21).
DATA
- {{DATA_KIS_AVG_MISSING_FREQUENCY}} — 실거래에서 KIS 평균가 누락이 실제로 관측된 빈도(있다면 운영 로그/사례). 백필 폴백 정책 결정의 근거 보강용. (없으면 저빈도·고영향 가정으로 진행)
11. Discovery Freeze
REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다.
섹션 참조
- 범위: # 5. 요구사항 목록 > 범위 경계
- 리스크/오픈 질문: # 6. 리스크/가정 목록
- 성공 기준: # 7. 초기 성공 기준
- 인계 전 확인: # 8. REQ로 넘기기 전 확인 체크
- 사용자 결정 필요: # 10. 사용자 결정 필요 항목 요약
Freeze 플래그
- Handoff Decision: REQ Drafting 진행 가능
- Handoff Rationale: FR-1~3(지정가 백필+로깅) M2 포함 사장님 확정. OQ-1(알람 구현범위/채널)·OQ-2(지정가 부재 폴백) 모두 design 단계 trex-core-dev 분석 후 확정으로 Deferred 처리(사장님 2026-06-21) → Open OQ 0건. REQ 초안 작성 인계 가능.
- Ready for REQ Drafting: true
- Confirmed By: 팀장(Claude)
- Confirmed At (KST): 2026-06-21 (KST)