gwoe-antragspruefer/docs/adr/0015-prod-deploy-ueber-git-checkout-und-citation-cross-block.md
Dotty Dotter d5b8cf4573 docs(adr 0015) + scripts: 2.0-Cut + Citation-Cross-Block-Fix dokumentieren
ADR 0015 fixiert die zwei strukturellen Entscheidungen vom 2.0-Cut:
- Prod-Deploy ueber sauberen git-Checkout statt Tar-Upload (loest
  ADR 0004 in Teilen ab)
- Reconstruct_zitate-Zwei-Pass: Zitate werden ueber beide Bloecke
  hinweg klassifiziert, dann erst geschrieben — Cross-Block-Move
  statt nur quelle-Korrektur

scripts/migrate-zitate-blocks.py: idempotentes String-basiertes
Migrations-Skript fuer bestehende Records mit altem Bug-Stand. Nicht
LLM-abhaengig, deterministisch. Beim 2.0-Cut auf 22 Assessments
angewendet (26 Zitate verschoben).
2026-05-10 13:28:56 +02:00

110 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 0015 — Prod-Deploy als sauberer git-Checkout + Citation-Block-Reklassifikation
| | |
|---|---|
| **Status** | accepted |
| **Datum** | 2026-05-10 |
| **Supersedes** | (Anteile von) ADR 0004 (Tar-Upload-Workflow) |
| **Refs** | v2.0.0-Tag, release/2.0-Branch, Commits 770d89088211c5 |
## Kontext
Beim 1.x → 2.0-Release-Cut wurden zwei strukturelle Probleme sichtbar, die
in einer Entscheidung zusammenhängen.
**Problem 1 — Prod-Repo-Mess.** Der prod-Pfad `/opt/gwoe-antragspruefer`
wurde seit April per Tar-Upload aktualisiert (siehe ADR 0004). Effekt:
Filesystem-Stand war neuer als der HEAD-Commit (4fbdc15 vom 10. April),
19 Files modifiziert, 30+ untracked. `git pull` war nicht mehr möglich,
ohne den Stand zu zerstören. Dev wurde parallel sauber per `git pull` aus
`main` deployed (Cron `auto-deploy.sh`). Die zwei Workflows divergierten.
**Problem 2 — Citation-Block-Misattribution.** `reconstruct_zitate` (ADR
0001 / Issue #60) hat bei einem Cross-Kind-Fallback-Match nur die
``quelle`` des Zitats korrigiert, das Zitat aber im ursprünglichen Block
belassen. Folge: Im wahlprogramm-Block standen Zitate aus
Grundsatzprogrammen, die quelle stimmte zwar, aber die Block-Zuordnung
suggerierte etwas Falsches. Reproduziert auf Antrag 18/18246 (NRW),
Bewertung GRÜNE.
## Optionen
### Workflow 1 — Beide Probleme über separate Migrationen lösen
**A.1 (Deploy):** Einmaliger Cut mit frischem `git clone`, dann beidseitig
git-pull-basiert. Tar-Upload-Pfad obsolet.
**A.2 (Deploy):** Tar-Upload retten, indem man HEAD nachzieht und
.gitignore erweitert, sodass Tar-überschriebene Files nicht als Diff
auftauchen.
**B.1 (Citations):** Zwei-Pass-Verarbeitung in `reconstruct_zitate`
erst klassifizieren über beide Blöcke hinweg, dann schreiben. Plus
einmaliges String-basiertes Migrations-Skript für die bestehenden 117
Records.
**B.2 (Citations):** Ganze Bewertungen neu generieren (LLM-Call),
sobald der Code-Fix lebt.
## Entscheidung
**Deploy: A.1.** Einmaliger sauberer git-clone auf prod, danach beide
Umgebungen identisch via `git pull`. Begründung: Der Tar-Mess wäre nie
sauber zu reparieren gewesen, ohne irgendwo eine Annahme zu treffen, was
"echt" ist. Ein frischer Clone setzt den Stand definitiv. Alle Volumes
(`data/`, `reports/`, `backups/`) bleiben unangetastet.
**Citations: B.1.** Code-Fix mit Zwei-Pass plus einmaliges Migrations-Skript.
Begründung: B.2 wäre nicht-deterministisch (LLM-Fluktuation), würde Tokens
verbrennen und liefert keine bessere Garantie als das deterministische
String-Match auf "Grundsatzprogramm" vs. "Wahlprogramm" im quelle-Label.
22 Assessments wurden migriert, 26 Zitate verschoben.
## Konsequenzen
### Deploy
- `/opt/gwoe-antragspruefer` ist seit dem Cut ein sauberer Checkout von
`release/2.0`.
- Nächster Standard-Deploy: `./scripts/deploy.sh` (Branch-Guard,
Pre-flight, Pre-Deploy-Backup, Health-Check, Uptime-Kuma).
- Major-Cuts: `./scripts/major-release-cut.sh <tag> <branch>`
inkl. Bundle-Fallback bei Gitea-Korruption (war beim 2.0-Cut nötig).
- Alter Pfad als `/opt/gwoe-antragspruefer-YYYYMMDD-HHMMSS-archive`
archiviert.
- ADR 0004 ist in Teilen abgelöst, der Tar-Upload-Pfad gilt nicht mehr.
### Citation-Binding
- `reconstruct_zitate` klassifiziert pro Fraktion über beide Blöcke
hinweg, schreibt erst danach in die jeweils passenden Blöcke.
- Test: ``tests/test_embeddings.py::TestReconstructZitate::test_zitat_aus_grundsatzprogramm_landet_im_parteiprogramm_block``
reproduziert den 18/18246-Fall.
- Migrations-Skript ``scripts/migrate-zitate-blocks.py`` ist idempotent
und kann jederzeit re-run werden, falls weitere Records aus älterem
Code-Stand reinkommen.
### DB-Wipe-Liste beim Major-Cut
`scripts/major-release-cut.sh` enthält die Liste der Tabellen, die beim
Cut geleert werden:
- `assessments`, `assessment_versions` — Bewertungen (Schema-Drift möglich)
- `presse_drafts`, `news_articles` — Cache-Daten
- `auto_rate_runs`, `jobs` — Queue-/Cron-Tracking
- `monitoring_scans`, `monitoring_daily_summary` — Live-Metriken
- `auth_bypass_uses`, `comments`, `merkliste`, `bookmarks`,
`email_subscriptions`, `votes`
**Erhalten bleiben:**
- `plenum_vote_results` — kostenlose Re-Ingest-Daten (PDFs werden vom
Server geholt, kein LLM nötig)
- `abgeordnetenwatch_votes`, `abgeordnetenwatch_polls` — re-fetchbar via
`sync_abgeordnetenwatch.py`, aber zeitaufwändig
- `embeddings.db` — extern als Volume, separat gehandhabt
Beim 3.0-Cut diese Liste prüfen: falls neue User-Daten-Tabellen
hinzukommen (z.B. erweiterte Bookmarks), gehört die Wipe-Entscheidung
dort explizit gemacht.