Files
trex-core/docs/batches/bat-032_20260610_execution-policy/planning.md
T
genichinandClaude Sonnet 4.6 fb05a73130 feat(rel-006): dcy-022/023 + BAT-032~034 — 실행 정책·qty 검증·allocated_capital 제거 통합
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>
2026-06-11 07:42:03 +09:00

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_slot kwargs: 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 만 송신; 슬롯 전이는 집행 루프 단독 → 불변식 보존.