Files
trex-core/docs/srs/Integration/req-018_fill-to-ledger-recording.md
T
genichinandClaude Opus 4.8 b851b927ee fix(ledger): dcy-015 outbox 영속 오류 분류 + 백오프/dead-letter (BAT-019)
portfolio-hub 404(미등록 포트폴리오)가 retryable 로 분류되어 백오프·상한 없이
초당 영구 재시도되던 버그(issue #13, 실측 930회) 정정.

거버넌스: 전부 change-req (신규 REQ 없음, dcy-015 OQ-3; 백오프 env 는 REQ-019 흡수).
- REQ-017: 404/400/422 → LedgerPermanentError 분류 (409 conflict / 408·429·5xx·
  network retryable 불변). LedgerPort 에 permanent 타입 추가
- REQ-019: 영속 → 터미널 delivery_failed 즉시(재시도 0). retryable 지수 백오프
  +jitter+next_retry_at, max_attempts 초과 시 dead-letter delivery_failed.
  list_pending 이 백오프 행 스킵(head-of-line 보호). 마이그레이션 007(status enum
  +next_retry_at). 백오프 env(base/cap/max-attempts)
- REQ-018: 터미널/dead-letter WARN + WriterStats.delivery_failed 카운터 가시화
- REQ-020: runtime-flows/data-model/interface-contract 정합

단일 터미널 delivery_failed(permanent/dead-letter, last_outcome 로 사유 구분) —
conflict_blocked 패턴과 동형. dead-letter 는 운영자 재처리 가능 상태.

검증: 단위 311 passed/34 skipped, 인프라 게이트(PG+RabbitMQ) 345 passed, ruff clean.
신규 test_ledger_outbox_backoff + adapter/PG 테스트, 기존 retryable 백오프 정합.
BAT-019 release-candidate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 16:12:17 +09:00

11 KiB

req-018: 체결→원장 기록 (집행 루프 fill hook)

  • Status: Implemented
  • Type: Integration
  • Priority: High
  • Owner: project maintainers

Intent

  • 코어 집행 루프가 체결(매수/매도) 시 해당 거래를 portfolio-hub 원장에 기록하도록, fill 전이 경로에 ledger 기록 hook 을 더하고 체결 데이터(execution_id/fee)를 브로커 계약으로 운반한다.

Requirement

  • 집행 루프가 매수 체결(pending_buy→holding)·매도 체결(pending_sell→closed) 시 LedgerPort 로 거래를 기록한다. ledger path 의 asset_id 는 슬롯 portfolio_id(= asset_id)를 직접 사용하고 side/qty/price/execution_id/fee/tax/executed_at 을 함께 보낸다.
  • FillStatus(broker_port) 가 execution_id 와 fee 를 운반하도록 계약을 확장한다. execution_id 는 결정적으로 합성한다(KIS: kis-daily-ccld:{ord_dt}:{ord_gno_brno}:{odno}:{tot_ccld_qty}, paper: paper:{broker_order_id}:{filled_qty}). fee 는 BrokerPort fee 계산(orbit calculate_fee(side, amount) 패턴), tax 는 기본 0 으로 한다.
  • 원장 기록 주체는 코어 집행 경로 단일로 한정한다(전략/도메인은 원장에 접근하지 않는다).

Acceptance Criteria

  1. Given idle 슬롯에 매수 intent → 체결, When 집행 루프 fill 전이, Then 슬롯이 holding 으로 전이되고 원장에 buy 거래 1건이 기록된다(asset_id = 슬롯 portfolio_id).
  2. Given holding 슬롯에 매도 intent → 체결, When 집행 루프 fill 전이, Then 슬롯이 closed 로 전이되고 원장에 sell 거래 1건이 기록된다.
  3. Given 체결된 주문, When fill 을 읽음, Then FillStatus 가 결정적 execution_id 와 계산된 fee(tax=0)를 운반한다.
  4. Given 슬롯에 portfolio_id 가 없는 체결, When fill 전이, Then 원장 기록을 건너뛰거나(또는 정의된 정책으로 처리) 슬롯 전이 자체는 정상 수행된다.
  5. Given 전략/도메인 코드, When 점검, Then 원장 기록은 코어 집행 경로에서만 발생한다(단일 기록 주체). (NFR-3)

Impacted Area

  • Docs: docs/runtime-flows.md(체결→원장 기록 흐름), docs/interface-contract.md(FillStatus 확장) — REQ-020 에서 정합
  • Modules: trex_core/application/execution.py(fill 전이에 ledger 기록 단계), trex_core/application/broker_port.py(FillStatus.execution_id/fee), trex_core/adapters/broker/{paper,kis}.py(execution_id 합성 + fee 계산)
  • Tests: stub 원장으로 매수/매도 체결 시 buy/sell 1건 + 슬롯 전이, FillStatus execution_id/fee 운반, portfolio_id 부재 처리

Notes

  • 출처: dcy-004 FR-2, OQ-1(asset_id == portfolio_id, orbit 근거), OQ-3(execution_id/fee/tax 출처), NFR-3.
  • OQ-1: 슬롯은 이미 buy intent 가 portfolio_id 를 공급해 캐시하므로 추가 매핑/조회 없이 path param 으로 사용한다.
  • portfolio_id 부재 시 기록 skip vs 거부 정책은 구현 시 확정(AC-4 는 둘 다 허용하되 슬롯 전이 일관성을 요구).
  • 멱등/무유실/재시도(correlation_id, outbox)는 REQ-019 에서 다룬다. 본 REQ 는 기록 호출 경로와 데이터 운반에 한정한다.

Change Log

CHG-20260604-01

  • Date: 2026-06-04
  • Author: Justin Ko

Change Summary

  • dcy-004 FR-2 로부터 최초 생성(Proposed). OQ-1/OQ-3 결정 반영, NFR-3(단일 기록 주체) 흡수.

Intent

  • 집행 루프 fill 전이에서 체결을 원장에 기록하는 경로와 FillStatus 확장(execution_id/fee)을 backlog 로 정규화.

Acceptance Criteria Delta

  • Added:
    • 매수/매도 체결 기록+전이, FillStatus execution_id/fee, portfolio_id 부재, 단일 기록 주체 5개 기준
  • Updated:
    • 없음
  • Removed:
    • 없음

Impacted Area Delta

  • Docs:
    • docs/runtime-flows.md, docs/interface-contract.md
  • Modules:
    • execution.py(ledger hook), broker_port.py(FillStatus), paper/kis 어댑터(execution_id/fee)
  • Tests:
    • 체결→기록 통합테스트, FillStatus 운반, portfolio_id 부재

Delivery Trace Delta

  • Batches:
    • none
  • Releases:
    • none

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: keep-current
  • Follow-up Action: confirm-req 후 batch 편성

Validation Plan

  • stub 원장으로 매수/매도 체결 lifecycle 통합테스트 + FillStatus 확장 테스트로 검증.

CHG-20260604-02

  • Date: 2026-06-04
  • Author: Justin Ko

Change Summary

  • Status 변경: Proposed -> Approved. confirm-req 승인 게이트 통과.

Intent

  • 집행 루프 fill 전이의 ledger 기록 hook 과 FillStatus 확장을 delivery input 으로 승인.

Acceptance Criteria Delta

  • Added:
    • 없음
  • Updated:
    • 없음
  • Removed:
    • 없음

Impacted Area Delta

  • Docs:
    • 없음
  • Modules:
    • 없음
  • Tests:
    • 없음

Delivery Trace Delta

  • Batches:
    • none
  • Releases:
    • none

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: Approved
  • Follow-up Action: batch 편성

Validation Plan

  • 기존 Acceptance Criteria 로 batch delivery 에서 검증.

CHG-20260604-03

  • Date: 2026-06-04
  • Author: Justin Ko

Change Summary

  • Status 변경: Approved -> Implemented. BAT-006 release-candidate verification evidence 기반.

Intent

  • 집행 루프 fill→ledger hook + FillStatus.execution_id/fee 확장 구현과 검증 evidence 확보 후 구현 완료 상태로 동기화.

Acceptance Criteria Delta

  • Added/Updated/Removed: 없음

Impacted Area Delta

  • Docs/Modules/Tests: 없음 (변경은 상태 전이만)

Delivery Trace Delta

  • Batches:
    • BAT-006 (release-candidate)
  • Releases:
    • none

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: Implemented
  • Follow-up Action: release 단계는 별도 진행

Validation Plan

  • AC-1: tests/application/test_execution_ledger.py::test_buy_fill_enqueues_one_ledger_item_and_writer_records_it.
  • AC-2: tests/application/test_execution_ledger.py::test_sell_fill_enqueues_sell_ledger_item.
  • AC-3: 위 buy 테스트가 FillStatus.execution_id/fee/tax 운반 직접 검증.
  • AC-4: tests/application/test_execution_ledger.py::test_portfolio_id_absent_skips_ledger_but_transitions_slot.
  • AC-5: tests/domain/test_domain_import_sweep.py + grep 결과(trex_core/application/execution.py 단일 enqueue 지점).

CHG-20260608-01

  • Date: 2026-06-08
  • Author: Justin Ko

Change Summary

  • (change-req, dcy-011/issue #11) _record_ledger 의 ledger skip 을 무성에서 가시화로 전환: portfolio_id/execution_id 누락 skip 시 WARN 로그 + ExecutionResult.ledger_skipped 카운터 노출(슬롯 전이는 그대로). BAT-015 재구현·재검증 완료 → Implemented 유지.

Intent

  • portfolio_id 없는 체결의 ledger silent skip(회계 누락)을 운영자가 탐지 가능하게(issue #11 제안 ②). OQ-4 결정으로 outbox 마커 행은 도입하지 않고 로그+메트릭만; 영구 탐지는 REQ-055 점검 쿼리에 위임.

Acceptance Criteria Delta

  • Updated:
    • AC-4: skip 시 무성 반환 → WARN 로그 + 카운터 가시화(두 skip 경로 모두).

Impacted Area Delta

  • Modules: trex_core/application/execution.py(_record_ledger 로그 + _log 추가)
  • Docs: docs/runtime-flows.md
  • Tests: tests/application/test_execution_ledger.py::test_ledger_skip_emits_warning

Delivery Trace Delta

  • Batches: BAT-015
  • Releases: none

Revalidation Impact

  • Reverification Needed: yes (BAT-015 에서 완료)
  • Existing Implementation Invalidated: no (관측만 추가, 전이 동작 불변)
  • Status Recommendation: Implemented (change-req → BAT-015 재검증)
  • Follow-up Action: confirm-req-implemented(BAT-015).

Validation Plan

  • BAT-015: ledger skip WARN 로그 단위(caplog) + 회귀.

CHG-20260608-02

  • Date: 2026-06-08
  • Author: Justin Ko

Change Summary

  • (change-req, dcy-013/issue #9) 부분 체결 후 외부 취소 시 체결분(ccld_qty)을 원장에 1회 기록한다. _on_partial_cancel 이 _record_ledger(기존)를 재사용해 partial fill 의 execution_id/fee/qty 를 정확히 운반. BAT-017 재구현·재검증 완료 → Implemented 유지.

Intent

  • 전량 체결만 다루던 원장 기록을 부분 체결+취소에도 확장해 체결분 누락/이중기록을 방지(정확 회계, OQ-1 A안).

Acceptance Criteria Delta

  • Updated:
    • AC-1/2 의 fill→원장 기록을 부분 체결 후 취소(체결분 1회)에도 적용.

Impacted Area Delta

  • Modules: trex_core/application/execution.py(_on_partial_cancel → _record_ledger 재사용)
  • Tests: tests/application/test_execution_cancel.py::test_partial_fill_then_cancel_records_and_keeps_remainder

Delivery Trace Delta

  • Batches: BAT-017
  • Releases: none

Revalidation Impact

  • Reverification Needed: yes (BAT-017 에서 완료)
  • Existing Implementation Invalidated: no (기록 경로 재사용, 호출 지점만 확장)
  • Status Recommendation: Implemented (change-req → BAT-017 재검증)
  • Follow-up Action: confirm-req-implemented(BAT-017).

Validation Plan

  • BAT-017: 부분 취소 시 sell 원장 1건(qty=체결분, price=체결가) 단위.

CHG-20260608-03

  • Date: 2026-06-08
  • Author: Justin Ko

Change Summary

  • (change-req, dcy-015/issue #13) ledger 터미널 실패 가시화 확장: delivery_failed(permanent/dead-letter)를 WriterStats.delivery_failed 카운터 + WARN 로그 + 구분 status 로 노출(dcy-011 ledger_skipped 가시화 패턴 정합). dead-letter 는 운영자 재처리 가능 상태이며 find_ledger_gap_slots(REQ-055)·skip 가시화와 연계. BAT-019 재구현·재검증 완료 → Implemented 유지.

Intent

  • ledger 가 끝내 기록되지 않는 실패(404 영속·dead-letter)가 무성 pending 으로 남지 않고 운영자에게 노출되도록(NFR-2 가시성).

Acceptance Criteria Delta

  • Updated:
    • 원장 미기록(터미널 delivery_failed) 시 WARN 로그 + 카운터 + 구분 status 가시화.

Impacted Area Delta

  • Modules: trex_core/application/ledger_outbox.py(WARN + WriterStats.delivery_failed)
  • Tests: tests/application/test_ledger_outbox_backoff.py::test_permanent_failure_emits_warning

Delivery Trace Delta

  • Batches: BAT-019
  • Releases: none

Revalidation Impact

  • Reverification Needed: yes (BAT-019 에서 완료)
  • Existing Implementation Invalidated: no (관측만 추가)
  • Status Recommendation: Implemented (change-req → BAT-019 재검증)
  • Follow-up Action: confirm-req-implemented(BAT-019).

Validation Plan

  • BAT-019: delivery_failed WARN 로그(caplog) + 카운터 단위.