# Sprint 7A-R1 – Explorer-Stabilität und RC-UI

**Basis:** `2c9c78d517ed98367605e0d04783506fe5bc7cf4`  
**Scope:** Explorer-Stabilität, Heute-Layout, verständliche Ereignisse und read-only Dateninventar. Kein Sprint 7B, keine neue Migration, keine neue medizinische Berechnung.

## Reproduktion des RC-Fehlers

Die Basisversion wurde isoliert aus dem Basis-Commit mit einer geschützten Kopie des privaten V5-Datensatzes gestartet. Die API-Antwortinhalte und Gesundheitswerte wurden nicht protokolliert.

Ablauf:

1. 30-Tage-Zeitraum;
2. fünf Reihen einschließlich Schlaf und Ruhepuls aus URL-Zustand geladen;
3. vier `/api/v1/series`-Requests kontrolliert mit HTTP 503 fehlschlagen lassen;
4. eine erfolgreiche Reihe solo geschaltet;
5. globales „Erneut versuchen“ ausgelöst.

Beobachtung der Basisversion:

- UI: `-3 Reihe(n) sichtbar; 4 Reihe(n) konnten nicht geladen werden.`
- Request: vier fehlgeschlagene `GET /api/v1/series` mit HTTP 503;
- Chart-Vertrag: eine erfolgreiche Chartreihe blieb intern vorhanden;
- Browser-Konsole: vier generische 503-Resource-Fehler; keine JavaScript-Exception;
- ein erwarteter abgebrochener Browser-Session-Request trat beim isolierten Seitenlebenszyklus als `net::ERR_ABORTED` auf.

**Technische Ursache:** `successful = shown.length - failedById.size` mischte die aktuell sichtbare Auswahl mit einer globalen Fehlermenge, in der auch inzwischen ausgeblendete Reihen verblieben. Solo/Filter/Retry konnten dadurch 1 − 4 rechnen. Parallel gab es keine `AbortController` pro Reihe; globales Retry lud alle sichtbaren Reihen, und der UI-Zustand wurde nur aus Payload-/Fehler-Maps statt aus expliziten Serienzuständen abgeleitet.

## Umsetzung

### Explorer

- Explizite Zustände je Reihe: `loading`, `visible`, `hidden`, `empty`, `failed`.
- Sichtbar-/Leer-/Fehleranzahlen werden ausschließlich aus der aktuellen sichtbaren Auswahl gezählt und können nicht negativ werden.
- Pro Reihe existieren Request-Version und `AbortController`; alte, abgebrochene oder entfernte Requests dürfen keinen neuen Zustand überschreiben.
- Ausblenden bricht den laufenden Request ab; Wiedereinblenden lädt die Reihe für den aktuellen Zeitraum neu.
- Globales Retry lädt nur aktuell sichtbare fehlgeschlagene Reihen; erfolgreiche Reihen bleiben sichtbar.
- Entfernen bereinigt Controller, Payload und Fehlerzustand.
- URL, Reload und `popstate` stellen Auswahl, Modus, Auflösung und Zeitraum konsistent wieder her.
- Kein Punkt: kompakter erklärter Leerzustand; ein Punkt: sichtbarer Einzelwert; mehrere Punkte: Verlauf.
- Suchergebnisse schließen nach Auswahl und blockieren keine benachbarten Steuerelemente mehr.

### Heute

- 12-Spalten-Desktopgrid: breite Tagesübersicht, Check-in/Aufgaben in sinnvoller rechter Spalte, ausreichend breite Medikation und Chronik, Ernährung und Datenvollständigkeit je halbe Breite.
- `align-items:start`, keine erzwungenen gleich hohen Inhaltskarten und keine globale Karten-Mindesthöhe.
- Unter 1050 px: `auto-fit/minmax`; unter 760 px zwei sinnvolle Spalten; klein mobil eine Spalte.
- Normale Wörter behalten `word-break: normal`, `overflow-wrap: normal` und werden nicht als Ersatz für schmale Restspalten zerbrochen.

