# BAT-010 Verification - Status: verified - Batch: BAT-010 ## Acceptance Mapping ### REQ-041 (SafetySellConfig env vars) | AC | Evidence | |----|---------| | AC-1: 기본값 120/60/60/30/None | `test_safety_sell_config.py::test_safety_sell_config_defaults` — 5개 기본값 모두 assert | | AC-2: TREX_WATCHDOG_TIMEOUT 파싱 | `test_safety_sell_config_env_tuning` — 180 파싱 확인 | | AC-3: TREX_WATCHDOG_GRACE_PERIOD 파싱 | 동일 테스트 — 90 파싱 확인 | | AC-4: TREX_FORCED_CLOSE_CHECK_INTERVAL 파싱 | 동일 테스트 — 45 파싱 확인 | | AC-5: TREX_STOP_LOSS_POLL_INTERVAL 파싱 | 동일 테스트 — 15 파싱 확인 | | TREX_MARKET_CLOSE_LIQUIDATION_TIME Optional | `test_safety_sell_config_env_tuning` "15:30" 파싱 + `test_market_close_liquidation_time_empty_string_becomes_none` None 변환 | ### REQ-035 (stop_loss_price / take_profit_price 필드) | AC | Evidence | |----|---------| | AC-1: 기본값 None | `test_price_threshold_fields.py::test_price_fields_default_to_none` | | AC-2: Decimal 저장·조회 round-trip | `test_price_fields_set_on_pending_buy` — Decimal("48000") round-trip via in-memory repo | | AC-3: 마이그레이션 멱등성 | `004_add_price_thresholds.sql` `IF NOT EXISTS` 패턴. 실 PostgreSQL round-trip은 Remaining Risks R-2 참조 | | AC-4: 매수 intent payload 포함 시 저장 | `test_price_fields_preserved_through_holding` — pending_buy→holding 전이 후 price fields 유지 | | AC-5: 미포함 시 None | `test_no_price_fields_sets_none` | | 계약 가드 | `test_contract.py::test_slot_fields_match_expected_contract` — EXPECTED_SLOT_FIELDS 포함 확인 | ### REQ-034 (per-slot WatchdogStore) | AC | Evidence | |----|---------| | AC-1: snapshot RPC 처리 시 holding slot last_seen_at 갱신 | `test_snapshot_rpc_watchdog.py::test_holding_slot_watchdog_updated_on_snapshot_rpc` | | AC-2: timeout 초과 슬롯 만료 판정 | `test_watchdog.py::TestIsExpired::test_old_update_is_expired` (200s > 120s timeout) | | AC-3: timeout 미초과 슬롯 비만료 | `test_just_within_timeout_not_expired` (100s < 120s timeout) | | AC-4: grace period 중 만료 유예 | `test_grace_period_defers_expiry_check` — in_grace_period+is_expired 조합 패턴 검증 | | AC-5: 재시작 시 store 초기화 | `test_new_store_is_empty` | | AC-6: 정상 poll 주기 슬롯 비만료 | `test_recently_updated_slot_not_expired` — update 직후 is_expired=False | | holding만 갱신, idle은 제외 | `test_idle_slot_watchdog_not_updated` | | 복수 holding 슬롯 모두 갱신 | `test_multiple_holding_slots_all_updated` | | backward compat (watchdog_store=None) | `test_no_watchdog_store_does_not_raise` | ### REQ-036 (SlotService.sell() + idempotency) | AC | Evidence | |----|---------| | AC-1: holding → pending_sell 전이 | `test_service_sell.py::test_sell_holding_transitions_to_pending_sell` | | AC-2: pending_sell 중복 호출 → 무전이 | `test_sell_idempotent_on_pending_sell` — transition_log PENDING_SELL 항목 1건만 확인 | | AC-3: idle 호출 → 오류, 상태 불변 | `test_sell_idle_slot_raises_transition_error` | | AC-4: execution 경로 재사용 | `test_sell_records_transition_log` — transit_slot 기반으로 log append 확인 | | AC-5: transport 독립 | `sell()` 구현이 RabbitMQ 의존 없는 service.transit_slot() 직접 호출 — 코드 검사로 확인 | | SlotNotFoundError | `test_sell_unknown_slot_raises_not_found` | | price fields 보존 | `test_sell_preserves_stop_loss_price` | ## Evidence - Test: - 신규 테스트 32종 all green (pytest 출력 확인) - `tests/domain/ + tests/runtime/ + 대상 tests/application/` 회귀 95 passed - `test_contract.py` 통과 — EXPECTED_SLOT_FIELDS 계약 유지 - Manual: - 없음 (단위 테스트로 모든 AC 커버) - Logs: - `32 passed in 0.09s` (신규 테스트 단독) - `95 passed in 0.13s` (회귀 포함) ## Architecture Impact Note - BAT-010은 project-structure.md / runtime-flows.md 업데이트를 BAT-011 REQ-042에 위임 - design.md Reference Doc Update Plan과 일치: 현 batch는 구현 evidence 확보 범위 - `test_daemon_no_http_surface` 기존 실패는 httpx 미설치 환경 이슈로 BAT-010 변경과 무관 ## Result - Ready for Release: true - Blocking Issues: - R-2: 실 PostgreSQL migration round-trip 미검증 — `IF NOT EXISTS` 패턴으로 안전성 확보, BAT-011 환경에서 검증 예정. release gate에서는 수용(additive-only schema 변경, 기존 row 영향 없음).