# 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:}`. ## 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)