# 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의 미세 조정이 아니라 독립 주기로 추적하는 편이 명확하다. # 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:424` `price = 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건뿐). - 기대 상태 - 체결됐는데 브로커 평균체결가가 없거나 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 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. - [x] 범위(In Scope/Out of Scope) 확정 - 기준: 알람 구현 범위(OQ-1)가 In Scope/이월 중 하나로 확정 — FR-1~3는 M2 In Scope 확정, 알람 구현 범위는 design review로 Deferred(설계 분석 후 사장님 결정) - [x] 성공 지표의 측정 방식/데이터 출처 확정 - 기준: S-1~S-3 측정안에 사장님/팀장 이견 없음 - [x] High 영향 리스크 우선순위 및 해소 책임자 지정 - 기준: 현재 High 리스크 없음(R-1/R-2 Medium) — design에서 R-2 결정 지점 단일화 책임자(trex-core-dev) 지정 - [x] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - 기준: OQ 목록에 `Open` 상태 항목이 0개이거나, 잔여 항목 전부 `Deferred` 처리 완료 — OQ-1/OQ-2 모두 design Deferred(사장님 2026-06-21) - [x] 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. 요구사항 목록 > 범위 경계](#5-요구사항-목록) - 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록) - 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준) - 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크) - 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#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)