Resolve dcy-004 OQ-1~3 from trex-orbit reference
- OQ-1 asset_id: asset_id == portfolio_id — use the slot's portfolio_id
directly as the ledger path param (orbit ledger.py / migration 003 /
coordinator). No symbol mapping or asset lookup.
- OQ-2 durability: ledger outbox (work item) + retry loop, correlation_id
{asset_id}:{order_id}:{execution_id} dedup, outcome vocabulary
(completed/duplicate_completed/retryable_failure/conflict_blocked) —
orbit LedgerWriter pattern; recording decoupled from slot transition.
- OQ-3 exec data: deterministic execution_id (KIS
kis-daily-ccld:{ord_dt}:{brno}:{odno}:{tot_ccld_qty} / paper synth),
fee via BrokerPort calculate_fee, tax default 0.
All dcy-004 open questions answered; R-2/R-4 resolved. Remaining gates
(scope-defer confirm, portfolio-hub contract data, Confirmed By) left for
confirm-discovery.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,9 +78,9 @@
|
||||
|
||||
## 기능 요구사항
|
||||
- FR-1: `LedgerPort.record_trade(asset, order_id, execution_id, side, qty, price, fee, tax, executed_at)` 추상화 + portfolio-hub 어댑터(`POST /v1/assets/{asset_id}/ledger/trades`) + 결정적 검증용 stub/in-memory 원장을 제공한다.
|
||||
- FR-2: 집행 루프가 매수 체결(`pending_buy→holding`)·매도 체결(`pending_sell→closed`) 시 해당 거래를 원장에 기록한다(슬롯 `portfolio_id`/symbol + 체결 데이터 사용).
|
||||
- FR-3: 원장 기록은 `execution_id` 로 멱등하다 — 동일 체결 재기록 시 portfolio-hub 중복/409(LedgerConflict)를 안전 처리하고 중복 원장 0.
|
||||
- FR-4: portfolio-hub 일시 장애 시 원장 기록을 재시도/보류해 유실하지 않는다(슬롯 전이 일관성과 분리).
|
||||
- FR-2: 집행 루프가 매수 체결(`pending_buy→holding`)·매도 체결(`pending_sell→closed`) 시 해당 거래를 원장에 기록한다. ledger path 의 `asset_id` 는 슬롯 `portfolio_id`(=asset_id, OQ-1 결정)를 사용하고 side/qty/price/체결데이터를 함께 보낸다.
|
||||
- FR-3: 원장 기록은 correlation_id(`{asset_id}:{order_id}:{execution_id}`)로 멱등하다 — 동일 체결 재기록 시 로컬 dedup + portfolio-hub 중복/409(LedgerConflict)를 안전 처리하고 중복 원장 0. execution_id 는 결정적 합성(OQ-3).
|
||||
- FR-4: 체결 시 원장 기록을 ledger outbox(work item)에 적재하고 재시도 루프가 portfolio-hub write 를 수행한다(orbit LedgerWriter 패턴). outcome = completed/duplicate_completed/retryable_failure/conflict_blocked. 슬롯 전이와 분리되어 일시 장애에도 유실 없이 결국 기록(conflict 는 운영자 해소).
|
||||
- FR-5: baseline 문서(runtime-flows/interface-contract/project-structure/data-model)를 ledger 레이어에 맞게 갱신한다.
|
||||
|
||||
## 비기능 요구사항
|
||||
@@ -105,13 +105,11 @@
|
||||
|
||||
## 리스크
|
||||
- R-1 (High): 원장 기록 유실/중복 — 체결은 됐는데 원장 미기록(장애) 또는 중복 기록 시 회계 부정확.
|
||||
- 완화 방안: execution_id 멱등(409/duplicate 안전 처리, FR-3) + 장애 재시도/보류(FR-4). stub 으로 결정적 테스트.
|
||||
- R-2 (Medium): asset_id 해석 — portfolio-hub 경로는 `asset_id`(canonical) 인데 슬롯은 symbol/portfolio_id 보유. 매핑 불명확.
|
||||
- 완화 방안: 매핑 규칙을 OQ-1 로 확정(portfolio_id/asset 매핑 또는 symbol→asset_id).
|
||||
- 완화 방안(OQ-2/OQ-3): correlation_id 멱등(409/duplicate 안전) + ledger outbox 재시도 루프(무유실) + conflict_blocked 운영자 해소. stub 으로 결정적 테스트.
|
||||
- R-2 (해소, OQ-1): asset_id 해석 — orbit 근거로 `asset_id == portfolio_id` 확정. 슬롯 `portfolio_id` 를 path 로 직접 사용(추가 매핑/조회 없음).
|
||||
- R-3 (Medium): 외부 의존 결합 — portfolio-hub 장애가 집행 경로를 막을 위험.
|
||||
- 완화 방안: 원장 기록을 슬롯 전이와 분리(전이는 우선, 기록은 재시도/보류). 어댑터 격리(NFR-1).
|
||||
- R-4 (Medium): fee/tax/execution_id 출처 — 체결 데이터에 수수료/세금/체결ID가 항상 있지는 않음(paper vs KIS).
|
||||
- 완화 방안: KIS 체결 조회/주문 응답에서 추출, 없으면 0/derived. OQ-3.
|
||||
- R-4 (해소, OQ-3): fee/tax/execution_id 출처 — execution_id 결정적 합성(KIS 규칙/paper synth), fee 는 BrokerPort 계산(orbit calculate_fee), tax 기본 0(정밀 모델 후속).
|
||||
|
||||
## 가정
|
||||
아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다.
|
||||
@@ -124,18 +122,17 @@
|
||||
답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 REQ 초안 작성 이전에 확인할 질문으로 남긴다.
|
||||
|
||||
- OQ-1: asset_id 해석 — portfolio-hub `{asset_id}` 를 슬롯의 무엇으로 채울지(`portfolio_id` == asset_id? symbol→asset_id 매핑? portfolio-hub get_assets 조회?).
|
||||
- 상태: Open
|
||||
- 처리 방안: 운영자/portfolio-hub 계약 확인. 기본안 검토: 슬롯 `portfolio_id` 를 asset_id 로 직접 사용 또는 symbol 기반 매핑.
|
||||
- 종료 조건: asset_id 소스가 정해져 FR-1/FR-2 에 연결되면 Answered.
|
||||
- OQ-2: 기록 내구성 방식 — fill 전이와 동일 경로 동기 기록(실패 시 재시도) vs 별도 ledger outbox(BAT-004 옵션 B 와 유사) 비동기.
|
||||
- 상태: Open
|
||||
- 처리 방안: 운영자 확인. 기본안: 동기 기록 + 실패 시 재시도/보류 마킹(슬롯에 ledger_recorded 플래그 또는 보류 큐). 강한 내구성 필요 시 outbox.
|
||||
- 종료 조건: 내구성 방식이 정해져 FR-4 수용 기준에 연결되면 Answered.
|
||||
- 상태: Answered (2026-06-04)
|
||||
- 결정: **`asset_id == portfolio_id`** — 슬롯의 `portfolio_id` 를 ledger path param 으로 직접 사용. symbol 매핑/get_assets 조회 불필요. 근거: trex-orbit `app/domain/ledger.py`("asset_id == portfolio_id for this system"), migration 003(Order Execution 이 `{portfolio_id}` path 로 write-back, 매수 커밋 시 슬롯에 캐시), `coordinator.py`(`asset_id = asset_id or portfolio_id`). trex-core 는 이미 buy intent 가 `portfolio_id` 를 공급해 슬롯에 캐시하므로 추가 조회 없이 그대로 사용.
|
||||
- 반영 위치: `# 5` FR-1·FR-2, `# 6` R-2(해소). buy intent 의 `portfolio_id` 필수 여부는 구현 시 결정(없으면 기록 skip 또는 거부).
|
||||
- OQ-2: 기록 내구성 방식 — fill 전이와 동일 경로 동기 기록 vs 별도 ledger outbox 비동기.
|
||||
- 상태: Answered (2026-06-04)
|
||||
- 결정: **별도 ledger outbox(work item) + 재시도 루프** (orbit `LedgerWriter`/recovery_work_item 패턴 차용). 체결 시 ledger 기록을 outbox 에 적재(슬롯 전이와 분리 → 전이는 우선, 기록은 eventually-consistent), 루프가 portfolio-hub write 시도. correlation_id = `{asset_id}:{order_id}:{execution_id}` 로 dedup, outcome 어휘 = completed / duplicate_completed / retryable_failure(재시도) / conflict_blocked(409, 운영자 해소). 근거: orbit `app/domain/ledger.py` 가 동일 패턴으로 무유실+멱등을 보장.
|
||||
- 반영 위치: `# 4`, `# 5` FR-3·FR-4, `# 6` R-1. (BAT-004 의 옵션 B outbox 와 유사 구조 — ledger 전용.)
|
||||
- OQ-3: 체결 데이터(execution_id/fee/tax) 출처 — KIS 체결조회/주문응답에서 추출 가능 범위, paper 더블의 합성 값.
|
||||
- 상태: Open
|
||||
- 처리 방안: KIS inquire-daily-ccld 응답 필드 확인 + paper 더블이 결정적 execution_id/fee 제공.
|
||||
- 종료 조건: 필드 출처/기본값이 정해지면 Answered.
|
||||
|
||||
- 상태: Answered (2026-06-04)
|
||||
- 결정: **execution_id 는 결정적 합성** — KIS: `kis-daily-ccld:{ord_dt}:{ord_gno_brno}:{odno}:{tot_ccld_qty}`(orbit kis.py 규칙 차용), paper: 결정적 synth(예: `paper:{broker_order_id}:{filled_qty}`). **fee 는 BrokerPort fee 계산**(orbit `calculate_fee(side, amount)` 차용), **tax 는 기본 0**(정밀 세금 모델은 후속). FillStatus/브로커가 execution_id·fee 를 운반하도록 contract 확장.
|
||||
- 반영 위치: `# 5` FR-1·FR-3, `# 6` R-4. (BrokerPort 에 fee 계산 + FillStatus.execution_id 추가는 구현 세부.)
|
||||
### 오픈 질문 처리 기준
|
||||
- `Open`: 아직 답이 없고 다음 단계 진행에 영향이 있는 상태다. 문서에 유지한다.
|
||||
- `Answered`: 답이 확정된 상태다. 관련 본문/요구사항에 반영한 뒤 오픈 질문 목록에서는 제거하거나 resolved 기록으로 이동한다.
|
||||
@@ -172,7 +169,7 @@ REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지
|
||||
- [ ] High 영향 리스크(R-1 원장 유실/중복) 처리 방침 확정
|
||||
- 기준: execution_id 멱등 + 재시도/보류로 수용 가능한지 운영자 확인.
|
||||
- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인
|
||||
- 기준: OQ 목록에 `Open` 0개 또는 잔여 전부 `Deferred` (현재 OQ-1~OQ-3 Open)
|
||||
- 기준: OQ 목록에 `Open` 0개 또는 잔여 전부 `Deferred` (OQ-1~OQ-3 전부 Answered → `Open` 0개)
|
||||
- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정
|
||||
- 기준: 운영자가 confirm-discovery 시점에 CONFIRMED_BY 를 지정한다.
|
||||
|
||||
@@ -189,12 +186,11 @@ REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지
|
||||
# 10. 사용자 결정 필요 항목 요약
|
||||
사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. 결정, 확인, 데이터 요청을 구분해서 적는다.
|
||||
|
||||
## DECIDE
|
||||
- {{DECIDE_ASSET_ID_SOURCE}} — portfolio-hub `{asset_id}` 소스: 슬롯 portfolio_id 직접 vs symbol→asset_id 매핑 vs get_assets 조회 (OQ-1)
|
||||
- {{DECIDE_LEDGER_DURABILITY}} — 기록 내구성: 동기+재시도/보류 vs 별도 ledger outbox (OQ-2)
|
||||
- ~~asset_id 소스~~ → 결정됨: `asset_id == portfolio_id`(슬롯 portfolio_id 직접 사용, orbit 근거) (OQ-1, 2026-06-04)
|
||||
- ~~기록 내구성~~ → 결정됨: 별도 ledger outbox + 재시도 루프(orbit LedgerWriter 패턴), correlation_id dedup, outcome 어휘 (OQ-2, 2026-06-04)
|
||||
|
||||
## CONFIRM
|
||||
- {{CONFIRM_EXEC_DATA_SOURCE}} — 체결 데이터(execution_id/fee/tax) 출처(KIS 추출 + paper 합성) 확정 (OQ-3)
|
||||
- ~~체결 데이터 출처~~ → 결정됨: execution_id 결정적 합성(KIS 규칙/paper) + fee BrokerPort 계산 + tax 0 (OQ-3, 2026-06-04)
|
||||
- {{CONFIRM_SCOPE_DEFER}} — 거래 외 트랜잭션·asset 동기화·reconciliation 을 후속으로 미루는 범위 경계 확정
|
||||
|
||||
## DATA
|
||||
|
||||
Reference in New Issue
Block a user