Commit Graph

45 Commits

Author SHA1 Message Date
Dotty Dotter
e04eb6d340 feat: Block 2.2 — BUND WP20 (BTW 2021, Scholz-Ampel) historisch indiziert
7 Wahlprogramme zur BTW 26.09.2021 — die Programme der Scholz-Ampel-Periode
(SPD+GRÜNE+FDP, vereidigt 08.12.2021, vorgezogenes Ende 25.03.2025):

- cdu-bund-2021 (gemeinsam CDU/CSU "Stabilitaet und Erneuerung", 140 S., 232 chunks)
- csu-bund-2021 (eigenstaendige CSU-Bayern-Fokus-Variante, 18 S., 24 chunks)
- spd-bund-2021 (Zukunftsprogramm "Aus Respekt vor Deiner Zukunft", 66 S., 105 chunks)
- gruene-bund-2021 (272 S. barrierefreie Fassung, 269 chunks)
- fdp-bund-2021 (Beschluss 14.-16.05.2021 Berlin, 68 S., 136 chunks)
- afd-bund-2021 ("Deutschland. Aber normal.", 210 S., 160 chunks)
- linke-bund-2021 ("Zeit zu handeln!", 168 S., 324 chunks)

Total: 1.250 Chunks.

Geltungszeitraum 2021-09-26 (Wahltag) bis 2025-02-23 (Wahltag BTW 2025,
exklusiv). Antraege aus dieser Periode bekommen jetzt automatisch das
korrekte Programm zurueckgeliefert via wahlprogramm_zum_zeitpunkt():

- 2024-01-01 BUND/SPD -> spd-bund-2021 (Scholz-Ampel)
- 2025-02-22 BUND/SPD -> spd-bund-2021 (noch alt)
- 2025-02-23 BUND/SPD -> spd-bund-2025 (BTW-Wahltag, Wechsel)

Tests: 117 gruen, plus neue test_bund_2024_returns_btw_2021 und
test_bund_grenze_btw_2021_btw_2025.

Block 2.2 abgeschlossen — Block 2 Roadmap (16 BL × 3 WPs) ist 2/16 BL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 10:25:51 +02:00
Dotty Dotter
445fcc90ca feat: Block 2.1 — NRW WP17 historische Wahlprogramme indiziert (Pilot)
5 Programme zur LTW NRW 14.05.2017 als historische Wahlprogramme im
Embeddings-Index — erster Datensatz für die zeitpunktige Bewertung
historischer Antraege:

- cdu-nrw-2017 (Laschet, 120 S., 172 chunks)
- spd-nrw-2017 (Kraft, 116 S., 169 chunks)
- gruene-nrw-2017 (131 S., 322 chunks)
- fdp-nrw-2017 (Lindner, 56 S., 92 chunks)
- afd-nrw-2017 (84 S., 78 chunks)

Geltungszeitraum 2017-05-14 (Wahltag WP17) bis 2022-05-15 (Wahltag
WP18, exklusiv). Eintraege liegen NUR in embeddings.PROGRAMME — die
WAHLPROGRAMME[NRW]-Struktur bleibt single-current (cdu-nrw-2022).

programme._migrate_from_legacy hat einen neuen Schritt 2b, der
typ=wahlprogramm-Eintraege aus embeddings.PROGRAMME mit explizitem
gueltig_ab/_bis als historische Wahlprogramme registriert. Damit
liefert wahlprogramm_zum_zeitpunkt() jetzt fuer NRW-Antraege aus dem
Zeitraum 2017-2022 das passende Programm.

Live-Verifikation auf gwoe-antragspruefer-dev:
- 2018-09-01 -> cdu-nrw-2017 (WP17)
- 2024-01-01 -> cdu-nrw-2022 (WP18)
- Grenze: 14.05.2022 -> WP17, 15.05.2022 -> WP18

Tests: 116 gruen, plus neue test_grenze_zwischen_wp17_und_wp18 und
angepasstes test_datum_vor_aktueller_wp_nrw_wp17.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:44:26 +02:00
Dotty Dotter
d16cacc7fe feat: Bewertungs-Kontext mit PDF-Link + Snapshot-Hinweis
Erweiterung des Geltungs-Kontext-Blocks (Antrag-Detail):
- Programm-Titel als Link auf das PDF ({titel} klickbar →
  /static/referenzen/{pdf}, opens in new tab).
- Seitenzahl als ergaenzende Info: "116 S." neben Geltungsdatum.
- Snapshot-Zeile am Block-Ende: "Diese Bewertung wurde am
  {datum} mit {modell} gegen den oben genannten Programm-Stand
  erzeugt." — macht klar, dass die Anzeige eine Momentaufnahme der
  damaligen LLM-Bewertung ist und nicht "live" gegen heutige
  Programme misst.

CSS:
- v3-geltung-pdf: ECG-blauer Link mit dezenter underline-Linie.
- v3-geltung-snapshot: kursiv, getrennt durch hairline-border, gedaempft.

