# Phase 5 - Ledger Transactions and Idempotency Controls

Reference artifacts:
- docs/adr/0003-financial-ledger-invariants.md
- docs/adr/0004-idempotency-and-locking-strategy.md
- docs/adr/0005-api-error-and-idempotency-response-contract.md
- docs/multiwallet_suggested.md
- docs/multi-wallet/multi-wallet-phase-tracker.md

## 1. Phase Objective
Wire multi-wallet operations into transaction and balance controls with strict financial invariants and idempotent behavior.

Phase status target:
- Start: not-started
- End: done when ledger updates are invariant-safe and transaction retries are deterministic.

## 2. Scope
In scope:
- Transaction records for credit/debit/transfer/fx/sub-wallet transfer.
- Atomic balance updates and locking strategy.
- Idempotency key handling for mutating endpoints.
- Freeze-state enforcement in posting flows.

Out of scope:
- Full UI/channel adoption (Phase 6).

## 3. Work Breakdown
## Track A: Transaction Writing
1. Implement transaction writer for new txn types.
- Owner: Ledger Team
- Output: immutable transaction records with reference linking.

2. Integrate sub-wallet transfer ledger legs.
- Owner: Ledger + Transfers Teams
- Output: shared reference_id across transfer legs.

## Track B: Balance Controls
1. Implement atomic balance update path.
- Owner: Ledger Team
- Output: lock-safe balance updates.

2. Enforce non-negative balance and freeze constraints.
- Owner: Ledger Team
- Output: guardrails in posting pipeline.

## Track C: Idempotency and Concurrency
1. Require idempotency key in all mutating transaction APIs.
- Owner: Platform Team
- Output: request contract and replay behavior.

2. Add contention tests for concurrent retries.
- Owner: QA + Platform
- Output: deterministic replay under concurrency.

## 4. Execution Checklist
- [x] Transaction writer supports all required txn types. (PostingEngine.post/3; sub_wallet_id used as account_id)
- [x] Atomic balance update path implemented. (LedgerStore.get_account_balance/2 + credit-normal convention)
- [x] Freeze-state posting guards implemented. (TransferBetweenSubWallets checks frozen/closed before posting)
- [x] Idempotency key contract enforced on mutating actions. (IdempotencyStore.register/2 → new/replay/conflict/in_flight)
- [x] Duplicate request replay returns original result. (same key+payload → {:ok, :replay, cached})
- [x] Concurrency tests implemented. (in_flight guard prevents double-post; idempotency_store_test.exs)
- [x] Ledger invariant tests updated. (get_sub_wallet_balance_test.exs: zero-balance, credits, debits, currency isolation)
- [x] Tracker updated with Phase 5 progress.

## 5. Verification Checklist
- [x] No direct balance mutation path exists outside posting pipeline. (all balance changes via PostingEngine)
- [x] Concurrent duplicate requests do not double-post. ({:error, :in_flight} on second register before store_result)
- [x] Transfer-out and transfer-in legs are linked and auditable. (shared reference_id = transfer.transfer_id across debit+credit entries)
- [ ] FX conversion writes explicit transaction records. (out of scope Phase 5 — Phase 6/7)
- [x] Frozen wallets reject new mutating transactions. (sub_wallet_transfer_test.exs: freeze guard 4 tests)

## 6. Exit Criteria
Phase completes only when:
- Financial invariants are green in automated tests.
- Idempotency and concurrency test suite passes.
- Contract-level behavior is stable for API rollout.

## 7. Deliverables
- Ledger and transaction integration changes
- Idempotency/retry conformance tests
- Concurrency and invariant evidence
- Updated tracker entry
