Files
portfolio-hub/docs/batches/bat-016_20260605_ledger-accounting-consolidation/index.md
T
genichinandClaude Opus 4.8 2a19b7f058 fix: ledger write idempotency for TimescaleDB hypertable (BAT-016 rework)
BAT-016's initial implementation passed only against mocked repositories and
broke on a real database. Two defects fixed:

1. insert_ledger_trade used `ON CONFLICT (portfolio_id, order_id, execution_id)
   WHERE order_id IS NOT NULL` but portfolio_ledger is a TimescaleDB hypertable,
   which cannot have that partial unique index (must include the partitioning
   column recorded_at). The statement errored against Postgres. Replaced with
   application-level idempotency: SELECT-before-insert inside the existing
   `SELECT ... FOR UPDATE` portfolio row lock, which serializes concurrent
   same-portfolio writes (race-safe). Duplicate returns current authoritative
   portfolio state (dcy-006 OQ-4 b).

2. `with self._connect() as conn:` closes the shared psycopg3 connection on exit,
   leaving the reused repository connection unusable. Switched to
   `with conn.transaction():` (commits without closing).

Added tests/test_ledger_consolidation_integration.py — real-Postgres integration
tests (new / duplicate / negative-balance) that close the mock-only verification
gap. Full suite: 376 passed.

SDLC: REQ-036/037 CHG-20260605-03 reconcile OQ-7 (ii) (DB partial unique →
application-level idempotency) since the hypertable makes the DB constraint
infeasible. REQ-036/037/038 → Implemented; BAT-016 → release-candidate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 22:11:17 +09:00

2.5 KiB

BAT-016: ledger 회계 책임 단일화 + portfolio_ledger 통합

  • Status: release-candidate
  • Profile: standard
  • Source Discovery: dcy-006
  • Included REQ: REQ-036, REQ-037, REQ-038
  • Excluded REQ: 없음

Summary

  • dcy-006(ledger trade write 회계 책임 단일화) 산출물 3건을 단일 batch로 묶는다. 신 path(POST /v1/portfolios/{id}/ledger/trades)를 portfolio 회계의 단일 권위 endpoint로 재정의하고, 두 ledger 테이블(portfolio_ledger/ledger_trades)을 portfolio_ledger 단일 회계 원장으로 통합하며, 응답에 거래 후 권위 상태를 포함해 trex-core daemon의 drift를 차단한다(issue #8).

Scope

  • In Scope:
    • REQ-036 (Migration): portfolio_ledger에 broker 컬럼(order_id/execution_id NULL, side, executed_at, ledger_entry_id PK) + partial UNIQUE index + NUMERIC(20,8) 타입 변경 + action→side + ledger_trades DROP + data-model.md
    • REQ-037 (Interface): 신 path 단일 트랜잭션 회계(음수 허용) + row lock + cash_balance_after/asset_quantity_after 응답 + duplicate 현 상태 + 도메인 모델/repository 통합(LedgerEntry 단일화, LedgerTrade 삭제) + interface-contract.md/runtime-flows.md
    • REQ-038 (Interface): 레거시 buy/sell deprecated 표기(deprecated=True + Deprecation: true 헤더), 동작 보존
  • Out of Scope:
    • 레거시 buy/sell endpoint 실제 제거 (후속 정리 batch/Discovery — dcy-006 Out of Scope)
    • prod 환경 ledger_trades 데이터 backfill (release 단계 별도 검토)
    • 응답 추가 필드(total_value_after, profit_buffer_after 등) — 본 issue는 cash/quantity만
    • REL-001/REL-002 일정과 혼재 (별도 REL-003 등으로 분리 — dcy-006 A-4)

Documents

Notes

  • 공통 trigger: issue #8 trex-core drift 방지 + 회계 원장 단일화
  • 공통 release: 별도 REL(REL-003 등) 분리 배포 (dcy-006 A-4 동의)
  • REQ-036(마이그레이션) 선행 — REQ-037/038은 portfolio_ledger 신 스키마 위에서 동작. 구현 순서 REQ-036 → REQ-037 → REQ-038.
  • 본 워크스페이스는 개발용 — prod race condition / 마이그레이션 정밀도(DOUBLE→NUMERIC) / action 분포 검증은 release 단계 위임(workspace_purpose 메모리, dcy-006 R-5/R-6/R-7).
  • 대규모 변경(마이그레이션 + 도메인 모델 통합 + 응답 확장 + 회계 동작 변경)이라 standard profile + 통합 회귀 필수.