`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>
6.1 KiB
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()동봉, canonicalslot_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_dictimport(단일 source of truth → BAT-007 stub 경로와 BAT-008 envelope 경로가 동일 슬롯 스키마 산출)._slot_to_dict = slot_to_dictalias 유지.trex_core/runtime/cli.py—_cmd_slots가resp["slots"](실제 슬롯 상태)를 읽어 status 포함 표시,--status를 슬롯 status 기준 client-side 필터(all/holding/buyable=idle/pending), watchdog-owned 를 slot.portfolio_id 로 결합;--statuschoices 에pending추가. 가격은entry_price(canonical 외부명) 표시._cmd_universe는assets[]유지. (REQ-032 CHG-20260608-03)docs/interface-contract.md— snapshot 응답에slots[]스키마 계약 추가(canonical shape),assets[]vsslots[]구분 명시, 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에 canonicalslots[]추가;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 일관성도 깨질 뻔해, canonicalslot_to_dict로 통일(외부명entry_price유지, dcy-012 호환).
Execution Log
- portfolio.py:
slots[]envelope 필드 +_slot_to_dict+ builder 동봉. - cli.py:
_cmd_slots가slots[]읽기·status 필터·watchdog 결합으로 정정,universe분리 유지. - 기존 테스트 4건(OLD 동작 검증)을 새 계약으로 갱신.
- 검증 수행(아래).
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.pybuild_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.mdsnapshot 응답에slots[]필드 계약 +assets[]vsslots[]구분 명시.- 필요 시
docs/runtime-flows.md보강.
M4 — 테스트/게이트
- envelope
slots[]스키마 단위(빈 배열·status enum·가격 필드 포함). slotsCLI 가 슬롯 상태(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[], clislots슬롯 상태 표시
구현 노트
- 순수 read 노출 — 슬롯 도메인/전이/워치독 판정/청산 무변경.
- 비침습: 요청은
actor="operator"/touch_watchdog=false유지(dcy-016). - 가격 노출은
slots[](operator) 한정 — strategyassets[]no-price 규칙 불변.