# Sprint 13 hotfix: global portfolio aggregation

## Scope

This hotfix changes the shared portfolio read model only. It does not rewrite or delete official source bytes, import batches, ledger events, snapshots, cost-basis lots, canonical projections, or historical manual values.

## Root cause

The PostFinance overview contains currency rows that combine a true currency cash amount and rounded FX rate with a CHF column representing the whole portfolio's currency exposure. Sprint 13 projected that exposure column as cash. The two projected values therefore summed to the official account total instead of the official cash subtotal.

A second inclusion collision existed in equity: instrument-bearing cash-settlement ledger rows could create shadow holdings on the trading-cash role, while the official holdings belong to the separate depot role. An older market-analysis snapshot could also override a newer official holdings snapshot.

## Contract

- Account totals from `postfinance_official_import` are controls, never additive holdings.
- Cash is resolved from the explicit `etrading_cash` role, original currency amounts, rounded source FX, and the signed-off cash subtotal.
- Rounded component CHF values are deterministically reconciled pro rata to the official subtotal; no adjustment asset is created.
- Holdings are resolved from the explicit `etrading_depot` role and official position snapshot.
- Cash-settlement ledger rows remain available for audit and cost basis but do not create holdings on the cash role when the official depot snapshot covers the instrument.
- A released market-analysis value replaces an official source value only when its `as_of` is newer. The effective valuation timestamp remains visible.
- Historical manual placeholders and immutable canonical rows remain present but are superseded by provenance-aware read-model selection.
- TrueWealth and non-PostFinance aggregation rules remain unchanged.

## Shared consumers

The shared cash resolver feeds the cash API and dashboard/Command Center cash overview. The role-aware official position resolver feeds dashboard positions, equity APIs, overview/advisor allocations, and future portfolio-analysis runs. The PostFinance summary uses the same reconciled source components.

## Delayed review findings reverified at the merge base

All three findings were rerun read-only against exact commit `17ad9ad9eba002b74ef18664fa1a008d926bf5fd` before applying the hotfix:

1. Same-day conflicts in `positions_snapshot` and `cash_balances`: **stale/already fixed**. The preview conflict test passed and confirm was not required to discover the conflict.
2. Immutable canonical projections in `transactions`, `positions_snapshot`, and `cash_balances`: **stale/already fixed**. Update and delete trigger assertions passed for all three tables.
3. `/api/postfinance/summary` privacy allowlist: **stale/already fixed**. The summary contract test passed and exposes no account, batch, snapshot, instrument, ISIN, document, customer, or account-number identifiers.

Evidence: the three exact base-commit tests passed (`3 passed`). The findings must be rerun again with the complete suite and final review at the hotfix HEAD.

## Regression coverage

The synthetic production-shape contract includes 22 positions, two currency cash rows, a misleading account-total-sized exposure projection, a historical manual placeholder, a separate E-Finance role, internal transfers, TrueWealth, and both older and newer market-analysis snapshots. It verifies no double counting, read-only GET behavior, historical preservation, privacy, and repeated-import idempotency.
