Files
trex-core/docs/batches/bat-022_20260608_slot-state-snapshot-visibility/implementation.md
T
genichinandClaude Opus 4.8 63da87c9b3 fix(cli): BAT-022 slots 명령이 universe 대신 실제 슬롯 상태 표시 (dcy-016 후속)
`trex-core slots` 가 snapshot RPC 의 universe `assets`(portfolio)를 슬롯 상태로
오인 표시하던 갭 정정. snapshot envelope 이 슬롯 상태를 운반하지 않아 발생
(10개 슬롯인데 universe 1개·status 없음 — BAT-007 HTTP 슬롯 read 제거 후
슬롯 상태 read 표면 부재가 근인).

- REQ-028 (CHG-20260608-01): snapshot envelope 에 read-only per-slot `slots[]`
  additive 추가(AC-4). strategy `assets[]`(universe, no-price) 불변.
- REQ-032 (CHG-20260608-03): `_cmd_slots` 가 envelope `slots[]`(실제 슬롯 상태)
  표시 + `--status` 를 슬롯 status 기준 client-side 필터 + watchdog 결합.
  `universe` 는 `assets[]` 유지. `universe --json` 도 universe 데이터로 scope.
- canonical `portfolio.slot_to_dict` 단일화 — BAT-007 stub / BAT-008 envelope
  두 경로가 동일 슬롯 스키마(외부명 `entry_price` 유지, dcy-012 호환).
- interface-contract 에 `slots[]` 계약 + `assets[]` vs `slots[]` 구분 반영.

검증: 단위 338 passed + ruff clean + 신규 코드 데몬으로 실 PostgreSQL/RabbitMQ
운영 재현 PASS(slots=10·status·DB 일치·universe 분리·비침습). REQ-028/032
Implemented, BAT-022 release-candidate. pytest 인프라 게이트는 Human Approval
Memo 수용(운영 재현이 실 경로 커버).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 19:54:42 +09:00

6.1 KiB

BAT-022 Implementation

  • Status: in-delivery
  • Batch: BAT-022
  • Profile: standard

Changed Files

  • trex_core/application/portfolio.py — SnapshotEnvelope 에 slots: list[dict](additive) + to_dict() 동봉, canonical slot_to_dict(s)(operator-facing: slot_id/trading_date/status/symbol/qty/avg_price/entry_price/allocated_capital/strategy_id/sell_strategy_id/portfolio_id/forced_close_at), build_snapshot_envelope 가 slot_to_dict 로 slots[](전체 슬롯 테이블) 산출. (REQ-028 AC-4)
  • trex_core/application/messaging_handlers.py — 로컬 _slot_to_dict 를 제거하고 portfolio.slot_to_dict import(단일 source of truth → BAT-007 stub 경로와 BAT-008 envelope 경로가 동일 슬롯 스키마 산출). _slot_to_dict = slot_to_dict alias 유지.
  • trex_core/runtime/cli.py — _cmd_slots 가 resp["slots"](실제 슬롯 상태)를 읽어 status 포함 표시, --status 를 슬롯 status 기준 client-side 필터(all/holding/buyable=idle/pending), watchdog-owned 를 slot.portfolio_id 로 결합; --status choices 에 pending 추가. 가격은 entry_price(canonical 외부명) 표시. _cmd_universe 는 assets[] 유지. (REQ-032 CHG-20260608-03)
  • docs/interface-contract.md — snapshot 응답에 slots[] 스키마 계약 추가(canonical shape), assets[] vs slots[] 구분 명시, CLI↔RPC 매핑 행 정정(slots = slot 상태). (REQ-028/032 baseline 동기화)
  • tests/application/test_snapshot_selection.py, tests/application/test_snapshot_handler.py — envelope key set 에 slots 추가, no-price 검증을 assets[] 로 scope.
  • tests/runtime/test_cli_operator.py — _SNAPSHOT 에 canonical slots[] 추가; slots 가 universe 가 아닌 슬롯 상태 표시·--status 슬롯 status 필터·watchdog 결합 테스트로 갱신.

Post-verification 보정 (BAT-022 범위 내, REQ-032)

  • 운영 사용 중 발견: universe --json 이 envelope 전체(assets + 신규 slots[] + watchdog[] + meta)를 덤프해 출력이 과다. envelope 에 slots[] 를 추가한 부수효과 — universe 는 universe(assets)만 보여야 함.
  • 수정: trex_core/runtime/cli.py _cmd_universe 의 json 을 {instance, view, assets, available_slots, degraded, reason} 로 scope(slots[]/watchdog[] 제외 — slots 명령 소관). slots --json 은 이미 {instance, status, slots} 로 scope 되어 일관.
  • 검증: 신규 단위 tests/runtime/test_cli_operator.py::test_universe_json_is_scoped_to_universe(키셋·누출 없음) + 라이브 trex-core universe --json → keys={assets,available_slots,degraded,instance,reason,view}, slots/watchdog 누출 없음. cli 17 passed, ruff clean.

