## Ergebnis nach Priorität ### P0 – Sicherheitsvertrag nicht zurückdrehen **Legacy-Opaque-ID auf `/health-doc/...`: aktuell unauthentisiert 401 statt 404** - **Aktueller richtiger Vertrag:** Alle Legacy-Dokumentrouten `/health-doc/*` sind seit `500fc56` authentisierungspflichtig. Deshalb muss eine unauthentisierte Anfrage unabhängig vom ID-Format **401** erhalten. - Die Sprint-6B-Anforderung bleibt gültig: Eine `api-document-*`-ID darf nicht als Legacy-ID funktionieren. Dieser Negativvertrag muss aber **authentisiert** geprüft werden. - **Kein Codefix:** Auth-Prüfung nicht hinter die Integer-Validierung verschieben; das würde die inzwischen eingeführte, einheitliche Schutzgrenze der Legacy-Dokumentroute abschwächen. - **Minimaler Testfix:** In `tests/test_dashboard_v5_sprint6b_api.py:647-649` den Request mit dem bereits vorhandenen Bearer-Token authentisieren und danach weiterhin **404** erwarten. Optional separat festhalten, dass derselbe Pfad ohne Auth **401** ergibt. ### P1 – echter Kompatibilitätsfehler **Sparse `nutrition_daily_summary_v2` ohne `histamine_max`** - **Aktueller richtiger Vertrag:** `nutrition.sighi_max` bleibt eine unterstützte Katalogmetrik. Bei einer älteren/sparsamen Datenbank ohne `histamine_max` muss ihre Availability **`supported_no_data`** sein; die gesamte Katalogsuche darf nicht mit SQL-Fehler abbrechen. `nutrition.histamine` darf weiterhin `available` melden. - Ursache: `metric_catalog_v2._availability()` baut bei `histamine_max` unconditionally ein `SELECT datum,histamine_max,...` (`metric_catalog_v2.py:385-395`). - **Minimaler Codefix:** Vor dem Query die Tabellenspalten über `PRAGMA table_info(nutrition_daily_summary_v2)` prüfen. Fehlt die für die jeweilige Metrik benötigte Spalte, direkt `count = 0` bzw. `supported_no_data` liefern. Die Prüfung sollte auch die gemeinsam verwendeten Spalten (`datum`, `item_count`, `histamine_unknown_count`, `histamine_label`) abdecken. - **Test bleibt grundsätzlich richtig:** `tests/test_dashboard_v5_sprint6b_catalog.py:180-214` ist eine sinnvolle Legacy-/Sparse-Schema-Regression und sollte nicht durch Hinzufügen von `histamine_max` zur Testtabelle entschärft werden. ### P2 – veraltete Tests nach absichtlicher Vertragsentwicklung **Browser-Session-Cookie: Test erwartet `Path=/api/v1`, Code liefert `Path=/`** - **Aktueller richtiger Vertrag:** **`Path=/`**. Commit `a7c57c2` hat Sessionauth explizit auch für `/health-actions/symptom-checkin` und `/health-actions/nutrition-mapping` eingeführt. Ein Cookie mit `Path=/api/v1` würde dort nicht gesendet und die neuen authentisierten Schreib-Queues brechen. - HttpOnly, SameSite=Strict, kurze serverseitige Laufzeit, Origin-Prüfung und One-Time-CSRF bleiben bestehen. - **Minimaler Testfix:** `tests/test_dashboard_v5_sprint6b1_integration.py:98` auf `Path=/` aktualisieren. - **Dokumentationsfix:** `docs/sprint6b-metric-catalog-read-api.md:154` ebenfalls von `Path=/api/v1` auf `Path=/` aktualisieren und den Grund „API plus authentisierte `/health-actions/*`“ nennen. - Kein Code-Rollback auf `/api/v1`. **Originaldokument: Test erwartet inline `document.pdf`, aktuell Attachment** - **Aktueller richtiger Vertrag:** - `/api/v1/documents/{opaque}/original` → **Download**, `attachment; filename="health-document-original."`. - `/api/v1/documents/{opaque}/preview-original` → **Inline-PDF-Vorschau**. - Diese Trennung wurde in `a205371` bewusst mit der Unterstützung weiterer Medienformate eingeführt. Beide Namen bleiben generisch und leaken keinen Originaldateinamen. - **Minimaler Testfix:** `tests/test_dashboard_v5_sprint6e1_original.py:193` auf `attachment; filename="health-document-original.pdf"` ändern. - Sinnvolle zusätzliche Regression: `preview-original` separat auf `inline`, PDF-only und `SAMEORIGIN` prüfen. - Kein Codefix zurück zu inline auf der Downloadroute. **Nutrition-Restore-Helfer verwendet überall `ORDER BY rowid`** - **Aktueller richtiger Vertrag:** Der Restore-Test muss auch SQLite-Tabellen ohne implizite `rowid` vergleichen können. - Reproduziert betroffen sind FTS5-Schattentabellen wie: - `health_document_machine_fts_config` - `health_document_machine_fts_idx` - `health_document_repeated_fts_config` - `health_document_repeated_fts_idx` Diese sind `WITHOUT ROWID`. - **Minimaler Testfix ausschließlich in** `tests/test_dashboard_v5_sprint6g_nutrition.py::_raw_tables`: - Spaltenzahl per `PRAGMA table_info(...)` ermitteln. - Deterministisch über alle Ergebnisspalten sortieren, z. B. `ORDER BY 1,2,...,N`, statt über `rowid`. - Das ist robuster als ein Rowid-Fallback und vergleicht weiterhin den vollständigen Tabelleninhalt als Multiset. Kein Produktionscodefix erforderlich. ## Verifikation und Arbeitsbaum - Historie/Blame und aktuelle Implementierung read-only untersucht; die Intentionsänderungen stammen insbesondere aus `500fc56`, `a205371` und `a7c57c2`. - Der WITHOUT-ROWID-Fehler wurde gegen eine neu erzeugte synthetische Fixture strukturell reproduziert. - Pytest konnte nicht ausgeführt werden, da im verfügbaren Python-Environment `pytest` nicht installiert ist. - **Keine Dateien erstellt oder geändert.** - Im Arbeitsbaum vorhandene Änderungen stammen aus paralleler Arbeit; ich habe sie nicht angefasst.