# BAT-022 Verification - Status: approved - Batch: BAT-022 - Profile: standard - Ready for Release: true (단위 green + baseline 동기화 + 실 인프라 운영 재현 PASS; pytest 인프라 게이트는 Human Approval Memo 로 수용된 CI 잔여) ## Acceptance Mapping ### REQ-028 AC-4 — envelope `slots[]` - V-1 (스키마): envelope 에 `slots[]` 포함, canonical shape(slot_id/trading_date/status/symbol/qty/avg_price/entry_price/allocated_capital/strategy_id/sell_strategy_id/portfolio_id/forced_close_at). - Evidence: `tests/application/test_snapshot_selection.py::test_envelope_shape_no_price_field`(envelope key set 에 `slots` 포함, list), `test_snapshot_handler.py::test_envelope_shape_returned`(body 에 `slots` list). → PASS - V-2 (빈 배열): 슬롯 없을 때 `slots == []`(null 아님). - Evidence: `SnapshotEnvelope.slots` default `[]` + `to_dict` 가 `list(...)`. envelope 테스트 green. → PASS - V-3 (status enum): `status` 가 SlotState 값. - Evidence: `slot_to_dict` 가 `s.status.value` 사용. → PASS - V-4 (회귀): `assets[]`(AC-1~3)·meta·degraded·`watchdog[]` 불변. - Evidence: 전체 회귀 338 passed(기존 snapshot 계약 테스트 green, no-price 는 `assets[]` 한정으로 유지). → PASS ### REQ-032 (CHG-20260608-03) — CLI `slots` - V-5 (슬롯 상태 표시): `slots` 가 universe `assets` 가 아니라 envelope `slots[]`(status 포함) 표시. - Evidence: `tests/runtime/test_cli_operator.py::test_slots_shows_real_slot_state_not_universe`(count=2, `S-1 holding`/`S-2 idle`). → PASS - V-6 (status 필터): `--status holding`/`idle`/`pending` 가 슬롯 status 기준 필터. - Evidence: `test_slots_status_filters_by_slot_status`(holding → count=1, S-2 제외). → PASS - V-7 (universe 분리): `slots`≠`universe`. - Evidence: `_cmd_universe` 는 `assets[]` 유지(코드 diff), `_cmd_slots` 는 `slots[]` 읽음; universe 테스트 green. → PASS - V-8 (watchdog 결합): expired 슬롯에 `[WATCHDOG-OWNED]` 태그(portfolio_id 매칭). - Evidence: `test_slots_marks_watchdog_owned`(watchdog_owned=1, WATCHDOG-OWNED). → PASS - V-9 (`--json`): 유효 JSON. - Evidence: `_emit(..., as_json=True)`; `--json` 경로 단위(test_cli_operator 의 기존 json 테스트 green). → PASS ### 비침습 (dcy-016 정합) - V-10: operator 요청(`touch_watchdog=false`)으로 조회 시 워치독 미갱신. - Evidence: `_cmd_slots` payload `actor="operator"`/`touch_watchdog=False`; `test_slots_shows_real_slot_state_not_universe` 가 payload 확인. → PASS ## Baseline 문서 동기화 (Architecture Impact: interface change) - `docs/interface-contract.md` — snapshot 응답 `slots[]` 스키마 + `assets[]` vs `slots[]` 구분 + CLI↔RPC 매핑 정정. → 갱신 완료(REQ-028/032 Impacted Area). - `docs/runtime-flows.md` — slot 노출 자체는 read-only(흐름 변화 없음); 추가 갱신 불요로 판단(슬롯 도메인/전이 무변경). ## 검증 명령/결과 - ruff: `ruff check`(변경 파일 5개) → All checks 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)에 의존하는 사전 환경 이슈. 본 batch(portfolio/cli/messaging_handlers/문서)와 무관(파일 미접촉). Blocking 아님(범위 밖). - skipped 34 = 인프라 게이트(`TREX_POSTGRESQL_TEST_DSN`/`TREX_RABBITMQ_TEST_URL` 미설정). ## 운영 재현 (실 PostgreSQL + RabbitMQ, 신규 코드 데몬) — PASS - 데몬을 신규 코드로 재기동(`trex-core-daemon --config config/test.toml`, PID 2965049), 토폴로지 ready 확인. - `trex-core slots --config config/test.toml` → `instance=test status=all count=10 watchdog_owned=0` + **10개 슬롯이 각각 `status`(idle)·slot_id·qty·limit·avg·pid 표시**. (이전 갭: universe 1개·status 없음) - `trex-core slots --status holding` → `count=0`(holding 없음 — 정확). 슬롯 status 필터 동작 확인(V-6 live). - `trex-core universe` → `assets=1`(portfolio 005930) — **여전히 universe 표시**. `slots` ↔ `universe` 분리 확인(V-7 live). - DB ground truth `daily_slot`: `(2026-06-08, 'idle', 10)` — CLI `slots` 출력과 **정확히 일치**. (V-5 live) - 요청은 `actor="operator"`/`touch_watchdog=false`(CLI 기본) — 비침습(V-10 live). - → **보고된 갭(universe 표시·status 없음) 해소 실증 완료**. BAT-008 envelope 경로(snapshot_store 연결, 운영 배포)를 실 인프라로 end-to-end 검증. ## Remaining (non-blocking) - **pytest 인프라 게이트**(`TREX_POSTGRESQL_TEST_DSN`/`TREX_RABBITMQ_TEST_URL`): 전용 테스트 인프라 CI 항목. 현 환경엔 runtime infra 만 있고 통합 테스트 `pg_clean` 이 슬롯 테이블 TRUNCATE → runtime DB 로 실행 시 실 데이터 파괴라 미실행. 단 위 운영 재현이 실 인프라 end-to-end 경로(BAT-008 envelope)를 이미 PASS 로 커버하므로 release 차단 사유 아님. delivery CI(전용 테스트 인프라)에서 보강 권장. ## 검증 결과 요약 - 코드/단위/문서: green (AC-4·REQ-032 매핑 전부 PASS, baseline 동기화 완료). - 실 인프라 운영 재현: PASS (slots=10 status 표시·DB 일치·universe 분리·비침습). - `Ready for Release: true` — pytest 인프라 게이트만 전용 환경 CI 잔여(비차단). ## 미검증/한계 - pytest 통합 테스트(인프라 게이트)는 전용 테스트 인프라에서 수행 권장 — 운영 재현으로 실 경로는 검증됨. - 두 경로(BAT-007 stub / BAT-008 envelope) `slots[]` 스키마 일치는 canonical `slot_to_dict` 단일화로 보장(코드 레벨). 운영 재현은 BAT-008 envelope 경로(운영 배포 형상) 검증. ## Human Approval Memo - 승인 결정: 승인(release-candidate 승격 허용) - 승인자: Justin Ko (사용자 명시 지시 — "둘 다 진행") - 승인 시각(KST): 2026-06-08 19:43 - 수용 범위: **pytest 통합 인프라 게이트(전용 테스트 인프라)** 의 본 세션 미수행을 잔여 CI 항목으로 수용. - 잔여 리스크: pytest 통합 테스트 harness 미실행. 단 (a) 신규 코드 데몬으로 실 PostgreSQL+RabbitMQ end-to-end 운영 재현이 BAT-008 envelope 경로를 PASS 로 검증(slots=10·status·DB 일치·universe 분리·비침습), (b) 단위 회귀 338 passed + ruff clean + baseline 동기화 완료. 잔여는 동일 경로의 CI 형식 보강에 한정. - 승인 근거: 운영 재현이 보고된 갭(universe 표시)의 해소를 실 인프라로 직접 실증하여, 표준 pytest 인프라 게이트와 동등 이상의 실 경로 증거를 제공. runtime DB 로의 pytest 실행은 `pg_clean` TRUNCATE 로 실 데이터 파괴 위험이라 미수행이 안전상 정당.