## Final review: **FAIL — 1 High, 2 Medium findings** ### High — “Atomic” mapping-set confirmation commits each mapping prematurely - **Files/lines:** - `src/jarvis_finance/services/portfolio_data.py:457-538` - `src/jarvis_finance/market_data/mappings.py:157-160` - `src/jarvis_finance/market_data/instruments.py:42-64` - **Problem:** `confirm_postfinance_instrument_mappings()` starts one transaction and passes `commit=False`, but `confirm_instrument_price_mapping()` calls `ensure_instrument_metadata_quality()`, which unconditionally executes `conn.commit()`. If a later one of the 22 decisions fails, earlier instruments, mappings, alerts, and audit entries remain committed despite the outer rollback. - **Verified:** after calling `confirm_instrument_price_mapping(..., commit=False)`, `conn.in_transaction` became false and the mapping survived an explicit rollback. - **Action:** propagate transaction ownership into the quality helper—e.g. add `commit=False` support or remove commits from nested helpers—and add a failure-on-later-mapping regression test proving zero mappings/instruments/audits survive. ### Medium — ISIN uniqueness is case-sensitive while application identity is case-insensitive - **Files/lines:** - `src/jarvis_finance/storage/migrations.py:466-475` - `src/jarvis_finance/market_data/mappings.py:57-64` - **Problem:** migration duplicate detection and the unique index use raw `isin`, while mapping logic uppercases ISINs and other queries use `upper(isin)`. SQLite therefore allows both `us0000000001` and `US0000000001` as separate canonical instruments. - **Verified:** both case variants could be inserted after migration 43. - **Action:** normalize existing non-empty ISINs before indexing and enforce uniqueness on `upper(trim(isin))` (or use `COLLATE NOCASE`), with a migration test covering legacy lowercase/case-variant rows. ### Medium — Historical FMP quotes invent USD when currency is absent - **Files/lines:** - `src/jarvis_finance/market_data/prices.py:127-141` - `src/jarvis_finance/services/portfolio_analytics.py:351-356` - **Problem:** a valid historical row containing only date/close is assigned `USD`. This fabricates metadata and causes approved non-USD mappings such as `APC.F/EUR` to be rejected as `currency_mismatch`; USD rows are accepted based on an unsupported assumption. - **Action:** use the confirmed mapping currency as the historical quote currency, or return missing currency and resolve it explicitly in the orchestrator. Do not default historical rows to USD. Add a non-USD historical-row test with the currency field omitted. ### Verification - Focused tests: **24 passed** - Ruff on changed Sprint-9 surfaces: **passed** - `git diff --check`: **passed** - Repository files created or modified by review: **none** - Initial test invocation was blocked by productive-runtime environment guards; rerunning with disposable `/tmp` test paths passed.