docs(batch): draft-batch BAT-030 (dcy-020 BAT-δ cutover) + design 확정

dcy-020 최종 배치. design 확정(사용자 결정):
- D1: 전체 rebuild — daily_slot 비우고 universe+브로커 잔고 기준 재생성,
  보유 carry-over 정본=브로커 잔고
- D2: 전부 완성 — literal inactive 전면화 + idle/closed 별칭 제거 +
  entry_count/trading_date 컬럼 drop
- D3: 집행 매도 수량 브로커 정본(미러 fallback 없음, 0이면 skip+divergence)
- D4: 실 cutover 는 운영자(REL 단계, 리허설 후); 본 배치는 스크립트+코드+test DB 리허설
batches/index BAT-030 등록.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 12:36:09 +09:00
co-authored by Claude Opus 4.8
parent 78a743a2ef
commit cec34be5f4
6 changed files with 153 additions and 0 deletions
@@ -0,0 +1,47 @@
# 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 로 읽는다.
## 설계 목표
- 자산 중심 모델을 완성하고 라이브로 안전 전환. 보유 포지션 무손실·집행 정확·비가역 변경 통제.
## 1. cutover (REQ-064) — 전체 rebuild (D1)
- **전체 rebuild**: 해당 instance_key 의 daily_slot 을 비우고 universe + 브로커 잔고 기준으로 재생성한다. **보유 carry-over 의 정본 = 브로커 잔고**(D3 와 일관).
- 절차(cutover 스크립트, Python — broker + universe 필요):
1. 사전: 거래 세션 외, in-flight(pending_*) 0 확인(아니면 수렴 대기). 백업.
2. 해당 instance_key 슬롯 삭제(또는 신규 테이블 swap).
3. universe(get_portfolios) 의 모든 자산 → 영구 슬롯 생성(`inactive`).
4. 브로커 잔고(get_balance)의 각 보유 (symbol, qty) → universe 로 symbol→portfolio_id 매핑 → 해당 자산 슬롯을 `holding`(qty=브로커 수량, avg_price=브로커/원장) 으로 설정.
5. instance_key 태깅, 부분 UNIQUE → 전체 UNIQUE 승격.
- 매핑 실패(브로커 보유 symbol 이 universe 에 없음) → 중단/경고(운영자 판단; 자동 청산 없음).
- **실 cutover 는 운영자 실행**(D4) — 본 배치는 cutover 스크립트 + test DB 리허설 제공.
## 2. 집행 매도 수량 브로커 정본 (REQ-062 M2(b))
- `execution.py` dispatch: 매도 시 `qty = int(slot.qty)` → `broker.get_balance()` 의 해당 symbol `hldg_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` 행 → `inactive` UPDATE.
## 4. 컬럼 drop (REQ-056 잔여)
- `entry_count` drop(미사용). 슬롯 `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 은 백업 복원.
## 체크포인트 결정 필요
1. **D1 — cutover 방식**: 보유 행 재사용 + vestigial idle 삭제 + reconcile(권장) vs 전체 rebuild.
2. **D2 — 본 배치 완성 범위**: literal inactive + 별칭 제거 + entry_count/trading_date drop **전부 완성**(권장) vs 일부 유지.
3. **D3 — 집행 매도 qty**: 브로커 정본(미러 fallback 없음, 0이면 skip+divergence)(권장) 확인.
4. **D4 — 실 cutover 실행 주체**: 운영자(REL 단계, 리허설 후)(권장) — 본 세션은 마이그레이션+코드+test DB 리허설까지.
@@ -0,0 +1,16 @@
# BAT-030 Implementation
- Status: not-started
- Batch: BAT-030
## 구현 요약
- (run-batch-delivery 진입 시 작성) design.md 체크포인트(D1~D4) 확정 후 채운다.
## 변경 내역
- (대기)
## 테스트
- (대기)
## 검증 실행
- (대기)
@@ -0,0 +1,32 @@
# BAT-030: 자산 중심 cutover — 라이브 전환·집행 정본·모델 완성 (dcy-020 BAT-δ)
- Status: planning
- Profile: standard
- Source Discovery: dcy-020
- Included REQ: REQ-064 (풀→영구 cutover), REQ-062 (잔여: 청산 수량 브로커 정본), REQ-056/057/065 (잔여: entry_count/trading_date drop·literal inactive·baseline 마감)
## Summary
- dcy-020 의 **마지막 배치(BAT-δ)** — 자산 중심 모델을 **완성하고 라이브로 전환**한다. 가장 위험: 라이브 트레이딩 데이터 cutover + 집행 동작 변경 + 모델 완성(별칭/컬럼 정리).
- 핵심: (1) 라이브 cutover(풀 행→영구 자산 행, 보유 carry-over, instance_key 태깅), (2) 집행 dispatch 매도 수량 = **브로커 잔고 정본**(REQ-062 잔여, M2(b)), (3) literal `inactive` 전면화 + `idle`/`closed` 별칭 제거 + CHECK 제약 갱신, (4) `entry_count`/슬롯 `trading_date` 컬럼 drop, (5) 자산 중심 default 운영 전환(max_active_slots), (6) baseline 문서 마감(REQ-065).
## Scope
- In Scope:
- REQ-064: cutover 마이그레이션 + 절차 + 롤백(라이브는 운영자 실행)
- REQ-062 잔여: execution dispatch 매도 수량 브로커 잔고 정본(M2(b))
- REQ-056/057 잔여: literal inactive(+CHECK 마이그레이션), idle/closed 별칭 제거, entry_count/trading_date 컬럼 drop
- REQ-065: baseline 3문서 마감 + dcy-001/014/019 폐기 확정
- 자산 중심 default 전환(운영 config) + run-the-app(자산 중심 e2e)
- Out of Scope:
- 포지션 사이징(issue #1, OQ-4 분리 — 후속 Discovery)
- 신규 기능(본 배치는 모델 완성·전환만)
## Documents
- Planning: [planning.md](./planning.md)
- Design: [design.md](./design.md)
- Implementation: [implementation.md](./implementation.md)
- Verification: [verification.md](./verification.md)
## Notes
- Source discovery 단일(dcy-020). BAT-027/028/029 후속, dcy-020 최종.
- **최고 위험**: 라이브 데이터·집행 전환. **실 cutover 는 운영자 실행**(본 배치는 마이그레이션·코드·리허설 제공). design 체크포인트에서 cutover 절차·롤백·운영자 입회·전환 순서 확정 후 구현.
- 본 배치 완료 후 REQ-056~065 confirm-req-implemented → REL.
@@ -0,0 +1,44 @@
# BAT-030 Planning
- Status: confirmed
- Batch: BAT-030
- Profile: standard
## Included REQ
- REQ-064 (Migration, Approved): 풀→영구 자산 슬롯 cutover + 롤백.
- REQ-062 (Integration, Approved 잔여): 청산 수량 브로커 정본(M2(b), execution dispatch).
- REQ-056/057 (잔여): entry_count/trading_date 컬럼 drop, literal inactive + 별칭 제거.
- REQ-065 (Documentation): baseline 마감.
## Delivery Plan (전환 순서 — 안전 우선)
1. **literal inactive 전면화**: `state.py` IDLE/CLOSED 별칭 제거(또는 deprecate), 코드가 `inactive` 산출. `execution.py` PENDING_SELL→`INACTIVE`·PENDING_BUY→`INACTIVE`. postgresql/cli/ops_checks 의 'idle'/'closed' → 'inactive'. CHECK 제약 마이그레이션(010: 'inactive' 허용 + 기존 idle/closed→inactive UPDATE).
2. **M2(b) 집행 매도 수량 브로커 정본**: dispatch 매도 `int(slot.qty)` → `broker.get_balance()` 해당 symbol hldg_qty. 미러 stale 무관 정확.
3. **컬럼 drop**: `entry_count`·슬롯 `trading_date`(또는 opened_at 재의미) drop 마이그레이션 + 모델/EXPECTED_SLOT_FIELDS/persistence 정합. (legacy preallocation 경로도 제거.)
4. **cutover 마이그레이션(REQ-064)**: 기존 보유(holding, portfolio_id 보유) 행은 그대로 자산 슬롯; vestigial idle 풀 행(portfolio_id NULL) 정리; instance_key 태깅(009 default 'default'); UNIQUE 부분→전체 승격 검토.
5. **default 전환**: 운영 인스턴스 TOML 에 `max_active_slots` 설정(자산 중심 활성) — 운영자 배포 단계.
6. **baseline 마감(REQ-065)** + run-the-app 자산 중심 e2e(test DB).
## Dependencies
- Internal: BAT-027/028/029(스키마·상태머신·reconcile·admission·divergence). 전 단계 green.
- External: 전략 모듈 slot_id 계약 전환(BAT-029 dual-accept 로 무중단; portfolio_id 매수 폐기 시 전략 전환 필요).
## Design Gate
- Design Required Before Implementation: yes
- Reason: (a) **라이브 데이터 cutover** — 보유 포지션 무손실·롤백·in-flight(pending) 처리·운영자 입회 절차를 설계에서 확정. (b) literal inactive 전환은 BAT-027 별칭의 역-cascade(코드+CHECK 마이그레이션+다수 테스트). (c) 집행 dispatch 매도 수량 변경은 라이브 주문 동작. (d) 컬럼 drop 은 비가역 — 순서·롤백 필수. → design.md 확정 후 구현 전 체크포인트.
## Milestones
1. M1 — literal inactive + CHECK 마이그레이션(010) + 별칭 제거 + 테스트
2. M2 — 집행 매도 수량 브로커 정본
3. M3 — entry_count/trading_date drop 마이그레이션 + 정합
4. M4 — cutover 마이그레이션(REQ-064) + 리허설(test DB)
5. M5 — baseline 마감 + run-the-app 자산 중심 e2e
## Risks
- R-live (High): 라이브 cutover 로 보유 포지션 손실/집행 중단. 대응: 보유 행 보존(이미 portfolio_id 보유)·거래 세션 외 실행·롤백 스크립트·운영자 입회·리허설(test DB) 선행.
- R-irreversible (High): 컬럼 drop 비가역. 대응: drop 전 백업, 단계적(코드 미참조화 → drop), 롤백은 직전 리비전+컬럼 복원.
- R-cascade (Medium): literal inactive 역전환의 테스트/코드 cascade. 대응: BAT-027 별칭 지점 일괄 전환 + 회귀 green 게이트.
- R-exec (Medium): 집행 매도 qty 변경 회귀. 대응: 단위+리허설, 미러 fallback 없이 broker 권위.
## Notes
- 실 cutover 는 운영자 실행(본 배치는 마이그레이션·코드·리허설 제공). confirm-release 전 cutover 리허설 + run-the-app evidence 필수.
- green 기준: 단위 전체 회귀(literal inactive·drop 무파손) + cutover 리허설(보유 보존·롤백) + 자산 중심 e2e.
@@ -0,0 +1,13 @@
# BAT-030 Verification
- Status: not-started
- Batch: BAT-030
## Acceptance Mapping
- (draft-batch-verification / confirm-batch-verification 단계에서 작성)
## Evidence
- (대기)
## Result
- Ready for Release: false (구현 전)
+1
View File
@@ -37,3 +37,4 @@
| BAT-027 | standard | planning | REQ-056, REQ-057 | dcy-020 (BAT-α) | [bat-027](./bat-027_20260610_asset-permanent-slot-foundation/) |
| BAT-028 | standard | planning | REQ-058, REQ-059, REQ-060 | dcy-020 (BAT-β) | [bat-028](./bat-028_20260610_universe-reconcile-and-active-admission/) |
| BAT-029 | standard | planning | REQ-061, REQ-062, REQ-063 | dcy-020 (BAT-γ) | [bat-029](./bat-029_20260610_asset-keyed-intent-and-divergence/) |
| BAT-030 | standard | planning | REQ-064, REQ-062, REQ-056·057·065(잔여) | dcy-020 (BAT-δ) | [bat-030](./bat-030_20260610_asset-centric-cutover/) |