feat(cli): dcy-016 운영자 CLI 확장 (universe/slots/enter/exit) + 워치독 억제 (BAT-020)
운영자가 조회·매수·매도를 CLI 로 수행하되 데몬 RabbitMQ RPC 로 통일해 단일 writer admission·불변식을 보존(DB 직접 쓰기 없음)하고, 운영자 조회가 전략 생존 신호로 오인되지 않게 워치독을 억제한다. 거버넌스: 전부 change-req (신규 REQ 없음, dcy-016 OQ-3). - REQ-032: CLI universe/slots(snapshot RPC) + enter(buy)/exit(sell) intent RPC + 인스턴스 라우팅(--config/--instance/default) + enter/exit 안전장치 (확인 프롬프트 기본 ON / --yes(paper) / --yes --live(이중 ack) / --dry-run) + 전 명령 --json. pause/resume 는 direct-DB 유지 - REQ-022: CLI request-reply RPC 클라이언트(call_rpc) 재사용 - REQ-021/034: snapshot 요청 워치독 억제 플래그(touch_watchdog/actor=operator) → 핸들러가 last_seen_at 갱신 스킵. 기본값 현행 유지(하위호환). 운영자 조회가 죽은 전략의 safety-sell 을 무력화하던 결함(R-4) 제거 - REQ-026: interface-contract/runtime-flows 정합 CLI 는 rpc/confirm 주입 가능(테스트 broker/DB-free). snapshot envelope 은 asset-centric 이라 exit 은 운영자 제공 slot_id 사용(slot_id 노출은 본 주기 밖). 검증: 단위 327 passed/34 skipped, 인프라 게이트(PG+RabbitMQ) 361 passed, ruff clean. 신규 test_cli_operator(14) + snapshot 워치독 억제(2). BAT-020 release-candidate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
- Baseline Seed: .stage-pilot/bootstrap/baseline.yaml
|
||||
- Status: draft
|
||||
- Owner: project maintainers
|
||||
- Last Updated (KST): 2026-06-08 (BAT-019)
|
||||
- Last Updated (KST): 2026-06-08 (BAT-020)
|
||||
- Source Discovery / Batch: bootstrap-baseline (pre-Discovery); HTTP API = dcy-002 / BAT-002
|
||||
- Primary Runtime: daemon (HTTP API) + library (slot 도메인)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
- RabbitMQ `trex.intent.req` :: 전략 모듈의 매수/매도 admission RPC (request-reply, BAT-007)
|
||||
- RabbitMQ `trex.events` :: 체결/슬롯 상태 이벤트 topic exchange (pub/sub, BAT-007)
|
||||
- RabbitMQ `trex.control.req` :: 운영자 제어 RPC — pause/resume/list + kill_switch/resume_kill_switch (request-reply, BAT-012; 구 `trex.pause.req` 확장)
|
||||
- `trex-core` CLI :: pause/resume/paused 운영 명령 (BAT-008)
|
||||
- `trex-core` CLI :: 운영 명령 — pause/resume/paused(direct-DB, BAT-008) + universe/slots/enter/exit(데몬 RPC, dcy-016/BAT-020)
|
||||
- SlotService :: 슬롯 생명주기 도메인 서비스(전이/사전할당/가용성/재진입 카운트)
|
||||
- SlotRepository (Protocol) :: 도메인 ↔ 저장소 경계 계약
|
||||
- BrokerPort (Protocol) :: 단일 브로커 세션 경계(submit/poll/cancel) + `OrderRequest`/`OrderAck`/`FillStatus`
|
||||
@@ -136,8 +136,11 @@ sell payload 는 `{"intent_type":"sell", "intent_id":..., "slot_id":..., "reason
|
||||
{ "view": "all" | "buyable" | "held" # default "all"
|
||||
"strategy_key": "<slug>" # optional, == filter on active_strategy_id
|
||||
"trading_date": "YYYY-MM-DD" # optional, default UTC today
|
||||
"touch_watchdog": bool # optional, default true (dcy-016/REQ-021)
|
||||
"actor": "operator" # optional; "operator" => touch_watchdog 강제 false
|
||||
}
|
||||
```
|
||||
- **워치독 억제(dcy-016/REQ-021/034)**: 기본(`touch_watchdog` 미지정/true)은 응답에 포함된 holding 슬롯의 워치독 `last_seen_at` 을 갱신한다(전략 폴링=생존 신호, REQ-034). `touch_watchdog=false` 또는 `actor="operator"` 면 갱신을 건너뛴다 — 운영자 CLI 조회(`universe`/`slots`)가 죽은 전략을 살아있는 것으로 오인시켜 safety-sell 을 무력화하지 않도록(R-4). 운영자 CLI 는 항상 억제 플래그를 보낸다. 기본값은 현행 유지(전략 모듈 무변경, 하위호환).
|
||||
|
||||
코어가 reply-to 큐로 보내는 응답 envelope:
|
||||
```
|
||||
@@ -160,7 +163,21 @@ sell payload 는 `{"intent_type":"sell", "intent_id":..., "slot_id":..., "reason
|
||||
```
|
||||
**No `price` field on items** (REQ-028 AC-3 / REQ-027 AC-1).
|
||||
|
||||
- 워치독 신호 (REQ-034): `trex.snapshot.req` 처리는 read-only 응답 산출에 더해, 응답에 포함된 모든 `holding` 슬롯의 워치독 `last_seen_at` 을 갱신한다. 즉 전략 모듈이 스냅샷을 폴링하는 것 자체가 해당 슬롯의 생존 신호이며, 폴링이 끊긴(워치독 만료) 슬롯만 safety-sell 트리거 대상이 된다.
|
||||
- 워치독 신호 (REQ-034): `trex.snapshot.req` 처리는 read-only 응답 산출에 더해, 응답에 포함된 모든 `holding` 슬롯의 워치독 `last_seen_at` 을 갱신한다. 즉 전략 모듈이 스냅샷을 폴링하는 것 자체가 해당 슬롯의 생존 신호이며, 폴링이 끊긴(워치독 만료) 슬롯만 safety-sell 트리거 대상이 된다. (dcy-016: `touch_watchdog=false`/`actor="operator"` 요청은 이 갱신을 건너뛴다 — 운영자 조회 제외.)
|
||||
|
||||
### 운영자 CLI ↔ RPC 매핑 (dcy-016 / REQ-032)
|
||||
|
||||
운영자 CLI 명령은 데몬 RabbitMQ RPC 로 통일된다(단일 writer admission 보존, DB 직접 쓰기 없음). 인스턴스 라우팅: `--config <toml>`(canonical, REQ-048) 또는 `--instance <key>`(단축·override), 미지정 시 `default`.
|
||||
|
||||
| CLI | RPC 큐 | payload | 비고 |
|
||||
|---|---|---|---|
|
||||
| `universe` | `trex.snapshot.req[.{instance}]` | `{view:"all", actor:"operator", touch_watchdog:false}` | 자산 목록 조회(워치독 억제) |
|
||||
| `slots [--status held\|buyable\|all]` | `trex.snapshot.req[.{instance}]` | `{view, actor:"operator", touch_watchdog:false}` | `holding`→`held` view |
|
||||
| `enter <portfolio_id> [--capital/--qty/...]` | `trex.intent.req[.{instance}]` | buy intent(`portfolio_id` 필수, symbol 서버 resolve) | 안전장치 필수 |
|
||||
| `exit <slot_id> [--price]` | `trex.intent.req[.{instance}]` | sell intent(`slot_id`, optional `limit_price`) | 가격 미지정 시 시장가 |
|
||||
| `pause/resume/paused` | (RPC 아님) | — | direct-DB 유지(OQ-3) |
|
||||
|
||||
- enter/exit 안전장치(OQ-2): 확인 프롬프트 기본 ON, `--yes`(paper 생략), **live(`broker=kis`+allow_live)는 `--yes --live` 이중 ack**, `--dry-run` 미리보기. `--json` 은 비대화형이라 enter/exit 에 `--yes` 필수(미지정 시 자동 제출 없이 에러). 모든 명령 출력에 대상 인스턴스 표시, admission 응답(`status/slot_id/reason`)을 표시하며 rejected 면 비0 종료.
|
||||
|
||||
### `trex.control.req` 제어 RPC (BAT-012 / REQ-043, REQ-032)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user