# Sprint 20B – Performance-Aktivierung und tägliche Bewertungsreihe v1

**Ausgangsbasis:** produktiv verifizierter Sprint-20-Hotfix-Merge `7f1d76bc62e19861e55929273859e27ca6d74970` (PR #38), nicht der vor dem Hotfix liegende SHA `5e83b291…`
**Schema:** 49, unverändert
**Releasegrenze:** Implementierung und synthetische Tests erlaubt; keine produktiven Imports, Backfills, Bestandsänderungen, Policy-Confirms oder Aktivierung eines schreibenden Timers ohne erneute ausdrückliche Nutzerbestätigung.

## Belegte bestehende Automatik

Es existiert genau ein Schedulerpfad:

- `finance-manager-market-valuation.timer` → `finance-manager-market-valuation.service`
- User-systemd, täglich um `23:30 Europe/Zurich`, persistent; PostFinance berücksichtigt intern den Börsenkalender, Krypto den Kalendertag
- Aufruf: `python -m jarvis_finance.cli.main run-daily-market-valuation`
- keine FinanceManager-Crontab, kein separater Worker und kein In-App-Scheduler
- Orchestrierung: `services/portfolio_analytics.run_daily_market_valuation`

Der Job schreibt über die bereits vorhandenen Tabellen:

- `market_prices`
- `fx_rates`
- `market_data_runs`
- `portfolio_valuation_snapshots`
- `portfolio_analysis_snapshots`
- `benchmark_snapshots`
- `audit_log` sowie bei Datenqualitätsproblemen vorhandene Alertstrukturen

Belegte Läufe: tägliche erfolgreiche Runs bis 2026-08-01. Seit dem danach deployten Sprint-20-Stand scheitert der CLI-Start vor dem Job in `apply_migrations()` an einem FK-Kompatibilitätspfad, obwohl die produktive Datenbank bereits Schema 49 hat. Die CLI muss für diesen Job deshalb die vorhandene Schema-Version nur prüfen und darf nicht bei jedem Timerlauf erneut DDL ausführen.

## Ursache der unveränderten Kryptodaten

Der bestehende tägliche Job verarbeitet ausschließlich `confirmed_canonical_positions()` aus PostFinance-/Brokerage-Aktivitäten. Er ruft weder den vorhandenen CoinGecko-Refresh noch eine Krypto-Tagesbewertung auf und materialisiert keinen `crypto_portfolio`-Account. Daher blieb Krypto seit dem letzten bestätigten Krypto-Preis-/Bestandsstand am 15.05.2026 unverändert. Das ist kein Dashboardfehler.

## Persistenzentscheidung

Schema 49 reicht aus:

- Scope und Trackingvertrag: `performance_scope_classifications` + `performance_cashflow_coverage.source`
- bestätigter Startbestand: bestehende Krypto-Holdings/Auditstruktur beziehungsweise vorhandene Totalwert-/Account-Snapshots
- Tageswerte: `portfolio_valuation_snapshots`
- aktiver Tageswert: höchste `snapshot_version` pro Scope und fachlichem Kalendertag; ältere Versionen bleiben unverändert erhalten
- FX-Provenienz: Snapshot-FX-Felder plus verknüpfter Run
- Input-Fingerprint, Laufstatus und Audit: `market_data_runs` + `audit_log`; Snapshot `source_reference` verweist auf den Run
- Coverage: bestehende Performance-Coverage-Services

Es fehlt kein belegtes Pflichtfeld; keine Migration.

## Trackingmodi

| Quelle | Rolle | Modus |
|---|---|---|
| PostFinance E-Trading Depot und Settlement-Cash | Anlagerendite | Transaktionsmodus |
| Krypto | Anlagerendite | vollständiger Transaktionsmodus oder bestätigter Snapshot-Startbestand |
| True Wealth | Anlagerendite | verwalteter Gesamtwert mit bestätigten externen Flows |
| AKB, Raiffeisen, PostFinance E-Finance | Vermögen/Kontosaldo | aus der Anlagerendite ausgeschlossen |

Bankkonten bleiben durch die bestehende explizite Scope-Klassifikation außerhalb der Anlageperformance und blockieren sie nicht.

## Minimale Erweiterung ohne zweite Engine oder Schedulerarchitektur

1. Bestehenden systemd→CLI-Pfad beibehalten und standardmäßig fail-closed hinter einer expliziten Aktivierungsvariable halten.
2. Im selben CLI-Lauf nach dem vorhandenen PostFinance-/Markt-/FX-Schritt einen Krypto-Tagesabschluss ausführen; keine zweite Timerarchitektur.
3. PostFinance nach letztem Handelsschluss, Krypto je Kalendertag 24/7; True Wealth ausschließlich bei einem neuen bestätigten Gesamtwert.
4. Tagesleser nach `substr(valuation_at,1,10)` kanonisieren, damit Uhrzeiten desselben fachlichen Tages keinen künstlichen zusätzlichen Stichtag erzeugen.
5. Fingerprint um Cash- und bewertungsrelevante Inputs ergänzen; Cash-Snapshot strikt `balance_date <= as_of` auswählen.
6. Providerfehler auditiert als unvollständigen Lauf abschließen, aber keinen neuen bestätigten Tageswert erzeugen.
7. UI: genau eine kompakte Einrichtungskarte mit drei Aufgaben; technische Gründe nur unter `Daten & Diagnose`.
8. Preview-/Confirm-/Audit-Grenzen vorhandener Import- und Snapshotpfade wiederverwenden. Backfill wird ausschließlich über einen fingerprintgebundenen Preview-/Confirm-Vertrag gestartet und bleibt nach Deployment unbestätigt.

## Aktivierungsgrenze

Der eingecheckte Dienst ist ohne `JARVIS_FINANCE_DAILY_VALUATION_ENABLED=1` nicht schreibfähig. Eine spätere Aktivierung erfordert separat:

1. vollständige produktive Eingaben je Quelle,
2. read-only Preview und Fingerprint,
3. ausdrückliches Confirm für Import/Backfill,
4. separaten ausdrücklichen Auftrag zur Timeraktivierung.

## Verifikation des Releasekandidaten

- Synthetische Tests decken Aktivierungs-Preview/Confirm, Input-Drift, Idempotenz, wiederaufnehmbare Teil-Backfills, ausschließlich bestätigte Krypto-Aktivitäten, exakte Tagespreise, Providerfehler, unveränderten letzten bestätigten Wert, Bankkonto-Ausschluss, Cash-Cutoff/Fingerprint, append-only Supersession, Scope-Performance und Kalendertag-Kanonisierung ab.
- Backend-Gesamtsuite: `922 passed`.
- Frontend-Gesamtsuite: `222 passed`; Typecheck und Produktionsbuild erfolgreich.
- Browser-UAT 1440/820/390 px: kein horizontaler Overflow, genau eine Einrichtungskarte mit drei Aufgaben, fünf KPI-Karten, keine technischen Reason-Codes, keine externen Render-Requests.
- Read-only-Produktionssentinel vor/nach UAT identisch: 96 Tabellen, Schema 49, Integrity `ok`, 0 FK-Verletzungen, unveränderter logischer Digest.
- Der Timer bleibt nach Deployment fail-closed. Kein Backfill, Import, Snapshot, Marktupdate oder täglicher Schreibjob wird im Release aktiviert.
- Produktive Bestätigung erfolgt erst in einem separaten Schritt mit konkreten Nutzerdateien/Werten und neuem Sentinel.
