## Ergebnis Read-only geprüft: Repository steht sauber auf `c37b798d6e8100829534a1d9322f3b03e805db14`; keine Dateien geändert. V4 muss für diesen Scope nicht berührt werden. ## Kleinster Umsetzungspfad ### 1. Deutsche Panel- und Berichtbezeichnungen **Dateien/Funktionen** - `scripts/health/dashboard_v5/render.py` - `VIEW_LABELS` - `render()` - `base_labels` - `record_markup` - Tagesabschnitte in `calendar_markup` - `scripts/health/assets/health-assets/dashboard-v5-record.js` - `tabLabels` - `renderReport()` - `renderLabs()` - `scripts/health/assets/health-assets/dashboard-v5-api-explorer.js` - `renderChart()`, insbesondere gestapelte `yAxis`-Namen, aktuell nur Einheit statt Metrikname **Minimaländerungen** - Sichtbare Bezeichnungen konsistent auf das Zielbild bringen: - Hauptbereich bleibt `Akte` - Untertab/Überschrift `Arzt-Zusammenfassung` → `Arztbericht` - `Labore` → konsistent `Labor` oder durchgehend `Laborwerte` - Technische IDs, Endpunkte und URL-Tab-ID `report` unverändert lassen. - Gestapelte Explorer-Panels explizit mit Metrik und Einheit beschriften, z. B. `Ruhepuls (bpm)` statt nur `bpm`. Keine Contract- oder Datenänderung nötig. --- ### 2. Ernährungsdurchschnitte ehrlich benennen und mit Nenner-Metadaten versehen **Aktueller Stand** `read_api._nutrition_days()` berechnet den Mittelwert ausschließlich über Tage, an denen der jeweilige Nährstoff dokumentiert ist. Die Antwort enthält nur: ```json { "label": "...", "value": 12.3, "unit": "g", "documented_days": 4 } ``` Damit kann die UI „Durchschnitt vorhandener Tage“ anzeigen, aber Zeitraum, Nennersemantik und Missingness-Regel sind nicht maschinenlesbar. **Dateien/Funktionen** - `scripts/health/dashboard_v5/nutrition_contract.py` - `NutrientContract` - optional zentrale Konstanten für Aggregations-/Missingness-Vertrag - `scripts/health/dashboard_v5/read_api.py` - `_nutrition_days()`, Zeilenbereich um `averages` - `_doctor_report()`, Weitergabe von `nutrition_summary` und `nutrition_inflammation_factors` - `scripts/health/assets/health-assets/dashboard-v5-nutrition.js` - `renderTrendPayload()` - `scripts/health/assets/health-assets/dashboard-v5-record.js` - `renderReport()`, Ernährungstabelle **Additiver Antwortvertrag pro Durchschnitt** ```json { "label": "Ballaststoffe", "value": 12.3, "unit": "g", "aggregation": "arithmetic_mean_documented_days", "documented_days": 4, "period_documented_days": 10, "missing_days_excluded": true } ``` Optional auf Summary-Ebene zusätzlich `range_from`/`range_to`. **Deutsche Formulierung** - `Durchschnitt pro Tag mit dokumentiertem Wert` - Metadaten: `4 Tage mit dokumentiertem Wert im gewählten Zeitraum` - Nicht `Tagesdurchschnitt`, wenn dies Vollständigkeit über alle Kalendertage suggeriert. - Kein Auffüllen fehlender Tage mit null. `inflammation_statement` bleibt neutral; keine Index-, Zielwert- oder Kausalitätsaussage ergänzen. --- ### 3. Drei explizite Referenzkontexte Die fachlichen Grundlagen existieren bereits in `MetricV2.reference_policy` und `baseline_rule`, werden von `/api/v1/series` aber nicht als verständlicher Kontext ausgegeben. Die UI zeigt derzeit nur Laborreferenzen im Tooltip und ignoriert persönliche Baselines weitgehend. **Die drei öffentlichen Kontexte sollten sein** 1. **Persönlicher Verlauf** - rollender Median ausschließlich früherer Beobachtungen - keine medizinische Norm oder Zielvorgabe 2. **Beobachtungsspezifischer Laborreferenzbereich** - aus genau diesem verifizierten Originalbefund - darf zwischen Beobachtungen wechseln 3. **Nur dokumentierter Wert** - keine persönliche Baseline und kein verifizierter medizinischer Referenzbereich - insbesondere Ernährung/Symptome **Dateien/Funktionen** - `scripts/health/dashboard_v5/metric_catalog_v2.py` - `MetricV2.reference_policy` - `MetricV2.baseline_rule` - `METRICS_V2` - `public_metric()` - `scripts/health/dashboard_v5/read_api.py` - neue kleine Projektion `_reference_context(metric)` - `_series()` – additives Top-Level-Feld `reference_context` - `_verified_lab_rows()` – bestehende observation-spezifische `reference` unverändert - `scripts/health/assets/health-assets/dashboard-v5-api-explorer.js` - `buildSeries()` - `renderChart()`/Tooltip - zugängliche Tabelle in `renderTable()` - `scripts/health/assets/health-assets/dashboard-v5-record.js` - `referenceText()` für Labor bleibt beobachtungsspezifisch **Empfohlener öffentlicher Contract** ```json { "reference_context": { "kind": "personal_baseline", "label": "Persönlicher Vergleich", "medical_reference": false, "method": "rolling_median_prior_observations", "window_days": 30, "minimum_observations": 3 } } ``` Weitere `kind`-Werte: - `observation_specific_laboratory_range` - `documented_value_without_reference` Keine technischen Werte wie `personal_baseline` oder `observation_specific_verified_original` direkt in der deutschen UI anzeigen. --- ### 4. Nahrungsergänzungen: geplant strikt von tatsächlich dokumentiert trennen **Aktueller Stand** Es gibt keine eigenständige Supplement-Semantik. `medication_administrations` kennt nur `event_type`; Supplemente könnten derzeit nur als Medikamentennamen erscheinen und wären nicht sicher unterscheidbar. Eine Namensheuristik wäre ungeeignet. **Kleinste additive Migration** - `scripts/health/dashboard_v5/patient_action_schema.py` - bei `medication_administrations` ergänzen: ```python ("entry_kind", "TEXT NOT NULL DEFAULT 'medication' CHECK(entry_kind IN ('medication','supplement'))") ``` - `scripts/health/migrate_patient_action_schema.py` - bestehende `apply_migration()`, `assert_schema()`, Copy-/Restore-Gates weiterverwenden - bestehende Zeilen erhalten automatisch `medication` - keine automatische Klassifikation anhand des Namens **Read-Contract-Touchpoints** - `scripts/health/dashboard_v5/read_api.py` - `_day_medications()`: auf `entry_kind='medication'` begrenzen - neue gemeinsame Hilfsfunktion für Status-Buckets oder `_day_supplements()` - `_record_medications()`: Medikamentenabfrage begrenzen - `_record_summary()` - `_doctor_report()` - `REPORT_SECTIONS`: additives `supplements` - Tagespayload additives `supplements` mit denselben vier Buckets: - `planned` - `administered` - `missed` - `corrected` - `scripts/health/assets/health-assets/dashboard-v5-day-controller.js` - eigener Abschnitt `Nahrungsergänzungen` - Labels `Geplant` und `Tatsächlich dokumentiert/eingenommen` - `scripts/health/assets/health-assets/dashboard-v5-record.js` - eigener Akten-/Arztberichtabschnitt - nie geplante Einnahme als tatsächlich eingenommen zusammenfassen - `scripts/health/dashboard_v5/render.py` - Tagespanel-Markup für Nahrungsergänzungen - Arztbericht-Checkbox **Write-Pfad nur falls Part A auch Erfassung verlangt** Dann zusätzlich: - `scripts/health/health_dashboard_server.py` - `validate_patient_action()` - explizites `entry_kind`, strikt allowlisted - `scripts/health/health_dashboard_action_worker.py` - `validate_patient_payload()` - `apply_patient_action()` - Insert von `entry_kind` Falls Part A nur Anzeige/Arztbericht umfasst, diesen Write-Scope zurückstellen. Bestehende Medikamentenerfassung bleibt unverändert `medication`. --- ### 5. Arztbericht: auswählbare Charts statt fest codierter sechs Reihen **Aktueller Stand** `read_api._doctor_report()` lädt in `observations` immer diese sechs Metriken fest: - `apple.sleep` - `apple.hrv` - `apple.resting_heart_rate` - `apple.steps` - `apple.distance` - `apple.active_energy` Die UI kann nur ganze Abschnitte wählen, nicht einzelne Charts. **Dateien/Funktionen** - `scripts/health/dashboard_v5/read_api.py` - neue Konstante `DOCTOR_REPORT_CHART_METRICS` - `_doctor_report()` - `dispatch_api()` für `/api/v1/doctor-report` - `scripts/health/assets/health-assets/dashboard-v5-record.js` - `FILTER_KEYS.report`: `charts` ergänzen - `sanitizeFilters()`: Arrays für `charts` wie bereits `sections` behandeln - `renderReport()`: Chart-Checkboxen, Query, Rendern/Entsorgen der ECharts-Instanzen - `scripts/health/assets/health-assets/dashboard-v5-api-explorer.js` - keine Kopplung herstellen; höchstens kleine reine Chart-Option-Hilfe extrahieren - `scripts/health/assets/health-assets/dashboard-v5.css` - `.doctor-summary-chart` - Print-Größe und Seitenumbruch **API-Vertrag** Query additiv: ```text /api/v1/doctor-report?...&charts=apple.sleep,apple.hrv,lab.crp ``` Regeln: - nur IDs aus einer festen Arztbericht-Allowlist - Duplikate ablehnen - Obergrenze, z. B. sechs Charts - unbekannte oder Panel-Metriken mit `chart_not_allowed` ablehnen - gewählte Liste als `selected_chart_metrics` zurückgeben - leere Auswahl erzeugt keine Charts - Laborpunkte behalten ihre observation-spezifischen Referenzen - keine Browser- oder DB-Persistenz nötig; URL/History-State reicht Die bestehende lokale ECharts-Datei und Browser-Session werden wiederverwendet; keine neue Asset-Quelle und kein zweiter Session-Bootstrap. ## Fokussierte Tests ### Python Neuer enger Test-Slice: - `tests/test_dashboard_v5_sprint6f_b_a.py` Fälle: 1. Ernährungsmittelwert verwendet nur dokumentierte Werte und liefert Nenner-/Missingness-Metadaten. 2. Fehlender Wert wird nicht als null in den Mittelwert aufgenommen. 3. `/series` liefert genau die drei öffentlichen Referenzkontexte: - Apple-Metrik → persönlicher Vergleich - Labor → beobachtungsspezifischer Originalreferenzbereich - Ernährung/Symptom → dokumentierter Wert ohne Referenz 4. Bestehende Supplementzeilen defaulten nach Migration nicht versehentlich aus alten Medikamenten. 5. Synthetisches Supplement `planned` erscheint nur geplant; `administered` nur tatsächlich dokumentiert. 6. Arztbericht akzeptiert allowlistete Chartauswahl, bewahrt Reihenfolge und lehnt unbekannte, doppelte oder zu viele IDs ab. 7. Leere Chartauswahl erzeugt keine Beobachtungsreihen. 8. Migration zweimal ausführen: zweiter Lauf null Änderungen; Row Counts, Integrity und Restore bleiben korrekt. Bestehende Tests gezielt ergänzen: - `tests/test_dashboard_v5_sprint6g_b3.py` - Migrationsschema um `entry_kind` - `tests/test_dashboard_v5_sprint6g_nutrition.py` - neue Durchschnittsmetadaten - `tests/test_dashboard_v5_sprint6e_record.py` - Supplements und Arztbericht-Chartfilter - `tests/fixtures/dashboard_v5_fixture.py` - je eine synthetische geplante und tatsächliche Supplementzeile ### Browser Neuer Slice: - `tests/browser/dashboard_v5_sprint6f_b_a.spec.js` Maximal sechs Kernfälle: 1. Gestapelte Explorer-Panels zeigen Metrikname plus Einheit. 2. Tooltips unterscheiden die drei Referenzkontexte in verständlichem Deutsch. 3. Ernährungskarten sagen `Durchschnitt pro Tag mit dokumentiertem Wert` und zeigen den Nenner. 4. Nahrungsergänzungen zeigen Planung und tatsächliche Dokumentation getrennt. 5. Zwei ausgewählte Arztbericht-Charts erscheinen; nicht ausgewählte nicht; Druck enthält nur die Auswahl. 6. 390 px: keine horizontale Überläufe, Checkboxen/Buttons mindestens 44 px. ## Sicherheits-/Scope-Grenzen - `scripts/health/health_dashboard_server.py` Auth, Host/Origin, CSRF und CSP nicht aufweichen. - Keine Inline-Skripte, externen Charts oder zweite Browser-Session. - Keine Änderung an Dashboard V4. - Keine Namensheuristik zur Supplementklassifikation. - Keine Diagnose-, Kausalitäts-, Dringlichkeits-, Zielwert-, Dosierungs- oder Supplementempfehlung. **Dateien erstellt/geändert:** keine. **Probleme:** keine Repository-Blocker; Supplemente benötigen als einzigen echten Datenmodellschritt eine explizite additive Klassifikation, weil der aktuelle Bestand sie nicht sicher von Medikamenten unterscheidet.