## P0 — 0 No P0 findings. ## P1 — 4 1. **Repeated Preview → Confirm can duplicate the same True Wealth cashflow** - **Files:** `src/jarvis_finance/services/performance_hardening.py:519-543`, `:621-664` - Existing confirmed rows are included in the next fingerprint but never compared with proposed entries for economic duplication. Re-previewing the identical cashflow produces a new fingerprint; a different `confirmation_id` then creates another transaction because transaction identity includes that confirmation ID. - **Reproduced:** two confirmations of the same CHF 1,000 deposit each reported `written_cashflows=1`. - **Impact:** duplicated external cashflows materially corrupt TTWROR/XIRR. - **Fix:** derive a stable economic row identity independent of confirmation ID, reject or no-op exact persisted duplicates transactionally, and represent corrections as append-only versions/reversals. 2. **Incomplete daily valuations override complete official PostFinance components** - **File:** `src/jarvis_finance/services/portfolio_performance.py:528-555` - A source is eligible merely when both account IDs occur; quality must not be `complete`. The unconditional source priority then selects `daily_market_fx*` over complete official components. - **Reproduced:** one complete depot row plus one partial cash row selected CHF `322399.2170831154` instead of the reconciled official CHF `321149.23`, with `stale_price`. - **Impact:** materially false daily portfolio value and avoidable unavailable performance despite a complete official source. - **Fix:** require exactly one latest `quality_status='complete'` component for every expected account before source-priority selection; otherwise fall back to the complete official source. 3. **Setup API can say “ready” while its own reclassification blocks activation** - **File:** `src/jarvis_finance/services/performance_hardening.py:776-801` - Status becomes `ready` whenever either TTWROR or XIRR is already complete. The subsequently calculated `diagnostics.reclassification.can_activate` is ignored. - **Impact:** `/performance/setup` and the UI can display “Bereit zur Aktivierung” while the activation preview rejects the same source as unclear. - **Fix:** derive readiness from all activation gates, including `can_activate`, cashflow coverage, component completeness, and required source-specific blockers. 4. **Official PostFinance component provenance can be silently discarded** - **Files:** `src/jarvis_finance/services/portfolio_analytics.py:402-415`, `src/jarvis_finance/services/postfinance_service.py:851-872` - Snapshot equality ignores `source` and `source_reference`. If an existing daily valuation happens to equal an official component, `store_valuation_snapshot()` returns `False` and writes no official component or supersession lineage. - **Reproduced:** an official component equal to an existing daily row returned `written=False`; the latest source remained `daily_market_fx_v4`. - **Impact:** the confirmed import does not reliably materialize the promised official component history and loses source-specific audit lineage. - **Fix:** include provenance/source identity in idempotency semantics and version/supersede distinct-source observations explicitly. ## P2 — 2 1. **Multiple same-day official snapshots are not canonicalized before materialization** - **File:** `src/jarvis_finance/services/portfolio_performance.py:491-555` - Every eligible same-day official snapshot is appended to one source group. Later aggregation happens to overwrite account/day values according to list order, rather than the reader selecting one canonical snapshot explicitly. - **Impact:** fragile ordering-dependent behavior and duplicate `Valuation` objects exposed to future consumers. - **Fix:** rank official snapshots per business day first, then materialize only the canonical snapshot’s two components. 2. **Reclassification reports an empty activity set as activatable** - **File:** `src/jarvis_finance/services/performance_hardening.py:341-415` - `can_activate` is solely `unclear_count == 0`, so zero activities returns `True`. - **Impact:** misleading standalone preview contract, even though another activation layer may add a separate history blocker. - **Fix:** require positive, period-appropriate evidence or return a distinct no-activity blocker. ## Missing release verification - The schema gate only asserts `MIGRATION_VERSION == 49`; it does not open a prior installed v49 database and exercise the changed confirm/import paths. - API tests check membership in `READ_ONLY_POST_PATHS`, not actual middleware behavior under disabled write mode: preview allowed, confirm denied, and preview causing zero DB changes. - No regression covers re-previewing and reconfirming an already-persisted cashflow. - No tests cover partial daily components versus complete official components, equal-value/different-source provenance, contradictory setup readiness, or multiple same-day official imports. - No deployment/read-only smoke evidence brackets startup/UI/API access with all-table digests and timer state. - Focused evidence run: Sprint 20C tests `9 passed`; related backend tests `52 passed`; frontend component tests `6 passed`. - **Files modified:** none.