# 0. 문서 상태 이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - 상태: confirmed - 문서 ID: dcy-012_20260608_sell-order-pricing-entry-price-bug - 이슈명: 매도 주문이 현재가가 아닌 entry_price(매수가) 지정가로 나가는 버그 — sell dispatch 가격 정책 부재 - 작성 시각(KST): 2026-06-08 12:30 KST - 마지막 갱신 시각(KST): 2026-06-08 15:40 KST - 대체됨: 없음 - 후속 Discovery 참조: 없음 - 생성된 REQ 참조: REQ-013/007/036/002/006/003/015 (전부 change-req, 신규 REQ 없음 — OQ-3). REQ-007=CHG-20260608-02, 그 외=CHG-20260608-01. delivery: BAT-016 # 1. 계획 상태 요약 현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다. - 연계 문서 현황: - 관련 점수 파일: 미생성 - 관련 TODO/메모: GitHub issue #10 (fourblocks2020/trex-core), 관련 issue #9(pending_sell 갇힘) - 해석: - 매도(sell) 주문 집행 경로(`_dispatch`)가 buy/sell 구분 없이 `slot.entry_price`(매수가)를 지정가로 사용해, 매도가 현재 시장가가 아닌 매수가에 걸린 지정가 주문으로 나가는 정합성 버그를 정식 SDLC 주기로 착수한다. - 이번 Discovery에서는 sell dispatch 의 가격 결정 정책(시장가 vs 현재가 지정가 vs 인텐트 전달 가격)을 판정하고, safety-sell(자율 매도)과 RPC 재량 매도에 어떤 정책을 적용할지 범위를 정한다. 이미 Implemented·released(REL-001/003) 된 집행 경로(dcy-003 broker execution) 변경이고, 매도 지정가 운반을 위해 슬롯 `entry_price` 를 side 무관 `limit_price` 로 내부 rename(Option A) 하므로, 거버넌스는 OQ-3 결정에 따라 기존 REQ(REQ-013/007/036/002/006/003/015) `change-req` 로 처리하고 신규 REQ 는 생성하지 않는다. # 2. 요구사항 판정 결과 이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다. - 판정: 신규 - 근거 - 기존 Discovery(dcy-001~dcy-011) 중 sell dispatch 의 주문 가격 결정 정책을 다룬 문서는 없다. dcy-003(broker execution + outbox)은 `_dispatch`/주문 제출 경로를 도입했지만 buy/sell 가격 분기를 정의하지 않았고, dcy-007(safety-sell)은 손절/익절 트리거 조건과 `get_current_price` 평가를 다루되 집행 시 매도 주문 가격을 재정의하지 않았다. dcy-010(영속 거부 backoff)은 거부 재시도만 다룬다. - 변경이 이미 Implemented·released 된 집행 경로(`_dispatch`)의 주문 가격/주문유형(지정가 vs 시장가) 의미를 바꾸고, 매도 인텐트 계약(`SellIntent`)에 optional 가격 필드를 추가하므로, 기존 Discovery 미세 조정이 아니라 독립 주기로 추적하는 것이 명확하다. # 3. 문제점의 요약 문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다. - 현재 상태 - `trex_core/application/execution.py` 의 `_dispatch`(execution.py:84~)는 `side = "buy" if PENDING_BUY else "sell"` 로 side 를 구하지만, 바로 다음 `limit = int(slot.entry_price) if slot.entry_price else None`(execution.py:91)에서 side 를 무시하고 buy/sell 공통으로 `entry_price`(매수가)를 지정가로 쓴다. `order_type` 은 `"00"(지정가) if limit is not None else "01"(시장가)`(execution.py:99)로 결정되므로, 매도도 매수가에 걸린 지정가 주문으로 나간다. - 버그의 발현은 슬롯의 매수 유형에 의존한다. `entry_price` 는 지정가 매수일 때만 채워지고 시장가 매수에서는 NULL 로 남으며(체결가는 `avg_price` 에만 기록, 매수 체결 시 `entry_price` 미갱신), 매수 후에는 `_dispatch` 의 limit 계산이 유일한 행위적 소비처다. 따라서 (a) 지정가 매수로 진입한 슬롯은 매도 시 `entry_price`(매수가)로 지정가 매도가 나가 버그가 발현되고, (b) 시장가 매수로 진입한 슬롯은 `entry_price=NULL → limit=None → order_type="01"` 로 우연히 시장가 매도가 나가 정상 동작한다. 즉 issue #10 은 지정가 매수 슬롯에서 재현된다. - `trex_core/application/intents.py` 의 `SellIntent`(intents.py:68~)는 `intent_id/slot_id/reason/sell_strategy_id/extra` 만 가지며 가격 필드가 없다. `_admit_sell`(intents.py:193~)은 `HOLDING → PENDING_SELL` 상태 전이만 수행하고 가격 파라미터를 넘기지 않아, 슬롯의 `entry_price` 는 매수 때 값 그대로 유지된다. - `trex_core/application/broker_port.py` 의 `get_current_price(symbol)`(broker_port.py:94)는 존재하지만 `_dispatch` 에서 호출되지 않는다. 현재 이 메서드는 safety-sell 워커의 손절/익절 평가에서만 쓰인다(`trex_core/application/safety_sell.py:182`). - `trex_core/domain/slot/models.py` 의 Slot 은 `avg_price`(매수 체결가, models.py:27)·`entry_price`(매수 지정가, models.py:28)만 가지며 매도 시점 시장가를 담을 필드가 없다. - `docs/interface-contract.md`(92행)의 sell payload 계약은 `{intent_type:"sell", intent_id, slot_id, reason, sell_strategy_id}` 로, 가격 필드가 없다(현 코드와 일치). - baseline 문서(`docs/project-structure.md`, `docs/runtime-flows.md`)는 존재하며 최신이다. sell 집행은 기존 runtime flow(주문 dispatch)에 포함돼 있고, 이번 변경은 그 흐름의 매도 가격 결정 단계를 정정한다. - 기대 상태 - 매도(`pending_sell`) 집행 시 매수 지정가가 아니라 OQ-1 하이브리드 정책에 맞는 가격으로 주문이 나간다 — 인텐트가 가격을 지정하면 그 지정가, 미지정이면 시장가. (현재가 자동 조회 지정가는 미채택.) - 손절(stop-loss) 상황에서는 가격 미전달로 시장가 매도가 나가 의도대로 체결되어, 미체결 매도가 `pending_sell` 에 갇히는 문제(issue #9)의 직접 원인이 제거된다. - 이해관계자 - 문서 작성자(AI agent) — Discovery/REQ/Batch 산출물 작성 - 리뷰어/승인자 — 매도 가격 정책 및 집행 경로 변경 승인 - 운영 담당자 — released 집행 경로 변경에 따른 실거래 영향 관리 - 전략 모듈 개발자 — 재량 매도(RPC) 인텐트 호출부 변경 가능성 - 제약사항 - 이미 released(REL-001/003) 된 집행 경로 변경이므로 ad-hoc 수정이 아니라 정식 SDLC(change-req 또는 신규 REQ) 경유가 필요하다. - KIS 주문 계약상 `ORD_DVSN`(00 지정가 / 01 시장가)과 `ORD_UNPR` 의미가 정해져 있어, 매도 가격 유무가 곧 주문유형·가격 필드 매핑을 결정한다. ## 주요 사용자 시나리오 사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다. - safety-sell 워커가 손절 조건(현재가 < stop_loss_price)으로 매도를 트리거했는데, 집행이 매수가 지정가로 나가 체결되지 않고 슬롯이 `pending_sell` 에 갇힌다 → 정책에 맞는 가격으로 즉시 체결되어야 한다. - 전략 모듈이 RabbitMQ 로 재량 매도(sell intent)를 보내면, 현재 시장가 기반으로 매도가 집행되어 의도한 청산이 이뤄진다. - 현재가가 매수가보다 높은 상황에서 매도 시, 매수가에 걸린 불리한 지정가가 아니라 시장가(또는 인텐트가 지정한 가격)로 체결되어 손실 없이 청산된다. # 4. 이번에 정의할 변경 이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다. 기능, 구조, 규칙 변경을 함께 포함해도 된다. - 슬롯의 매수 전용 `entry_price` 를 **side 무관 "현재 pending 주문 지정가" 단일 필드(내부 rename: `limit_price`)** 로 재정의한다. pending 진입 시(매수: buy intent 지정가 / 매도: sell intent optional 가격) set 하고, pending 이탈(→HOLDING, →CLOSED) 시 None 으로 clear 한다(매수 지정가의 매도 누수 = #10 근본 원인을 구조적으로 차단). 감사 이력은 기존처럼 transition_log 가 보존한다. - `_dispatch` 는 side 분기로 가격을 고르지 않고 `slot.limit_price` 하나만 읽는다 — 값이 있으면 지정가(`order_type="00"`), 없으면 시장가(`order_type="01"`)(OQ-1 하이브리드). - `SellIntent`/sell payload 에 optional 매도 가격 필드를 추가하고, `_admit_sell`(및 `SlotService.sell` optional 파라미터)이 그 가격을 슬롯 `limit_price` 로 운반한다. safety-sell/kill-switch 는 가격 미전달 → 시장가. - 인터페이스 계약 문서(`docs/interface-contract.md`)와 sell 집행 runtime flow 기술을 새 정책에 맞춰 갱신한다. (단, buy/sell payload 의 외부 필드명 `entry_price` rename 은 dcy-012 범위 밖 — REQ-007/dcy-011 과 조율; 본 주기는 내부 슬롯 컬럼/도메인 필드 rename 까지.) ## 영향 범위 변경이 미칠 코드/문서/운영 범위를 명시해 REQ 정제와 batch planning에서 추정 누락을 줄인다. - 코드 영향: - `trex_core/domain/slot/models.py` — 슬롯 필드 `entry_price` → `limit_price`(side 무관 "현재 pending 주문 지정가") 내부 rename - `trex_core/domain/slot/service.py` — `transit_slot`/`_apply_transition_fields` 에서 →HOLDING·→CLOSED 시 `limit_price` 를 None 으로 clear(현 →IDLE 리셋 분기 패턴 재사용), `SlotService.sell` 에 optional 매도 지정가 파라미터 추가(safety-sell/kill-switch 미전달 → 시장가), 매수 경로는 buy 지정가를 `limit_price` 로 set - `trex_core/application/execution.py` — `_dispatch` 가 `slot.limit_price` 단일 필드만 읽어 가격/주문유형 결정(side 분기 제거, 핵심 버그 지점) - `trex_core/application/intents.py` — `SellIntent` optional 매도 가격 필드, `_admit_sell` 이 가격을 슬롯 `limit_price` 로 운반. `BuyIntent`/`_admit_buy` 의 매수 지정가도 `limit_price` 로 매핑 - `trex_core/application/messaging_handlers.py` — 외부 payload 필드명(`entry_price`)과 내부 `limit_price` 의 경계 매핑(외부 필드명 rename 은 본 주기 밖) - `trex_core/adapters/persistence/postgresql.py`, `trex_core/adapters/persistence/sql/` — 슬롯 컬럼 `entry_price` → `limit_price` rename 마이그레이션 + 매핑 갱신 - `trex_core/adapters/broker/kis.py` — `submit_order` 의 `ORD_DVSN`/`ORD_UNPR` 매핑은 OrderRequest 변경에 따라 자동 반영(직접 수정 최소) - 문서 영향: - `docs/interface-contract.md` — sell payload 매도 가격 필드 추가 및 주문유형 매핑 갱신 - `docs/runtime-flows.md` — sell 집행 흐름의 가격 결정 단계 정정 + limit_price 생애주기(set/clear) - `docs/data-model.md` — 슬롯 `entry_price` → `limit_price` 컬럼 의미/이름 갱신 - 운영 영향: - released 집행 경로의 매도 동작 변경 + 슬롯 컬럼 rename 마이그레이션 → 실거래 매도 체결 방식 변화 및 스키마 변경, 배포 전 검증·마이그레이션 절차 필요 # 5. 요구사항 목록 실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다. ## 기능 요구사항 - FR-1: 슬롯의 매수 전용 `entry_price` 를 side 무관 단일 지정가 필드 `limit_price`(내부 rename)로 재정의한다. `limit_price` 는 pending 진입 시 해당 주문(매수/매도)의 지정가로 set 되고, pending 이탈(→HOLDING, →CLOSED) 시 None 으로 clear 되어 매수 지정가가 매도로 누수되지 않는다. - FR-2: `_dispatch` 는 side 분기 없이 `slot.limit_price` 만 읽어 주문유형/가격을 결정한다 — 값이 있으면 `order_type="00"`(지정가, 그 가격), 없으면 `order_type="01"`(시장가). 매수가(과거 entry_price 의미)를 매도 지정가로 재사용하지 않는다. - FR-3: `SellIntent` 및 sell payload 계약에 optional 매도 가격 필드를 추가하고, `_admit_sell`(및 `SlotService.sell` optional 파라미터)이 이를 슬롯 `limit_price` 로 전달한다. 매수 경로는 buy 지정가를 동일 `limit_price` 로 set 한다. - FR-4: safety-sell·kill-switch(자율 매도)는 가격 미전달로 시장가, RPC 재량 매도는 가격 지정 시 지정가로 동작한다 — 단일 메커니즘(가격 유무 분기)을 모든 매도에 일관 적용한다(OQ-2). - FR-5: `docs/interface-contract.md`·`docs/runtime-flows.md`·`docs/data-model.md` 를 확정된 매도 가격 정책과 `limit_price` 생애주기(set/clear)·컬럼 rename 에 맞춰 갱신한다. ## 비기능 요구사항 성능, 운영성, 일관성, 자동화 안정성 등 기능 외 요구사항을 적는다. - NFR-1: 체결성 — 매도 트리거(특히 손절)는 가격 미전달로 시장가가 되어 의도대로 즉시 체결되고, 미체결로 `pending_sell` 에 갇히는 케이스(issue #9 연계)를 유발하지 않아야 한다. - NFR-2: 가격 안전성 — 매도가 매수 지정가에 걸려 불리하게 체결되거나 영원히 미체결되는 정합성 오류가 재발하지 않아야 한다. `limit_price` 의 clear-on-exit 로 매수 지정가가 매도 주문에 잔존하지 않아야 한다. - NFR-3: 계약 호환 — sell payload 의 매도 가격 필드는 optional 이어야 하며, 미지정(기존 호출 형태)은 시장가로 안전하게 동작해 기존 재량 매도 호출을 깨지 않아야 한다. 외부 payload/read 필드명(`entry_price`)은 본 주기에서 rename 하지 않아 기존 계약 호환을 유지한다. ## 범위 경계 이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다. - In Scope - 슬롯 `entry_price` → `limit_price` 내부 rename(도메인 모델/DB 컬럼/persistence) + pending 이탈 시 clear 생애주기 - `_dispatch` 가 `slot.limit_price` 단일 필드로 가격/주문유형 결정(side 분기 제거) - `SellIntent`/sell payload optional 가격 필드 + 슬롯 `limit_price` 운반(`_admit_sell`/`SlotService.sell`) - 인터페이스/런타임/데이터모델 문서 갱신, 슬롯 컬럼 rename 마이그레이션 - Out of Scope - buy 주문 가격 의미 변경(매수 지정가는 그대로 `limit_price` 로 set — 동작 동일, 저장 위치명만 통일) - 외부 buy/sell payload·slot read 의 필드명(`entry_price`) rename — REQ-007/dcy-011 과 조율할 별도 계약 변경 - issue #9(KIS 외부 취소 시 pending_sell 갇힘) 자체의 복구 로직 — 본 버그는 #9 의 한 원인을 제거하나, #9 의 별도 복구는 후속 이슈로 분리 - dispatch 시 현재가 자동 조회(`get_current_price`) 기반 지정가 — OQ-1 에서 미채택(급락 손절 시 재차 미체결 위험) # 6. 리스크/가정 목록 불확실성과 전제 조건을 분리해서 적는다. 리스크는 영향과 완화 방안을, 가정은 현재 판단의 전제를 기록한다. ## 리스크 - R-1 (High): released 집행 경로의 매도 동작을 바꾸므로, 정책 선택이 잘못되면 실거래 매도가 의도와 다르게 체결될 수 있다. - 완화 방안: paper-broker/스텁으로 시나리오(손절/익절/현재가>매수가/현재가<매수가) 검증 후 배포하고, change-req 로 REQ-013/007/036/002/006/003/015 변경 이력을 남긴다. - R-2 (Medium): 재량 매도가 지정가로 들어오면, 시장가가 그 지정가에 닿지 않을 때 미체결로 `pending_sell` 에 머물 수 있다(지정가의 본질적 특성). - 완화 방안: 지정가 미체결 처리(취소/재시도/타임아웃)는 기존 dispatch 폴/롤백 경로와 issue #9 복구 범위에서 다루고, 본 주기는 가격 결정 분기에 집중한다. 운영자는 재량 매도 지정가의 미체결 리스크를 인지한다. - R-3 (Low, OQ-2 결정으로 해소): reason 별 코드 차등을 두지 않고 가격 유무로 분기하므로, safety-sell 은 가격 미전달로 항상 시장가가 되어 손절 체결성이 보장되고 재량 매도만 선택적으로 지정가를 쓴다. - 완화 방안: `SlotService.sell` 의 가격 파라미터 기본값을 None(시장가)으로 두어 자율 매도 경로가 실수로 지정가를 받지 않도록 한다. - R-4 (Medium): `entry_price → limit_price` 슬롯 컬럼 rename 과 clear-on-exit 도입은 도메인/persistence/마이그레이션을 건드려, 누락 시 매수 지정가 복원이나 영속 매핑이 깨질 수 있다. - 완화 방안: 컬럼 rename 마이그레이션과 전이별 set/clear(특히 →HOLDING·→CLOSED clear, →PENDING set)를 단위 테스트로 검증하고, 외부 payload/read 필드명은 그대로 유지(경계 매핑)해 계약 호환을 보존한다. ## 가정 아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다. - A-1: dcy-011(BAT-015) 이 Implemented 되어 매수 시 `symbol` 이 항상 서버 resolve 로 슬롯에 채워지므로, 매도 dispatch 의 KIS 주문에 쓸 `slot.symbol` 이 신뢰성 있게 존재한다(가정 충족 확인됨). - A-2: safety-sell([safety_sell.py:98](trex_core/application/safety_sell.py))·kill-switch([killswitch.py:61](trex_core/application/killswitch.py))는 `SlotService.sell(slot_id, actor, reason)` 로 가격을 전달하지 않으므로, 가격 파라미터를 optional(default None)로 추가해도 자율 매도 경로는 자동으로 시장가가 된다. - A-3: 매수 주문 가격 의미는 그대로 유지된다 — buy 지정가는 동일 `limit_price` 로 set 되어 매수 동작은 변하지 않고, 슬롯 상태 전이 규칙(허용 전이 집합)도 유지된다. 변경은 가격 필드의 의미 통일(side 무관)과 pending 이탈 시 clear 추가뿐이다. - A-4: KIS 시장가 매도(`ORD_DVSN="01"`)가 paper 및 실계좌에서 정상 수용된다(DATA 로 확인). ## 오픈 질문 답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 REQ 초안 작성 이전에 확인할 질문으로 남긴다. - OQ-1: 매도 가격 정책 — (1) 시장가 매도, (2) 현재가 기반 지정가, (3) 인텐트 전달 가격 중 무엇을 채택하는가(단일 또는 조합)? - 상태: Answered (2026-06-08, 사용자 결정 — 하이브리드: 인텐트가 가격을 지정하면 지정가, 미지정이면 시장가) - 결정: `SellIntent`/sell payload 에 optional 매도 가격 필드를 둔다. 가격이 있으면 `order_type="00"`(지정가)로 그 가격에, 없으면 `order_type="01"`(시장가)로 매도한다. 매수가(`entry_price`)는 매도 가격으로 절대 사용하지 않는다. dispatch 에서 `get_current_price` 조회는 하지 않는다(옵션 2 미채택). - 반영 위치: FR-1/FR-2/FR-3, 4. 변경 항목, 영향 범위 - OQ-2: 정책 적용 범위 — safety-sell(손절/익절/긴급)과 RPC 재량 매도에 동일 정책을 적용하는가, reason 별 차등(예: 손절=시장가, 재량=지정가)을 두는가? - 상태: Answered (2026-06-08, 사용자 결정 — 가격 유무로 분기, reason 별 코드 차등 없음) - 결정: 단일 메커니즘(가격 유무 분기)을 모든 매도에 적용한다. safety-sell/kill-switch 는 `SlotService.sell(slot_id, actor, reason)` 로 가격을 전달하지 않으므로 자동으로 시장가가 되어 체결성이 보장된다. 재량 매도(RPC)만 가격을 optional 로 실어 지정가 통제를 쓸 수 있다. - 반영 위치: FR-4, A-2, R-3 - OQ-3: 거버넌스 경로 — 본 변경을 기존 REQ(dcy-003 집행 계열, sell 인텐트 계약 REQ)의 change-req 로 처리할지, 신규 REQ 로 추적할지? - 상태: Answered (2026-06-08, 사용자 결정 — change-req 우선) - 결정: 기존 Implemented REQ 본문 수정(change-req)으로 처리한다. change-req 대상 — REQ-013(주문 집행 루프: `_dispatch` 가 `slot.limit_price` 단일 필드로 결정), REQ-007(intent 제출 API: sell payload optional 매도 가격 필드), REQ-036(자동 매도 내부 경로: `SlotService.sell` optional 가격 파라미터), REQ-002(slot 순수 도메인: `entry_price→limit_price` rename + pending 이탈 clear 전이 의미), REQ-006(PostgreSQL 영속화+스키마: 컬럼 rename 마이그레이션), REQ-003(컬럼 계약 가드 테스트: 컬럼명 변경 반영), REQ-015(브로커/집행 baseline 문서 정합). 하이브리드+rename 모두 기존 REQ 범위 안에서 표현 가능하므로 신규 REQ 는 생성하지 않는다. (Option A 의 rename 으로 change-req 대상이 slot 도메인/persistence 까지 넓어짐 — 비용은 거버넌스 footprint 증가, 이득은 매수 지정가의 매도 누수 구조적 차단.) - 반영 위치: 1. 거버넌스 해석, R-1 완화 방안, 8. 확인 체크 ### 오픈 질문 처리 기준 - `Open`: 아직 답이 없고 다음 단계 진행에 영향이 있는 상태다. 문서에 유지한다. - `Answered`: 답이 확정된 상태다. 관련 본문/요구사항에 반영한 뒤 오픈 질문 목록에서는 제거하거나 resolved 기록으로 이동한다. - `Deferred`: 지금 단계에서 결정하지 않고 다음 단계 또는 후속 이슈로 넘기는 상태다. 넘길 대상과 이유를 반드시 적는다. - `Dropped`: 더 이상 유효하지 않은 질문이다. 삭제 사유를 짧게 남기고 목록에서 제거한다. # 7. 초기 성공 기준 이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. 가능하면 데이터 출처까지 연결한다. - S-1: 매도 dispatch 가 매수 지정가를 재사용하지 않음을 코드/테스트로 보장한다 — `limit_price` 가 pending 이탈 시 clear 되어, 가격 미전달 매도는 `order_type="01"`(시장가), 가격 전달 매도는 `order_type="00"`(해당 지정가)로 발행. - S-2: safety-sell 손절 트리거 시나리오(가격 미전달)에서 매도가 시장가로 정상 체결되어 `pending_sell` 갇힘이 발생하지 않는다. - S-3: `entry_price → limit_price` 컬럼 rename 마이그레이션 후 기존 슬롯 데이터가 보존되고, `limit_price` 생애주기(→PENDING set / →HOLDING·→CLOSED clear)가 의도대로 동작한다. - S-4: 변경된 매도 가격 정책·rename 이 `docs/interface-contract.md`·`docs/runtime-flows.md`·`docs/data-model.md` 에 반영되고, 코드(execution.py, intents.py, slot service/models, persistence)와 문서가 일치한다. ## 측정 방식 및 데이터 출처 각 성공 기준을 어떻게 측정할지와 어떤 데이터나 문서를 근거로 쓸지 적는다. - S-1 측정 방식: 단위/통합 테스트(가격 미전달→시장가, 가격 전달→지정가, entry_price 미사용 케이스) 통과 / 데이터 출처: `_dispatch` 테스트, paper-broker 주문 기록(OrderRequest) - 검증 필수 조건: 버그는 `entry_price` 가 채워진 **지정가 매수 슬롯**의 매도에서만 재현되므로, 검증 시나리오는 반드시 **지정가 매수(entry_price 채워짐)로 진입한 슬롯의 매도** 케이스를 포함해야 한다. 시장가 매수(entry_price=NULL) 슬롯만 테스트하면 수정 전후 모두 시장가 매도가 나가 버그를 검출하지 못한다. 권장 케이스 — (a) 지정가 매수 슬롯 + 가격 미전달 매도 → 시장가(entry_price 미사용 증명), (b) 지정가 매수 슬롯 + 가격 전달 매도 → 그 지정가, (c) 시장가 매수 슬롯 매도 → 시장가(회귀 안전성). - S-2 측정 방식: safety-sell 손절 시나리오 e2e 검증 후 슬롯 상태가 closed 로 전이 / 데이터 출처: 슬롯 상태 스냅샷, 주문/체결 로그 - S-3 측정 방식: 마이그레이션 실행 후 슬롯 행 보존 확인 + 전이별 set/clear 단위 테스트(→PENDING set, →HOLDING·→CLOSED clear) 통과 / 데이터 출처: 마이그레이션 SQL, `transit_slot` 테스트, persistence 라운드트립 - S-4 측정 방식: 코드-문서 정합 리뷰(diff 대조) / 데이터 출처: `docs/interface-contract.md`, `docs/runtime-flows.md`, `docs/data-model.md`, 변경 코드 diff # 8. REQ로 넘기기 전 확인 체크 REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다. - [x] 범위(In Scope/Out of Scope) 확정 - 기준: 매도 가격 정책(OQ-1 하이브리드)·적용 범위(OQ-2 가격 유무 분기)·거버넌스(OQ-3) 모두 확정됨 - [x] 성공 지표의 측정 방식/데이터 출처 확정 - 기준: S-1~S-4 의 테스트/검증 출처가 실제 실행 가능한 형태로 지정됨 - [x] High 영향 리스크 우선순위 및 해소 책임자 지정 - 기준: R-1(실거래 매도 동작 변경)·R-4(컬럼 rename/마이그레이션)의 change-req 대상(REQ-013/007/036/002/006/003/015)이 OQ-3 으로 확정됨. 해소 실무 책임자 배정은 REQ/batch planning 단계로 넘김(비차단). - [x] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - 기준: OQ-1~OQ-3 모두 `Answered`, `Open` 0개 - [x] Freeze 확정 담당자(CONFIRMED_BY) 지정 - 기준: Confirmed By = Justin (사람 승인자 지정 완료) # 9. 파일 처리 결과 이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다. 이후 추적과 리뷰 시 근거로 사용한다. - 처리 결과: 생성 - 생성 경로: docs/discovery/dcy-012_20260608_sell-order-pricing-entry-price-bug.md - 참조 문서: - GitHub issue #10 (fourblocks2020/trex-core) — 매도가 entry_price 지정가로 나가는 버그 - docs/discovery/dcy-003_20260604_broker-execution-and-outbox.md — `_dispatch`/주문 제출 경로 도입 근거 - docs/discovery/dcy-007_20260606_core-autonomous-safety-sell.md — safety-sell 트리거·`get_current_price` 평가 - docs/discovery/dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve.md — slot.symbol 서버 resolve 보장(가정 A-1) - trex_core/application/execution.py:84-104 — `_dispatch` 매도 가격 버그 지점(limit 줄 91) # 10. 사용자 결정 필요 항목 요약 사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. 결정, 확인, 데이터 요청을 구분해서 적는다. ## DECIDE - (없음 — OQ-1/OQ-2 확정으로 매도 가격 정책 해소) > 결정 완료(2026-06-08): OQ-1 매도 가격 정책 = 하이브리드(가격 지정 시 지정가, 미지정 시 시장가) / OQ-2 적용 범위 = 가격 유무 분기 단일 메커니즘(reason 별 차등 없음). ## CONFIRM - 없음 — 거버넌스 경로는 OQ-3 으로 확정됨(REQ-013/007/036/002/006/003/015 change-req, 신규 REQ 없음). ## DATA - (비차단) KIS 시장가 매도(`ORD_DVSN="01"`)의 paper/실계좌 수용 및 체결 특성 — REQ/delivery 단계의 acceptance/verification 에서 계측·확인할 운영 데이터(A-4). Discovery 본문만으로 FR/NFR·범위·성공 기준이 REQ 초안으로 충분하므로 confirm 차단 사유가 아니다. # 11. Discovery Freeze REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다. ## 섹션 참조 - 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록) - 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록) - 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준) - 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크) - 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약) ## Freeze 플래그 - Handoff Decision: 승인 - Handoff Rationale: confirm-discovery 완료. Option A(슬롯 `entry_price→limit_price` 내부 rename + clear-on-exit) 설계 반영. 오픈 질문 OQ-1~OQ-3 모두 Answered (매도 가격=하이브리드: 가격 지정 시 지정가/미지정 시 시장가 / 가격 유무 분기, reason 차등 없음 / 거버넌스=REQ-013/007/036/002/006/003/015 change-req, 신규 REQ 없음). C 유형 플레이스홀더 0개, 저장소 사실관계 일치(줄번호 정정 포함). DATA(KIS 시장가 매도)는 REQ/delivery 단계 계측 비차단. REQ 초안 작성 인계 가능. - Ready for REQ Drafting: true - Confirmed By: Justin - Confirmed At (KST): 2026-06-08 14:50 KST