feat(ledger): dcy-018 option D cash/position write-back + 추정 현금 (BAT-023)
ledger write 응답의 portfolio-hub 권위 cash/quantity 를 스냅샷에 write-back 해
매수/매도 직후 "수량 live·현금 stale" 비대칭 제거(option D 활성화). portfolio-hub#8
(*_after 응답) 동작 중 확인으로 그간 deferred 됐던 REQ-030 을 닫음.
거버넌스: 전부 change-req (신규 REQ 없음, dcy-018 OQ-3 a).
- REQ-017: record_trade → LedgerWriteOutcome{result, cash_balance_after,
asset_quantity_after}. 어댑터가 응답 root flat *_after 파싱(new+duplicate, 누락 None)
- REQ-019: LedgerWriter 에 SnapshotStore 주입 → new+duplicate write-back
(best-effort, *_after 절대값이라 멱등). LedgerOutbox.pending_cash_delta()
- REQ-029: 추정 현금 오버레이(_apply_cash_estimate, cash_estimated 라벨, OQ-4 i)
+ 슬롯 오버레이 유지(OQ-1 B). 미정산 outbox delta 기반, write-back 수렴
- REQ-030: option D 활성화 → Approved→Implemented
best-effort 격리(NFR-1): write-back/추정 실패가 ledger 멱등·청산 무차단.
배치 번호: 동시 커밋된 BAT-022(slot-state, dcy-016)와 충돌해 BAT-023 으로 배정.
검증: 단위 350 passed/35 skipped, 인프라 게이트(PG+RabbitMQ) 385 passed, ruff clean.
신규 test_ledger_option_d + adapter/PG 테스트. BAT-023 release-candidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
- Baseline Seed: .stage-pilot/bootstrap/baseline.yaml
|
||||
- Status: draft
|
||||
- Owner: project maintainers
|
||||
- Last Updated (KST): 2026-06-08 (BAT-021)
|
||||
- Last Updated (KST): 2026-06-08 (BAT-023)
|
||||
- Source Discovery / Batch: bootstrap-baseline (pre-Discovery); 데몬/HTTP 흐름 = dcy-002 / BAT-002
|
||||
- Primary Runtime: daemon (HTTP API) + library (slot 도메인)
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
- `strategy_key` 일치(`==`) 직교 필터.
|
||||
- degraded 상태가 있으면 `degraded=true + reason + sanitized message` 동봉.
|
||||
4. envelope: `{assets[], view, available_slots, degraded, reason, message}` — `assets` 는 항상 배열, null 금지. 항목 필드는 `symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params`, **price 필드는 없음**.
|
||||
5. 추정 현금 오버레이(dcy-018/REQ-029, OQ-4): 미정산(pending) ledger outbox 행이 있는 자산은 `cash_balance += pending cash delta`(매수 −, 매도 +) + `cash_estimated:true` 라벨로 노출 → option D write-back 도착 시 권위값으로 수렴(pending 제거). best-effort(실패 시 응답 불변). 수량은 슬롯 오버레이(REQ-029)가 정확값이라 추정 불요.
|
||||
|
||||
## Flow: `per-slot 워치독 갱신` (BAT-010/011 / REQ-034, REQ-040)
|
||||
|
||||
@@ -244,9 +245,10 @@
|
||||
|
||||
1. `LedgerOutbox.list_pending(limit)` 으로 pending work item 을 FIFO 로 가져온다. **백오프 중(`next_retry_at > now`)인 행은 건너뛴다**(dcy-015/REQ-019 head-of-line 보호, NFR-3).
|
||||
2. row 의 현재 상태가 이미 `completed` 면 (e.g. 동시/재처리) `duplicate_completed` 로 마킹하고 어댑터를 호출하지 않는다.
|
||||
3. `LedgerPort.record_trade(trade)` 호출.
|
||||
- `LedgerWriteResult.NEW` → outcome `completed`, row status `completed`.
|
||||
- `LedgerWriteResult.DUPLICATE_OK`(어댑터 server-side dedup) → outcome `duplicate_completed`, row status `completed`, ledger 중복 0.
|
||||
3. `LedgerPort.record_trade(trade)` 호출 → `LedgerWriteOutcome{result, cash_balance_after?, asset_quantity_after?}`.
|
||||
- `result=NEW` → outcome `completed`, row status `completed`.
|
||||
- `result=DUPLICATE_OK`(어댑터 server-side dedup) → outcome `duplicate_completed`, row status `completed`, ledger 중복 0.
|
||||
- **option D write-back(dcy-018/REQ-019/030)**: `new`·`duplicate` outcome 의 `cash_balance_after`/`asset_quantity_after`(None 아님)를 `SnapshotStore.update_cash_position(asset_id, …)` 로 반영(best-effort — 실패해도 ledger outcome 무차단, NFR-1). `*_after` 가 **절대 권위값**이라 duplicate 도 멱등. 응답 누락(구 hub)·409/422 는 write-back skip.
|
||||
- `LedgerConflictError`(portfolio-hub 409) → outcome `conflict_blocked`, row status `conflict_blocked` (자동 재시도 중단, 운영자 해소 대상).
|
||||
- `LedgerPermanentError`(portfolio-hub **404/400/422**, dcy-015/REQ-017, issue #13) → outcome `permanent_failure`, row status **`delivery_failed`**(터미널, 재시도 0). 재시도로 해소 불가한 클라이언트 오류(미등록 포트폴리오 등) → 즉시 중단 + WARN.
|
||||
- `LedgerRetryableError`(timeout/5xx/network/408/429) → **지수 백오프 + jitter**(`delay = min(base × 2^(attempts-1), cap)`, `next_retry_at` 설정) 후 다음 due tick 에 재시도. **`max_attempts` 초과 시** outcome `dead_lettered`, row status **`delivery_failed`**(dead-letter, 터미널) + WARN. 무한 1초 재시도 제거.
|
||||
|
||||
Reference in New Issue
Block a user