# BAT-011 Verification - Status: verified - Batch: BAT-011 ## Acceptance Mapping ### REQ-037 (forced_close_at 만기 자동 매도 루프) | AC | Evidence | |----|---------| | AC-1: 만기+워치독 만료 → sell() | `test_safety_sell_worker.py::TestForcedClose::test_expired_past_due_sells` | | AC-2: 미만기(now+1h) → 미호출 | `test_future_not_due_no_sell` | | AC-3: 워치독 활성 → 미호출(보호) | `test_watchdog_active_protected` | | AC-4: forced_close_at None → 제외 | `test_no_forced_close_excluded` | | AC-5: pending_sell 중복 미호출 | `test_idempotent_on_pending_sell` (transition_log PENDING_SELL 1건) | | AC-6: interval 주기 | `TestRunOnce::test_base_tick_is_finest_interval` + `safety_sell.base_tick_sec`/`run_once` `_due` 캐던스(코드) | | grace 보호 | `test_grace_period_defers` | ### REQ-038 (stop-loss·take-profit KIS polling + 트리거) | AC | Evidence | |----|---------| | AC-1: stck_prpr ≤ stop_loss → 손절 | `TestPriceTriggers::test_stop_loss_triggers` | | AC-2: stck_prpr ≥ take_profit → 익절 | `test_take_profit_triggers` | | AC-3: 두 조건 미충족 → 미호출 | `test_neither_condition_no_sell` | | AC-4: 워치독 활성 → KIS 호출 0 | `test_watchdog_active_no_kis_call` (broker.calls == []) | | AC-5: 임계값 None → 제외 | `test_no_thresholds_excluded` | | AC-6: pending_sell 중복 미호출 | `test_idempotent_on_pending_sell` | | AC-7 (CHG-04): 시세 tr `FHKST01010100`(실전/모의 공용) + stck_prpr | `test_kis_price.py::test_tr_price_is_quotations_tr` + `test_get_current_price_parses_stck_prpr`; **실 KIS LIVE 검증**: `get_current_price('005930')=Decimal('329000')`(rt_cd=0). 구 `TTTC8397R` 는 LIVE rt_cd=1 "없는 서비스 코드" 로 폐기 | | AC-8: 시간당 호출 ≤ N×(3600/interval) | `test_quota_estimate`(N=3,interval=30→360) + `test_only_eligible_slots_polled`(워치독 만료+임계 슬롯만 poll) | | 가격 미수신 → skip | `test_price_unavailable_skips` | ### REQ-039 (장 마감 강제 청산) | AC | Evidence | |----|---------| | AC-1: 시각 도래 → 전체 holding sell() | `TestMarketClose::test_time_reached_liquidates_all` | | AC-2: 워치독 활성 포함 청산 | `test_watchdog_active_included` | | AC-3: 미설정 → 미동작 | `test_not_configured_no_sell` | | AC-4: 거래일 1회 발동 가드 | `test_once_per_day_guard` | | AC-5: pending_sell 중복 미호출 | REQ-036 idempotency(`SlotService.sell`) — `test_service_sell.py::test_sell_idempotent_on_pending_sell` 승계, 청산 경로 동일 sell() 사용 | | AC-6: grace period 무관 청산 | `test_grace_period_does_not_block` | | 발동 시각 이전 → 미동작 | `test_before_time_no_sell` | ### REQ-040 (update_thresholds intent RPC) | AC | Evidence | |----|---------| | AC-1: stop_loss_price 갱신 | `test_update_thresholds_handler.py::test_updates_stop_loss` | | AC-2: take_profit + forced_close 갱신 | `test_updates_take_profit_and_forced_close` | | AC-3: last_seen_at 리셋 | `test_resets_watchdog_last_seen` | | AC-4: 부분 갱신(미포함 유지) | `test_partial_update_keeps_other_fields` | | AC-5: null → 해제 | `test_explicit_null_clears` | | AC-6: non-holding → ignored/not_holding | `test_non_holding_ignored` | | AC-7: reply_to → updated 응답 | `test_reply_updated_status` | | 미존재 슬롯 → ignored/slot_not_found | `test_unknown_slot_ignored` | ### REQ-042 (baseline 문서 정합) | AC | Evidence | |----|---------| | AC-1: interface-contract update_thresholds 계약 | `docs/interface-contract.md` `trex.intent.req update_thresholds 액션` 블록 + Patterns 행 | | AC-2: interface-contract price 선택 필드 | buy payload 에 `stop_loss_price`/`take_profit_price` 추가 | | AC-3: runtime-flows 4종 흐름 | `docs/runtime-flows.md` 워치독 갱신/forced_close/가격 체크/장 마감 흐름 4종 추가 | | AC-4: runtime-flows A-5 주석 갱신 | broker degrade 흐름의 "A-5 미구현" → dcy-007 REQ-037~041 해소로 갱신 | | AC-5: project-structure trex-safety-sell 스레드 | `docs/project-structure.md` 7 스레드 목록 + safety_sell.py/watchdog.py 모듈 + 변경 로그 | ## Evidence - Test: - 신규 테스트 38종 green (test_kis_price 7 + test_safety_sell_worker 23 + test_update_thresholds_handler 8). - 단위 전체 회귀: `236 passed / 23 skipped`(`::test_sandbox_token_and_submit` deselect — `.env=LIVE` 산물). - 인프라 게이트(PG trex_core_test + RabbitMQ): `259 passed`(마이그레이션 001~004 적용 + PG repo round-trip 포함). - `ruff check trex_core tests` → All checks passed. - Manual: - 없음(트리거 로직은 결정적 단위 테스트로 커버; 실 KIS 라이브 트리거는 운영 실증 이월). - Logs: - `236 passed, 23 skipped, 1 deselected in ~0.8s` / `259 passed ... in ~11s`. ## Carried-Over Items - BAT-010 R-2 (실 PostgreSQL `004_add_price_thresholds.sql` round-trip): **해소** — 인프라 게이트 259 passed(마이그레이션 적용 + PG repo 테스트 green)로 확인. - 운영 실증 이월(차기 거래일): stop-loss·take-profit·forced_close·장 마감의 실 KIS 라이브 트리거 1건 관찰. 휴장/운영 제약으로 본 batch 는 mock·정적 검증까지. release feedback 으로 추적. ## Result - Ready for Release: true - Blocking Issues: - 없음. 잔여(실 KIS 라이브 트리거 운영 실증)는 blocker 아님 — paper/mock 결정적 검증 + KIS 어댑터 tr_id/파싱 단위 검증으로 release gate 충족. 차기 거래일 운영 관찰로 보강(REL feedback).