# BAT-016 Implementation - Status: completed - Batch: BAT-016 ## 구현 요약 - dcy-012 매도 가격 버그(issue #10)를 슬롯 `entry_price`→`limit_price` rename + clear-on-exit 생애주기 + dispatch 단일 필드 결정으로 정정. 전부 change-req(신규 REQ 없음). ## 변경 내역 ### REQ-002 — 슬롯 도메인 rename + 생애주기 - `trex_core/domain/slot/models.py`: `Slot.entry_price` → `limit_price`(주석: side 무관 pending 주문 지정가, clear-on-exit); `EXPECTED_SLOT_FIELDS` 의 entry_price → limit_price. - `trex_core/domain/slot/service.py`: - `transit_slot`/`_apply_transition_fields` 파라미터 `entry_price` → `limit_price`. - IDLE reset 분기: `entry_price=None` → `limit_price=None`. - generic 경로: `to_state ∈ {PENDING_BUY, PENDING_SELL}` 면 set(입력 or 유지), 아니면(HOLDING/CLOSED) `new_limit_price=None` clear. - `SlotService.sell(..., *, limit_price=None)` 추가 → transit_slot 에 전달. ### REQ-013 — dispatch 단일 필드 - `trex_core/application/execution.py::_dispatch`: `limit = int(slot.limit_price) if slot.limit_price else None`(side 분기/entry_price 재사용 제거). order_type 은 limit 유무로 "00"/"01". ### REQ-007 — sell intent 가격 - `trex_core/application/intents.py`: `SellIntent.limit_price: Optional[float] = None`; `_admit_sell` → `transit_slot(..., limit_price=intent.limit_price)`; `_admit_buy` → `limit_price=intent.entry_price`(BuyIntent.entry_price 외부 필드 유지). - `trex_core/application/messaging_handlers.py`: sell 핸들러 `limit_price=_opt_float(body.get("limit_price"))`; buy payload `entry_price` 유지; `_slot_to_dict` 외부 키 `"entry_price"` 유지하되 `s.limit_price` 매핑(NFR-3). ### REQ-036 — 자동 매도 시장가 - `SlotService.sell` optional `limit_price`(default None) → safety-sell/kill-switch 자율 매도는 가격 미전달 → 시장가. ### REQ-006 — 마이그레이션 + persistence - `trex_core/adapters/persistence/sql/006_rename_entry_price_to_limit_price.sql`(신규): idempotent DO-block rename(컬럼 존재 && 신컬럼 부재 시에만). 순수 rename → 데이터 보존. - `trex_core/adapters/persistence/postgresql.py`: `_SLOT_COLUMNS`/update_slot SQL+바인딩/_row_to_slot 의 entry_price → limit_price. ### REQ-003 — 컬럼 계약 가드 - `EXPECTED_SLOT_FIELDS` rename 으로 `test_contract.py`/`test_migration_and_drift.py` 자동 반영(상수 참조). PG 게이트에서 실 컬럼 limit_price 검증. ### REQ-015 — baseline 문서 - `docs/runtime-flows.md`: dispatch 가격 결정(slot.limit_price 단일 필드) + limit_price 생애주기 set/clear. Last Updated → BAT-016. - `docs/interface-contract.md`: sell payload optional limit_price + ORD_DVSN 매핑. Last Updated → BAT-016. - `docs/data-model.md`: 슬롯 limit_price 컬럼 의미/생애주기. Last Updated → BAT-016. ## 테스트 - 신규 `tests/application/test_sell_pricing.py`(recording paper broker): 4건 — (a) 지정가 매수+시장가 매도(entry_price 미사용), (b) 지정가 매수+지정가 매도, (c) SlotService.sell 시장가+closed, (d) 시장가 매수 매도 회귀. - `tests/domain/slot/test_service.py`: PENDING_BUY→HOLDING 시 `limit_price is None` 단언 추가; 두 →HOLDING 전이의 obsolete `entry_price=` 인자 제거. ## 검증 실행 - 단위: `TREX_BROKER=paper .venv/bin/python -m pytest -q` → `286 passed / 32 skipped`(`::test_sandbox_token_and_submit` deselect — LIVE `.env` 환경 의존, 본 batch 무관). - 인프라 게이트: `TREX_POSTGRESQL_TEST_DSN=...(trex_core_test) TREX_RABBITMQ_TEST_URL=... pytest -q` → `318 passed`(006 rename 마이그레이션 적용 + 컬럼 계약 limit_price + 마이그레이션 idempotency 포함). - `ruff check trex_core tests` → All checks passed.