## Schlussverdikt: **BLOCK** **P0: 0 · P1: 6 · P2: 1** ### P1 — Release-blockierend 1. **Vorhersehbare Transaktions-ID kann eine Bestätigung lautlos verschlucken** - `src/jarvis_finance/services/truewealth_productization.py:407-435` - `INSERT OR IGNORE` akzeptiert eine bereits belegte `transaction_id`, ohne deren Semantik zu validieren. Synthetisch reproduziert: Preview meldet einen neuen Cashflow, eine fremde `fee`-Transaktion belegt die Stable-ID, Confirm schreibt `0` Cashflows und protokolliert dennoch Erfolg. - **Fix:** Normales `INSERT`; bei Kollision unter Write-Lock sämtliche Dimensionen validieren (Typ, Konto, Datum, Betrag, Währung, Lineage, Source). Nur eine exakt kompatible Zeile darf als idempotenter No-op gelten, sonst fail-closed. 2. **Gemischte valide und FX-/Währungs-fehlerhafte Treffer werden teilweise bestätigt** - `src/jarvis_finance/services/truewealth_productization.py:235-260,341-390` - Ein erkannter Empfänger-Cashflow mit fehlendem CHF-/FX-Nachweis landet nur in `excluded`; wenn daneben ein valider Treffer existiert, bleibt `can_confirm=true`. Reproduziert: `1 secure + 1 matching USD/FX-missing`, leere globale `reason_codes`, Confirm schreibt und auditiert nur die CHF-Zeile. - Das kann Historie unbemerkt unvollständig machen; die aktivierte Zukunftsverarbeitung behandelt solche Fälle ebenfalls als `no_candidates`. - **Fix:** Empfänger-Treffer mit ungültiger Provenienz/CHF-Semantik als blockierende unresolved candidates führen; Confirm und Automation müssen bei jedem solchen Treffer vollständig stoppen. 3. **Bankerkennung hängt weiterhin an einem Präsentationsnamen** - `src/jarvis_finance/services/truewealth_productization.py:96-115` - `lower(a.name) LIKE '%raiffeisen%'` ist keine stabile Source-/Account-Zuordnung. Synthetisches Umbenennen desselben validen Checking-Kontos ließ den Treffer vollständig verschwinden. - **Fix:** Stabile, auditierte Bankquelle→Budgetkonto-Zuordnung verwenden und unter Confirm-Lock Rolle, Aktivität, Währung und Source-Provenienz erneut validieren. 4. **Valuation-Audit dupliziert sensible Roh- und Instrumentdaten** - `src/jarvis_finance/services/truewealth_valuation.py:353-357` - `new_values={**locked, ...}` persistiert u. a. ISIN, Instrumentname, Quantity, Source-Row-Referenzen, Preis-/FX-Providerdaten, Evidence JSON und Cashflow-Lineage. Synthetisch im Audit nachgewiesen. - **Fix:** Nur redaktierte Zusammenfassung, opaque IDs, Counts, Reason Codes und Input-Fingerprint auditieren; detaillierte Provenienz bleibt in den kanonischen Tabellen. 5. **Model-Preview-API erzeugt nach dem ersten Modellwert einen Response-Validation-Fehler** - Produzent: `src/jarvis_finance/services/truewealth_valuation.py:236-242` - Schema: `src/jarvis_finance/api/schemas/performance_activation.py:730-745` - Der Produzent liefert `source="truewealth_modelled_valuation_v1"`, das Schema erlaubt ausschließlich `"truewealth_modelled_daily"`. Mit vorhandenem Modellwert reproduziert als Pydantic `ValidationError`; der Endpoint läuft dadurch auf HTTP 500. - **Fix:** Einen kanonischen Source-Identifier end-to-end verwenden oder bewusst auf einen stabilen öffentlichen Alias projizieren. 6. **Aktivierungs-Performance ignoriert bestätigte Auszahlungen** - `src/jarvis_finance/services/truewealth_valuation.py:528-600` - Die Abfrage berücksichtigt ausschließlich `external_deposit`; `withdrawals` und `withdrawal_total_chf` sind hart auf leer/null gesetzt. Reproduziert: CHF 300 Auszahlung wurde als `0.00` ausgewiesen und das Anlageergebnis um CHF 300 verfälscht. - **Fix:** Keine zweite Finanzformel pflegen. Den kanonischen Cashflow-Selektor bzw. die bestehende TTWROR/XIRR-Engine verwenden und Ein-/Auszahlungen mit korrekter Vorzeichenkonvention übernehmen. ### P2 1. **Daily-Job kann fachlich blockierte Quellen mit Exit-Code 0 abschließen** - `src/jarvis_finance/cli/main.py:428-443` - Nur Exceptions mit Status `failed` führen zu Exit 1; ein aktivierter, aber wegen fehlender Preise/FX blockierter Modelllauf bleibt prozessseitig erfolgreich. - **Fix:** Aktivierte Pflichtquellen mit `blocked`/unvollständigem Ergebnis im aggregierten Jobstatus und Exit-Code als nicht erfolgreich behandeln. ### Verifikation - Gezielte Sprint-20D-Tests: **27 passed** - `compileall` und `git diff --check`: erfolgreich - Zusätzliche synthetische Gegenproben reproduzierten die Stable-ID-Kollision, partielle FX-Bestätigung, namensabhängige Bankerkennung, Audit-Datenreplikation, API-Schemaabweichung und fehlende Auszahlung. - **Keine Dateien erstellt oder verändert; keine Produktionsdatenbank verwendet.**