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

4.5 KiB
Raw Blame History

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.