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>
This commit is contained in:
2026-06-05 22:11:17 +09:00
co-authored by Claude Opus 4.8
parent 44f2102d26
commit 2a19b7f058
11 changed files with 414 additions and 63 deletions
@@ -1,6 +1,6 @@
# REQ-038: 레거시 buy/sell endpoint deprecated 표기
- Status: Approved
- Status: Implemented
- Type: Interface
- Priority: Low
- Owner: Justin Ko
@@ -39,6 +39,34 @@
## Change Log
### CHG-20260605-03
- Date: 2026-06-05
- Author: Justin Ko
#### Change Summary
- Status: Approved → Implemented
#### Intent
- BAT-016 confirm-batch-verification 완료. 레거시 buy/sell `deprecated=True` + `Deprecation: true` 헤더 구현, 동작 보존. AC-1~4 검증(`tests/test_auth.py::test_legacy_buy_sell_routes_emit_deprecation_header` 포함). 전체 376 passed.
#### Acceptance Criteria Delta
- No change
#### Impacted Area Delta
- No change
#### Delivery Trace Delta
- Batches:
- BAT-016 (release-candidate)
- Releases:
- REL-003 (예정)
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: implemented
- Follow-up Action: 실제 endpoint 제거는 후속 정리 트랙
### CHG-20260605-02
- Date: 2026-06-05
- Author: Justin Ko