CHANGES_REQUIRED - **P2 — `budget_transfers` join can multiply financial rows.** `household_financials.py:103-105` joins transfer memberships with an `OR`, while the schema has no uniqueness constraint preventing one transaction from belonging to multiple `budget_transfers` rows (`migrations.py:1012-1027`). A synthetic duplicate membership—valid under the schema—changed one two-leg CHF 900 transfer from `(confirmed_count=2, transfer_count=2, volume=900)` to `(4, 4, 1800)`. The same multiplication can corrupt income, expense, refund-category totals, and transaction counts if an invalid relation references those rows. Join through a one-row-per-transaction membership CTE and fail closed on conflicting memberships, or enforce the invariant in schema and migration. - **P2 — changed analytics surfaces still present incomplete financial data as trustworthy zeroes.** `budget_analytics_v2.py:26-107` and `:111-188` consume nullable canonical effects but discard `unavailable_chf`/`unlinked_refund` metadata. `budget_overview.py:86-102` similarly returns an empty category summary without incompleteness metadata. A synthetic confirmed EUR expense with missing FX produced cockpit income/expense/net `0.00`, no quality keys, budget-vs-actual `warnings=[]`, and an empty category summary. Propagate `data_status`, unavailable counts, and warnings through every changed cockpit/analysis/category contract. - **P2 — transaction-page response can rewrite the URL after navigation.** `HouseholdTransactionsPage.vue:71-90,110,126` guards overlapping loads but does not invalidate or abort them on unmount. If the initial request resolves after navigation, `syncUrl()` uses the destination’s current pathname and appends stale transaction filters to it. Add an unmount generation increment/abort, as already done on the review page, and avoid global URL mutation from an unmounted component. **Paired-transfer closure:** The original double-count defect is closed for valid writer-produced one-to-one pairs. Focused tests passed (`2 passed`): global CHF 900 pair → volume 900, each account scope → 900, unmatched CHF 100 → total 1000, missing-FX pair → null with one unavailable logical unit; monthly/chart/overview propagation is correct. It is not fully release-closed because the unconstrained join still permits row multiplication. - Reviewed complete `039d005…b5c3ddd` diff; no P0/P1 found. - Exact HEAD verified before/after: `b5c3ddd8003410bc8a4e31c4d07589d46875c90d`. - Worktree clean before/after; `git diff --check` clean. - No files created or modified; no full suites rerun.