Files
trex-core/docs/batches/bat-012_20260607_kill-switch-control/design.md
T

5.3 KiB

BAT-012 Design

  • Status: confirmed
  • Batch: BAT-012

Architecture Summary

BAT-012 는 운영자 비상 정지(kill-switch)를 기존 인프라 위에 추가한다.

  1. 제어 채널 일원화 (trex.control.req): 기존 trex.pause.req 단일 목적 큐를 action discriminator 기반 제어 채널로 확장. make_control_rpc_handler 가 pause/resume/list(REQ-032 위임) + kill_switch(REQ-045) + resume_kill_switch(REQ-046)를 분기. daemon 의 pause consumer 스레드를 control consumer 로 교체(스레드 수 7 불변).
  2. day-scoped 제외 store (killswitch_exclusion + PostgreSQLKillSwitchStore): (portfolio_id, trading_date) 키. snapshot_pause(영구 pause)와 분리. list_excluded(today) 가 당일 항목만 반환 → day-scoped 자동 복귀.
  3. kill_switch 실행: 범위별 holding 조회 → 순차 SlotService.sell() → 당일 제외 표시 → 이력 로깅. dcy-007 safety-sell 과 독립(REQ-036 idempotency 로 충돌 무해).
  4. masking 합성 + resume: snapshot envelope masking 에 killswitch_today 추가. resume_kill_switch 가 day-scoped 제외 row 삭제(청산된 슬롯은 비가역).

Changed Areas

  • Docs:
    • docs/interface-contract.md — 제어 채널 trex.control.req + action 목록 + kill_switch/resume_kill_switch payload/응답 + masking 소스 (REQ-047)
    • docs/runtime-flows.md — kill-switch 발동/masking/자동복귀/resume 흐름 (REQ-047)
    • docs/project-structure.md — control consumer + killswitch_exclusion 테이블/store + 005 sql (REQ-047)
  • Modules:
    • trex_core/adapters/messaging/topology.py — CONTROL_REQ_QUEUE = "trex.control.req" (PAUSE_REQ_QUEUE 대체/별칭)
    • trex_core/application/messaging_handlers.py — make_control_rpc_handler(action dispatch) + kill_switch / resume_kill_switch handler
    • trex_core/adapters/persistence/sql/005_create_killswitch_exclusion.sql (신규)
    • trex_core/adapters/portfolio/killswitch_store.py — PostgreSQLKillSwitchStore
    • trex_core/application/portfolio.py(envelope builder) — masking 소스에 list_excluded(today) 추가
    • trex_core/application/killswitch.py(신규, 후보) 또는 domain/slot/service.py — 범위별 holding 순차 sell() 진입점
    • trex_core/runtime/daemon.py — pause consumer → control consumer 교체 + killswitch_store 배선 + snapshot/control handler 주입
  • Interfaces:
    • trex.control.req action 계약: pause|resume|list|kill_switch|resume_kill_switch
    • kill_switch payload {action, scope: portfolio|global, portfolio_id?, actor?} → {status, scope, portfolio_id?, liquidated}
    • resume_kill_switch payload {action, scope, portfolio_id?, actor?} → {status, scope, portfolio_id?}
    • KillSwitchStore.exclude/clear/list_excluded(trading_date)

Key Decisions (초안 — 구현 전 확정 대상)

  1. 제어 큐 전환 방식: trex.control.req 단일 채널로 일원화. 기존 trex.pause.req 하위호환은 (a) 별칭 큐 동시 선언 유지 vs (b) control.req 단일화 + 클라이언트 갱신 중 택1 — release rollout 영향이라 확정 필요(R-1). 기본안: control.req 단일화(RPC pause 사용처는 전략/운영 한정, CLI 무영향).
  2. 전역 제외 표현: killswitch_exclusion.portfolio_id = '*' sentinel(기본안) vs scope 컬럼 분리. masking 소비처(REQ-046)와 계약만 일치하면 됨. 기본안: '*' sentinel + list_excluded 가 sentinel 포함 시 전체 마스킹 신호로 반환.
  3. kill_switch 실행 진입점: 신규 application/killswitch.py(범위별 holding 조회 + 순차 sell() + store exclude + 로깅)로 분리(기본안). domain service 는 단일 슬롯 책임 유지, 복수 슬롯 오케스트레이션은 application 계층.
  4. trading_date 기준: 데몬 기존 관례(UTC date) 사용 — REQ-045 표시·REQ-046 조회·자동복귀 모두 동일 키. (safety-sell _trading_date(now) 와 일치)
  5. dcy-007 독립성: kill_switch 는 safety-sell worker 스레드와 상태/락 공유 없음. 동일 슬롯 동시 sell() 은 REQ-036 PENDING_SELL idempotency 로 1회만 전이.

Edge Cases

  • kill_switch scope=portfolio + portfolio_id 누락 → {status:error, reason:portfolio_id_required}.
  • 대상 중 이미 pending_sell → sell() 건너뜀(idempotent), liquidated 카운트에서 제외 여부는 구현 결정(기본: 신규 전이만 카운트).
  • resume_kill_switch 후 이미 청산된 슬롯 → 상태 불변(매도 비가역). resume 은 제외 row 만 삭제.
  • 다음 거래일 → list_excluded(D+1) 에 전일 row 미포함 → 자동 복귀(별도 동작 불필요).
  • 데몬 재시작(같은 거래일) → store 영속 → masking 유지(NFR-3).
  • unknown action → {status:error, reason:unknown_action:<a>}.

Architecture Impact

  • runtime-flows: 제어 채널 + kill-switch 4흐름 추가 — REQ-047 에서 문서화.
  • project-structure: control consumer 전환 + 신규 store/테이블/sql — REQ-047 에서 문서화.
  • interface-contract: pause→control 채널 계약 갱신 — REQ-047.

Reference Doc Update Plan

  • interface-contract.md: 제어 채널 action 목록 + kill_switch/resume_kill_switch 계약 + masking 소스 (REQ-047 AC-1/2)
  • runtime-flows.md: 발동/masking/자동복귀/resume 흐름 (REQ-047 AC-3)
  • project-structure.md: control consumer + killswitch_exclusion/store + 005 sql (REQ-047 AC-4)