diff --git a/PROGRESS.md b/PROGRESS.md index 0e29494..3e1d051 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -13,6 +13,55 @@ Schritt (und beim Abbruch mitten im Schritt den Zwischenstand). Format: --- +## 2026-10-07 – Wiederaufnahme nach Pause: Bestandsaufnahme, Test-Runner, Benchmarks, Live-Test stabilisiert + +**Erledigt:** +- **Bestandsaufnahme:** Repo synchron mit Gitea (0 vor/0 hinter), Arbeitsbaum + war sauber, Toolchain unverändert (Flutter 3.44.4 / Dart 3.12.2). + `flutter analyze` sauber (nur bekannter onUpdate-Hinweis), 36 Unit-Tests + grün. Autopilot (PC + Pi) weiterhin pausiert. +- **Lokale Suche als Modul:** `_localMessageSearch` aus `search_modal.dart` + nach `lib/features/search/local_message_search.dart` verschoben – gleiche + Deckel (1500/Raum, 60 Treffer, 500er-Blöcke), gleiche Schleife, nur der + Medien-Filter kommt jetzt als Parameter. 5 Vertragstests + (`test/local_message_search_test.dart`) auf der echten SDK-DB-Schicht. +- **Benchmarks** (`benchmark/`, `docs/TESTS_UND_BENCHMARKS.md`): Klartext vs. + SQLCipher (Sync-Schreiben, App-Start, Chat öffnen, Suche) + Migrationsdauer; + JSON-Berichte, Baseline in `benchmark/baseline/`, Regressionswarnung >25 %. + Ergebnis: SQLCipher-Aufschlag im Rauschen (±5–10 %), Migration ≈ 42 ms/MB, + Suche (Worst Case) 64 ms für 10 000 Nachrichten. +- **`scripts/test.ps1`:** Analyse + Unit-Tests (+ `-Live`, `-Bench`, `-All`, + `-UpdateBaseline`) mit Zusammenfassung; baut die SQLCipher-DLL bei Bedarf. +- **Live-Test sporadisch rot → Ursache gefunden, Test stabilisiert:** siehe + Befund unten. `live_encryption_e2e_test.dart` meldet sich jetzt über + `_logoutWithoutStraySync` ab (Sync anhalten, laufenden Long-Poll + auslaufen lassen, dann Logout). Danach 3 Läufe in Folge grün (Ergebnis + siehe unten). + +**Befund (neu in ROADMAP, M1-Bereich):** matrix 6.2 `_innerSync` wirft den +Fehler einer Sync-Antwort, bevor geprüft wird, ob die Anfrage noch aktuell +ist. Die 401 eines alten Long-Polls nach einem Logout löst ein erneutes +`clear()` aus – nach einem schnellen Re-Login auf demselben Client würde das +die neue Session löschen. Im Test trat es als „databaseFactory not +initialized" nach `dispose()` auf. Upstream `main` unverändert (geprüft). +App-Logout-Pfad noch NICHT angefasst (heilig, braucht Gerätetest). + +**Offen/Nächster Schritt:** Bernds Rückmeldungen aus der Beta-Testphase +(v0.1.36) einsammeln, dann Prioritäten setzen: Klick-Tests aus +`docs/PC_TESTPLAN.md`, App-Logout-Pfad gegen den SDK-Wettlauf prüfen, +Abhängigkeits-Updates (ROADMAP M2, Achtung `sqlcipher_flutter_libs` EOL). + +**Stolperfallen:** (1) sqflite liefert für denselben Pfad dieselbe +Verbindung zurück – ein zweites Öffnen+Schließen kappt die erste +(Benchmark-„database_closed"). (2) Benchmark-Reihenfolge: der Dart-JIT wird +während des Laufs schneller, der zuerst gemessene Modus verlor ±20 % → +großer Aufwärm-Durchlauf + A-B-B-A. (3) `dart format` NUR auf neue Dateien +anwenden – Bestandsdateien sind nicht formatiert, sonst riesiger Diff. +(4) Vor einer Aussage nachmessen: Schreibkosten hängen NICHT nennenswert von +der Raumgröße ab (250 vs. 4000 Nachrichten/Raum ≈ +15 %). + +--- + ## 2026-07-06 – Nacht-Session (C+B): 60-FPS-Streaming + Call mit ZWEI echten Test-Accounts real durchgeklickt **Erledigt:** Fokus (C) Streaming und (B) Calls – beides mit zwei echten diff --git a/README.md b/README.md index 685e9a4..f3b58ee 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ für die unterstützte Dart-Version). flutter pub get flutter run -d windows # schnellster Praxistest während der Entwicklung flutter analyze # muss sauber bleiben +pwsh scripts/test.ps1 # Analyse + Tests (-Live, -Bench, -All: siehe docs/TESTS_UND_BENCHMARKS.md) ``` Unterstützte Zielplattformen: Android, Windows, Linux, iOS, macOS (Ordner @@ -52,5 +53,6 @@ lib/ - `CLAUDE.md` – Arbeitsregeln und Infrastruktur für die Zusammenarbeit mit Claude - `ROADMAP.md` / `PROGRESS.md` – aktueller Stand und nächste Schritte +- `docs/TESTS_UND_BENCHMARKS.md` – Tests, Live-Tests, Benchmarks (ein Befehl) - `docs/NOTIFICATIONS.md` – Push-Architektur (native Anzeige vs. Hintergrund-Entschlüsselung) - `docs/matrix-sdk/` – Hinweise zum verwendeten Matrix-SDK diff --git a/ROADMAP.md b/ROADMAP.md index fdb66fa..e473de5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -169,6 +169,21 @@ Punkte abhaken (`[x]`), wenn erledigt UND in `PROGRESS.md` protokolliert. E2EE-Empfang live belegt, auth_log unauffällig; App läuft seit 12:43 für die Langzeit-Beobachtung weiter. **Offen (Klick/Bernd):** Senden, Logout-Warnung, Re-Login mit Lesbarkeits-Check. +- [ ] **SDK-Wettlauf: verspätete 401 einer alten Sync-Anfrage löscht ggf. die + NEUE Session** (gefunden 2026-10-07 über einen sporadisch roten + Live-Test, siehe PROGRESS.md). matrix 6.2 `Client._innerSync` wirft den + Fehler einer Sync-Antwort, BEVOR geprüft wird, ob die Anfrage noch + aktuell ist (`_currentSyncId`). Läuft beim Logout noch ein Long-Poll + (bis 30 s) mit dem alten Token, kommt dessen M_UNKNOWN_TOKEN danach an + und das SDK ruft `clear()` – nach einem schnellen Re-Login auf + demselben Client wäre das ein „Random-Logout" direkt nach dem Login. + Upstream (famedly/matrix-dart-sdk `main`, 2026-10-07) unverändert; + neuere SDKs versuchen bei vorhandenem Refresh-Token aber zuerst einen + Refresh statt `clear()` (entschärft). Im Live-Test per + `_logoutWithoutStraySync` umgangen. **Offen:** App-Logout-Pfad prüfen + (läuft der Re-Login auf demselben Client-Objekt? dann vor + `client.logout()` Sync anhalten + laufenden Long-Poll abwarten) – + heiliger Pfad, nur mit Gerätetest; ggf. Upstream-Issue melden. ## M2 – Das große Refactoring (erst nach M0/M1!) @@ -253,6 +268,29 @@ lassen, ohne dass andere Module angefasst werden müssen. prüfen), siehe „Fragen an Bernd"/Nächster-Schritt in den jeweiligen PROGRESS.md-Einträgen) - [ ] Nach JEDEM Schritt: App läuft, Kernflows getestet, Commit +- [x] Test-/Benchmark-Gerüst: `scripts/test.ps1` (Analyse, Unit-, Live-Tests, + Benchmarks mit einem Befehl), `benchmark/` mit Baseline, lokale Suche + als testbares Modul (`lib/features/search/`). Siehe + `docs/TESTS_UND_BENCHMARKS.md`, PROGRESS.md 2026-10-07. +- [ ] **Abhängigkeiten aktualisieren (3 Monate Stand, 119 Pakete veraltet)** – + einzeln, jeweils mit `scripts/test.ps1 -All` abgesichert: + - **`sqlcipher_flutter_libs` ist EOL:** 0.7.0 ist ein leerer Platzhalter + (pub.dev). Unsere Bindung `^0.6.8` schließt ihn aus – NIEMALS per + `pub upgrade --major-versions` mitziehen, sonst fehlt SQLCipher und + die App kann die verschlüsselte DB nicht mehr öffnen + (`AppDatabase` wirft dann bewusst, kein Datenverlust, aber Aussperren). + Nachfolger: `sqlite3` 3.x mit `hooks: user_defines: sqlite3: source: + sqlcipher` – Kompatibilität mit `sqflite_common_ffi` und Android + vorher klären; Migrations-/DB-Tests + Gerätetest Pflicht. + - `matrix` 6.2 → 13.x (großer Sprung, Breaking Changes; heiliger + Login-/Krypto-Pfad), `flutter_vodozemac` 0.5 → 0.8 gehört dazu. + - `livekit_client` 2.7 → 2.13 (innerhalb der Bindung möglich), + `flutter_webrtc`-Override 1.4.1 → 1.6.2: der Windows-Audiogeräte-Fix + (libwebrtc #142) ist auch in 1.6.2+hotfix.4 NICHT enthalten + (Changelog geprüft 2026-10-07) → Dummy-PeerConnection-Workaround + bleibt nötig. + - `flutter_markdown` ist eingestellt (pub: „replaced by + flutter_markdown_plus“) → umstellen (Markdown-Vorschau im Dokument-Viewer). ## M3 – Calls: Logik, UI & Audio (Discord als Referenz) diff --git a/docs/PC_TESTPLAN.md b/docs/PC_TESTPLAN.md index 35e5dbd..41e1acb 100644 --- a/docs/PC_TESTPLAN.md +++ b/docs/PC_TESTPLAN.md @@ -21,6 +21,10 @@ Schnellster Weg: `flutter run -d windows`. VoicePrefs-Vertragstests in `test/settings_prefs_test.dart`), mehrfach gelaufen (vor/nach jedem Umbau des Tages). +- [x] **Seit 2026-10-07: alles Automatisierbare mit EINEM Befehl** – + `pwsh scripts/test.ps1 -All` (Analyse, 41 Unit-Tests, Live-Test mit + Test-Account, Benchmarks). Details: `docs/TESTS_UND_BENCHMARKS.md`. + ## 1. Härtetest Login/Krypto (M1 – PFLICHT, zuerst!) Deckt die Fixes 63e4919, 9dc83f7, 891f348 ab (Uta-Random-Logout + Guard). diff --git a/docs/TESTS_UND_BENCHMARKS.md b/docs/TESTS_UND_BENCHMARKS.md new file mode 100644 index 0000000..65d0b5d --- /dev/null +++ b/docs/TESTS_UND_BENCHMARKS.md @@ -0,0 +1,115 @@ +# Tests & Benchmarks + +Stand: 2026-10-07. Alles läuft mit **einem Befehl** aus dem Projektordner: + +``` +pwsh scripts/test.ps1 # Analyse + Unit-Tests (~1 min) – vor jedem Commit +pwsh scripts/test.ps1 -Live # + Live-Test gegen steggi-matrix.work (Test-Account) +pwsh scripts/test.ps1 -Bench # + Benchmarks (Datenbank/Verschlüsselung, Migration) +pwsh scripts/test.ps1 -All # alles (~4 min) +``` + +Am Ende steht eine Zusammenfassung mit OK/FEHLER je Schritt. Fehlt die +SQLCipher-Bibliothek (frischer Checkout), baut das Skript einmalig +`flutter build windows --debug`. + +**Für Bernd in einem Satz:** Die Tests prüfen automatisch die heiklen Stellen +(Login-/Logout-Schutz, Verschlüsselung der Datenbank, Suche, Einstellungen), +die Benchmarks messen, ob die App dabei langsamer wird. Was man nur mit Klicken +oder zwei echten Geräten prüfen kann, steht weiterhin in `docs/PC_TESTPLAN.md`. + +## Tests (`test/`) + +| Datei | Prüft | Läuft wann | +|---|---|---| +| `app_database_test.dart` | SQLCipher: Bibliothek echt, Header-Erkennung, Klartext→verschlüsselt-Migration, falscher Schlüssel, Fehlschlag lässt Daten unangetastet | immer (braucht die DLL aus dem Windows-Build) | +| `soft_logout_guard_test.dart` | Uta-Random-Logout-Fix: Token-Refresh-Fehler enden nie im stillen Logout | immer | +| `auth_log_test.dart` | Login-Protokoll (Diagnose für Logout-Bugs) | immer | +| `power_levels_safety_test.dart` | Space-Admin kann sich nicht selbst aussperren | immer | +| `settings_prefs_test.dart` | VoicePrefs-Fassade (gespeicherte Spracheinstellungen) | immer | +| `streaming_presets_test.dart` | 60-FPS-Streaming-Presets (Auflösung/FPS/Bitrate) | immer | +| `local_message_search_test.dart` | Lokale Nachrichtensuche (Strg+K): Treffer, Sortierung, Groß-/Kleinschreibung inkl. Umlaute, Medien-Filter, Trefferdeckel | immer (neu 2026-10-07) | +| `live_encryption_e2e_test.dart` | Echter Login (pyramidtest1) → Platte verschlüsselt → Neustart → Logout → Re-Login → alte Nachricht lesbar; Utas Update-Fall mit echter Session | nur mit `-Live` | +| `live_call_setup_test.dart` | Kein Test im engeren Sinn: legt den Voice-Testraum für GUI-Call-Tests mit zwei Test-Accounts an | nur manuell mit `PYRAMID_LIVE_TEST=1` | + +`test/support/synthetic_matrix_data.dart` erzeugt synthetische Räume und +Nachrichten über die **echte SDK-Speicherschicht** – komplett offline, ohne +Konten. Tests und Benchmarks nutzen sie gemeinsam. + +Live-Tests: Zugangsdaten liegen AUSSERHALB des Repos +(`%USERPROFILE%\.pyramid-autopilot\test-accounts.txt` bzw. `PYRAMID_TEST_ACCOUNTS`). +Es sind die Test-Accounts `pyramidtest1/2`, nie Bernds oder Utas Konten. + +## Benchmarks (`benchmark/`) + +Laufen bewusst NICHT im normalen `flutter test` mit (nur `-Bench` bzw. +`flutter test benchmark --concurrency=1`). + +| Suite | Misst | +|---|---| +| `db_benchmark_test.dart` | Klartext- vs. SQLCipher-DB mit derselben Bibliothek: Sync-Schreiben (Transaktionen wie beim echten Sync), App-Start (DB öffnen + Raumliste), Chat öffnen (50 Nachrichten), lokale Suche (ohne Treffer = Worst Case, mit Treffern) | +| `migration_benchmark_test.dart` | Dauer der einmaligen Klartext→SQLCipher-Migration beim ersten Start nach dem Update (exakt der App-Codepfad), danach Vollständigkeitsprüfung | + +**Wie gemessen wird:** DB im eigenen Isolate wie in der App; ungemessener +Aufwärm-Durchlauf; Modi abwechselnd A-B-B-A (ohne das gewann einfach der +später gemessene Modus um ±20 %, weil der Dart-JIT während des Laufs schneller +wird); Median mehrerer Durchläufe. + +**Baseline & Regressionen:** Jeder Lauf schreibt `build/benchmarks/.json` +und vergleicht mit `benchmark/baseline/.json`. Mehr als 25 % langsamer +(und bei Zeiten mehr als 2 ms absolut) wird als „⚠ LANGSAMER" markiert. +Umgebungsvariablen: + +- `-UpdateBaseline` bzw. `PYRAMID_BENCH_UPDATE_BASELINE=1` – aktuelle Werte als + neue Baseline speichern (nach bewusster Änderung oder auf neuer Hardware). + Die Baseline gilt nur für den Rechner, auf dem sie entstand. +- `PYRAMID_BENCH_STRICT=1` – Regressionen lassen den Lauf scheitern. +- `PYRAMID_BENCH_SCALE=0.2` – kleinere Datenmenge für einen schnellen Probelauf + (andere Mengen sind mit der Baseline nicht vergleichbar). + +### Erste Ergebnisse (2026-10-07, Bernds PC, 12 Kerne, Commit b2413ef) + +20 Räume × 500 Nachrichten (DB-Suite), 20 × 1000 (Migration): + +| Messung | Klartext | SQLCipher | +|---|---|---| +| Sync-Schreiben je Nachricht | 0,25 ms | 0,26 ms | +| App-Start (DB + Raumliste) | 4,1 ms | 4,3 ms | +| Chat öffnen (50 Nachrichten) | 0,33 ms | 0,32 ms | +| Suche ohne Treffer (10 000 Nachrichten) | 64 ms | 64 ms | +| Suche mit Treffern | 32 ms | 32 ms | +| Migration Klartext → SQLCipher | – | 325 ms für 7,8 MB (≈ 42 ms/MB) | + +Was das heißt: + +- **Die Verschlüsselung kostet praktisch nichts.** Alle Unterschiede liegen im + Messrauschen (±5–10 %, zwei Läufe hintereinander). Die Kosten stecken im + Matrix-SDK selbst (JSON-Verarbeitung), nicht in SQLCipher. +- **Sync-Schreiben** liegt bei ~0,26 ms pro Nachricht und hängt kaum von der + Raumgröße ab (nachgemessen: 250 vs. 4 000 Nachrichten pro Raum ≈ +15 %). +- **Suche** wächst linear mit der Zahl der gespeicherten Nachrichten + (gedeckelt auf 1 500 pro Raum). Hochrechnung, nicht gemessen: 100 aktive + Räume am Deckel ≈ 150 000 Nachrichten ≈ 1 s pro Suche auf diesem PC – + auf Handys entsprechend länger. Kandidat für einen Suchindex (FTS), falls + das in der Praxis stört. +- **Migration**: Hochrechnung für eine 100-MB-DB ≈ 4 s einmalig auf diesem + PC; auf Utas Handy vermutlich ein Mehrfaches davon (nicht gemessen). + +## Bekannte Grenzen (ehrlich) + +- Synthetische Daten: unverschlüsselte Räume, keine Olm/Megolm-Sessions + (vodozemac läuft im Host-Test nicht). Die DB-Struktur ist aber die echte. +- Gemessen auf Windows im JIT-Modus von `flutter test`; die Release-App läuft + AOT-kompiliert und ist eher schneller. Für Vergleiche über die Zeit taugt + das, für absolute Aussagen über Handys nicht. +- Nicht automatisiert: alles mit Klicks, echte Calls/Audio, 60-FPS-Streaming + zwischen zwei Geräten, Android-Push → `docs/PC_TESTPLAN.md`. + +## Nächste sinnvolle Messungen + +- **Streaming (M4 „Ursache messen"):** WebRTC-`getStats()` des Senders + auswerten (`framesPerSecond`, `qualityLimitationReason`, Encoder-Name) – + zeigt direkt, ob CPU, Bandbreite oder Encoder bremst. Braucht eine kleine + Diagnose-Anzeige im Call und zwei echte Geräte. +- **UI-Flüssigkeit:** `integration_test` mit Frame-Timing beim Scrollen der + Raumliste/Timeline (Windows, Test-Account-Profil über `PYRAMID_PROFILE_DIR`).