실 DB 점검 중 마이그레이션 009 부분 유니크 인덱스가 legacy 풀 데이터(같은 자산이 closed+재진입 holding 으로 portfolio_id 중복)에 적용 불가 → cutover· 데몬 부팅 모두 차단되는 결함 확인. 데이터 보존 cutover 를 폐기하고 DB wipe + 자산 중심 재초기화로 전환(사용자 결정). 빈 테이블에는 009 인덱스가 정상 생성되고 자산 중심에서 (instance_key, portfolio_id)는 설계상 유일. - trex_core/runtime/reset.py 신규(trex-core-reset): slot-core 7테이블 wipe + apply_migrations 재적용 → 자산 중심 스키마 착지 검증. dry-run 기본/--yes 적용, 파괴적·DB 전역. 보유 carry-over 없음(재초기화 후 reconcile_core_holdings 재편입). - runtime/cutover.py + trex-core-cutover console script + test_cutover_rehearsal.py 삭제. - pyproject: trex-core-reset 등록. - tests/runtime/test_reset.py 신규 5건(PG-gated): wipe+착지·dry-run 무변경·멱등· wipe 후 admission·테이블 커버리지. - change-req REQ-064 CHG-20260610-03(cutover→재초기화 재정의) + srs index 갱신. - baseline 4문서(data-model/runtime-flows/project-structure/interface-contract) + BAT-030 design/planning/index/implementation/verification 도구 서술 reset 으로 교체. 검증: ruff clean, 단위 367 passed, PG+RabbitMQ 통합 411 passed/1 skip(KIS sandbox). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.4 KiB
4.4 KiB
BAT-030 Design
- Status: confirmed (D1~D4 확정 — 2026-06-10, 사용자 결정)
- Batch: BAT-030
체크포인트 결정(2026-06-10): D1=전체 rebuild(보유는 브로커 잔고 기준 carry-over) / D2=전부 완성(literal inactive + 별칭 제거 + entry_count·trading_date drop) / D3=집행 매도 qty 브로커 정본(미러 fallback 없음, 0이면 skip+divergence) / D4=실 cutover 는 운영자(REL 단계, 리허설 후). 아래 §1 을 전체 rebuild 로 읽는다.
2026-06-10 갱신(CHG-20260610-03): D1(데이터 보존 cutover) 폐기 — 실 DB 점검에서 마이그레이션 009 부분 유니크 인덱스가 legacy 풀 중복 데이터에 적용 불가한 결함 확인. DB wipe + 자산 중심 재초기화(
trex-core-reset)로 대체. §1 의 cutover(전체 rebuild·보유 carry-over·promote-unique)는 미적용; 보유는 재초기화 후 universe reconcile + reconcile_core_holdings(REQ-062)로 운영자 재편입. D2/D3 는 유효.
설계 목표
- 자산 중심 모델을 완성하고 라이브로 안전 전환. 보유 포지션 무손실·집행 정확·비가역 변경 통제.
1. cutover (REQ-064) — 전체 rebuild (D1)
- 전체 rebuild: 해당 instance_key 의 daily_slot 을 비우고 universe + 브로커 잔고 기준으로 재생성한다. 보유 carry-over 의 정본 = 브로커 잔고(D3 와 일관).
- 절차(cutover 스크립트, Python — broker + universe 필요):
- 사전: 거래 세션 외, in-flight(pending_*) 0 확인(아니면 수렴 대기). 백업.
- 해당 instance_key 슬롯 삭제(또는 신규 테이블 swap).
- universe(get_portfolios) 의 모든 자산 → 영구 슬롯 생성(
inactive). - 브로커 잔고(get_balance)의 각 보유 (symbol, qty) → universe 로 symbol→portfolio_id 매핑 → 해당 자산 슬롯을
holding(qty=브로커 수량, avg_price=브로커/원장) 으로 설정. - instance_key 태깅, 부분 UNIQUE → 전체 UNIQUE 승격.
- 매핑 실패(브로커 보유 symbol 이 universe 에 없음) → 중단/경고(운영자 판단; 자동 청산 없음).
- 실 cutover 는 운영자 실행(D4) — 본 배치는 cutover 스크립트 + test DB 리허설 제공.
2. 집행 매도 수량 브로커 정본 (REQ-062 M2(b))
execution.pydispatch: 매도 시qty = int(slot.qty)→broker.get_balance()의 해당 symbolhldg_qty. 미러 stale 무관 정확. 브로커 0 이면 매도 skip + divergence(REQ-062 A) 경로로 표면화.
3. literal inactive 전면화 (REQ-057 잔여)
state.py:idle/closed별칭 제거(또는 deprecated 유지하되 코드 산출은 inactive). 전이/리셋이inactive산출.execution.py: PENDING_SELL→INACTIVE(매도 체결), PENDING_BUY→INACTIVE(롤백). postgresql/cli/ops_checks 의'idle'/'closed'→'inactive'(쿼리/필터).- 마이그레이션 010(CHECK): status CHECK 에
'inactive'허용 + 기존idle/closed행 →inactiveUPDATE.
4. 컬럼 drop (REQ-056 잔여)
entry_countdrop(미사용). 슬롯trading_date: drop 또는opened_at재의미(이벤트 시간 속성으로). 모델/EXPECTED_SLOT_FIELDS/persistence/드리프트 가드 정합. legacy preallocation 경로 제거.- 비가역 → drop 전 코드 미참조화 선행, 백업, 롤백(직전 리비전+컬럼 복원).
5. default 전환
- 코드 default 변경 아님 — 운영 인스턴스 TOML 에
max_active_slots설정으로 자산 중심 활성(config 게이트). 배포 단계 운영자 작업.
6. baseline 마감 (REQ-065)
- data-model/runtime-flows/project-structure 를 최종 자산 중심으로 갱신, dcy-001/014/019·daily_symbol_entries 폐기 확정.
롤백
- 직전 released 리비전 + (필요시) 역마이그레이션(inactive→idle/closed, 컬럼 복원). 보유 행은 portfolio_id 보존이라 구 코드와 공존(부분). 컬럼 drop 은 백업 복원.
체크포인트 결정 필요
- D1 — cutover 방식: 보유 행 재사용 + vestigial idle 삭제 + reconcile(권장) vs 전체 rebuild.
- D2 — 본 배치 완성 범위: literal inactive + 별칭 제거 + entry_count/trading_date drop 전부 완성(권장) vs 일부 유지.
- D3 — 집행 매도 qty: 브로커 정본(미러 fallback 없음, 0이면 skip+divergence)(권장) 확인.
- D4 — 실 cutover 실행 주체: 운영자(REL 단계, 리허설 후)(권장) — 본 세션은 마이그레이션+코드+test DB 리허설까지.