docs(srs/batch): dcy-021 REQ + BAT-031 + Implemented 전환

- draft-req: REQ-066(사이징 도메인·end-to-end), REQ-067(baseline 정합) 신규
- change-req: REQ-057(CHG-03 holding→pending_buy)·REQ-061(CHG-04 사이징 intent)·
  REQ-062(CHG-03 부분 매도 min(주문,잔고)) — Implemented→Approved 후 재구현
- confirm-req: REQ-066/067 Approved
- BAT-031 batch(index/planning/design D1~D4/implementation/verification) → release-candidate
- confirm-batch-verification 승인 + confirm-req-implemented:
  REQ-057/061/062/066/067 → Implemented (BAT-031 verification 근거)
- srs/batch index + dcy-021 discovery 생성 REQ 역참조 갱신

(issue #21 dcy-022 는 별도 작업으로 미포함)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 18:53:53 +09:00
co-authored by Claude Opus 4.8
parent e4be4d60c2
commit 5ee5f7f4e2
13 changed files with 517 additions and 10 deletions
@@ -0,0 +1,47 @@
# BAT-031 Design
- Status: confirmed (D1~D4, 2026-06-10)
- Batch: BAT-031
## 설계 원칙
- 수량 정본 = **브로커 잔고**(REQ-062). 슬롯 `qty` 는 (a) pending 동안 = **주문 수량**, (b) 체결/롤백 후 = **브로커 잔고(보유)** 로 재동기화한다. core 는 "의도 수량"을 별도 저장하지 않는다(dcy-021 OQ-1).
- avg_price 는 증액 시 가중평균, 매도(부분/전량) 시 cost basis 유지(dcy-021 OQ-3).
- 모든 전이는 dcy-020 자산 중심 모델에 additive(무회귀, NFR-2).
## D1 — 증액: 주문 수량 vs 보유 수량 (브로커 정본 재동기화)
- `HOLDING→PENDING_BUY`(증액): `slot.qty := intent.qty`(추가 주문 수량), `avg_price` **보존**(가중평균용), `limit_price := price`. (generic 전이 규칙이 caller None 일 때 avg 보존 → 별도 service 분기 불요)
- dispatch 매수: `qty = slot.qty`(주문 수량) 그대로.
- `PENDING_BUY→HOLDING`(체결): 보유 = **브로커 잔고 total**, avg_price = 가중평균.
- `old_qty = max(0, broker_total − filled)`, `old_avg = slot.avg_price or 0`, `new_avg = (old_qty×old_avg + filled×fill_price)/broker_total`(broker_total 0 이면 fill_price).
- 초기 매수도 동일 공식(avg None→0, old_qty=0 → new_avg=fill_price) — 통일.
## D2 — 초기 매수 vs 증액 판별
- `INACTIVE→PENDING_BUY`(초기): slot 이 inactive 라 avg_price=None.
- `HOLDING→PENDING_BUY`(증액): avg_price 보존(>0).
- 체결/롤백 핸들러는 **브로커 잔고**로 판별(잔고>0 → 증액/보유 잔존, 0 → 초기/미보유). avg_price 보존은 가중평균 계산에만 사용.
## D3 — 증액/매도 롤백
- 매수 거부 `_rollback`: 브로커 잔고>0 → `PENDING_BUY→HOLDING`(qty=브로커 잔고, 증액 실패해도 기존 보유 유지) / 잔고 0 → `PENDING_BUY→INACTIVE`(초기 매수 실패).
- 매도 거부: `PENDING_SELL→HOLDING`(qty=브로커 잔고) (기존).
## D4 — 부분 매도 + 전량 매도 구분 + 부분 체결
- pending_sell 의 `slot.qty` 의미: **부분 매도** intent(SellIntent.qty 지정) → `slot.qty = 주문 수량`; **전량 매도**(svc.sell/safety-sell/kill-switch, qty 미지정) → `slot.qty = None`("전량" sentinel). → `_apply_transition_fields` 의 PENDING_SELL 진입 규칙: `new_qty = caller qty`(None 보존, mirror 안 씀).
- dispatch 매도: `qty = 브로커잔고 if slot.qty is None else min(int(slot.qty), 브로커잔고)`. 0 이면 skip+WARN(divergence, REQ-062). → 전량은 항상 브로커 정본(stale mirror 무관), 부분은 min(주문, 잔고)·잔고 이상이면 전량.
- `PENDING_SELL→체결`: 체결 후 **브로커 잔고**로 분기 — 잔고>0 → `HOLDING`(qty=잔고, avg=cost basis 유지) / 0 → `INACTIVE`. (기존 항상 INACTIVE 에서 변경 — 부분 매도 잔량 holding 지원)
- 부분 체결: 실제 체결분만 ledger(기존 `_record_ledger` = `fs.filled_qty`), 미체결 잔량 미추적. dcy-013 `_on_partial_cancel` 도 브로커 정본 resync 로 정합.
## D-impl — 브로커 잔고 조회
- `_poll` tick 시작 시 `broker.get_balance()` 1회 fetch → symbol→hldg_qty 맵을 fill/rollback 핸들러에 전달(체결당 중복 호출 회피). dispatch 의 매도 잔고 맵과 동일 패턴(BAT-030 M2).
## intent (REQ-061)
- 매수 admission: 대상 슬롯이 `INACTIVE` → 초기 매수(M 캡 적용); `HOLDING` → **증액**(M 캡 미적용 — active 수 불변); `pending_*` → `already_active`. (증액은 별도 intent 타입 없이 holding 슬롯 buy 로 검출)
- 매도 admission: `SellIntent.qty`(선택) 추가 — 지정 시 부분 매도(slot.qty=order), 미지정 시 전량(slot.qty=None).
## 상태머신 (REQ-057)
- `_BASE_TRANSITIONS` 에 `(HOLDING, PENDING_BUY)` 추가 → 13 transitions.
## 롤백/회귀
- 전부 additive. 기존 초기 매수/전량 매도/safety-sell/kill-switch/reconcile 경로 무회귀(전량 매도 slot.qty=None·dispatch 브로커 정본은 기존 동작과 동일 결과).
## 체크포인트 결정
- D1~D4 확정(브로커 정본 재동기화로 "주문 수량 vs 보유 수량" 충돌 해소, 별도 필드 없음). 구현 진행.
@@ -0,0 +1,39 @@
# BAT-031 Implementation
- Status: done
- Batch: BAT-031
- 일자: 2026-06-10
## 구현 요약
design.md D1~D4 그대로 구현. 수량 정본=브로커 잔고 재동기화로 "주문 수량 vs 보유 수량" 충돌을 별도 필드 없이 해소.
- **M1 (REQ-057)**: `state.py` `_BASE_TRANSITIONS` 에 `(HOLDING, PENDING_BUY)` 추가 → 13 전이(증액).
- **M2 (REQ-066/062)**: `service.py` `_apply_transition_fields` — PENDING_SELL 진입 시 `qty = caller as-is`(None=전량 sentinel, 값=부분 주문 qty). 증액 pending(HOLDING→PENDING_BUY)은 generic 분기가 avg_price 보존(caller None)·qty=주문으로 처리(별도 분기 불요).
- **M3 (REQ-061)**: `intents.py` — `_admit_buy` 가 HOLDING 슬롯 매수를 **증액**으로 검출(M 캡 미적용, `position_increase` reason), PENDING_* 만 `already_active`. `SellIntent.qty`(부분) 추가, `_admit_sell` 가 qty 를 transit 에 전달. `messaging_handlers` sell 파서에 `qty` 추출.
- **M4 (REQ-062/066)**: `execution.py` — `_balance_map()` 헬퍼. dispatch 매도 `qty = 브로커잔고 if slot.qty is None else min(int(slot.qty), 브로커잔고)`(0이면 skip+WARN). `_on_filled`: 매수 체결 → 보유=브로커 잔고·avg 가중평균; 매도 체결 → 브로커 잔고>0 `pending_sell→holding`(cost basis) / 0 `→inactive`. `_on_partial_cancel` 도 브로커 정본 resync. `_rollback`: 매수 거부 시 브로커>0 `→holding`(증액 실패, 기존 보유 유지) / 0 `→inactive`.
- **M5 (REQ-067)**: data-model/runtime-flows/interface-contract/project-structure 4문서 사이징 정합.
## 변경 내역 (Changed Files)
- trex_core/domain/slot/state.py — holding→pending_buy 전이
- trex_core/domain/slot/service.py — PENDING_SELL qty sentinel
- trex_core/application/intents.py — 증액 admission, SellIntent.qty, partial sell
- trex_core/application/execution.py — _balance_map, 부분/전량 매도 dispatch, 매수 체결 가중평균, 브로커 정본 resync, 증액 롤백
- trex_core/application/messaging_handlers.py — sell qty 파싱
- docs: data-model/runtime-flows/interface-contract/project-structure (REQ-067)
- tests: test_state(13 전이), test_service(TestPositionSizing 3), test_execution(전량/부분 매도·증액·capacity 5신규), test_execution_cancel(브로커 정본 잔량)
## 테스트
- 단위 전체: **378 passed** (45 skipped), ruff clean
- 통합(PG+RabbitMQ): **422 passed, 1 skipped**(KIS sandbox, 환경 무관)
## 검증 실행 (run-the-app, 사이징 e2e)
라이브 trex_core(reset 후) + 실 RabbitMQ + paper + instance=test, M=5:
1. 초기 매수 qty=10 @1000 → holding 10 @1000
2. **증액 +5 @1200**(holding 슬롯 매수, admitted) → holding **15 @1066.6667**(가중평균)
3. **부분 매도 qty=6** → holding **9 @1066.6667**(cost basis 유지)
4. **전량 매도**(qty 미지정) → **inactive**(qty None)
- 데몬 로그 ERROR/Traceback 0. messaging sell qty 갭은 e2e 에서 발견·수정(부분 매도가 전량으로 가던 버그) 후 재검증 green.
## Remaining Risks / Blockers
- 전략 모듈(trex-orb) 사이징 intent 발행 전환 필요 — 기존 buy/sell 와 병존(additive)이라 무중단.
- 미체결 pending 고착 처분은 본 배치 범위 밖(issue #21 별도 Discovery).
@@ -0,0 +1,23 @@
# BAT-031: 보유 자산 포지션 사이징 (dcy-021)
- Status: release-candidate
- Profile: standard
- Source Discovery: dcy-021
- Included REQ: REQ-066 (사이징 도메인·end-to-end), REQ-067 (baseline 정합), REQ-057 (CHG-03 상태머신 holding→pending_buy), REQ-061 (CHG-04 사이징 intent), REQ-062 (CHG-03 부분 매도 집행)
## Summary
- dcy-021: 자산 영구 슬롯(dcy-020)의 수량 가변 전제 위에 **보유 포지션 수량 조정**(증액·부분 감액)을 구현한다. 명령형 계약(전략이 cash+quantity 로 qty+price 계산·전송), core 는 실행 substrate(target 미저장·미추적), 수량 정본 = 브로커 잔고.
## Scope
- In: 증액(holding→pending_buy→holding, avg_price 가중평균), 부분 감액(부분 매도 min(intent,잔고), 잔량 holding/전량 inactive, cost basis), 부분 체결 실제만 반영·미추적, 사이징 intent + 멱등, baseline 4문서.
- Out: 능동 capacity 배분, 자동 리밸런싱 스케줄러, 미체결 pending 고착 처분(issue #21).
## Documents
- Planning: [planning.md](./planning.md)
- Design: [design.md](./design.md)
- Implementation: [implementation.md](./implementation.md)
- Verification: [verification.md](./verification.md)
## Notes
- 집행 핫패스(라이브 주문) 변경 — additive·paper 검증. design.md 의 D1~D4 확정 후 구현.
- 본 배치 완료 후 REQ-057/061/062/066/067 confirm-req-implemented.
@@ -0,0 +1,42 @@
# BAT-031 Planning
- Status: confirmed
- Batch: BAT-031
- Profile: standard
## Included REQ
- REQ-066 (Interface, Approved): 사이징 도메인 수량/avg_price 재계산 + end-to-end.
- REQ-067 (Documentation, Approved): baseline 4문서 정합.
- REQ-057 (CHG-20260610-03, Approved): 상태머신 `holding→pending_buy` 전이.
- REQ-061 (CHG-20260610-04, Approved): 사이징 intent(증액/부분 매도, 명령형 qty+price).
- REQ-062 (CHG-20260610-03, Approved): 부분 매도 집행 `min(intent,잔고)`·부분 체결 실제만.
## Delivery Plan (마일스톤)
1. **M1 (REQ-057)**: `state.py` 전이 집합에 `HOLDING→PENDING_BUY` 추가(증액). test_state 갱신(13 transitions).
2. **M2 (REQ-066)**: `service.py` 전이 필드 규칙 — 증액 pending(avg_price 보존), 매수 체결 avg_price 가중평균 + 수량 = 브로커 정본 resync.
3. **M3 (REQ-061)**: `intents.py` 사이징 admission — 증액 매수(holding 슬롯 buy, `already_active` 예외)·부분 매도(SellIntent qty). messaging_handlers payload(qty/price).
4. **M4 (REQ-062)**: `execution.py` — 부분 매도 dispatch qty = `min(intent, 브로커 잔고)`, 매수/매도 체결 시 broker 정본 resync·avg 가중평균, 증액 롤백은 holding 복귀.
5. **M5 (REQ-067)**: baseline 4문서 정합 + run-the-app e2e.
## Dependencies
- Internal: dcy-020(자산 영구 슬롯·REQ-062 브로커 정본·집행 루프) 전 단계 green.
- External: 전략 모듈(trex-orb)이 사이징 intent 발행 — 기존 buy/sell 와 병존(additive)이라 무중단.
## Design Gate
- Design Required Before Implementation: yes
- Reason: M3/M4 는 **라이브 주문 집행 동작 변경**(증액 매수·부분 매도 dispatch). 증액 시 "주문 수량 vs 보유 수량" 충돌·avg_price 가중평균·증액 롤백·부분 체결 처리는 잘못 구현 시 과매수/과매도/평단 오류 → design.md 에서 확정.
## Milestones
1. M1 상태머신 + test
2. M2 service avg/qty
3. M3 intent
4. M4 execution
5. M5 baseline + e2e
## Risks
- R-exec (High): 증액/부분 매도 집행 회귀(과매수·과매도·avg drift). 대응: 브로커 정본 resync(REQ-062), 멱등, 단위+paper e2e.
- R-statemachine (Medium): 전이 추가 회귀. 대응: additive + test_state 회귀 가드.
- R-strategy (Medium): trex-orb 계약 전환. 대응: 기존 intent 병존.
## Notes
- green 기준: 단위 전체 회귀(증액/부분 매도/부분 체결/avg 가중평균) + paper run-the-app e2e + ruff.
@@ -0,0 +1,51 @@
# BAT-031 Verification
- Status: approved (confirm-batch-verification, 2026-06-10)
- Batch: BAT-031
- 검증 환경: Python 3.12 / PostgreSQL trex_core_test / 실 RabbitMQ / paper broker
## Acceptance Mapping
### REQ-066 (포지션 사이징 end-to-end)
| AC | 판정 | Evidence |
|---|---|---|
| AC-1 증액 가중평균 | pass | `test_increase_accumulates_qty_and_weights_avg_price`(10@1000 +5@1200 → 15@1066.67) + e2e 2단계 |
| AC-2 부분 매도 잔량 holding·cost basis | pass | `test_partial_sell_qty_is_min_intent_broker`(잔량 6, avg 1000) + e2e 3단계(9 @1066.67) |
| AC-3 전량 매도 → inactive | pass | `test_full_sell_qty_is_broker_balance`·`test_partial_sell_caps_at_broker_balance` + e2e 4단계 |
| AC-4 부분 체결 실제만 반영·미추적 | pass | `test_execution_cancel`(부분 체결→브로커 정본 잔량) + _on_filled/_on_partial_cancel 브로커 resync |
| AC-5 무회귀 | pass | 단위 378 / 통합 422 passed |
### REQ-057 (CHG-03 상태머신 holding→pending_buy)
| AC | 판정 | Evidence |
|---|---|---|
| AC-1 전이 집합(13) | pass | `test_state.py`(holding→pending_buy allowed, size 13) |
| AC-5 증액 전이·복귀 | pass | `test_holding_to_pending_buy_increase_preserves_avg` + e2e |
### REQ-061 (CHG-04 사이징 intent)
| AC | 판정 | Evidence |
|---|---|---|
| AC-6 증액 매수(holding) | pass | `test_increase_*` + e2e 2단계(admitted) |
| AC-7 부분 매도 qty·명령형·core 미저장 | pass | `test_partial_sell_*` + messaging sell qty 파싱 + e2e 3단계 |
### REQ-062 (CHG-03 부분 매도 집행)
| AC | 판정 | Evidence |
|---|---|---|
| AC-1 매도 = min(intent, 브로커)·이상이면 전량 | pass | `test_partial_sell_qty_is_min_intent_broker`·`test_partial_sell_caps_at_broker_balance` |
| AC-5 부분 체결 실제만·미추적 | pass | `test_execution_cancel` + _balance_map resync |
### REQ-067 (baseline 정합)
| AC | 판정 | Evidence |
|---|---|---|
| AC-1~3 data-model/runtime-flows/interface-contract/project-structure 정합 | pass | commit (사이징 흐름·13 전이·intent qty·가중평균 반영) |
## Evidence
1. 단위: `pytest tests` → **378 passed**, ruff clean.
2. 통합(PG `trex_core_test` + 실 RabbitMQ): **422 passed, 1 skipped**(KIS sandbox 환경 이슈, 무관).
3. **run-the-app e2e**(라이브 trex_core + 실 MQ + paper, M=5): 초기 매수 10@1000 → 증액 +5@1200 → holding 15@1066.67(가중평균) → 부분 매도 6 → holding 9@1066.67(cost basis) → 전량 매도 → inactive. 데몬 ERROR 0.
4. baseline 동기화: 4문서 + (run-the-app e2e 가 증액·부분/전량 매도 흐름 실증).
## Blocking Issues
- 없음. 전략 모듈(trex-orb) 사이징 전환은 병존(additive)이라 무중단; 미체결 pending 처분은 issue #21(별도) 범위.
## Result
- 포함 REQ AC 전부 evidence 연결. **Ready for Release: true** (코드·단위·통합·e2e·baseline). 실 운영 전환은 전략 모듈 사이징 발행 시 활성(계약 병존).
+1
View File
@@ -38,3 +38,4 @@
| BAT-028 | standard | release-candidate | REQ-058, REQ-059, REQ-060 | dcy-020 (BAT-β) | [bat-028](./bat-028_20260610_universe-reconcile-and-active-admission/) |
| BAT-029 | standard | release-candidate | REQ-061, REQ-062, REQ-063 | dcy-020 (BAT-γ) | [bat-029](./bat-029_20260610_asset-keyed-intent-and-divergence/) |
| BAT-030 | standard | release-candidate | REQ-064, REQ-062, REQ-056·057·065(잔여) | dcy-020 (BAT-δ) | [bat-030](./bat-030_20260610_asset-centric-cutover/) |
| BAT-031 | standard | release-candidate | REQ-066, REQ-067, REQ-057·061·062(CHG) | dcy-021 | [bat-031](./bat-031_20260610_position-sizing/) |
@@ -5,10 +5,10 @@
- 문서 ID: dcy-021_20260610_position-sizing-target-intent
- 이슈명: 포지션 사이징 — 활성 자산 슬롯 보유 수량 변경(HOLDING→HOLDING)·부분 매도·선언형 target intent (issue #1, dcy-020 OQ-4 후속)
- 작성 시각(KST): 2026-06-10 17:06 KST
- 마지막 갱신 시각(KST): 2026-06-10 17:39 KST (confirm-discovery 승인 — 전 OQ Answered, 상태 confirmed)
- 마지막 갱신 시각(KST): 2026-06-10 17:46 KST (draft-req: REQ-066·067 생성 + change-req REQ-057/061/062 예정)
- 대체됨: 없음
- 후속 Discovery 참조: 없음
- 생성된 REQ 참조: 없음
- 생성된 REQ 참조: REQ-066, REQ-067 (+ change-req REQ-057/061/062)
# 1. 계획 상태 요약
현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다.
@@ -0,0 +1,88 @@
# req-067: 포지션 사이징 baseline 문서 정합
- Status: Implemented
- Type: Documentation
- Priority: Medium
- Owner: project maintainers
## Intent
- dcy-021: 보유 포지션 사이징(증액·부분 감액·명령형 사이징 intent) 구현이 끝나면 cross-cutting baseline 문서를 실제 동작과 일치시켜, 이후 Discovery/REQ/Batch 가 정확한 기준을 참조하게 한다. (issue #1, dcy-020 OQ-4 후속)
## Requirement
- `docs/data-model.md`: 보유 슬롯 수량 가변(증액 누적·부분 감액 잔량)·avg_price 가중평균 재계산·cost basis 유지 규칙을 반영한다.
- `docs/runtime-flows.md`: 사이징 intent 수신 → 집행(증액 매수/부분 매도, 집행 수량 = min(intent, 브로커 잔고)) → 부분 체결 실제 반영·미추적 → 슬롯 holding 유지/inactive 종료 흐름과 확장된 상태 전이(HOLDING→PENDING_BUY 등)를 반영한다.
- `docs/interface-contract.md`: 사이징 intent payload(명령형 qty+price; 증액 buy-on-holding·부분 매도 qty)·이벤트·집행 수량 규칙을 반영한다.
- `docs/project-structure.md`: 사이징으로 영향받은 모듈(slot service·state·intents·execution) 책임 서술을 갱신한다.
## Acceptance Criteria
1. Given 사이징 구현 완료, When `docs/data-model.md` 확인, Then 수량 가변·avg_price 가중평균·cost basis 유지가 코드와 일치한다.
2. Given 사이징 구현 완료, When `docs/runtime-flows.md`·`docs/interface-contract.md` 확인, Then 사이징 intent·집행(min(intent,잔고))·부분 체결 미추적·상태 전이 확장이 실제와 일치한다.
3. Given baseline 갱신, When `docs/project-structure.md` 확인, Then 영향 모듈 서술이 구현과 일치한다.
## Impacted Area
- Docs: docs/data-model.md, docs/runtime-flows.md, docs/interface-contract.md, docs/project-structure.md
- Modules: 없음(문서)
- Tests: 없음(문서 리뷰)
## Notes
- 본 REQ 는 REQ-066 및 change-req(REQ-057/061/062) 구현 완료 후 마지막에 정합한다(dcy-020 REQ-065 와 동일 패턴).
- 출처: dcy-021 FR-4.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징)로부터 최초 생성(Proposed). 사이징 baseline 4문서 정합.
#### Intent
- 구현 후 cross-cutting baseline 을 실제 동작과 일치.
#### Acceptance Criteria Delta
- Added: data-model/runtime-flows·interface-contract/project-structure 정합 3개 기준
- Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: data-model/runtime-flows/interface-contract/project-structure / Modules: 없음 / Tests: 없음(문서 리뷰)
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정) / Releases: none
#### Revalidation Impact
- Reverification Needed: no(문서) / Existing Implementation Invalidated: no / Status Recommendation: keep-current / Follow-up Action: confirm-req → dcy-021 배치 마지막 정합.
#### Validation Plan
- 사이징 구현 완료 후 baseline 4문서 diff 리뷰.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-021 와 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md(Register Approved) / Modules: 없음 / Tests: 없음
#### Delivery Trace Delta
- Batches: none / Releases: none
#### Revalidation Impact
- Reverification Needed: no / Existing Implementation Invalidated: no / Status Recommendation: keep-current / Follow-up Action: dcy-021 배치 마지막 정합.
#### Validation Plan
- 승인 후 dcy-021 배치 verification 에서 baseline 정합 확인.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
@@ -12,10 +12,11 @@
- 보유 **수량(asset_quantity)의 정본은 portfolio-hub** 이며, 슬롯은 수량을 정본 소유하지 않고 로컬 best-effort 미러(option D write-back/추정)로 둔다. 실제 청산 시 매도 수량은 **브로커 잔고(`get_balance().hldg_qty`)를 정본**으로 조회한다. 불일치 감지는 `reconcile_positions`(REQ-031)를 확장해 **브로커 잔고 + hub 수량 + 코어 슬롯 holding** 3자를 비교하며, 브로커를 ground truth 로 한다. 해소: A(코어 holding/브로커 0) → 슬롯 `error` + 운영자 resolve; B(코어 flat/브로커 보유, 최위험) → WARN/alert + 격리 + 운영자 결정(자동 청산·자동 편입 금지); C(수량만 불일치) → 미러 갱신 + warning, 상태 변경 없음; D(hub 만 지연) → 기존 write-back. **조용한 자동 교정 금지·표면화**, 실주문은 운영자 게이트(issue #15). 감지 reconcile 은 일일 refresh 와 분리해 더 자주 수행 가능(브로커 잔고+슬롯 상태만 필요).
## Acceptance Criteria
1. Given 매도 청산, When 매도 수량 결정, Then 로컬 미러가 stale 해도 브로커 잔고 기준으로 정확히 청산된다.
1. Given 매도 청산, When 매도 수량 결정, Then 로컬 미러가 stale 해도 브로커 잔고 기준으로 정확히 청산된다. **부분 매도(dcy-021)**: 집행 수량 = `min(intent qty, 브로커 hldg_qty)`; intent 가 잔고 이상이면 전량 매도(→inactive).
2. Given 코어 holding 인데 브로커 0, When reconcile, Then 슬롯이 `error` 로 격리되고 safety-sell 대상에서 빠지며 운영자 resolve 가 요구된다.
3. Given 코어 flat 인데 브로커 보유, When reconcile, Then WARN/alert + 격리되고 자동 청산·자동 편입 없이 운영자 결정으로 넘어간다.
4. Given 둘 다 보유, 수량만 불일치, When reconcile, Then 미러만 갱신되고 상태 전이는 없으며 hub 지속 불일치는 warning 으로 노출된다.
5. Given 사이징 주문(증액/부분 매도)이 일부만 체결(dcy-021), When 집행, Then 실제 체결분만 ledger 기록·슬롯 반영하고 미체결 잔량은 core 가 추적/재시도하지 않는다(재수렴은 전략).
## Impacted Area
- Docs: docs/runtime-flows.md(불일치 해소·write-back)
@@ -91,3 +92,42 @@
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-029(M2a 불일치 reconcile)+BAT-030(M2b 매도 수량 브로커 정본) — 모든 AC 가 release-candidate 배치 verification 의 evidence 와 연결됨(단위 367/PG 29/MQ 21 passed + run-the-app 자산 중심 e2e). Blocking Issues 없음.
### CHG-20260610-03
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징) 반영: 부분 매도 집행 수량 = **`min(intent qty, 브로커 hldg_qty)`**(과매도 방지, 잔고 이상이면 전량→inactive). 사이징 주문 부분 체결 시 **실제 체결분만** ledger/슬롯 반영, 미체결 잔량 미추적(전략 재수렴). 기존 "매도 수량=브로커 정본"의 부분 매도 확장.
#### Intent
- 보유 수량 부분 감액을 브로커 정본 하에 과매도 없이 집행하고, 부분 체결은 실제 거래만 원장에 남긴다(dcy-021 OQ-3, dcy-013 부분 체결 처리 정합).
#### Acceptance Criteria Delta
- Added: AC-5(사이징 부분 체결 → 실제 체결만 반영·미추적)
- Updated: AC-1 에 부분 매도 집행 수량 = min(intent, 브로커 잔고)·이상이면 전량
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/runtime-flows.md, docs/interface-contract.md (REQ-067 정합)
- Modules: trex_core/application/execution.py(부분 매도 dispatch qty), reconciliation.py(불변)
- Tests: tests/application/test_execution*.py(부분 매도 min·부분 체결)
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (부분 매도 집행 수량 정책 신규)
- Existing Implementation Invalidated: no (전량 매도=브로커 정본 기존 동작 보존, 부분은 확장)
- Status Recommendation: revert-to-approved (부분 매도 집행 미구현 — dcy-021 배치에서 구현·검증)
- Follow-up Action: dcy-021 배치 구현 후 Implemented 복귀.
#### Validation Plan
- 부분 매도 min(intent,잔고)·잔고 이상 전량·부분 체결 실제만 ledger 단위 + 회귀.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
@@ -12,10 +12,11 @@
- 상태 집합을 `inactive → pending_buy → holding → pending_sell → inactive` (+ 모든 비-error → `error`, `error → {inactive, holding}` 운영자 resolve)로 재정의한다. 기존 `idle`·`closed` 는 영구 슬롯에서 단일 `inactive` 로 합치고 `closed→idle` 복구 전이를 제거한다. `holding`(포지션 열림)은 코어 슬롯의 로컬 정본으로 체결 시 동기 set, 매도 체결 시 동기 clear 한다(portfolio-hub `asset_quantity` 로 판단하지 않음). advisory lock 을 **인스턴스 스코프**(`pg_advisory_xact_lock(SLOT_LOCK_ID, hash(instance_key))`)로 두어 인스턴스 간 교차 직렬화를 제거한다.
## Acceptance Criteria
1. Given 상태머신, When 허용 전이 집합을 확인, Then `{inactive→pending_buy, pending_buy→holding, pending_buy→inactive, holding→pending_sell, pending_sell→inactive, pending_sell→holding, *→error, error→inactive, error→holding}` 와 정확히 일치한다.
1. Given 상태머신, When 허용 전이 집합을 확인, Then `{inactive→pending_buy, pending_buy→holding, pending_buy→inactive, holding→pending_buy, holding→pending_sell, pending_sell→inactive, pending_sell→holding, *→error, error→inactive, error→holding}` 와 정확히 일치한다(dcy-021 CHG-20260610-03: `holding→pending_buy` 증액 전이 추가).
2. Given 영구 슬롯, When 매도 체결로 종료, Then 슬롯은 `inactive` 로 돌아가고(별도 `closed`·`closed→idle` 없음) holding 로컬 플래그가 clear 된다.
3. Given 서로 다른 instance_key 의 두 슬롯, When 동시에 전이, Then 인스턴스별 락으로 서로를 차단하지 않는다(교차 경합 없음).
4. Given 같은 슬롯에 대한 동시 전이, When 병렬 처리, Then 인스턴스 스코프 락으로 직렬화되어 단일 writer 불변식이 유지된다.
5. Given 보유(holding) 슬롯 증액, When `holding→pending_buy` 전이, Then 허용되고 체결 시 `pending_buy→holding` 으로 복귀한다(dcy-021 REQ-066). 부분 매도 잔량은 기존 `pending_sell→holding` 전이로 holding 을 유지한다.
## Impacted Area
- Docs: docs/runtime-flows.md(전이 흐름), docs/data-model.md(상태)
@@ -93,3 +94,42 @@
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-027(토대)+BAT-030(literal inactive·별칭 제거) — 모든 AC 가 release-candidate 배치 verification 의 evidence 와 연결됨(단위 367/PG 29/MQ 21 passed + run-the-app 자산 중심 e2e). Blocking Issues 없음.
### CHG-20260610-03
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징, issue #1) 반영: 상태 전이 집합에 **`holding→pending_buy`(보유 슬롯 증액)** 를 추가하고, `pending_sell→holding`(기존)을 부분 매도 잔량 holding 유지 경로로 명시. 전량 매도만 `pending_sell→inactive`.
#### Intent
- 보유 자산 슬롯이 holding 을 유지한 채 수량 증액(추가 매수)·부분 감액을 표현하도록 상태머신을 additive 확장(dcy-020 이 고정한 "종료=전량 청산" 경계 해제).
#### Acceptance Criteria Delta
- Added: AC-5(holding→pending_buy 증액 전이 허용·체결 시 holding 복귀, 부분 매도 잔량 pending_sell→holding)
- Updated: AC-1 허용 전이 집합에 holding→pending_buy 포함
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/runtime-flows.md, docs/data-model.md (REQ-067 정합)
- Modules: trex_core/domain/slot/state.py(전이 추가), service.py(증액 qty/avg_price = REQ-066)
- Tests: tests/domain/slot/test_state.py(전이 집합·size), test_service.py
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (전이 집합 변경 — test_state 갱신·증액 경로 검증)
- Existing Implementation Invalidated: no (기존 전이 보존, additive) — 단 AC-1 "정확히 일치"가 신규 전이를 포함하도록 확장되어 재검증 필요
- Status Recommendation: revert-to-approved (신규 전이 미구현 — dcy-021 배치에서 구현·검증 후 confirm-req-implemented)
- Follow-up Action: dcy-021 배치 구현 + test_state 전이 집합 갱신 후 Implemented 복귀.
#### Validation Plan
- ALLOWED_TRANSITIONS 에 holding→pending_buy 포함·size 갱신 단위 테스트 + 증액 end-to-end(REQ-066).
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
@@ -17,6 +17,8 @@
3. Given 보유(holding) 아닌 슬롯, When 매도, Then `not_holding`(또는 not-holding 사유)로 거부된다.
4. Given 레거시 매수(`portfolio_id`), When 제출, Then `find_slot_by_portfolio` 로 슬롯에 매핑되어 동일하게 처리된다(dual-accept, 무중단).
5. Given 같은 `intent_id` 재전송, When 처리, Then 슬롯 중복 전이 없이 최초 결정과 동일 응답(멱등).
6. Given 보유(holding) 슬롯, When **증액 매수 intent**(qty+price)를 제출, Then `holding→pending_buy` 로 추가 매수가 집행된다(dcy-021, 이미 active 라도 증액은 허용 — `already_active` 예외).
7. Given 보유 슬롯, When **부분 매도 intent**(qty+price)를 제출, Then 명시 수량으로 `holding→pending_sell` 집행된다(집행 수량 정책 REQ-062). 사이징 intent 는 명령형(전략이 qty+price 계산·전송), core 는 target/의도 수량을 저장·추적하지 않는다.
## Impacted Area
- Docs: docs/runtime-flows.md(intent 흐름), docs/interface-contract.md(메시지 계약)
@@ -126,3 +128,42 @@
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-029(+BAT-030 trading_date 제거·e2e slot_id 매수) — 모든 AC 가 release-candidate 배치 verification 의 evidence 와 연결됨(단위 367/PG 29/MQ 21 passed + run-the-app 자산 중심 e2e). Blocking Issues 없음.
### CHG-20260610-04
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징) 반영: intent 계약에 **사이징 intent**(보유 슬롯 증액 매수 / 부분 매도)를 추가. 명령형 — 전략이 스냅샷 cash+quantity 로 **정수 주식 수(qty)+가격(price)** 을 계산해 보내고, core 는 실행만 한다(target/의도 수량 미저장·미추적). 증액은 이미 active 슬롯에도 허용(전량 매수 활성화의 `already_active` 와 구분).
#### Intent
- 보유 자산의 수량 조정을 기존 명령형 buy/sell 계약의 최소 additive 확장으로 표현(dcy-021 OQ-1/OQ-2 확정).
#### Acceptance Criteria Delta
- Added: AC-6(증액 매수 intent → holding→pending_buy), AC-7(부분 매도 intent qty → holding→pending_sell, 명령형·core 미저장)
- Updated: 없음(기존 활성/청산 계약 보존)
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/interface-contract.md(사이징 intent payload), docs/runtime-flows.md
- Modules: trex_core/application/intents.py(증액/부분 매도 admission), messaging_handlers.py(payload)
- Tests: tests/application/test_*intent*.py, 사이징 admission 신규
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (신규 사이징 계약 경로)
- Existing Implementation Invalidated: no (기존 slot_id 매수·전량 매도 계약 보존, additive)
- Status Recommendation: revert-to-approved (사이징 계약 미구현 — dcy-021 배치에서 구현·검증)
- Follow-up Action: dcy-021 배치 구현 후 Implemented 복귀.
#### Validation Plan
- 증액 매수·부분 매도 intent admission 단위 + end-to-end(REQ-066). 명령형·멱등·core 미저장 검증.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
@@ -0,0 +1,95 @@
# req-066: 보유 자산 포지션 사이징 — 증액·부분 감액 (수량/avg_price 재계산)
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- dcy-021: 자산 중심 영구 슬롯(dcy-020)의 "수량 가변 전제" 위에, 보유(holding) 자산 슬롯의 **수량을 holding 을 유지한 채 조정**(증액·부분 감액)하는 end-to-end 동작과 수량/avg_price 재계산 규칙을 정의한다. 전량 청산만 종료(inactive)한다. (issue #1, dcy-020 OQ-4 후속)
## Requirement
- 보유 슬롯 **증액**: 같은 슬롯이 `HOLDING→PENDING_BUY→HOLDING` 로 순환하며 **실제 체결분만큼** 보유 수량이 누적되고, `avg_price = (기존수량×기존평단 + 체결수량×체결가) / 총수량` 가중평균으로 재계산된다(REQ-057 전이·REQ-061 intent 계약 사용).
- 보유 슬롯 **부분 감액**: 같은 슬롯이 `HOLDING→PENDING_SELL` 로 전이하고, 체결 후 브로커 정본 수량을 반영해 잔량>0 이면 `HOLDING`(**cost basis=avg_price 유지**), 잔량 0(전량)이면 `INACTIVE` 로 종료한다(집행 수량 정책은 REQ-062).
- **부분 체결**: 증액·감액 모두 **실제 체결분만** 슬롯 수량/원장에 반영하고, 미체결 잔량은 core 가 추적·재시도하지 않는다(재수렴은 전략이 스냅샷 기준으로 재발행). 실현손익은 core 가 계산하지 않고 ledger/portfolio-hub 가 소유한다.
- 활성 자산 수(M 캡 대상, REQ-059)는 증액으로 증가하지 않는다(이미 active 인 자산의 수량 변경).
- 기존 활성/전량 청산/admission 경로는 무회귀(additive 확장).
## Acceptance Criteria
1. Given 100주 holding(avg 1000) 슬롯, When 50주(@1200) 증액 매수가 전량 체결, Then 슬롯은 holding 유지·수량 150·avg_price = (100×1000+50×1200)/150 = 1066.67(반올림 규칙 적용)로 재계산된다.
2. Given 100주 holding 슬롯, When 60주 부분 매도가 전량 체결, Then 슬롯은 holding 유지·수량 40·avg_price(cost basis) 불변이다.
3. Given 100주 holding 슬롯, When 전량(또는 잔고 이상) 매도가 체결, Then 슬롯은 INACTIVE 로 종료되고 점유 필드가 초기화된다.
4. Given 증액/부분 매도 주문이 일부만 체결(예: 50 중 30), When 집행, Then 실제 체결분(30)만 슬롯 수량·ledger 에 반영되고 미체결 잔량은 추적되지 않는다.
5. Given dcy-020 기존 경로(신규 활성·전량 청산·admission·M 캡), When 사이징 도입 후 회귀, Then 무회귀(green)다.
## Impacted Area
- Docs: docs/data-model.md(수량 가변·avg_price 재계산), docs/runtime-flows.md(사이징 흐름) — REQ-067 에서 정합
- Modules: trex_core/domain/slot/service.py(qty 누적·avg_price 가중평균·cost basis 유지), trex_core/domain/slot/state.py(REQ-057 change-req), trex_core/application/execution.py(부분 체결 반영), trex_core/application/intents.py(REQ-061 change-req)
- Tests: 증액 avg_price 가중평균, 부분 매도 잔량/전량 분기, 부분 체결 실제만 반영, 회귀 가드
## Notes
- 계약 형태(명령형 qty+price)는 dcy-021 OQ-1, 단위(정수 주식 수+가격)는 OQ-2, avg_price/cost basis/실현손익은 OQ-3, 트리거(intent 당 1회)는 OQ-4 확정.
- 본 REQ 는 사이징의 **도메인 수량/avg_price 의미·end-to-end 동작**을 소유한다. 상태 전이(REQ-057)·intent 계약(REQ-061)·집행 매도 수량(REQ-062)의 계약 변경은 각 change-req 로 기록한다.
- 반올림 규칙: avg_price 는 기존 슬롯 `avg_price`(float/NUMERIC) 정밀도를 따른다(별도 통화 반올림 정책 없음). 주식 수는 정수.
- 출처: dcy-021 FR-1/FR-2 + NFR-1/NFR-2.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징, issue #1)로부터 최초 생성(Proposed). 보유 슬롯 증액·부분 감액 end-to-end + 수량/avg_price 재계산.
#### Intent
- 자산 영구 슬롯의 수량 가변 전제 위에 보유 포지션 리사이즈를 정규화.
#### Acceptance Criteria Delta
- Added: 증액 가중평균/부분 감액 잔량·전량/부분 체결 실제만/무회귀 5개 기준
- Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: data-model/runtime-flows(REQ-067)
- Modules: domain/slot service·state(REQ-057), application/execution·intents(REQ-061/062)
- Tests: 증액·부분 매도·부분 체결·회귀
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정) / Releases: none
#### Revalidation Impact
- Reverification Needed: yes / Existing Implementation Invalidated: no / Status Recommendation: keep-current / Follow-up Action: confirm-req → dcy-021 배치.
#### Validation Plan
- 단위(avg_price 가중평균·잔량 분기·부분 체결) + run-the-app end-to-end.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-021(confirmed, handoff 승인, OQ-1~4 Answered)과 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md(Register Approved) / Modules: 없음 / Tests: 없음
#### Delivery Trace Delta
- Batches: none / Releases: none
#### Revalidation Impact
- Reverification Needed: no / Existing Implementation Invalidated: no / Status Recommendation: keep-current / Follow-up Action: suggest-batch-reqs → draft-batch.
#### Validation Plan
- 승인 후 dcy-021 배치 planning 에서 본 REQ AC 를 검증 기준으로 사용.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
+6 -6
View File
@@ -74,7 +74,7 @@
## Next Requirement ID
- Current: `REQ-066`
- Current: `REQ-068`
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
## Requirement Register
@@ -146,13 +146,13 @@
| REQ-063 | 운영자 표면 단일화 — slots = 자산 포지션 단일 뷰 | Interface | Implemented | Medium | project maintainers | [req-063](./Interface/req-063_unified-operator-slot-view.md) |
| REQ-064 | 풀 모델 → 자산 중심 DB 재초기화 (구 cutover) | Migration | Implemented | High | project maintainers | [req-064](./Migration/req-064_pool-to-permanent-slot-cutover.md) |
| REQ-065 | 자산 중심 모델 baseline 문서 정합 + 풀 모델 폐기 명시 | Documentation | Implemented | Medium | project maintainers | [req-065](./Documentation/req-065_asset-centric-baseline-alignment.md) |
| REQ-066 | 보유 자산 포지션 사이징 — 증액·부분 감액 (수량/avg_price 재계산) | Interface | Implemented | High | project maintainers | [req-066](./Interface/req-066_position-sizing-resize.md) |
| REQ-067 | 포지션 사이징 baseline 문서 정합 | Documentation | Implemented | Medium | project maintainers | [req-067](./Documentation/req-067_position-sizing-baseline-alignment.md) |
## Recent Change Log Summary
- 2026-06-10 :: REQ-057/061/062/066/067 → Implemented (confirm-req-implemented, BAT-031 dcy-021 포지션 사이징): 보유 슬롯 증액(holding→pending_buy, avg_price 가중평균)·부분 매도(min(주문,잔고), 잔량 holding/전량 inactive, cost basis)·부분 체결 실제만 반영. 수량 정본=브로커 잔고 재동기화. 단위 378/통합 422 passed + 사이징 e2e green. BAT-031 release-candidate.
- 2026-06-10 :: REQ-057/061/062 change-req (dcy-021 포지션 사이징, CHG: 057-03/061-04/062-03): Implemented→**Approved** 되돌림(신규 동작 미구현, dcy-021 배치에서 재구현·confirm-req-implemented 로 복귀). REQ-057 상태머신에 `holding→pending_buy`(증액) 전이 추가·부분 매도 잔량 pending_sell→holding 명시, REQ-061 사이징 intent(증액 매수/부분 매도, 명령형 qty+price·core 미저장) 추가, REQ-062 부분 매도 집행 수량=min(intent,브로커잔고)·부분 체결 실제만 ledger·미추적. REQ-066/067(신규)이 end-to-end·baseline 소유.
- 2026-06-10 :: REQ-066~067 신규 생성(Proposed) (draft-req, dcy-021 포지션 사이징/issue #1, dcy-020 OQ-4 후속): 보유 자산 슬롯의 holding 유지 수량 조정. REQ-066(Interface — 증액 HOLDING→PENDING_BUY→HOLDING qty 누적·avg_price 가중평균 / 부분 감액 잔량 holding·전량 inactive·cost basis 유지 / 부분 체결 실제만 반영·미추적), REQ-067(Documentation — baseline 4문서 정합). 명령형 계약(전략이 cash+quantity 로 qty+price 계산·전송, core 미저장)·정수 주식 수+가격(OQ-1/2), avg_price 가중평균·실현손익 hub(OQ-3), intent 당 1회(OQ-4). 기존 Implemented 계약 REQ-057(상태머신)·REQ-061(intent)·REQ-062(수량)은 change-req 로 확장 동반. 전부 **Proposed**(confirm-req 대기). (draft-req)
- 2026-06-10 :: REQ-056~065 신규 생성(Proposed) (draft-req, dcy-020 자산 중심 슬롯 모델 재설계): 익명 슬롯 풀 → portfolio-hub universe 자산과 1:1 **영구 슬롯** + 동시 활성(M) 제어로 substrate 전환. REQ-056(영구 슬롯 스키마·UNIQUE(instance_key,portfolio_id)·trading_date/entry_count 제거), REQ-057(상태머신 inactive↔pending_buy↔holding↔pending_sell·holding 로컬·인스턴스 스코프 lock), REQ-058(universe reconcile 생성/soft-retire/tombstone·degrade 보류·일일 preallocation 폐기), REQ-059(FCFS·M캡·무치환·over-cap), REQ-060(max_active_slots per-instance TOML), REQ-061(intent 자산 키 통일·sell-by-slot_id 폐기), REQ-062(수량 hub 정본+미러·청산 브로커·불일치 해소), REQ-063(slots 단일 뷰), REQ-064(풀→영구 cutover), REQ-065(baseline 정합·폐기 명시). 기존 REQ-002/003/005/006/007/048 등은 폐기/재정의 change-req 동반 예정. 단계적 배치(스키마·상태머신 → reconcile·admission → intent·수량·CLI → cutover) delivery. 전부 **Proposed**(confirm-req 대기). (draft-req)
- 2026-06-09 :: REQ-048/010 change-req→Implemented (CHG-20260609-01/02, trex-orb-v1 설정 관리 정합, BAT-026): config 디렉터리 기반 설정 관리 도입 — `--config` 를 이름으로 해석 + `--config-path <dir>`(기본 `./config`) + `resolve_config_toml`(슬래시 포함 값은 하위호환 명시 경로)(REQ-048), `.env` 를 config-dir 결정적 해석(`--env-file` 우선, 없으면 `<config_dir>/.env`, CWD 무관)으로 변경 + `config/.env.example` + `.gitignore` `config/*` 허용목록(REQ-010). 운영자 CLI 도 `--config-path`/`--env-file` 동일 적용. `from_env()` legacy 루트 `.env` 폴백 유지로 완전 하위호환(`.env` 이동은 운영 배포 시 무중단). batch-lite(BAT-026) 단위 23 + 전체 375 passed, ruff clean, 라이브 스모크(name·path 동일 결과) → 둘 다 **Implemented**. (change-req/confirm-req-implemented)
- 2026-06-09 :: REQ-002/003/006/007/009 change-req (CHG-20260609-01, dcy-019/issue #18, BAT-025): slot-scoped `entry_count` 추가 + closed 슬롯 직접 재할당. daily_slot/`Slot` 에 `entry_count`(기본 0) 필드 + `EXPECTED_SLOT_FIELDS` + 멱등 마이그레이션 008(REQ-002/006), 상태 머신 `closed→pending_buy` 신규 전이(8→9 base, ALLOWED_TRANSITIONS 14→15)(REQ-002), `_apply_transition_fields` closed→pending_buy clean-slate + 모든 `→pending_buy` 시 entry_count +1(REQ-002), `find_allocatable_slot`(idle∪closed, `entry_count→updated_at→slot_id`) selector + in-memory 동등(REQ-006), `_admit_buy` find_idle_slot→find_allocatable_slot + from_state=slot.status(REQ-007), 테스트 계약 정합(REQ-003), baseline 2문서(data-model/runtime-flows) 정합(REQ-009). 기존 `daily_symbol_entries`(symbol-scoped) 무관·미변경. 전부 change-req(신규 REQ 없음, OQ-1/2/3). 단위 366 passed(+KIS sandbox 1건은 live .env URL 로 사전 환경 실패·무관), ruff clean. PG 게이트 마이그레이션/드리프트는 라이브 runtime DSN 미사용(파괴적 truncate 회피)·test DSN 자동 검증. 전부 **Implemented** 유지. (change-req)
- 2026-06-09 :: REQ-032 change-req→Implemented (CHG-20260609-01/02, issue #17, BAT-024): `trex-core enter` 에 `--forced-close-at <ISO8601>` (절대시간) 옵션 추가 — 운영자가 매수 진입 명령 하나로 시간 기반 자동청산(forced_close) 시각 지정. CLI 가 buy intent payload 의 기존 `forced_close_at` 필드에 매핑(계약 REQ-007/021·도메인 REQ-066·forced-close 루프 REQ-037 이미 구현·불변, CLI 노출 갭만 보완). 잘못된 형식 제출 전 거부, 미지정 시 미포함(하위호환). 상대시간(`--hold-minutes`) 미채택. AC-5/6 신규. batch-lite(BAT-024) 단위 검증 → **Implemented**. 단위 353 passed, ruff clean. (change-req/confirm-req-implemented)
- 2026-06-08 :: REQ-017/019/029 change-req + REQ-030 Approved→Implemented (dcy-018, BAT-023): ledger write 응답의 권위 cash/quantity 를 portfolio 스냅샷에 write-back(option D 활성화) — 매수/매도 직후 "수량 live·현금 stale" 비대칭 제거. `record_trade`→`LedgerWriteOutcome{result, *_after}`+어댑터 `cash_balance_after`/`asset_quantity_after` 파싱(new+duplicate)(REQ-017), `LedgerWriter` SnapshotStore write-back best-effort+`pending_cash_delta`(REQ-019), 추정 현금 오버레이(`cash_estimated` 라벨)+슬롯 오버레이 유지(REQ-029, OQ-1 B/OQ-4 i), option D 활성화로 REQ-030 Approved→Implemented. 전부 change-req(신규 REQ 없음, OQ-3 a). portfolio-hub#8(`*_after`) 동작 중. 단위 350 passed, 인프라 게이트 385 passed, ruff clean. (change-req/confirm-req-implemented)
- 2026-06-10 :: REQ-056~065 Approved → Implemented (confirm-req-implemented): dcy-020 자산 중심 슬롯 모델 4개 배치(BAT-027 α/BAT-028 β/BAT-029 γ/BAT-030 δ, 전부 release-candidate) verification evidence 기준. BAT-030 에서 literal inactive·컬럼 drop·매도 수량 브로커 정본·cutover 도구·baseline 마감 완성, run-the-app 자산 중심 e2e green. 실 운영 cutover(REQ-064)는 REL 단계 운영자 실행.
- 2026-06-10 :: REQ-064 재정의 (change-req CHG-20260610-03): 데이터 보존 cutover → DB 재초기화(`trex-core-reset`). 마이그레이션 009 부분 유니크 인덱스가 legacy 풀 중복 데이터에 적용 불가한 결함 + dev/페이퍼 컨텍스트 → wipe+자산 중심 재초기화로 대체. 구 `trex-core-cutover` 도구·테스트 삭제, `tests/runtime/test_reset.py` 신규. Status Implemented 유지(reset evidence). (BAT-030)