### Ereignisse

Neun textuell und symbolisch identifizierbare Kategorien mit eigenen CSS-Variablen: Symptome/Beschwerden, Medikamente, Ernährung, Training, Sauna/Erholung, Labor, Termine, Dokumente und weitere Ereignisse.

- Marker: Farbe plus eingebettetes Symbol plus zugänglicher Name.
- Desktop: Hover/Fokus-Tooltip mit Datum, Uhrzeit, Kategorie und Titel.
- Touch/Klick: kompaktes Detailpanel; Aktion „Tag öffnen“ bzw. „Details öffnen“.
- Liste standardmäßig eingeklappt, nach Datum sortiert und mit denselben Kategorie-Badges.
- Filter, Marker und Listeneinträge verwenden dieselbe gefilterte Ereignismenge.
- Farben dienen nur der Kategorieunterscheidung und enthalten keine medizinische Wertung.

## Fokussierte Abnahme vor Release

| Gate | Ergebnis |
|---|---|
| Python Berechnungs-/Vertragstests | 22 bestanden |
| Playwright 7A-R1 | 6/6 bestanden |
| Zwei erfolgreiche Reihen, gestapelt/überlagert, aus-/einblenden, entfernen/neu hinzufügen | bestanden |
| Eine erfolgreiche + eine fehlgeschlagene Reihe; Retry nur Fehler | bestanden |
| Zeitraum, Reload, Zurück/Vorwärts | bestanden |
| 0-/1-Punkt-Vertrag | bestanden |
| Kategorien, Tooltip-/Touchdetail, Filter/Listengleichlauf | bestanden |
| Desktop 1440 px | bestanden |
| Laptop 1180 px | bestanden |
| Mobil 390 px | bestanden |
| 200 % Textgröße | bestanden |
| JS-, Python- und Shell-Syntax | bestanden |
| `git diff --check` | sauber |

Die Browserdaten der automatisierten Abnahme waren synthetisch. Nur die isolierte Fehlerreproduktion nutzte eine geschützte private Datenbankkopie; dabei wurden keine Gesundheitswerte ausgegeben und keine produktiven Aktionen ausgelöst.

## Read-only Inventar

Die vollständige sichere Abdeckungsmatrix und Athlytic-Abgrenzung stehen in [`sprint7a-r1-apple-health-inventory.md`](sprint7a-r1-apple-health-inventory.md).

Kernaussagen:

- beobachteter Auto-Export enthält ausschließlich `data.metrics`, kein Versionsfeld und keinen Workout-Container;
- Workouts und Workout Metrics sind im tatsächlichen Export nicht enthalten;
- der gesuchte Workout-Datensatz vom 26.07.2026 ist weder als Workout exportiert noch importiert;
- Athlytic ist nur als normale HealthKit-Quelle für Ruhepuls belegt; kein Bundle Identifier und keine proprietären Athlytic-Scores;
- alle beobachteten Export-Metriknamen sind im Import vorhanden, aber nur eine kuratierte Teilmenge ist im V5 auswählbar.

## Sicherheits-/Medical-Scope

- keine neue Schreibroute, Datenbankmigration, externe API, Navigation oder Berechtigung;
- keine Datenbankänderung während Inventar/Reproduktion;
- keine Diagnose-, Kausalitäts-, Recovery-, Stress-, Therapie- oder Ernährungsscore-Aussage;
- keine produktiven Gesundheitswerte in Logs oder Releasebericht;
- V4 bleibt unverändert.

## Bewusst offen

- Sprint 7B: Datenfrische-/Systemübersicht;
- separater kleiner Export-/Import-Sprint für Workouts und Workout Metrics nach iPhone-Konfigurationsprüfung;
- späterer, eigenständig spezifizierter Einfluss-/Belastungssprint;
- importierte, aber nicht katalogisierte Metriken in getrennten kleinen Sprints;
- Export-/Import-Zähldifferenzen dedupe-spezifisch read-only untersuchen.
