## Ergebnis **Kein P0-Finding.** Es bestehen jedoch mehrere **P1-Release-Blocker** und **P2-Probleme**. ### P1 — Scope-Auswahl zeigt fachlich falsche Portfolio-Werte - **Dateien:** `frontend/src/components/performance/PortfolioPerformancePanel.vue:49, 98–118` `frontend/src/components/performance/PortfolioPerformancePanel.test.ts:46–49` - **Problem:** Die Auswahl `postfinance`, `truewealth` oder `crypto` beeinflusst den Performance-Request nicht. `load()` fragt immer die globale `/portfolio/performance` ohne Scope/Account an. TTWROR/XIRR werden zwar für Nicht-Portfolio-Scope durch Statustext ersetzt, aber **Anlageergebnis und komplette Wertbrücke bleiben die globalen Portfolio-Werte**. Dadurch erscheinen unter „Crypto“ oder „TrueWealth“ CHF-Beträge eines anderen Scopes. - **Testlücke:** Der Crypto-Test prüft nur, dass kein `0.00%` vorkommt. Er erkennt nicht, dass weiterhin das globale `investment_result` und Attribution-Beträge sichtbar sind. - **Minimaler Fix:** Entweder nur `portfolio` auswählbar machen und andere Scopes reine Coverage-Ansichten ohne Performance-/Attributionswerte darstellen, oder einen serverseitigen, privacy-sicheren Scope-Parameter implementieren. Bei Nicht-Portfolio-Scope sämtliche globalen Werte und die Wertbrücke ausblenden. ### P1 — DB-Trigger lässt beliebige, nicht auditierte Rollenklassifikation zu - **Dateien:** `src/jarvis_finance/storage/migrations.py:1766–1786` `src/jarvis_finance/services/performance_scope.py:29–30` - **Problem:** Die Rollen-Allowlist wird nur im Python-Helper geprüft. Der DB-Trigger verlangt lediglich irgendeinen Classification-Datensatz mit `included=1`. `classification_role`, `decision_version` und der referenzierte Audit-Datensatz werden fachlich nicht validiert. - **Verifiziert:** Eine Classification mit Rolle `ordinary_bank_account`, Version `bogus` und einem Audit-Datensatz mit `entity_type='other'` konnte direkt eingefügt werden; anschließend akzeptierte die DB `performance_included=1`. - **Minimaler Fix:** DB-seitige `CHECK`-/Trigger-Invarianten für freigegebene Rollen und `investment_performance_scope_v1`; außerdem prüfen, dass der referenzierte Audit-Datensatz zum Account, Entity-Typ und Zielwert passt. Direkte Änderungen an `performance_scope_classifications` entweder unveränderlich machen oder ebenfalls über auditierte Trigger absichern. ### P1 — Tages-Cashflows passen nicht auf Tagesbewertungen - **Dateien:** `src/jarvis_finance/ledger/performance.py:226–236` `src/jarvis_finance/services/portfolio_performance.py:644–650` - **Problem:** `ttwror_daily_v1` fordert Gleichheit des vollständigen Zeitpunkts. Der Service liefert jedoch `event_timestamp`, während Bewertungen typischerweise als Tagesdatum bzw. Mitternacht vorliegen. Eine Einzahlung am selben Kalendertag um 12:00 Uhr wird deshalb fälschlich als fehlende Cashflow-Bewertung abgelehnt. - **Verifiziert:** Bewertungen `2025-01-01`/`2025-01-02` plus Einzahlung `2025-01-01T12:00:00Z` ergaben `missing_cashflow_valuation`. - **Minimaler Fix:** Den TTWROR-v1-Vertrag explizit auf kalendarische Bewertungsgrenzen normalisieren und pro Tag genau eine kanonische Pre-/Post-Cashflow-Konvention anwenden. Dazu Tests mit realistischen `event_timestamp`-Werten ergänzen. ### P1 — Coverage-Vertrag bleibt unabhängig von vorhandenen Daten statisch „unavailable“ - **Datei:** `src/jarvis_finance/services/portfolio_performance.py:58–160` - **Problem:** PostFinance-TTWROR/XIRR, Crypto und das Gesamtportfolio werden in `build_performance_coverage()` fest auf `unavailable` gesetzt; das Gesamtportfolio hat immer null Stichtage. Auch nach Ergänzung einer klassifizierten Crypto-Historie kann der Coverage-Endpunkt daher nie korrekt `complete` melden. Gleichzeitig kann die kanonische Performanceberechnung nach einer Crypto-Klassifikation Werte liefern. API-Badge und Performancevertrag können widersprüchlich werden. - **Minimaler Fix:** Coverage aus denselben kanonischen Scope-, Bewertungs- und Cashflow-Regeln wie `build_portfolio_performance()` ableiten. Keine hartcodierten Statuswerte; explizite Scope-Resultate und Reason-Codes berechnen. ### P1 — Backend-Testgate ist rot - **Datei:** `tests/unit/test_portfolio_performance_foundation.py:304–305` - **Problem:** Der neue Test greift auf nicht existierende Felder `summary.ttwror` und `summary.xirr_annualized_personal` zu. Der aktuelle Vertrag verwendet `ttwror_cumulative` und `xirr_annualized`. - **Ausführung:** Gezielter Backend-Lauf: **66 passed, 1 failed** (`KeyError: 'ttwror'`). - **Minimaler Fix:** Assertions auf die tatsächlichen kanonischen Felder umstellen und weiterhin explizit prüfen, dass beide Werte bei unklassifizierten Cashflows `None` sind. ### P2 — Historischer unbekannter Datensatz kann saubere spätere Periode sperren - **Dateien:** `src/jarvis_finance/ledger/performance.py:116–132` `src/jarvis_finance/services/portfolio_performance.py:624–638` - **Problem:** `activity_reasons` wird über die gesamte bis `to_date` geladene Historie gebildet. Sobald die angefragte Periode irgendeine Aktivität enthält, werden diese globalen Gründe übernommen. Damit kann eine unbekannte Aktivität vor `from_date` eine ansonsten sauber klassifizierte spätere Periode sperren – entgegen dem Kommentar in Zeilen 628–630. - **Minimaler Fix:** Reversal-/Support-Gründe periodengenau berechnen; nur periodenübergreifende Reversals berücksichtigen, die tatsächlich eine Aktivität der angefragten Periode neutralisieren. ### P2 — Chart richtet Cashflows nicht an ihren tatsächlichen Daten aus - **Datei:** `frontend/src/components/performance/PortfolioPerformancePanel.vue:116` - **Problem:** Beide Linien berechnen ihre X-Koordinaten separat nur aus dem jeweiligen Array-Index. Zwei Cashflows werden daher immer über die gesamte Chartbreite verteilt, unabhängig von ihren echten Zeitpunkten und den Bewertungsdaten. - **Minimaler Fix:** Gemeinsame X-Skala aus `at`/Zeitstempeln verwenden und beide Reihen auf denselben Zeitraum projizieren. ## Tests und Reviewumfang - Vollständigen uncommitted Diff einschließlich vier neuer Dateien gegen `origin/main` geprüft. - Frontend-Fokustests: **10/10 bestanden**. - Backend-Fokustests: **66 bestanden, 1 fehlgeschlagen**. - `git diff --check`: ohne Befund. - **Keine Repository-Dateien verändert.** Für den Backend-Test temporär erzeugte `.venv`/`uv.lock` wurden wieder entfernt. - Während des Reviews änderte sich der Worktree parallel; die Findings und Zeilenangaben beziehen sich auf den zuletzt gelesenen aktuellen Stand.