# Sprint 7C-F – Medikamentenbestand und additive Migration

## Reproduzierbare Ausgangslage

Read-only inventarisiert am Basis-Commit `3f69e46823269c97260976270e53acbcc45f00d4` gegen die aktive private Health-Datenbank. In dieser Datei stehen nur aggregierte technische Befunde; keine Medikamentennamen, Dosen, Notizen oder anderen medizinischen Rohdaten.

- Medikamentenstamm (`medikamente`): **7 Zeilen**
- Legacy-Medikationsereignisse (`medication_administrations`): **5 Zeilen**
- ausdrücklich als verabreicht/eingenommen klassifizierbar: **4**
- fachlich nicht sicher in den kanonischen Statusvertrag einordenbar: **1** → Anzeige `unknown`
- Ereignisse mit dokumentiertem Folgetermin: **4**
- ausdrücklich dokumentierte Auslassungen: **0**
- Korrekturereignisse: **0**
- Ereignisse mit Applikationsweg: **5**, zwei Originalbezeichnungen
- Ereignisse mit Notiz: **5**
- Ereignisse mit eindeutigem Zeitpunkt: **5**
- erkannte Duplikatgruppen: **0**
- widersprüchliche Statuskombinationen: **0**
- verwaiste Legacy-Ereignisse ohne exakt passenden Stammdatensatz: **0**
- Quelle der fünf Ereignisse: eine dokumentierte manuelle Quellklasse
- Dosisfelder: zwei fehlend, drei freie beziehungsweise zusammengesetzte Textformate
- strukturierte Charge: **0**
- strukturierte Injektionsstelle: **0**

## Bewusst nicht interpretierte Legacyfelder

- Freie `dose`-Texte werden weder in Wert und Einheit zerlegt noch numerisch normalisiert.
- Bestehende `event_type`-Werte außerhalb der expliziten Allowlist werden nicht umklassifiziert; sie erscheinen als `unknown`.
- Bestehende Applikationswege bleiben in `route` unverändert. Eine kontrollierte Anzeigeabbildung ist read-only; unbekannte Bezeichnungen werden `unknown`.
- Verordnungsstatus wird nicht aus Datum, Medikamentenname, Darreichungsform, Folgetermin oder Ereignissen abgeleitet.
- Vergangene Planung wird nicht als Auslassung interpretiert.
- Fehlende Relation, Charge, Injektionsstelle, strukturierte Dosis und Provenienz bleiben `NULL` beziehungsweise unbekannt.

## Fachliche Granularität

1. **Verordnung** – dokumentierter Medikamentenstamm mit eigenem Status und Provenienz.
2. **Geplanter Termin** – `event_type=planned`; beweist keine Verabreichung.
3. **Tatsächliches Ereignis** – ausschließlich ausdrücklich `administered`.
4. **Auslassung** – ausschließlich ausdrücklich `missed`.
5. **Korrektur** – neues unveränderliches Ereignis mit `corrects_event_id`, Zielstatus und verpflichtender Begründung; das Ursprungsereignis bleibt erhalten.

Read-only Darstellungsvertrag: `health.medication_history.v1`
Action-Vertrag: `health.medication_action.v1`

## Genaue Schemaerweiterungen

`medikamente` erhält ausschließlich nullable Felder:

- `prescription_status`
- `prescription_status_source`
- `prescription_status_provenance`
- `business_revision`

`medication_administrations` führt beziehungsweise bestätigt folgende nullable strukturierte Felder:

- `medication_id`
- `planned_event_id`
- `planned_dose_value`, `planned_dose_unit`
- `actual_dose_value`, `actual_dose_unit`
- `route_original`, `route_normalized`
- `injection_region`, `injection_side`, `injection_detail`
- `lot_number`
- `corrects_event_id`
- `corrected_target_status`
- `correction_reason`
- `business_revision`

Hinzu kommen:

- `medication_schema_meta` als Schemamarker;
- `medication_public_identity_key` mit einem zufälligen 32-Byte-Schlüssel für HMAC-basierte öffentliche Referenzen;
- Indizes für Medikament/Zeit, Planrelation, genau eine wirksame Planverbrauchsrelation und genau einen direkten Korrekturschritt;
- Trigger für strukturierte Allowlist-Validierung, Relationstreue, lineare Korrekturzyklen sowie Update-/Delete-Sperren strukturierter oder bereits korrigierter Ursprungsereignisse.

Die alte automatische SQLite-Unique-Constraint `(datum, medication_name, event_type)` wird ausschließlich in der **separaten Kandidatenkopie** durch einen copy-first Tabellenneubau ohne diese fachlich zu grobe Constraint ersetzt. Dabei werden Tabelle, explizite IDs, sämtliche vorhandenen Spaltenwerte und die fünf Legacyzeilen vollständig kopiert und per typisiertem logischem Digest verglichen. Dies erlaubt mehrere ausdrücklich dokumentierte, zeitlich verschiedene Ereignisse desselben Medikaments am selben Tag; es findet keine Datenumklassifizierung statt.

## Migration

- Name: `sprint7c_f_additive_medication_history`
- Schemaversion: `7`
- Implementierung: `scripts/health/migrate_sprint7c_f_medication_schema.py`
- Schema-Contract: `scripts/health/dashboard_v5/medication_schema.py`

Die Migration arbeitet ausschließlich copy-first:

1. konsistentes SQLite-Onlinebackup mit SHA-256;
2. tatsächlicher Restore in ein separates Ziel und logischer Vergleich;
3. Migration einer Wegwerfkopie, zweiter Lauf ohne Änderungen;
4. Vergleich aller ursprünglichen Spalten und Zeilen über typisierte logische Digests;
5. vollständiger Vergleich der 7 Stamm- und 5 Ereigniszeilen;
6. Erzeugung einer separaten migrierten Kandidaten-DB;
7. erneuter idempotenter Lauf, `integrity_check=ok`, Foreign-Key-Fehler 0;
8. erst im kontrollierten Cutover atomare Installation dieser Kandidaten-DB.

Es gibt keine parallele Medikationsdatenbank und keine strukturierten Pflichtinformationen in `notes`.

## Rollback

Vor Cutover bleiben produktive DB und V4 unangetastet. Beim Cutover wird das frische konsistente Backup als bestätigter Restore-Punkt bewahrt. Bei Legacy-Digest-/Zeilenzahlabweichung, Relationsfehler, Nicht-Idempotenz, Integritäts-/FK-Fehler, Statusumklassifizierung, fehlender Worker-Idempotenz, P0/P1, Neustartschleife oder verändertem V4-Hash wird die Kandidateninstallation abgebrochen beziehungsweise die bestätigte Backup-DB atomar zurückgesetzt. Neue Runtime-Dateien werden aus dem owner-only Rollback-Verzeichnis wiederhergestellt.
