feat: add kill-switch control flow
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user