Advance dcy-004 ledger slice: confirm Discovery, draft+approve REQ-017~020, draft BAT-006

- confirm-discovery dcy-004: draft→confirmed (Confirmed By: Justin Ko),
  OQ-1~3 resolved, scope/R-1 accepted, portfolio-hub contract deferred to REQ/delivery
- draft-req: REQ-017 (LedgerPort + portfolio-hub adapter + stub), REQ-018
  (fill→ledger recording + FillStatus exec_id/fee), REQ-019 (ledger outbox
  durability + correlation_id idempotency), REQ-020 (baseline alignment);
  NFR-1~3 absorbed
- confirm-req: REQ-017~020 Proposed→Approved
- draft-batch: BAT-006 (standard) bundling REQ-017~020 from dcy-004
- Update SRS/Discovery/batches indexes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 22:32:27 +09:00
co-authored by Claude Opus 4.8
parent 88f5af434b
commit 01a51d0c16
13 changed files with 681 additions and 21 deletions
@@ -0,0 +1,42 @@
# BAT-006 Design
- Status: draft
- Batch: BAT-006
## Architecture Summary
- BAT-004 execution loop 위에 ledger write-back 레이어를 추가한다. **application** 에 `LedgerPort`와 ledger outbox use case, **adapters/ledger** 에 in-memory/stub 및 portfolio-hub HTTP 어댑터, **runtime** 에 ledger retry worker/config 를 둔다. execution fill 전이는 슬롯 상태 전이를 먼저 보장하고 ledger 기록은 outbox 로 적재해 eventually-consistent 하게 처리한다.
## Changed Areas
- Docs: runtime-flows(체결→ledger outbox→portfolio-hub retry/conflict 흐름), interface-contract(`LedgerPort`, `FillStatus` 확장, portfolio-hub endpoint), project-structure(ledger adapter/outbox 위치), data-model(ledger trade fields, outbox work item, correlation_id).
- Modules:
- application: `LedgerPort`, ledger exceptions, ledger outbox command/service, execution fill hook.
- adapters/ledger: in-memory/stub ledger, portfolio-hub HTTP adapter.
- adapters/broker: paper/KIS `FillStatus.execution_id` 합성, fee 계산 운반.
- runtime: portfolio-hub config, ledger retry loop lifecycle.
- persistence: ledger outbox work item store/schema.
- Interfaces: `LedgerPort.record_trade(...)`, `FillStatus.execution_id/fee`, portfolio-hub `POST /v1/assets/{asset_id}/ledger/trades`.
## Key Decisions
1. `asset_id == portfolio_id`: 슬롯의 `portfolio_id` 를 ledger path param 으로 직접 사용한다. 매핑 조회나 asset master 동기화는 후속 범위다.
2. outbox 우선: fill 전이 경로는 ledger 직접 HTTP write 대신 durable outbox work item 을 적재한다. 슬롯 전이는 ledger write 성공과 분리한다.
3. 멱등 키: `correlation_id = {asset_id}:{order_id}:{execution_id}` 로 로컬 dedup 하고 portfolio-hub 409 는 `conflict_blocked` 로 분류한다.
4. outcome 어휘: `completed`, `duplicate_completed`, `retryable_failure`, `conflict_blocked` 네 가지로 worker 결과를 고정한다.
5. 도메인 순수성: `trex_core/domain` 은 portfolio-hub, HTTP, ledger adapter 를 import 하지 않는다. LedgerPort 는 application 경계, HTTP adapter 는 adapters 경계에 둔다.
6. 단일 기록 주체: 전략/도메인이 아니라 execution fill path 만 ledger outbox item 을 생성한다.
## Edge Cases
- 동일 `execution_id` work item 이 2회 생성/처리됨 → correlation_id 로 dedup, 원장 중복 0, outcome `duplicate_completed`.
- portfolio-hub 일시 실패/timeout → `retryable_failure`, 다음 worker tick 에 재시도, 슬롯 상태는 이미 전이된 상태 유지.
- portfolio-hub 409 conflict → `conflict_blocked`, 자동 무한 재시도 중단, 운영자 해소 대상으로 남김.
- `portfolio_id` 없는 체결 → 정의된 정책에 따라 ledger 기록 skip 또는 blocked outcome 으로 처리하되 슬롯 전이는 정상 수행.
- KIS 체결 데이터 부족 → 결정적 execution_id 합성 규칙으로 보강하고, fee 는 BrokerPort 계산, tax 는 0.
- retry worker 재시작 → persisted outbox 상태를 기준으로 미완료 item 만 재처리.
## Architecture Impact
- both (project-structure + runtime-flows). interface-contract(`LedgerPort`, `FillStatus`)와 data-model(outbox/correlation_id)도 갱신한다.
## Reference Doc Update Plan
- project-structure.md: `application` ledger port/outbox service, `adapters/ledger`, runtime retry worker, persistence schema 위치를 반영한다.
- runtime-flows.md: fill transition 이후 outbox 적재, retry worker, completed/duplicate/conflict/retryable 흐름을 추가한다.
- interface-contract.md: `LedgerPort.record_trade(...)`, `FillStatus.execution_id/fee`, portfolio-hub ledger endpoint/409 mapping 을 추가한다.
- data-model.md: ledger trade payload fields, outbox work item fields/status/outcome, `correlation_id` 멱등 규칙을 추가한다.
@@ -0,0 +1,35 @@
# BAT-006 Implementation
- Status: draft
- Batch: BAT-006
## Plan Summary
- LedgerPort 계약과 portfolio-hub/stub adapter 를 추가하고, execution fill 경로가 ledger outbox work item 을 적재하도록 연결한다. retry worker 와 dedup/outcome 처리를 구현한 뒤 baseline 문서를 실제 코드와 맞춘다.
## Changed Files
- 예정:
- `trex_core/application/*` — LedgerPort, ledger outbox service, execution fill hook.
- `trex_core/adapters/ledger/*` — in-memory/stub ledger, portfolio-hub adapter.
- `trex_core/adapters/broker/*` — FillStatus execution_id/fee 운반.
- `trex_core/runtime/*` — portfolio-hub config, retry worker lifecycle.
- persistence/migration 파일 — ledger outbox work item store.
- `docs/runtime-flows.md`, `docs/interface-contract.md`, `docs/project-structure.md`, `docs/data-model.md`.
- tests — ledger adapter, fill lifecycle, outbox retry/dedup/conflict, import sweep.
## Execution Log
1. 대기: `draft-batch-planning`/`draft-batch-design` 확인 후 구현 시작.
## Validation
- 예정:
- stub ledger `record_trade` 단위테스트.
- portfolio-hub adapter request contract + 409 mapping 테스트.
- buy/sell fill lifecycle 통합테스트.
- duplicate execution_id 중복 0 테스트.
- retryable failure 후 eventually completed 테스트.
- `conflict_blocked` 자동 재시도 중단 테스트.
- `trex_core/domain` import sweep.
- baseline 문서-코드 정합 리뷰.
## Remaining Risks
- portfolio-hub 실제 계약/자격증명 미가용 시 external integration evidence 가 stub/contract 수준으로 제한될 수 있다.
- outbox persistence schema 가 기존 repository transaction 경계와 맞지 않으면 design 조정이 필요하다.
@@ -0,0 +1,30 @@
# BAT-006: portfolio-hub ledger 통합
- Status: draft
- Profile: standard
- Source Discovery: dcy-004
- Included REQ: REQ-017, REQ-018, REQ-019, REQ-020
- Excluded REQ: 없음
## Summary
- dcy-004 슬라이스(체결을 외부 회계/포지션 원장에 기록)를 하나의 delivery 단위로 묶는다. BAT-004 의 주문 집행 루프 위에 `LedgerPort` + portfolio-hub 어댑터 + fill hook + ledger outbox 재시도/멱등 처리를 추가하고, baseline 문서를 실제 ledger 레이어와 정합시킨다.
## Scope
- In Scope:
- REQ-017: `LedgerPort.record_trade(...)` 계약, portfolio-hub ledger 어댑터, 결정론 stub/in-memory 원장, `TREX_PORTFOLIO_HUB_*` config.
- REQ-018: 매수/매도 fill 전이 시 ledger 기록 hook, `FillStatus.execution_id/fee` 확장, `asset_id = slot.portfolio_id` 사용, 단일 기록 주체 유지.
- REQ-019: ledger outbox work item, correlation_id 멱등, retry worker, outcome(`completed`/`duplicate_completed`/`retryable_failure`/`conflict_blocked`) 분류.
- REQ-020: runtime-flows/interface-contract/project-structure/data-model ledger baseline 정합.
- Out of Scope (후속 Discovery):
- `post_portfolio_transaction` 입출금 등 거래 외 트랜잭션, asset master 동기화, portfolio-hub ↔ core 양방향 reconciliation, 포지션 재구성, safety floor, 매수·매도 전략 데몬, 실계좌 go-live.
## 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-004 단일. 확정 결정: `asset_id == portfolio_id`, 별도 ledger outbox + retry loop, execution_id 결정적 합성(KIS/paper), fee 는 BrokerPort 계산, tax 기본 0.
- 핵심 리스크: 원장 기록 유실/중복(R-1), portfolio-hub 장애가 execution path 를 막는 결합(R-3). outbox + dedup + adapter 격리 + stub failure injection 으로 완화한다.
- portfolio-hub 실제 계약/자격증명은 orbit `post_ledger_trade` 동일 가정을 시작점으로 두되, verification 에서 adapter contract evidence 또는 미가용 blocker 를 분리 기록한다.
@@ -0,0 +1,47 @@
# BAT-006 Planning
- Status: draft
- Batch: BAT-006
- Profile: standard
## Included REQ
- REQ-017 (Integration): LedgerPort 추상화 + portfolio-hub 어댑터 + stub 원장
- REQ-018 (Integration): 체결→원장 기록 fill hook
- REQ-019 (Exception): ledger outbox durability + correlation_id 멱등
- REQ-020 (Documentation): ledger 레이어 baseline 문서 정합
## Delivery Plan
- 의존 순서대로 구현한다.
1. REQ-017: `trex_core/application` 에 `LedgerPort` 계약과 ledger 예외를 정의하고, `trex_core/adapters/ledger` 에 in-memory/stub 원장과 portfolio-hub HTTP 어댑터를 추가한다.
2. REQ-018: `FillStatus` 가 `execution_id`/`fee` 를 운반하도록 broker port 와 paper/KIS 어댑터를 확장하고, execution fill 전이에 ledger 기록 입력을 연결한다.
3. REQ-019: 직접 write 대신 ledger outbox 적재 + retry worker 로 경로를 고정하고, `correlation_id = {asset_id}:{order_id}:{execution_id}` dedup/outcome 분류를 구현한다.
4. REQ-020: 실제 코드 경계와 data model 이 확정된 뒤 baseline 4문서(runtime-flows/interface-contract/project-structure/data-model)를 갱신한다.
## Dependencies
- Internal:
- REQ-018 은 REQ-017 의 `LedgerPort`와 stub 원장 선행.
- REQ-019 는 REQ-018 의 fill 기록 이벤트를 직접 write 가 아니라 outbox work item 으로 전환.
- REQ-020 은 REQ-017~019 구현 결과에 의존.
- BAT-004 의 execution loop, BrokerPort, FillStatus, PostgreSQL runtime 위에서 확장한다.
- External:
- portfolio-hub ledger API(`POST /v1/assets/{asset_id}/ledger/trades`, orbit `post_ledger_trade` 패턴).
- portfolio-hub URL/token 환경 변수(`TREX_PORTFOLIO_HUB_*`).
- HTTP client, PostgreSQL(outbox persistence), 기존 .env loading(REQ-010).
## Design Gate
- Design Required Before Implementation: yes
- Reason: 신규 application port + external adapter + execution fill lifecycle + outbox durability/retry worker + baseline data model 이 모두 구조/인터페이스/런타임에 영향. 구현 전 `record_trade` 계약, fill event shape, outbox schema/state machine, failure/outcome policy 를 design.md 에 고정해야 한다.
## Milestones
1. M1 — REQ-017: LedgerPort + stub ledger + portfolio-hub adapter contract/409 handling + config.
2. M2 — REQ-018: FillStatus execution_id/fee 확장 + paper/KIS 결정적 값 운반 + buy/sell fill hook.
3. M3 — REQ-019: ledger outbox store + retry worker + correlation_id dedup + conflict/retry outcomes.
4. M4 — REQ-020: baseline 4문서 정합.
5. M5 — 통합 verification: buy/sell lifecycle, duplicate 0, retry eventually completed, conflict_blocked, import sweep.
## Risks
- R-1 (High): 원장 기록 유실/중복. 대응: outbox persistence + correlation_id dedup + duplicate_completed/conflict_blocked outcome + failure injection tests.
- R-2 (High): fill 전이와 ledger write 결합으로 슬롯 전이 지연/실패. 대응: 슬롯 전이는 우선 진행하고 ledger write 는 outbox retry 로 분리.
- R-3 (Medium): portfolio-hub 계약/자격증명 미가용. 대응: stub/in-memory 완전 검증, adapter contract test, 실제 통합은 evidence 또는 blocker 로 분리.
- R-4 (Medium): 도메인 순수성/단일 기록 주체 침식. 대응: LedgerPort 는 application 계약, HTTP 는 adapters 격리, `trex_core/domain` import sweep, 기록 주체는 execution path 로 한정.
- R-5 (Medium): REQ-020 baseline 이 구현보다 먼저 확정되어 drift 발생. 대응: baseline 갱신은 M4 로 후행하고 verification 에 코드-문서 정합 점검 포함.
@@ -0,0 +1,40 @@
# BAT-006 Verification
- Status: draft
- Batch: BAT-006
## Acceptance Mapping
- REQ-017:
- AC-1: in-memory stub 원장 `record_trade(...)` 1회 호출 시 거래 1건 적재와 필드 보존 evidence.
- AC-2: portfolio-hub adapter 가 `POST /v1/assets/{asset_id}/ledger/trades` 에 `execution_id` 포함 payload 를 전송하는 contract evidence.
- AC-3: portfolio-hub 409 응답이 `LedgerConflictError` 또는 `conflict_blocked` 경로로 표면화되는 evidence.
- AC-4: `trex_core/domain` portfolio-hub/HTTP 의존 0 import sweep evidence.
- REQ-018:
- AC-1: idle 슬롯 매수 intent 체결 시 holding 전이 + buy ledger item/record 1건 evidence.
- AC-2: holding 슬롯 매도 intent 체결 시 closed 전이 + sell ledger item/record 1건 evidence.
- AC-3: `FillStatus` 가 결정적 `execution_id`, fee, tax=0 을 운반하는 evidence.
- AC-4: `portfolio_id` 부재 체결 정책(skip/block)과 슬롯 전이 일관성 evidence.
- AC-5: ledger 기록 주체가 execution path 로 한정되는 code review/import evidence.
- REQ-019:
- AC-1: 동일 execution_id 2회 처리 시 원장 중복 0 evidence.
- AC-2: retryable portfolio-hub failure 후 retry 로 eventually completed evidence.
- AC-3: 409 conflict 가 `conflict_blocked` 로 남고 무한 자동 재시도하지 않는 evidence.
- AC-4: 이미 기록된 work item 재처리 시 `duplicate_completed` evidence.
- AC-5: portfolio-hub 불가 직후에도 슬롯 전이는 진행되는 분리 evidence.
- REQ-020:
- AC-1: 4개 baseline 문서에 ledger 레이어 반영 evidence.
- AC-2: LedgerPort, FillStatus, outbox 구조, 원장 필드 설명이 코드와 모순되지 않는 review evidence.
- AC-3: baseline 문서 변경 이력에 REQ-017~020 반영 기록 evidence.
## Evidence
- Test:
- 대기: 구현 후 테스트 결과 기록.
- Manual:
- 대기: baseline 문서-코드 정합 리뷰 기록.
- Logs:
- 대기: 필요 시 portfolio-hub adapter contract 또는 skip/blocker 로그 기록.
## Result
- Ready for Release: false
- Blocking Issues:
- 구현 및 검증 미진행.
+1
View File
@@ -13,3 +13,4 @@
| BAT-003 | batch-lite | release-candidate | REQ-010 | dcy-002 | [bat-003](./bat-003_20260604_daemon-dotenv-config/) |
| BAT-004 | standard | release-candidate | REQ-011, REQ-012, REQ-013, REQ-014, REQ-015 | dcy-003 | [bat-004](./bat-004_20260604_broker-execution-and-outbox/) |
| BAT-005 | batch-lite | release-candidate | REQ-016 | dcy-003 | [bat-005](./bat-005_20260604_kis-token-redis-cache/) |
| BAT-006 | standard | draft | REQ-017, REQ-018, REQ-019, REQ-020 | dcy-004 | [bat-006](./bat-006_20260604_portfolio-hub-ledger-integration/) |