BAT-032 (dcy-022): timeout_sec/slippage_pct 실행 정책, 미체결 자동 취소, 보호 지정가, `trex-core cancel` 백스톱. 마이그레이션 012. BAT-033: `trex-core enter --qty` 필수 검증 — 미지정 시 RPC 전 즉시 오류. BAT-034 (dcy-023): allocated_capital 죽은 필드 전 경로 제거 (domain·intent· persistence·snapshot·CLI). 마이그레이션 013(비가역 DROP). 외부 발신자 unknown key 무시 수신 의미론 적용. REL-006 confirmed: BAT-026~034 통합 릴리즈, pre-release smoke 증거 포함. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.7 KiB
3.7 KiB
BAT-032 Planning
- Status: done
- Batch: BAT-032
Milestones
| ID | 목표 | 연결 REQ |
|---|---|---|
| M1 | 실행 정책 계약·파싱·슬롯 저장 | REQ-068, REQ-061(CHG-05) |
| M2 | slippage 보호 지정가 dispatch | REQ-070, REQ-013(CHG-03 partial) |
| M3 | timeout 집행 + race 처리 | REQ-069, REQ-013(CHG-03 partial) |
| M4 | 운영자 cancel 백스톱 CLI + control RPC | REQ-071 |
| M5 | baseline 문서 정합 | REQ-072 |
M1 상세 (실행 정책 계약·파싱·슬롯 저장)
Slot모델:timeout_sec: Optional[int],slippage_pct: Optional[float]필드 추가.EXPECTED_SLOT_FIELDS갱신.- Migration 012:
ALTER TABLE daily_slot ADD COLUMN IF NOT EXISTS timeout_sec INTEGER; ADD COLUMN IF NOT EXISTS slippage_pct FLOAT; BuyIntent/SellIntent:timeout_sec/slippage_pct추가.IntentService:__init__에default_order_timeout_sec: Optional[int] = None추가._admit_buy/_admit_sell에서 effective_timeout = intent.timeout_sec ?? config_default → transit_slot 에 전달.SlotService.transit_slotkwargs:timeout_sec/slippage_pct전달._apply_transition_fields에서 PENDING_* 진입 시 set, 탈출(→HOLDING/→INACTIVE) 시 clear.messaging_handlers.py:timeout_sec=_opt_int(body.get("timeout_sec")),slippage_pct=_opt_float(body.get("slippage_pct"))파싱 추가.DaemonInstanceConfig:default_order_timeout_sec: Optional[int] = None추가, from_toml 파싱.DaemonConfig+ daemon runtime 배선: IntentService 에 default_order_timeout_sec 전달.
M2 상세 (slippage 보호 지정가 dispatch)
execution._dispatch: limit 계산 후 slippage 적용:import math if limit is not None and slot.slippage_pct: factor = 1 + slot.slippage_pct/100 if side == "buy" else 1 - slot.slippage_pct/100 limit = int(math.ceil(limit * factor)) if side == "buy" else int(math.floor(limit * factor))_log.debug(...)로 slippage 적용 기록.
M3 상세 (timeout 집행)
ExecutionResult:timeout_cancelled: int = 0추가._poll의 else branch(_check_stale_pending호출)에서 timeout 체크 추가:self._check_stale_pending(slot, now, r) # Alert-only (REQ-014, no change) self._try_timeout_cancel(slot, now, r) # NEW: cancel if timeout_sec exceeded_try_timeout_cancel:slot.timeout_sec있고 경과 시간 초과 시 →broker.cancel_order(...)best-effort →r.timeout_cancelled += 1→ WARNING 로그. 실패 시 WARNING, 상태 불변.
M4 상세 (운영자 cancel 백스톱)
messaging_handlers.make_control_rpc_handler:cancel_pending액션 추가.cancel_pending_fn콜백(slot_id → bool) 주입.execution.ExecutionService.cancel_pending_slot(slot_id): 슬롯 조회 → PENDING_* 이면broker.cancel_order송신. 슬롯 직접 전이 없음.cli.py:cancel <slot_id>서브커맨드 추가.--dry-run/--yes/--live안전장치. control RPC 경유.- daemon.py 배선: make_control_rpc_handler 에 cancel_pending_fn 전달.
M5 상세 (baseline 문서)
docs/interface-contract.md: buy/sell payload 에timeout_sec/slippage_pct추가.docs/runtime-flows.md: 집행 루프·dispatch 섹션에 timeout 취소·slippage·cancel 백스톱 흐름 추가.
위험 요소
- R-1 (취소-체결 race): cancel_order 송신 후 즉시 롤백하지 않고 다음 poll 수렴 → 기존 is_terminal_reject/is_partial_cancel 경로 재사용 완화.
- R-2 (부분 체결 보존): timeout cancel → is_partial_cancel → 기존
_on_partial_cancel선례(dcy-013) 재사용. - R-3 (단일 writer): cancel CLI 는 cancel_order 만 송신; 슬롯 전이는 집행 루프 단독 → 불변식 보존.