Tests: 88 grün (test_legislaturen + test_wahlprogramme + test_embeddings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:48:30 +02:00
Dotty Dotter
c7861cfb58 feat: Antrag-Detail um Bewertungs-Kontext erweitert
Vor der Programm-Treue-Sektion eine kompakte Info-Box, die transparent
macht, was zur Antragszeit fuer das jeweilige Parlament galt:

- **Wahlperiode** (Nummer + Konstituierung-bis-Ende-Spanne) ueber
  legislatur_zum_zeitpunkt(bl, antrag_datum)
- **Regierung zur Antragszeit** (Name + Koalitionsparteien + Vereidigung,
  ggf. Endedatum bei Sukzessionen wie Dreyer III -> Schweitzer I) ueber
  regierung_zum_zeitpunkt(bl, antrag_datum)
- **Bewertet gegen die folgenden Wahlprogramme** (pro Antragsteller-
  Fraktion mit gueltig-seit-Datum) ueber wahlprogramm_zum_zeitpunkt
  pro Partei

Daten kommen aus den neuen Modulen app/legislaturen.py + app/programme.py.
Helper laufen historisch korrekt — z.B. ein Antrag aus 2020-02-15 in TH
wuerde "Kemmerich I (FDP)" zurueckliefern.

Aktuell zeigen alle Antraege die jeweils "aktuelle" Regierung & das
aktuelle Programm, weil keine historischen Wahlprogramme im Embeddings-
Index sind. Die Architektur ist aber fuer den Tag vorbereitet, wo
historische Programme indiziert werden.

Implementation:
- main.py: _render_antrag_detail laedt geltung_kontext und gibt es ans
  Template weiter. ISO-Datum aus row["datum"] (nicht aus dem display-
  formatierten antrag["datum"]).
- v3/screens/antrag_detail.html: neue Sektion v3-geltung vor Programm-
  Treue-Block.
- static/v3/v3.css: neue v3-geltung-Klassen mit dezentem Doku-Look.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:45:44 +02:00
Dotty Dotter
a80ac17218 feat: 6 Grundsatzprogramme + Landesgrundsatzprogramme indiziert
Neu in embeddings.PROGRAMME (typ=parteiprogramm mit gueltig_ab):
- csu-grundsatz: CSU "Für ein neues Miteinander" (2023-05-06, 125 chunks)
  ersetzt das bisher indizierte CSU 2016-Programm logisch
- cdu-grundsatz-nrw: CDU NRW "Aufstieg, Sicherheit, Perspektive"
  (2015-06-13, Landesgrundsatzprogramm, 127 chunks)
- cdu-grundsatz-sn: CDU Sachsen "Zukunftsplan für Sachsen"
  (2023-11-20, Landesgrundsatzprogramm, 52 chunks)
- cdu-grundsatz-lsa: CDU Sachsen-Anhalt "Unsere Verantwortung. Unsere
  Zukunft." (2023-09-30, Landesgrundsatzprogramm, 74 chunks)
- ssw-grundsatz: SSW Rahmenprogramm (2016-04-16, Landesgrundsatzprogramm
  für Schleswig-Holstein, 65 chunks)
- fw-grundsatz: FREIE WAEHLER Bundesgrundsatzprogramm (Stand 09/2025;
  FW nicht im Bundestag, gilt fuer FW Bayern + FW RLP, 43 chunks)

programme.py:
- _migrate_from_legacy() unterscheidet jetzt grundsatzprogramm-bund
  (bundesland=None) und grundsatzprogramm-land (bundesland gesetzt).
- _ADDITIONAL_PROGRAMME-Slot vereinfacht — alle Daten leben in
  embeddings.PROGRAMME.

Auf gwoe-antragspruefer-dev indiziert (text-embedding-v4):
486 neue Chunks, 0 failed. wahlprogramm-shas.lock.json + -links.yaml
gepinnt mit allen 6 SHA-256-Hashes.

Test-Suite: 88 grün (test_legislaturen + test_wahlprogramme + test_embeddings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:30:06 +02:00
Dotty Dotter
991d1eb903 feat: Programme + Legislaturen-Registry mit historisch korrekter Geltung
Neue Module:
- app/programme.py: zentrale Programm-Registry (alle Wahl- und Grundsatz-
  programme in einem Index), mit Geltungsdaten gueltig_ab/gueltig_bis und
  Helpern wahlprogramm_zum_zeitpunkt(), grundsatzprogramm_zum_zeitpunkt(),
  alle_versionen(). Skelett fuer 6 zusaetzliche Eintraege (CSU 2023,
  CDU NRW 2015, CDU SN 2023, CDU LSA 2023, SSW SH 2016, FREIE WAEHLER)
  vorbereitet — PDFs folgen.
- app/legislaturen.py: 56 Legislaturen + 70 Regierungen fuer 16 BL + Bund.
  Helper legislatur_zum_zeitpunkt(), regierung_zum_zeitpunkt(),
  regierungen_einer_wp() fuer historisch korrekte Antrags-Bewertung
  (z.B. Kemmerich-28-Tage-Kabinett, RP-Uebergang Dreyer III -> Schweitzer I,
  BUND Scholz-Ampel -> geschaeftsfuehrend -> Merz I).
- tests/test_legislaturen.py: 20 Tests zu Konsistenz + Historie.

Datenbasis: 8 BTW-2025-Wahlprogramme (CDU, CSU, SPD, GRUENE, FDP, AfD,
LINKE, BSW) als PDFs hinzugefuegt. SHA-256-Pinning in
app/wahlprogramm-shas.lock.json (separat).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:18:33 +02:00
Dotty Dotter
a5ca3da842 fix: Topbar in Safari — overflow-x:hidden raus, flex-wrap raus, safe-area-inset rein
User-Bericht: 'Die obere Menueleiste verschwindet hinter den Tabs in
Safari. Und ich kann nicht mehr auf Anmelden klicken.'

Drei zusammenhaengende Probleme im Mobile-Media-Query:

1. body.v2 { overflow-x: hidden } war als Notbremse fuer Layout-Overflow
   gedacht, aber Safari (WebKit) interpretiert das so, dass position:
   sticky-Kinder nicht ueber den scrollenden Container kommen — die
   Topbar haftet nicht mehr richtig und kann hinter Safaris eigener
   Tab-Bar verschwinden. Raus damit.
   minmax(0, 1fr) auf v2-shell reicht als Overflow-Schutz.

2. flex-wrap: wrap auf der Topbar liess die Auth-/Theme-/Bundesland-
   Items in eine zweite Zeile umbrechen. Sticky-Elements mit
   variabler Hoehe haben in Safari Render-Bugs (clipping, click-
   absorption). Stattdessen jetzt: weniger wichtige Items
   (Methodik/Quellen-Links + Bundesland-Selector) auf Mobile via
   display:none ausgeblendet. Brand, Auth-Control und Theme-Toggle
   bleiben — passen problemlos in eine 32-px-Zeile.

3. padding-top: env(safe-area-inset-top, 0) fuer iOS-Safari, damit
   die Topbar Saafais Chrome-Overlap respektiert (Notch, URL-Bar,
   Tab-Bar im 'Compact'-Mode).

Plus z-index: 200 auf der Topbar — schaerfer als alle Page-Elemente,
sodass Anmelden-Button garantiert klickbar bleibt selbst wenn
darunterliegende Elemente in Edge-Cases ueberlappen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 14:00:57 +02:00
Dotty Dotter
a89334c6e7 fix: News — alle Items anzeigen, nur Summary-Absatz clampen (4 Zeilen)
User-Feedback: 'Es duerfen ruhig mehrere Items angezeigt werden. Aber
der Summary Text soll gekuerzt sein.'

Vorher: nur erstes Item sichtbar, Rest display:none.
Jetzt: alle Items sichtbar, Summary-<p> jedes Items auf 4 Zeilen
clamped. Titel/Meta/Tags/PM-Button bleiben pro Item komplett.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:53:42 +02:00
Dotty Dotter
7545d714f8 fix: News-Clamp auf Summary statt aufs ganze Item — PM-Button bleibt sichtbar
User-Feedback: 'Bei der Kuerzung der Beitraege geht der PM Generieren-
Button unter.' Mein 9-Zeilen-line-clamp lag auf dem ganzen Item-DIV
und schnitt deshalb den Button am Ende weg.

Fix: nur Summary-<p> wird auf 5 Zeilen geclampt; Meta, Title, Tags
und PM-Button bleiben unangetastet sichtbar. Item-Hoehe haengt damit
mehr von Title-Laenge ab, ist aber immer komplett.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:52:41 +02:00
Dotty Dotter
f0588714bf fix: Topbar-Wrap auf Mobile, Klassische-Ansicht raus, Tags-Greying + Title-Bug
Drei Korrekturen:

1. Mobile-Topbar: Auth-Widget + Bundesland-Selector + Theme-Toggle
   pushten die rechte Kante über 390 px Phone-Viewport. Fix: Topbar
   darf in @media (max-width: 900px) flex-wrappen, height auto,
   row-gap fuer mehrzeilig.

2. Topbar-Link "Klassische Ansicht" → /classic entfernt (verlinkt auf
   das alte v1-Frontend; v2 bzw. das neue v3 sind die aktiven Modi).

3. /tags-Seite hatte zwei Bugs:
   - Titel wurde aus a.titel (existiert nicht) statt a.title gelesen
     → User sah nur Drucksachen-Nummern und dachte "kaum Daten".
   - Kein Visual-Feedback welche Tag-Kombinationen leer wären.
   Beide gefixt: title-Field korrekt, plus Tag-Greying via class
   .tag-pill.disabled fuer Tags die zu 0 Treffern fuehren wuerden.
   Ausserdem Score-Field gwoeScore-Fallback und HTML-Escape fuer alle
   Strings (vorher XSS-anfaellig bei Title/Fraktion).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:05:10 +02:00
Dotty Dotter
848039627c fix: Mobile Overflow — minmax(0,1fr) + overflow-x:hidden
CSS-Grid 1fr-Track schrumpft per Spec NICHT unter min-content der Kinder.
Bei 390-px-Viewport bleibt der Track deshalb auf ~968px stehen (max-
content der weitesten Inhalte). Standard-Fix: minmax(0,1fr) hebt das
auf, body.overflow-x:hidden als Notbremse, overflow-wrap:anywhere
fuer lange unbreakable Strings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:59:22 +02:00
Dotty Dotter
d8d8f99965 fix: Mobile-Overflow — v2-shell auf 100vw zwingen, sonst wuchs 1fr-Grid auf Content-Breite
Bug auf 390-px-Phone-Viewport: html/body waren korrekt 390 px, aber
.v2-main rendert mit 968 px Breite, alle Inhalte überlaufen horizontal
um 200-580 px. Ursache: .v2-shell hatte im mobile-Media-Query nur
grid-template-columns: 1fr — ohne explizite width:100% nimmt Grid die
max-content-Breite des 1fr-Tracks an, was bei .v3-page max-width:880
auf 880+padding wächst. Folge: Sidebar ausgeblendet, aber Layout
trotzdem auf Desktop-Breite.

Fix in @media (max-width: 900px):
- body.v2 .v2-shell { width: 100%; max-width: 100vw; min-width: 0; }
- body.v2 .v2-main  { max-width: 100%; min-width: 0; padding: 16px 12px; }
- body.v2 .v2-topbar/.v2-footer { max-width: 100%; }

body-Selector mit body.v2-Prefix für Spezifität gegen die Default-
Regel ohne body.v2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:55:03 +02:00
Dotty Dotter
535c2f15e4 fix: Citation-Binding partei-skopiert (Cross-Partei-Misattribution gestoppt)
Bug: AfD-Parteiprogramm-Block enthielt ein Zitat mit quelle "CDU
Grundsatzprogramm 2024, S. 33" (DRS 21/4939). Ursache: reconstruct_zitate
hatte alle Chunks aller Parteien in einen Pool gemischt. Wenn der LLM
unter AfD-Parteiprogramm einen Text emittierte, der zufaellig auch im
CDU-Programm vorkam, matched der Code den CDU-Chunk und ueberschrieb
quelle/url mit CDU-Werten.

Fix: Match strikt auf chunks_by_party[fraktion][kind]. Fallback auf
gleiche Partei/andere Kategorie (z.B. AfD hat nur Grundsatz-, kein
Wahlprogramm im Index). Wenn kein Match in der eigenen Partei → Zitat
verwerfen statt fremde quelle behalten. Lieber 0 Zitate als ein
Misattributions-Zitat.

Plus v3-UI:
- News-Box von ganz hinten nach oberhalb "Neu analysieren" verschoben
- News-Liste auf 1 Item gekuerzt + 9-Zeilen-Clamp via -webkit-line-clamp

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:51:03 +02:00
Dotty Dotter
1ef5578e02 feat(v3): v3 wird Default unter /antrag/{drs}, v2 zieht nach /v2/antrag/{drs}
Routen:
- /antrag/{drs}     → v3 (Standard, Bürger:innen-Modus single column)
- /v2/antrag/{drs}  → v2 (alter Profi-Modus, weiterhin erreichbar)
- /v3/antrag/{drs}  → Alias auf v3 (für alte Bookmarks)

UI-Hinweise auf alternative Ansichten ausgeblendet:
- v3-Topbar-Pill "Bürger:innen-Modus · Beta" + "→ Profi-Modus"-Toggle raus
- v2-Topbar-Link "→ Bürger:innen-Modus · v3 Beta" raus

Im Admin-Bereich (/v2/admin/stand) neuer Block "Alternative Ansichten"
mit Beispiel-Drucksache, Live-Link auf v3 (Default) und v2 (Profi).
Nur Admins sehen die Hinweise auf v2.

Trennlinien-Cleanup im Rest-Block:
- Doppellinie unter Abstimmungsergebnis aufgelöst (.v3-rest hatte
  border-top, das v3-section.border-bottom doppelt war).
- Neue Trennlinien via Klasse v3-rest-divider-top vor:
  · Teilen-Block (zwischen Ähnliche und Teilen)
  · Aktions-Links (zwischen Teilen und administrativem Bereich)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:29:06 +02:00
Dotty Dotter
9eaa376fbe feat(v3): Wortwahl entjargonisiert, Layout-Reorganisation, Score mit Farb-Tint
Wortwahl (User-feedback: "vermeide Konfidenz, neutralere Formulierung
als Heuchelei"):
- "Konfidenz" → "Bewertungs-Sicherheit" (Tooltip behält wissenschaftl. Begriff)
- "Heuchelei-Marker"/"Opportunismus-Marker" → einheitlich
  "Wahlprogramm-Konflikt" (Tooltip behält wissenschaftl. Klassifikation)
- "Mehrheit kontra GWÖ-Empfehlung" → "Mehrheit gegen GWÖ-Empfehlung"
- Marker-Legende-Block entfernt (Tooltip pro Marker reicht)

Layout-Reorganisation:
- Stärkster/Schwächster Wert nach oben — zwischen Bewertung und
  User-Aktionen (vorher in "Rest"). Grid 2-spaltig, responsive.
- Konsistenz-Hinweis ("Mehrheit ... GWÖ-Empfehlung") an die Spitze
  des Abstimmungsergebnis-Blocks (vorher in "Rest").
- Marker-Legende komplett raus.

Visuelles:
- Score x/10 mit Farb-Tint hinterlegt: --score-{high,mid,low}-bg/-fg
  aus tokens.css. Farbe folgt der Score-Schwelle (≥7 grün, 4-6 mittel,
  <4 rot).
- Globale `body.v2 p { max-width: 72ch }` mit höherer Spezifität für
  .v3-page-Children überschrieben — alle Body-Texte nehmen volle Breite.

Programm-Treue Fallback:
- Wenn keine Zitate für ein Programm gefunden: erklärender
  Hinweistext im Body-Bereich, statt leerer Block.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:16:39 +02:00
Dotty Dotter
f471586f33 feat(v3): Themen, Kernpunkte, Schwerpunkt, Konfidenz, fehlende Programme, Wahlperiode + Ähnliche Anträge
DB-Felder die bisher in der UI fehlten, jetzt in v3 sichtbar:

- _row_to_detail() liefert themen, kernpunkte, schwerpunkt, link,
  konfidenz, fehlende_programme, wahlperiode an's Frontend.
- _wahlperiode_silent() leitet die WP aus datum+bundesland ab via
  wahlperioden.wahlperiode_for() — silent-fail bei Lookup-Fehler.

v3-Template:
- Wahlperiode in der Antrag-ID-Zeile ("18. Wahlperiode")
- Themen-Chips als Reihe unter byline
- Kernforderungen als Bullet-Liste in der Zusammenfassungs-Sektion
- Konfidenz-Pille (hoch/mittel/niedrig) neben der Empfehlung
- Schwerpunkt-Felder (Top-Matrix-Cells) als Chips über der Matrix
- Disclaimer "fehlende Programme" am Programm-Treue-Block
- Original-PDF-Link im Aktions-Block
- Ähnliche Anträge als eigener Block, geladen via JS aus
  /api/assessment/similar (Re-Use des bestehenden Endpoints aus #108)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:01:18 +02:00
Dotty Dotter
4de2df9cea feat(v3): single-column Restructure — neue Reihenfolge, CD-konforme Radien
User-Spec: 1a (single column überall), CD-Rundungen subtil 2-4 px,
keine 8px-Pills, keine Kreise. v3 wird nach Reife der neue Default.

Reihenfolge:
1. Metadaten/Titel
2. Zusammenfassung
3. Bewertung — Score xl + Empfehlung daneben + verdict_body voll breit
4. Merken + Bewertung treffend
5. Matrix 5×5 (volle Profi-Variante mit Klick-Modal)
6. Programm-Treue — pro Partei: WP-Zeile + PP-Zeile (default closed),
   Klick auf die Zeile expandiert Begründung + Belege. Score-Chip
   rechtsbündig.
7. Verbesserungsvorschläge — volle Breite, kein max-width
8. Abstimmungsergebnis — Plenum + namentliche Abstimmung
9. Rest — PDF/Teilen/Re-analyze/Historie + Stärken/Schwächen +
   Konsistenz-Hinweis + Marker-Legende + News-Box + Kommentare

v2-Templates unangetastet (Sub-Blocks vom letzten Commit beibehalten,
nur main-Block wird in v3 komplett überschrieben). v2-JS-Handler
bleiben funktionsfähig — gleiche DOM-IDs (v2-merkliste-btn, v2-vote-up,
v2-comments-list, v2-matrix-field-modal, …) im neuen Layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:51:33 +02:00
Dotty Dotter
895187ac36 feat(v3): Bürger:innen-Modus visuell ausgebaut — Wort-Etikett, 5-Werte-Bars, Glossar, Collapsibles
v2 unangetastet — v3 überschreibt nur Sub-Blocks. Neue v2-Blocks
für Override-Punkte: antrag_id_section, score_hero_section,
matrix_section, verbesserungen_section, aktions_section,
comments_section.

v3-Anpassungen:
1. Drucksache-ID: "Antrag im Landtag NRW · Drucksache 18/18246" —
   "Drucksache" als Glossar-Hinweis klickbar.
2. Score-Hero: großes Wort-Etikett ("Stark gemeinwohlfördernd" /
   "Gemischt" / "Widerspricht dem Gemeinwohl") aus verdict_title oder
   abgeleitet. Score-Zahl als kleiner Untertitel mit Glossar-Link.
   Akzentfarbe links (grün/blau/rot je nach Score).
3. Matrix: 5 Werte als Diverging-Bars (-5..+5) sofort sichtbar;
   volle 5×5-Matrix in <details>. Aggregation = Spalten-Mittel über
   die 5 Berührungsgruppen.
4. Verbesserungsvorschläge: <details> default zu, Hint-Text mit Anzahl.
5. Aktions-Links: JSON-Export raus — nur PDF + Permalink.
6. Kommentare: <details> default zu (für Erst-Leser:innen unwichtig).

Glossar-System: 6 Begriffe (Drucksache, Fraktion, GWÖ-Score,
GWÖ-Matrix, Heuchelei-Marker, Opportunismus-Marker) mit Klick/Focus-
Tooltip via Modal. Trigger: Element mit class="v3-glossar"
data-glossar="<key>".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:15:50 +02:00
Dotty Dotter
acda3cdb3a fix: Programm-Treue Sub-Labels (Einschätzung, Belege) zurück + Bewertung-Tag
Der vorherige Refactor hatte die expliziten Sub-Headers im Body
abgeworfen. User wollte sie zurück (BELEGE-Layout-Spec):
- Header-Row: Programm-Label links, "Bewertung"-Tag + Score-Chip rechts
- Body: Sub-Label "Einschätzung" über der Begründung,
        Sub-Label "Belege" über den Zitaten

Default bleibt <details open> — alles sofort lesbar, Falt-Toggle
optional. Chevron ▾ am Label rotiert beim Schließen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:11:12 +02:00
Dotty Dotter
bd0fe54559 fix: Programm-Treue im BELEGE-Layout, default-OPEN statt default-closed
User-Feedback: voriges Layout war "Usability-Alptraum" — alle 8 Blöcke
(4 Fraktionen × 2 Programme) waren default-closed, was 8 Klicks pro
Antrag bedeutete um Begründungen zu lesen.

Fix: <details open> als Default. Inhalt sofort vollständig sichtbar
beim Scrollen. Faltmechanismus bleibt für User, die die Liste nur
skimmen wollen — Chevron ▾ am Label rotiert beim Falten. Hover-Affordanz
über Label-Color-Change zum Brand-Blau (kein extra Caret-Element).

Layout-Spec bleibt: pro Partei zwei Treue-Blöcke (Wahlprogramm,
Parteiprogramm). Summary = Label + Score-Chip rechts. Body =
Einschätzung-Text + Belege via quote_card-Macro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 10:03:04 +02:00
Dotty Dotter
c4750d3274 feat(v3): Bürger:innen-Modus-Sandbox unter /v3/antrag/{drs}
Skelett für Issues #184 + #185 — minimal, nicht-disruptiv:

- v3/base.html extendet v2/base.html (Topbar/Sidebar/Footer geteilt)
- v3/screens/antrag_detail.html extendet vorerst v2-Screen 1:1 und
  injiziert nur Beta-Pill + Toggle "→ Profi-Modus"
- v2/screens/antrag_detail.html bekommt Topbar-Link "→ Bürger:innen-
  Modus (v3 Beta)" → /v3/antrag/<drs>
- _render_antrag_detail() teilt DB-Reads/Context zwischen v2 + v3 —
  Datenbasis garantiert in Sync, Unterschied ist nur template_name
- _MATRIX_EXPLANATIONS auf Modul-Ebene ausgelagert (war bisher
  inline im v2-Route, jetzt von beiden Modi referenziert)
- v3.css als Add-On nach v2.css (lädt im v3/base head)

Was v3 noch NICHT tut: Score-Hero-Vereinfachung, Matrix→5-Werte,
Glossar-Tooltips, Default-Collapsing der Profi-Blöcke (Verbesserungen,
Kommentare). Diese Iterationen folgen pro PR — v2 bleibt unberührt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:55:06 +02:00
Dotty Dotter
c4f8ce398a feat: Matrix-Klick mit Antrags-Begründung + Vote-Block-Verbesserungen
Matrix-Info-Modal:
- _row_to_detail liefert label+aspect je Matrix-Cell ans Frontend
- Modal zeigt antragsspezifische Bewertung (Label + ausformulierte
  Begründung + Rating-Chip) UND die allgemeine Felderklärung
  (was misst dieses Feld?). v1-Verhalten wiederhergestellt.

Abstimmungsergebnis (Vote-Block):
- Outlink-Pfeil ↗ ist jetzt ein klickbares <a> auf v.quelle_url
  (target=_blank). Vorher: Span ohne Link, Pfeil tat nichts.
- Marker ⚠ (Heuchelei) und ! (Opportunismus) bekommen sichtbare
  Hover-Affordanz (Hintergrund + dotted-border on focus). Native
  title= bleibt fuer Screenreader-/Tooltip aktiv. tabindex=0+role=button
  macht sie keyboard-erreichbar.
- Legende unter dem Vote-Pill-Block erklaert die Marker beim
  ersten Auftreten in einer Liste — wird nur eingeblendet wenn auf
  dem Block mindestens ein Marker tatsaechlich vorkommt.
- Vote-Pills via Klassen v2-vote-pill/-ja/-nein/-enth statt
  Inline-Styles (CD-Annaeherung).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:33:53 +02:00
Dotty Dotter
70d9790b4b feat(#177): Programm-Treue im BELEGE-Layout — pro Partei zwei aufklappbare Blöcke (WP+PP)
- _row_to_detail liefert zitate inline pro Wahlprogramm/Parteiprogramm-Block
- Template rendert <details>: Summary mit Score-Chip, Body mit Einschätzung+Belege
- v2.css: neue Klassen v2-treue-block/-label/-body, v2-pill, v2-einschaetzung
- Separate "Belege — Partei"-Sektion entfernt (ist jetzt inline pro Programm)

Tests: tests/test_v2_pdf_consistency.py (#176 generalisiert) bleibt grün —
fraktions_scores trägt zusätzliche zitate-Felder, ändert aber keine
Score/Begründungs-Werte aus dem Vergleich.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:21:42 +02:00
Dotty Dotter
d80e6e7aad feat(#177 Phase 21+22): Verdict-Umfluss + Merken bei Bewertung
Phase 21 — Score-Hero auf Float-Layout:
- Score-Zahl floated links, Verdict-Text fließt rechts daneben UND
  unter sie weiter (vorher: flex-baseline, Text bricht nicht um).
- overflow:hidden auf Container fuer clean float-clearing.

Phase 22 — Merken-Button oben rechts auf gleicher Höhe wie 'Bewertung'-Label:
- Visuelle Einheit: 'Bewertung'-Header links, Merken-Button rechts.
- Vorher: Merken-Button stand alleinig zwischen Score und Vote-Block,
  optisch losgeloest.

Refs: #177

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:13:37 +02:00
Dotty Dotter
eb0669d6ac feat(#147): Hover-Tooltips fuer Abkuerzungen auf Antrag-Detail
User-Feedback: '(A)' hinter Partei, 'WP', 'PP' brauchen Erklaerung
fuer Erstleser:innen. Loesung: ausfuehrliche title-Tooltips plus
visuelle Affordanz (cursor:help).

Geaendert:
- v2-badge-antragsteller / -regierung: cursor:help
- v2-score-chip[title]: cursor:help
- (A) → 'A — Antragstellende Fraktion: hat den Antrag eingereicht.'
- (R) → 'R — Regierungsfraktion: traegt die aktuelle Mehrheit im Landtag.'
- WP-Chip: 'WP — Wahlprogramm-Treue (0–10): wie gut passt der Antrag
  zum aktuellen Wahlprogramm? + Begruendung'
- PP-Chip: analog fuer Parteiprogramm-Treue
- Score-Hero: Tooltip mit GWÖ-Score-Definition + Methodik-Verweis
- 'Enth.:' im Abstimmungs-Block: dotted underline + Tooltip 'Enth. —
  Enthaltung: weder Zustimmung noch Ablehnung'

Closes #147
2026-04-28 08:46:27 +02:00
Dotty Dotter
d0d941444d feat(#144): Matrix-Ueberschriften ausschreiben + Hover-Tooltips
Statt Abkuerzungen (Wuerde, Solid., Liefer., Verwalt., Gesell.) jetzt
voll ausgeschrieben: Menschenwuerde, Solidaritaet, Lieferant:innen,
Verwaltung, Gesellschaft & Natur, etc.

Hover-Tooltip pro Spalte/Zeile mit Erklaerung + Staatsprinzip
(Rechtsstaatsprinzip, Gemeinnutz, Umwelt-Verantwortung, ...).
Matrix-Felder bekommen Tooltip mit Feldname als Vorschau, der
volle Erklaerungstext bleibt im Click-Modal (showField).

Layout: rhdr-Spalte 130/150px, line-height 1.25, min-height 36px,
damit lange Begriffe sauber umbrechen koennen.

Closes #144
2026-04-28 01:53:38 +02:00
Dotty Dotter
a8d7b72702 feat(v2): Feedback-Widget mit Audit-Trail + Screenshot + direkter Gitea-Anbindung
- Component v2/components/feedback_widget.html: Button unten links oberhalb der
  Queue, Klick oeffnet Modal mit vorausgefuellten Kontext-Feldern (URL,
  Drucksache, Viewport, User-Agent, letzte 15 Klicks, letzte 10 Console-Errors,
  letzte 5 Page-Loads). Eingaben: Titel, Beschreibung, optional Screenshot
- Audit-Trail-Sammler in localStorage (Ringbuffer 30 Klicks, 10 Errors)
- Screenshot via self-hosted html2canvas 1.4.1 (194 KB unter app/static/v2/lib/)
- Backend POST /api/feedback (rate-limit 5/h):
  - validiert + html-strippt Inputs
  - erstellt Gitea-Issue per API mit Label 'feedback' (Label wird idempotent angelegt)
  - laedt Screenshot als Issue-Asset hoch (Gitea Issue-Attachment-API)
- 4 neue Settings: gitea_token, gitea_api_url, gitea_repo_owner, gitea_repo_name
- Server .env um GITEA_TOKEN ergaenzt
- 10 neue Unit-Tests (mit gemocktem httpx)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 01:00:44 +02:00
Dotty Dotter
fab1bddd3c fix(v2): Hamburger-Toggle wirklich ausblenden (Specificity-Konflikt + Cache)
Bug: .v2-topbar button {display:inline-flex} ueberschreibt .v2-menu-toggle{display:none}
wegen hoeherer Specificity. Fix: Selektor .v2-topbar .v2-menu-toggle + !important.

Plus app_version 1.0.0 -> 1.0.1 als Cache-Buster fuer alle CSS-Refs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:37:55 +02:00
Dotty Dotter
b1ad2bd45d fix(v2): Hamburger-Menü-Toggle nur auf Mobile (< 900 px) sichtbar
Auf Desktop ist die Sidebar permanent — der Burger-Button hatte dort keine
Funktion. display: none default + @media max-width:900px → inline-flex.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:28:51 +02:00
Dotty Dotter
7f070b5e6c fix(v2): Topbar harte Hoehe 32px + Kleine-Anfragen-Heuristik in Landtag-Suche
Topbar:
- height: 32px (statt auto), line-height: 1, alle children max 24px
- Topbar-Icons explizit auf 12x12 (statt 14)
- selects/buttons/a mit fester Hoehe 22px, padding 2px 6px

Landtag-Suche:
- search_landtag filtert jetzt Drucksachen aus, deren Titel typische
  Frage-Praefixe haben (Welche/Wie viele/Wann/Was/Hat/Ist/...)  oder mit '?'
  enden — bei NRW-OPAL liefert der Adapter alle als 'sonstige', daher
  Title-Heuristik. Server-side, damit alle Adapter profitieren.
- Neuer Helper drucksache_typen.likely_kleine_anfrage_titel()

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:23:22 +02:00
Dotty Dotter
88f9c7db6c fix: PDF-Endpoint setzt OpenAction auf gefundene Seite + Topbar weiter komprimiert
Vorher: /api/wahlprogramm-cite lieferte das gesamte PDF mit Highlight-Annot
auf der gefundenen Seite, aber der Browser-PDF-Viewer landete auf Seite 1.
Sieht User: 'PDF oeffnet, aber falsche Seite'.

Jetzt: doc.xref_set_key(catalog, 'OpenAction', '[<page-ref> 0 R /Fit]')
schreibt eine PDF-Open-Action ins Dokument-Catalog. Reader springt beim
Oeffnen direkt auf target_page_idx, ohne dass Browser-Hash-Anker noetig sind.

Plus: Topbar select/button padding-top/bottom 1px, links 0px (User: 'nur so
hoch wie noetig').

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:06:39 +02:00
Dotty Dotter
489a1915f8 fix: PDF-Highlight strippt führende Seitenzahl + Topbar noch kompakter
- render_highlighted_page: führende Seitenzahl-Tokens ('44 Gute Bildung …')
  vor search_for entfernen — LLMs ziehen den Header oft ins Zitat mit, was
  PyMuPDFs Volltext-Match scheitern lässt
- v2-Topbar: padding 4px -> 2px, line-height 1.2, min-height entfernt
  (auto-size, nur so hoch wie noetig)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:04:26 +02:00
Dotty Dotter
50c026e3a0 fix(v2): Topbar-Höhe runter, Share-Felder erweitert (Kopieren/LinkedIn/Email/Bild), Smoke-Test 401-Pattern
- Topbar padding 10px -> 4px, min-height 32px (User: 'Header weniger hoch')
- Share-Buttons im Antragsdetail erweitert auf 7 Plattformen analog v1:
  Kopieren (Clipboard), Threads, X, Mastodon, LinkedIn, E-Mail (mailto), Bild (Freepik)
- v2DetailShareCopy/Email/Image-Helper, ANTRAG_TOPICS ans Template uebergeben
- Smoke-Test akzeptiert 401 fuer auth-protected Routen (curl ohne Accept-Header
  bekommt 401-JSON, echte Browser bekommen 302-Redirect via _auth_redirect_handler)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:57:04 +02:00
Dotty Dotter
565849bd84 feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
  (ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
  Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze

Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
  /api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie

Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
Dotty Dotter
ad1db2a924 feat: 16 BL-Adapter, Drucksache-Typen, Mail-Digest, Clustering, Redline-Parser
- 16 aktive BL-Adapter + BUND (parlamente.py 3397 LOC)
- drucksache_typen.py: BL-spezifische Typ-Normalisierung (#127)
- mail.py: SMTP + Daily-Digest (#124)
- clustering.py: Embedding-Naehe-Graph + Bubble-Chart (#105)
- redline_utils.py: §INS§/§DEL§-Parser + PDF-Cite-URL-Builder
- embeddings v3->v4 Migration (#123, ADR 0006)
- chart.js + d3.v7 als statische Assets fuer Auswertungen-Cluster

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:54:50 +02:00
Dotty Dotter
790fe1a121 CDU Grundsatzprogramm: korruptes 2007er ersetzt durch echtes 2024er (82 Seiten) 2026-04-10 20:25:56 +02:00
Dotty Dotter
660498e8e3 LINKE Bremen (78p via Wayback) + CDU Hessen Langfassung (164p) + AfD SL registriert 2026-04-10 20:22:50 +02:00
Dotty Dotter
78f3e4e9f0 Wahlprogramme HB/HE/SN + AfD SL: 15 neue Programme registriert
Bremen WP 21 (2023): SPD, CDU, GRÜNE — 3 PDFs
  (AfD Bremen + LINKE Bremen nicht als PDF downloadbar)
Hessen WP 21 (2023): CDU, AfD, SPD, GRÜNE, FDP — 5 PDFs
Sachsen WP 8 (2024): CDU, AfD, BSW, SPD, LINKE, GRÜNE — 6 PDFs
Saarland: AfD SL 2022 ("Heimat ist wählbar") — aus real3d-flipbook
  extrahiert (pdfUrl in data-flipbook-options). 102 Seiten.

Total: 84 Programme registriert. Indexierung erfolgt nach Deploy.
2026-04-10 20:14:22 +02:00
Dotty Dotter
11e4da0bf3 Wahlprogramme BY/NI/SL: 11 PDFs registriert + Linke-Grundsatzprogramm
Bayern WP 19 (2023): CSU, GRÜNE, FW, AfD, SPD — 5 PDFs
Niedersachsen WP 19 (2022): SPD, CDU, GRÜNE, AfD — 4 PDFs
Saarland WP 17 (2022): SPD, CDU — 2 PDFs (AfD SL nicht auffindbar)

Plus: DIE LINKE Erfurter Programm 2011 (111 Chunks indexiert)
Plus: AfD Grundsatzprogramm 2016 (128 Chunks, vorheriger Commit)

Alle PDFs verifiziert: korrekte Seitenzahlen, keine HTML-Wrapper,
Parteiname und Wahljahr im Titel korrekt. Quellen: offizielle
Partei-Websites, Wayback Machine, originalsozial.de.

Indexierung erfolgt nach Deploy im Container.
2026-04-10 18:27:38 +02:00
Dotty Dotter
1f53ca5a25 #63: Linke Erfurter Programm 2011 + AfD registriert — alle 6 Grundsatzprogramme komplett 2026-04-10 18:23:20 +02:00
Dotty Dotter
4565a5cf0c #63 teilweise: AfD-Grundsatzprogramm 2016 registriert + PDF (96 Seiten, via Wayback Machine) 2026-04-10 17:30:28 +02:00
Dotty Dotter
a4af79688a Add 30 Wahlprogramme für TH/BB/HH/SH/BW/RP (#37, #39, #40, #32, #41, #42)
Sechs der zehn aktiven Bundesländer hatten bisher keine Wahlprogramme
indexiert (alle sechs heute neu aktiviert: BW/HH/TH in Phase 1, SH/BB/RP
in Phase 2). Antrag-Analysen für diese BL fielen damit auf föderale
Grundsatzprogramme als Fallback zurück.

Beschafft via abgeordnetenwatch.de für die jeweils laufende WP:

- TH WP8 (LTW 01.09.2024): CDU, AfD, LINKE, BSW, SPD — 5 PDFs
- BB WP8 (LTW 22.09.2024): SPD, AfD, CDU, BSW — 4 PDFs
- HH WP23 (Bürgerschaftswahl 02.03.2025): SPD, CDU, GRÜNE, LINKE, AfD — 5 PDFs
- SH WP20 (LTW 08.05.2022): CDU, SPD, GRÜNE, FDP, SSW — 5 PDFs
- BW WP17 (LTW 14.03.2021): GRÜNE, CDU, AfD, SPD, FDP — 5 PDFs
- RP WP18 (LTW 14.03.2021): SPD, CDU, AfD, GRÜNE, FREIE WÄHLER, FDP — 6 PDFs

Insgesamt 30 PDFs in app/static/referenzen/, plus 30 Einträge in
WAHLPROGRAMME[bl][partei] und embeddings.PROGRAMME.

Naming-Schema wie etabliert: <partei>-<bl>-<jahr>.pdf, also
spd-th-2024.pdf, fw-rp-2021.pdf etc.

Wichtig zu Memory feedback_legislaturprogramme: alle BL nutzen das
Programm der LAUFENDEN Wahlperiode, NICHT Programme aus späteren
Wahlen. BW und RP wählen am 08.03.2026 / 22.03.2026 neu — der
18./19. Landtag konstituiert sich erst, daher sind die 17./18. WP
mit den 2021er Programmen weiterhin laufend bis zur Konstituierung.

Indexierung im prod-Container ist NICHT Teil dieses Commits — muss
separat ausgeführt werden:

  ssh vserver 'docker exec gwoe-antragspruefer python -c "
  from app.embeddings import index_programm
  from pathlib import Path
  d = Path(\"/app/app/static/referenzen\")
  for pid in [
      \"cdu-th-2024\",\"afd-th-2024\",\"linke-th-2024\",\"bsw-th-2024\",\"spd-th-2024\",
      \"spd-bb-2024\",\"afd-bb-2024\",\"cdu-bb-2024\",\"bsw-bb-2024\",
      \"spd-hh-2025\",\"cdu-hh-2025\",\"gruene-hh-2025\",\"linke-hh-2025\",\"afd-hh-2025\",
      \"cdu-sh-2022\",\"spd-sh-2022\",\"gruene-sh-2022\",\"fdp-sh-2022\",\"ssw-sh-2022\",
      \"gruene-bw-2021\",\"cdu-bw-2021\",\"afd-bw-2021\",\"spd-bw-2021\",\"fdp-bw-2021\",
      \"spd-rp-2021\",\"cdu-rp-2021\",\"afd-rp-2021\",\"gruene-rp-2021\",\"fw-rp-2021\",\"fdp-rp-2021\",
  ]:
      index_programm(pid, d)
  "'

77 pytest tests passing — der File-Existenz-Check in test_wahlprogramme.py
hätte einen Tippfehler im PDF-Namen sofort gefangen.

Erledigt UI-Aktivierungs-Issues #37 (TH), #39 (BB), #40 (HH), #32 (SH),
#41 (BW), #42 (RP).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 08:03:11 +02:00
Dotty Dotter
8992cffc64 Add MV+BE Wahlprogramme zur jeweils laufenden Legislatur (#4, #10)
11 PDFs in app/static/referenzen/ + Einträge in WAHLPROGRAMME
und embeddings.PROGRAMME für die beiden bisher nur per
föderalem Grundsatzprogramm-Fallback abgedeckten Landtage:

- **MV** (WP 8, seit 26.10.2021): CDU, SPD, GRÜNE, FDP, AfD, LINKE
  Wahlprogramme zur LTW 26.09.2021. Issue #4.

- **BE** (WP 19, konstituiert nach Wiederholungswahl 12.02.2023):
  CDU, SPD, GRÜNE, LINKE, AfD Programme zur AGH-Wahl 26.09.2021.
  Die Wiederholungswahl 2023 nutzte dieselben Programme wie die
  Originalwahl, daher die "be-2023.pdf"-Benennung mit Programm-
  jahr 2021. Issue #10.

Quellen: abgeordnetenwatch.de Mirror für 9 PDFs, library.fes.de
für SPD MV, cdu-mv.de direkt für CDU MV, fdp-mv.de direkt für
FDP MV. Alle PDFs verifiziert via pdftotext gegen das im Programm
genannte Wahldatum, um zu vermeiden, dass aktuellere
Wahlkampf-Entwürfe (z.B. das CDU "Berlin-Plan 2026") als
Legislatur-Programm fehlinterpretiert werden.

Indexierung in die embeddings-DB ist NICHT Teil dieses Commits —
sie muss separat im prod-Container ausgeführt werden:

  docker exec gwoe-antragspruefer python -c "
  from app.embeddings import index_programm
  from pathlib import Path
  d = Path('/app/static/referenzen')
  for pid in ['cdu-mv-2021','spd-mv-2021','gruene-mv-2021',
              'fdp-mv-2021','afd-mv-2021','linke-mv-2021',
              'cdu-be-2023','spd-be-2023','gruene-be-2023',
              'linke-be-2023','afd-be-2023']:
      index_programm(pid, d)
  "

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 08:24:33 +02:00
Dotty Dotter
87874a7a14 Activate LSA: Wahlprogramme + ingest + frontend (#2)
Brings Sachsen-Anhalt online as the second supported Bundesland after
NRW. Closes the gap that issue #2 left open: with the PortalaAdapter
already in place from c7242f8, this commit adds the reference data and
flips the activation switch.

Wahlprogramme (LTW Sachsen-Anhalt 06.06.2021)
- Six PDFs added under app/static/referenzen/{cdu,spd,gruene,fdp,afd,
  linke}-lsa-2021.pdf, plus paged plain-text extractions under
  app/kontext/*.txt for the keyword fallback search.
- Sources verified by hand:
  - CDU "Unsere Heimat. Unsere Verantwortung." (cdulsa.de, 82 pages)
  - SPD "Zusammenhalt und neue Chancen" (FES library, 77 pages)
  - GRÜNE "Verlässlich für Sachsen-Anhalt" (gruene-lsa.de, 164 pages)
  - FDP "Wahlprogramm zur Landtagswahl 2021" (Naumann-Stiftung, 76 pages)
  - AfD "Alles für unsere Heimat!" (klimawahlen.de mirror, 64 pages)
  - LINKE "Wahlprogramm zur Landtagswahl 2021" (dielinke-sachsen-anhalt.de,
    88 pages)
- The CDU PDF was the trickiest: KAS blocks bot downloads via
  Cloudflare; the cdulsa.de copy was located by an autonomous web
  search and verified to be byte-identical with the official document.

Embeddings indexed (in production container, OpenAI-compatible
DashScope embeddings via the existing index_programm pipeline):
- CDU 134, SPD 145, GRÜNE 183, FDP 100, AfD 64, LINKE 143 chunks
- Total LSA: 769 new chunks alongside the existing 775 NRW chunks
  and 335 federal Grundsatzprogramm chunks.

wahlprogramme.py
- WAHLPROGRAMME["LSA"] populated with all six parties (canonical fraction
  codes, original titles, page counts).

embeddings.py
- PROGRAMME extended with the six new "<partei>-lsa-2021" entries that
  the indexer pipeline expects.

bundeslaender.py
- LSA flipped to aktiv=True. The frontend dropdown will now offer
  Sachsen-Anhalt as a selectable bundesland and analyzer.get_bundesland_
  context() will produce a real LSA prompt block (CDU/SPD/FDP as
  governing fractions, all six landtagsfraktionen).

End-to-end smoke test (live in production container before commit)
- Adapter: PortalaAdapter.search() returned current Anträge of März 2026
  (LINKE + GRÜNE) with correct titles and PDF URLs.
- Semantic search for an LSA "ÖPNV in der Altmark" sample antrag
  matched LINKE S.53, SPD S.68, FDP S.52 — all three with similarity
  > 0.6 and topical hits (Regionalisierungsmittel, ÖPNV-Förderprogramm,
  Wasserstoffnetz).

Resolves issue #2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:12:32 +02:00
Dotty Dotter
63de3ca20d Initial commit: GWÖ-Antragsprüfer v1.0
Features:
- GWÖ-Matrix 2.0 Analyse für NRW-Landtagsanträge
- Verbesserungsvorschläge im Redline-Format (Original/Vorschlag/Begründung)
- Wahlprogramm- und Parteiprogrammtreue-Bewertung
- Landtag-Suche via OPAL-API
- Tag-Wolke mit Multi-Select Filter
- Partei-Filter mit Durchschnittswerten
- PDF-Report-Generierung
- Security Headers (CSP, X-Frame-Options, etc.)
- Persistente SQLite-DB via Docker Volumes

Tech Stack:
- FastAPI + Jinja2
- Qwen LLM via DashScope API
- SQLite + aiosqlite
- WeasyPrint für PDF
- Docker Compose mit Traefik
2026-03-28 22:30:24 +01:00