검증 중 발견 (중요)

  • BAT-007 stub 경로(messaging_handlers)는 이미 _slot_to_dict 로 slots[] 를 반환하고 있었다 — 갭은 BAT-008 envelope 경로(snapshot_store 연결 시, 운영 배포)에만 존재했다(build_snapshot_envelope 이 slots 미동봉). 두 경로의 슬롯 dict 스키마가 달라 CLI 일관성도 깨질 뻔해, canonical slot_to_dict 로 통일(외부명 entry_price 유지, dcy-012 호환).

Execution Log

  1. portfolio.py: slots[] envelope 필드 + _slot_to_dict + builder 동봉.
  2. cli.py: _cmd_slots 가 slots[] 읽기·status 필터·watchdog 결합으로 정정, universe 분리 유지.
  3. 기존 테스트 4건(OLD 동작 검증)을 새 계약으로 갱신.
  4. 검증 수행(아래).

Validation

  • ruff: ruff check(변경 파일) → All checks passed.
  • 타깃 단위: pytest tests/application/test_snapshot_selection.py tests/application/test_snapshot_handler.py tests/runtime/test_cli_operator.py → 31 passed.
  • 전체 회귀: pytest -q → 338 passed, 1 failed, 34 skipped. 유일 실패 tests/adapters/broker/test_kis.py::test_sandbox_token_and_submit 는 KIS 샌드박스 env(TREX_KIS_BROKER_BASE_URL 이 live URL)에 의존하는 사전 환경 이슈로 본 변경(portfolio/cli)과 무관.

Remaining Risks

  • 인프라 게이트(실 PostgreSQL/RabbitMQ)·운영 재현(trex-core slots 가 실제 슬롯 N개 status 표시)은 verification 단계에서 확인 필요.
  • KIS 샌드박스 env 테스트 실패는 본 batch 범위 밖(환경 설정) — verification 에서 분리 기록.

구현 단계

M1 — REQ-028 envelope slots[]

  • trex_core/application/portfolio.py build_snapshot_envelope 에 slots[] 산출 추가.
    • _slot_to_dict(slot) 헬퍼: {slot_id, status, symbol, qty, limit_price, avg_price, portfolio_id} 매핑(없는 값 null).
    • slot_repo.list_slots(trading_date) 순회 → slots 리스트, to_dict() payload 에 "slots" 동봉. 빈 배열 [].
  • assets[]/meta/watchdog[]/degraded 불변 확인.

M2 — REQ-032 CLI slots

  • trex_core/runtime/cli.py _cmd_slots:
    • slots = resp.get("slots", []) 로 변경(기존 assets).
    • --status → 슬롯 status 필터 매핑(all/holding(held)/buyable(idle)/pending).
    • 출력: count=len(slots) + 슬롯별 slot_id status symbol qty price portfolio_id + watchdog-owned 태그(portfolio_id 매칭).
    • --json 경로 유지.
  • _cmd_universe 무변경(assets[] 유지) 확인.

M3 — 문서

  • docs/interface-contract.md snapshot 응답에 slots[] 필드 계약 + assets[] vs slots[] 구분 명시.
  • 필요 시 docs/runtime-flows.md 보강.

M4 — 테스트/게이트

  • envelope slots[] 스키마 단위(빈 배열·status enum·가격 필드 포함).
  • slots CLI 가 슬롯 상태(status 포함) 표시, universe(assets[])와 구분.
  • --status 필터 케이스(idle/holding/pending).
  • 전체 회귀 + ruff + 인프라 게이트 green.

변경 파일 (예상)

  • trex_core/application/portfolio.py (build_snapshot_envelope, _slot_to_dict)
  • trex_core/runtime/cli.py (_cmd_slots)
  • docs/interface-contract.md
  • tests: snapshot envelope slots[], cli slots 슬롯 상태 표시

구현 노트

  • 순수 read 노출 — 슬롯 도메인/전이/워치독 판정/청산 무변경.
  • 비침습: 요청은 actor="operator"/touch_watchdog=false 유지(dcy-016).
  • 가격 노출은 slots[](operator) 한정 — strategy assets[] no-price 규칙 불변.