diff --git a/docs/roadmap-programme-2026-05-08.md b/docs/roadmap-programme-2026-05-08.md new file mode 100644 index 0000000..203f867 --- /dev/null +++ b/docs/roadmap-programme-2026-05-08.md @@ -0,0 +1,161 @@ +# Roadmap Programme/Legislaturen — Entscheidungen 2026-05-08 + +Ergebnis der strategischen Klärungs-Runde im Anschluss an [ADR +0013](adr/0013-programme-legislaturen-zeitpunktige-bewertung.md). Alle 11 +offenen Fragen entschieden. + +## Entscheidungen im Überblick + +| ID | Frage | Entscheidung | +|----|-------|--------------| +| A1 | Historische Indexierung | **Volle historische Indexierung** (~50 PDFs, 3 Vorperioden × 16 BL) | +| A2 | Kleine/historische Fraktionen | **Auch historische** (BIW Bremen, BVB/FW Brandenburg) | +| B1 | Antrag vor Regierungsbildung | **Programm gilt ab Wahltag** | +| B2 | Opposition vs. Regierung | **Alle ab Wahltag** (löst B1 implizit) | +| B3 | CDU+CSU teilen Programm | **CSU als Alias auf CDU-Eintrag** | +| B4 | BSW kein Grundsatzprogramm | **Manifest 2023 als parteiprogramm-Eintrag** | +| C1 | Programm-Updates verfolgen | **Cron: monatlich Parteiwebseiten checken** | +| C2 | Reindexierung | **Cron: täglich, nur fehlende** | +| C3 | PDF-Quellen-Stabilität | **+ Eigener Mirror auf Toppyr-Server** | +| D1 | Neue Auswertungen | **Alle vier:** Programmwechsel, Treuequote, Koalitions-Shift, Regierung-im-Detail | +| D2 | UI-Investition | **Eigene Detail-Views** für Regierung & Wahlperiode | +| E1 | Prod-Deploy | **Erst nach historischer Indexierung** (v1.1.0 als Belohnung) | +| E2 | WAHLPROGRAMME konsolidieren | **Erst nach historischer Indexierung** | + +## Implementierungs-Reihenfolge (logische Abhängigkeiten) + +### Block 1 — Schema-Refactor (ohne neue Daten, schnell) + +**1.1** B1+B2: `gueltig_ab` umstellen von Regierungsbildung auf Wahltag +- Migration: pro Wahlprogramm-Eintrag das `wahltermin` aus + `legislaturen.py` holen → `gueltig_ab = wahltermin` +- `regierungsbildung` bleibt erhalten für die UI-Anzeige "Regierung zur + Antragszeit" (Bewertungs-Kontext) +- Tests anpassen: B1 (vor-Regierungsbildung) liefert nun das Wahlprogramm + ab Wahltag + +**1.2** B3: CSU-Alias-Mechanismus +- Optionales `alias_of`-Feld im Programm-Schema +- `csu-bund-2025` wird zu `{"alias_of": "cdu-bund-2025", ...}` +- Lookup-Helper resolvt Aliase automatisch + +**Aufwand:** kurz (1-2h Code + Tests) + +### Block 2 — Daten-Beschaffung (Background-Agents parallel) + +**2.1** A1: 50 historische Wahlprogramme beschaffen +- 16 BL × ~3-5 Vorperioden × ~5 Parteien = ~50 PDFs +- Per Bundesland Liste + URLs zusammensuchen (Background-Agent) +- Lokale Mirrors anlegen (siehe C3) +- SHA-256 in `wahlprogramm-shas.lock.json` pinnen + +**2.2** A2: Historische Fraktionen ergänzen +- BIW Bremen 2023-Programm beschaffen + im Schema (HB-Eintrag) ergänzen +- BVB/FREIE WÄHLER Brandenburg WP7 (2019-2024) beschaffen +- In `legislaturen.REGIERUNGEN` ggf. aktualisieren falls nötig + +**2.3** B4: BSW Manifest 2023 indizieren +- PDF beschaffen (URL: bsw-vg.de/wp-content/uploads/2024/01/BSW_Parteiprogramm.pdf + oder neuere Version) +- Als `bsw-manifest` in `embeddings.PROGRAMME` einbauen mit + `gueltig_ab="2023-10-23"` +- programme.py: Eintrag als `grundsatzprogramm-bund` registrieren + +**Aufwand:** mittel — eigene Session(en), DashScope-API-Last + +### Block 3 — Infrastruktur (Cron + Mirror) + +**3.1** C3: Mirror-Server-Setup +- Auf Toppyr-Server: `/var/www/programme-mirror/` als statisches PDF-Archiv +- Spiegel via rsync von `app/static/referenzen/` +- URLs in `wahlprogramm-links.yaml` um `mirror_url`-Feld erweitern + +**3.2** C1: Monatlicher Cron — Parteiwebseiten-Update-Check +- `scripts/check-programm-updates.sh` per Cron alle 30 Tage +- Liest `wahlprogramm-links.yaml`, ruft jede URL ab, vergleicht SHA-256 +- Bei Hash-Mismatch oder 404: Telegram-Notification an Topic 4247 +- Output in `data/programm-updates.log` + +**3.3** C2: Täglicher Cron — inkrementelles Reindexing +- `scripts/reindex-fehlende.sh` per Cron 03:00 Uhr +- Nutzt vorhandene `reindex_embeddings.py`-Logik (skip-already-indexed) +- Loggt in `auto_rate_runs`-ähnliche Tracking-Tabelle + +**Aufwand:** kurz-mittel + +### Block 4 — Auswertungen + UI (Detail-Views) + +**4.1** D2: "Regierung im Detail"-View (`/regierung/{name}`) +- Pro Kabinett: Anträge der Amtszeit, Score-Verteilung, Auffälligkeiten, + Programm-Treue-Quote der Regierungsfraktionen + +**4.2** D1: Programmwechsel-Diff (`/partei/{name}/programmwechsel`) +- Wahlprogramm 2017 vs. 2022 — semantischer Diff via Embeddings +- Heatmap pro GWÖ-Wert: hat sich die Programmatik verschoben? + +**4.3** D1: Treuequote-Zeitreihe (`/auswertungen/treuequote`) +- Pro Regierung: % der Anträge, die ≥7 Treue-Score zum eigenen + Wahlprogramm haben → Erfüllungsgrad der Wahlversprechen + +**4.4** D1: Koalitions-Shift (`/partei/{name}/koalitionen`) +- Stimmverhalten der gleichen Partei in verschiedenen Koalitionen + vergleichen + +**Aufwand:** lang — eigenes Feature-Projekt + +### Block 5 — Konsolidierung + Release + +**5.1** E2: WAHLPROGRAMME als View über programme.PROGRAMME +- `wahlprogramme.WAHLPROGRAMME` wird `@property` auf + `programme.PROGRAMME`-Filter +- `embeddings.PROGRAMME` analog +- ~1h Code, alle Tests müssen grün bleiben + +**5.2** analyzer.py auf zeitpunktige Helper migrieren +- `wahlprogramm_zum_zeitpunkt(bl, partei, antrag.datum)` statt + `WAHLPROGRAMME[bl][partei]` +- `find_relevant_chunks` mit Datum-Filter (nur Programme mit + `gueltig_ab ≤ antrag.datum < gueltig_bis`) +- Smoke-Test gegen 5 historische Anträge: stimmen die Ergebnisse? + +**5.3** E1: Production-Release v1.1.0 +- main → release/1.1 branch +- Tag v1.1.0 +- Deploy auf prod (gwoe.toppyr.de) mit komplettem Stack +- ADR 0014 für Release-Bilanz + +**Aufwand:** mittel + +## Grobe Zeitplanung + +| Block | Sessions | Wann | +|-------|----------|------| +| Block 1 (Schema-Refactor) | 1 | jederzeit | +| Block 2 (Daten-Beschaffung) | 3-5 | nach Block 1 | +| Block 3 (Infra) | 1-2 | parallel zu Block 2 möglich | +| Block 4 (Auswertungen) | 4-6 | nach Block 2 | +| Block 5 (Konsolidierung + Release) | 1-2 | als Letztes | + +## Gotchas und offene Detail-Fragen + +- **B1+B2 Migration:** muss in einem einzigen Commit passieren + (Schema-Bruch). Tests refactoren. +- **A2 historische Fraktionen:** BVB/FW Brandenburg ist ein Wahlbündnis, + nicht eine Partei — wie modellieren? (Optionen: als Alias auf BVB + + FW separat, oder als eigenständigen Schlüssel.) +- **B3 Alias:** wenn `csu-bund-2025` ein Alias auf `cdu-bund-2025` ist, + muss die UI klar machen "CDU+CSU teilen sich dieses Programm" und + nicht zwei separate Bewertungs-Quellen suggerieren. +- **C1 Cron:** wie unterscheidet er "neue Version desselben Programms" + von "Webseiten-Layout-Änderung mit gleichem PDF"? SHA-256-only + reicht für Layout-Tolerance nicht — alternativ: nur PDF-Bytes prüfen. +- **D1 Programmwechsel-Diff:** semantischer Diff zwischen zwei + Wahlprogrammen ist nicht trivial. Embedding-Cosine pro Chunk-Paar? + Oder summarized-by-LLM? Eigene Architektur-Entscheidung. + +## Nächster konkreter Schritt + +**Block 1 anfangen** — Schema-Refactor `gueltig_ab = Wahltag` und +CSU-Alias-Mechanismus. Das ist eine geschlossene Session, baut +direkt auf den bestehenden Modulen auf, und macht das Schema sauberer +für alles, was folgt.