gwoe-antragspruefer/app/bundeslaender.py

466 lines
19 KiB
Python
Raw Normal View History

"""Zentrale Konfiguration aller 16 deutschen Bundesländer.
Dieses Modul ist die Single Source of Truth für alle bundeslandspezifischen
Daten: Parlamente, Regierungen, Wahlperioden, Doku-Systeme, etc. Andere
Module (main.py, parlamente.py, wahlprogramme.py, analyzer.py) lesen
ausschließlich von hier.
Stand: April 2026. Nach jeder Landtagswahl bzw. Regierungsbildung müssen
die betroffenen Einträge aktualisiert werden.
Datenquellen: Wikipedia, offizielle Landtagsseiten, parlamentsspiegel.de,
https://github.com/okfde/dokukratie (für Doku-System-Zuordnung).
"""
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class Bundesland:
"""Konfiguration eines deutschen Bundeslands.
Attributes:
code: Übliches Kürzel im politischen Sprachgebrauch (NRW, BY, LSA).
Bei Mehrdeutigkeit ISO-3166-2-DE-Suffix; Sachsen-Anhalt nutzt
jedoch das politisch dominante "LSA" statt ISO "ST".
name: Vollständiger Landesname.
parlament_name: Offizieller Name des Parlaments.
wahlperiode: Aktuelle Wahlperiode als Zahl.
wahlperiode_start: Beginn der aktuellen WP (ISO-Datum).
naechste_wahl: Nächste reguläre Landtagswahl (ISO-Datum), oder None
wenn noch nicht festgesetzt.
regierungsfraktionen: Parteien der aktuellen Landesregierung in
Reihenfolge der Größe.
landtagsfraktionen: Alle aktuell im Landtag vertretenen Fraktionen.
doku_system: Verwendetes Parlamentsdokumentationssystem.
Werte: "OPAL", "StarWeb", "ParlDok", "PARDOK", "PARLIS",
"PARiS", "Eigensystem".
doku_base_url: Basis-URL der Parlamentsdokumentation.
drucksache_format: Beispielhaftes Format einer Drucksachen-ID,
z.B. "18/12345" für NRW WP18.
dokukratie_scraper: Code-Name des Dokukratie-Scrapers (falls
vorhanden), nützlich für künftige Adapter-Implementierung.
aktiv: Ob das Bundesland im Frontend auswählbar und im Analyzer
unterstützt ist. Inaktive Bundesländer werden im UI als
"(bald)" angezeigt und sind disabled.
anmerkung: Optionale Hinweise zu Sondersituationen (z.B.
Koalitionsverhandlungen, jüngste Wahl, geschätzte Termine).
"""
code: str
name: str
parlament_name: str
wahlperiode: int
wahlperiode_start: str
naechste_wahl: Optional[str]
regierungsfraktionen: list[str]
landtagsfraktionen: list[str]
doku_system: str
doku_base_url: str
drucksache_format: str
dokukratie_scraper: Optional[str]
aktiv: bool = False
anmerkung: str = ""
# Hauptregister: code -> Bundesland-Instanz.
# Reihenfolge alphabetisch nach offiziellem Namen für stabile UI-Sortierung.
Phase G: BundestagAdapter via DIP-API (#56) Schließt #56 (Bundespolitik überprüfbar machen). Neuer ``BundestagAdapter`` in ``app/parlamente.py``, neuer ``BUND``-Eintrag in ``app/bundeslaender.py`` als 17. Parlament-Slot. API: - DIP-Search-API auf ``search.dip.bundestag.de/api/v1/drucksache`` - API-Key aus ``dip-config.js`` gescraped (öffentlich, klartext) - Auth via URL-Param ``?apikey=...`` plus ``Origin: https://dip.bundestag.de``- Header (Origin-Locking, server-to-server-tauglich) - Pagination via ``cursor``-Parameter, 100 Hits pro Page - ``f.drucksachetyp=Antrag`` und ``f.wahlperiode=21`` als Server-Filter Mapping: - ``dokumentnummer`` → ``Drucksache.drucksache`` - ``titel`` → ``title`` - ``urheber[*].titel`` → durch ``parteien.extract_fraktionen`` zu ``["AfD"]``/``["GRÜNE"]``/etc. — die ``"Fraktion der AfD"``- Schreibweise wird vom zentralen Mapper aus #55 bereits korrekt geparst, kein Adapter-spezifisches Pattern nötig - ``fundstelle.pdf_url`` → ``link`` - ``datum`` → bereits ISO ``YYYY-MM-DD`` ``get_document(drucksache)`` nutzt ``f.dokumentnummer`` als direkter Server-Filter, kein linearer Pagination-Scan. BUND-Eintrag in ``bundeslaender.py``: - ``code="BUND"``, ``parlament_name="Deutscher Bundestag"``, ``wahlperiode=21``, ``wahlperiode_start="2025-03-25"`` (Konstituierung 21. WP nach BTW 2025), ``regierungsfraktionen=["CDU", "CSU", "SPD"]`` (Kabinett Merz) - ``aktiv=True`` — taucht automatisch in ``alle_bundeslaender()`` und ``aktive_bundeslaender()`` auf, damit die UI- und Auswertungs-Pipelines BUND ohne zusätzliche Sonderpfade kennen - 17 Einträge in ``BUNDESLAENDER`` statt 16 — Tests entsprechend aktualisiert (``test_sixteen_bundeslaender_plus_bund``, ``test_alle_bundeslaender_returns_all``, ``test_all_wahlperioden_lists_each_bl_twice``) Live-Probe direkt im Repo: ``` adapter: Deutscher Bundestag (DIP), wahlperiode=21 search returned 5 docs 21/5136 2026-03-31 | ['AfD'] | Transparenz, Wirtschaftlichkeit ... 21/5064 2026-03-27 | ['GRÜNE'] | Ausverkauf der Energieinfrastruktur ... 21/5059 2026-03-27 | ['AfD'] | Berufsfreiheit für Selbstständige ... get_document('21/5136') -> drucksache=21/5136 ``` 176 Unit-Tests grün, Live-Verifikation Sub-A im Container nach Deploy. Refs: #56, #59 (Phase G) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:04:11 +02:00
# Sonder-Eintrag "BUND" für den Deutschen Bundestag (technisch kein BL,
# aber teilt die gesamte Adapter/Analyzer-Pipeline mit den 16 BL).
BUNDESLAENDER: dict[str, Bundesland] = {
Phase G: BundestagAdapter via DIP-API (#56) Schließt #56 (Bundespolitik überprüfbar machen). Neuer ``BundestagAdapter`` in ``app/parlamente.py``, neuer ``BUND``-Eintrag in ``app/bundeslaender.py`` als 17. Parlament-Slot. API: - DIP-Search-API auf ``search.dip.bundestag.de/api/v1/drucksache`` - API-Key aus ``dip-config.js`` gescraped (öffentlich, klartext) - Auth via URL-Param ``?apikey=...`` plus ``Origin: https://dip.bundestag.de``- Header (Origin-Locking, server-to-server-tauglich) - Pagination via ``cursor``-Parameter, 100 Hits pro Page - ``f.drucksachetyp=Antrag`` und ``f.wahlperiode=21`` als Server-Filter Mapping: - ``dokumentnummer`` → ``Drucksache.drucksache`` - ``titel`` → ``title`` - ``urheber[*].titel`` → durch ``parteien.extract_fraktionen`` zu ``["AfD"]``/``["GRÜNE"]``/etc. — die ``"Fraktion der AfD"``- Schreibweise wird vom zentralen Mapper aus #55 bereits korrekt geparst, kein Adapter-spezifisches Pattern nötig - ``fundstelle.pdf_url`` → ``link`` - ``datum`` → bereits ISO ``YYYY-MM-DD`` ``get_document(drucksache)`` nutzt ``f.dokumentnummer`` als direkter Server-Filter, kein linearer Pagination-Scan. BUND-Eintrag in ``bundeslaender.py``: - ``code="BUND"``, ``parlament_name="Deutscher Bundestag"``, ``wahlperiode=21``, ``wahlperiode_start="2025-03-25"`` (Konstituierung 21. WP nach BTW 2025), ``regierungsfraktionen=["CDU", "CSU", "SPD"]`` (Kabinett Merz) - ``aktiv=True`` — taucht automatisch in ``alle_bundeslaender()`` und ``aktive_bundeslaender()`` auf, damit die UI- und Auswertungs-Pipelines BUND ohne zusätzliche Sonderpfade kennen - 17 Einträge in ``BUNDESLAENDER`` statt 16 — Tests entsprechend aktualisiert (``test_sixteen_bundeslaender_plus_bund``, ``test_alle_bundeslaender_returns_all``, ``test_all_wahlperioden_lists_each_bl_twice``) Live-Probe direkt im Repo: ``` adapter: Deutscher Bundestag (DIP), wahlperiode=21 search returned 5 docs 21/5136 2026-03-31 | ['AfD'] | Transparenz, Wirtschaftlichkeit ... 21/5064 2026-03-27 | ['GRÜNE'] | Ausverkauf der Energieinfrastruktur ... 21/5059 2026-03-27 | ['AfD'] | Berufsfreiheit für Selbstständige ... get_document('21/5136') -> drucksache=21/5136 ``` 176 Unit-Tests grün, Live-Verifikation Sub-A im Container nach Deploy. Refs: #56, #59 (Phase G) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:04:11 +02:00
"BUND": Bundesland(
code="BUND",
name="Deutscher Bundestag",
parlament_name="Deutscher Bundestag",
wahlperiode=21,
wahlperiode_start="2025-03-25", # Konstituierung 21. WP nach BTW 2025
naechste_wahl="2029-09-30", # geschätzt
regierungsfraktionen=["CDU", "CSU", "SPD"], # Kabinett Merz, schwarz-rot
landtagsfraktionen=["CDU", "CSU", "AfD", "SPD", "GRÜNE", "LINKE", "BSW", "FDP"],
doku_system="DIP",
doku_base_url="https://search.dip.bundestag.de",
drucksache_format="21/12345",
dokukratie_scraper=None,
aktiv=True,
anmerkung=(
"DIP-API auf search.dip.bundestag.de mit öffentlichem "
"API-Key aus dip-config.js und Origin-Header-Locking auf "
"https://dip.bundestag.de. ~600 Anträge pro Wahlperiode. "
"Kabinett Merz seit Mai 2025 (CDU/CSU+SPD nach BSW-Aus). "
"BundestagAdapter implementiert in #56."
),
),
"BW": Bundesland(
code="BW",
name="Baden-Württemberg",
parlament_name="Landtag von Baden-Württemberg",
wahlperiode=17,
wahlperiode_start="2021-05-01",
naechste_wahl="2031-03-08",
regierungsfraktionen=["GRÜNE", "CDU"],
landtagsfraktionen=["GRÜNE", "CDU", "AfD", "SPD", "FDP"],
doku_system="PARLIS",
doku_base_url="https://parlis.landtag-bw.de",
drucksache_format="17/12345",
dokukratie_scraper="bw",
Activate Baden-Württemberg via PARLISAdapter (#29, Phase 1) PARLIS auf parlis.landtag-bw.de läuft technisch auf demselben eUI-Backend wie LSA-PADOKA und BE-PARDOK, hat aber drei wichtige Unterschiede, die eine eigene Klasse statt einer PortalaAdapter- Subklasse rechtfertigen: 1. Body-Schema: minimales lines mit l1/l2/l3/l4 (statt LSA/BE 2/3/4/10/11/20.x/90.x), serverrecordname=vorgang, format=suchergebnis-vorgang-full, sort=SORT01/D SORT02/D SORT03, keine parsed/json-Felder. Quelle: dokukratie/scrapers/portala.query.bw.json plus HAR-Verifikation gegen die Live-Instanz. 2. Async polling: die initiale SearchAndDisplay-Antwort liefert nur search_id mit status=running, KEINE report_id. Erst eine zweite SearchAndDisplay-Anfrage mit id=<search_id> (ohne search-Component) bekommt nach 1-3 Sekunden die report_id zurück. Reverse-engineered aus esearch-ui.main.js requestReportOK() Z. ~1268. 3. Hit-Format: report.tt.html liefert Records als JSON-in-HTML-Comments <!--{"WMV33":[...],"EWBV22":[...],...}-->. Komplett anderes Format als LSA Perl-Dump oder BE HTML-Cards. Felder: - EWBV22: "Drucksache 17/10323" - EWBD05: direkter PDF-URL - WMV33: Schlagworte (joined by ;) - WMV30: Urheber-Kurzform - EWBV23: "Antrag <Urheber> <DD.MM.YYYY>" Smoke-Test (lokal): BW q='': 8 hits in 17s, jüngste WP17-Anträge mit Datum + Fraktion BW q='Schule': 8 hits, alle wirklich Schul-bezogen (Hochschule, Grundschule, Schwimmunterricht, Lehrerbedarf etc.) BW q='Klima': 8 hits, Klimaschutz/CO2/Energieberatung get_document(17/10323): roundtrip funktioniert bundeslaender.py: aktiv=True für BW; Anmerkung erweitert mit PARLISAdapter-Verweis und drei-Unterschiede-Hinweis für künftige Wartung. Test test_four_active_bundeslaender umbenannt zu test_active_bundeslaender_include_phase_1_set, prüft jetzt nur Subset-Bedingung statt exakter Count, damit Phase-1/2-Erweiterungen keine Test-Updates brauchen. Phase 1 (1/3) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:38:04 +02:00
aktiv=True,
anmerkung=(
Activate Baden-Württemberg via PARLISAdapter (#29, Phase 1) PARLIS auf parlis.landtag-bw.de läuft technisch auf demselben eUI-Backend wie LSA-PADOKA und BE-PARDOK, hat aber drei wichtige Unterschiede, die eine eigene Klasse statt einer PortalaAdapter- Subklasse rechtfertigen: 1. Body-Schema: minimales lines mit l1/l2/l3/l4 (statt LSA/BE 2/3/4/10/11/20.x/90.x), serverrecordname=vorgang, format=suchergebnis-vorgang-full, sort=SORT01/D SORT02/D SORT03, keine parsed/json-Felder. Quelle: dokukratie/scrapers/portala.query.bw.json plus HAR-Verifikation gegen die Live-Instanz. 2. Async polling: die initiale SearchAndDisplay-Antwort liefert nur search_id mit status=running, KEINE report_id. Erst eine zweite SearchAndDisplay-Anfrage mit id=<search_id> (ohne search-Component) bekommt nach 1-3 Sekunden die report_id zurück. Reverse-engineered aus esearch-ui.main.js requestReportOK() Z. ~1268. 3. Hit-Format: report.tt.html liefert Records als JSON-in-HTML-Comments <!--{"WMV33":[...],"EWBV22":[...],...}-->. Komplett anderes Format als LSA Perl-Dump oder BE HTML-Cards. Felder: - EWBV22: "Drucksache 17/10323" - EWBD05: direkter PDF-URL - WMV33: Schlagworte (joined by ;) - WMV30: Urheber-Kurzform - EWBV23: "Antrag <Urheber> <DD.MM.YYYY>" Smoke-Test (lokal): BW q='': 8 hits in 17s, jüngste WP17-Anträge mit Datum + Fraktion BW q='Schule': 8 hits, alle wirklich Schul-bezogen (Hochschule, Grundschule, Schwimmunterricht, Lehrerbedarf etc.) BW q='Klima': 8 hits, Klimaschutz/CO2/Energieberatung get_document(17/10323): roundtrip funktioniert bundeslaender.py: aktiv=True für BW; Anmerkung erweitert mit PARLISAdapter-Verweis und drei-Unterschiede-Hinweis für künftige Wartung. Test test_four_active_bundeslaender umbenannt zu test_active_bundeslaender_include_phase_1_set, prüft jetzt nur Subset-Bedingung statt exakter Count, damit Phase-1/2-Erweiterungen keine Test-Updates brauchen. Phase 1 (1/3) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:38:04 +02:00
"PARLIS auf parlis.landtag-bw.de läuft auf demselben "
"eUI-Backend wie LSA-PADOKA und BE-PARDOK, aber mit drei "
"Unterschieden: minimales lines-Schema (l1/l2/l3/l4), "
"asynchrones Polling (initial → search_id → poll → "
"report_id) und Hit-Records als JSON-in-HTML-Comments. "
"Eigene Adapter-Klasse PARLISAdapter (#29). Wahl zum 18. "
"Landtag fand am 08.03.2026 statt; Koalitionsverhandlungen "
"GRÜNE+CDU laufen, Kabinett Kretschmann III geschäftsführend. "
"Nach Konstituierung des 18. LT ca. Mai 2026 müssen WP und "
"Wahltermin aktualisiert werden."
),
),
"BY": Bundesland(
code="BY",
name="Bayern",
parlament_name="Bayerischer Landtag",
wahlperiode=19,
wahlperiode_start="2023-10-30",
naechste_wahl="2028-10-08",
regierungsfraktionen=["CSU", "FW"],
landtagsfraktionen=["CSU", "GRÜNE", "FW", "AfD", "SPD"],
doku_system="Eigensystem",
doku_base_url="https://www.bayern.landtag.de",
drucksache_format="19/1234",
dokukratie_scraper="by",
anmerkung="Wahltermin 2028 noch nicht offiziell festgesetzt; Schätzung Herbst 2028.",
),
"BE": Bundesland(
code="BE",
name="Berlin",
parlament_name="Abgeordnetenhaus von Berlin",
wahlperiode=19,
wahlperiode_start="2023-04-27",
naechste_wahl="2026-09-20",
regierungsfraktionen=["CDU", "SPD"],
landtagsfraktionen=["CDU", "SPD", "GRÜNE", "LINKE", "AfD"],
doku_system="PARDOK",
doku_base_url="https://pardok.parlament-berlin.de",
drucksache_format="19/1234",
dokukratie_scraper="be",
Activate Berlin (PARDOK) — search-only MVP (#3) PortalaAdapter is now parameterizable and serves both LSA and Berlin from a single class. Berlin is activated as the third live bundesland (after NRW + LSA), with the deliberate caveat that the LTW 2023 Wahlprogramme are not yet indexed. PortalaAdapter refactor - Class attributes (bundesland, name, base_url, db_id, wahlperiode) moved into the constructor. New optional parameters: - portala_path: "/portal" for LSA, "/portala" for Berlin - document_type: "Antrag" for LSA, None for Berlin (BE's ETYPF index uses different value strings; the document_type subtree is dropped from the action.search.json tree) - pdf_url_prefix: "/files/" by default; absolute URLs in the hit list are passed through unchanged (Berlin embeds full starweb/adis/citat/... links) - date_window_days: 730 for LSA, 180 for BE (BE has ~10x more documents per WP, narrower window keeps payloads bounded) - _build_search_body builds the JSON tree dynamically: when document_type is None, the entire ETYPF/DTYPF/DART subtree is omitted, mirrored in the parsed/sref display strings as well. - _parse_hit_list_html now auto-detects between two formats: 1. LSA-style: <pre>$VAR1 = …</pre> Perl Data::Dumper records (existing parser, untouched). 2. Berlin-style: production HTML cards with efxRecordRepeater divs, h3 titles, h6 metadata lines containing the document type, drucksachen-id and date, plus a direct <a href="…pdf"> to the PDF on the same host. - Berlin extracts originator parties from the h6 line ("Antrag CDU, SPD" → ["CDU","SPD"], typ "Antrag") via the new word-boundary _normalize_fraktion regex. - _normalize_fraktion rewritten with regex word boundaries, fixing a long-standing bug where comma-separated fraction lists like "CDU, SPD" failed to match CDU. Also picks up BSW for the Brombeer/SPD-BSW landtage and "Senat von Berlin" as Landesregierung. bundeslaender.py - BE flipped to aktiv=True. anmerkung documents the Wahlprogramm- Lücke and the auto-detected hit-list format. Live verified against pardok.parlament-berlin.de: - WP 19 with 180-day date window returns 2962 hits, page 1 contains 5 records all with title, drucksache, date, PDF URL. - 19/3107 ("Kleingewässerprogramm") correctly extracted as Antrag of CDU+SPD; 19/3104-3106 as Vorlagen zur Beschlussfassung; 19/3108 as Vorlage zur Kenntnisnahme. - LSA still returns the same 5 current Anträge of März 2026 — no regression from the refactor. Known limitation (will be tracked as a follow-up issue) - Berlin Wahlprogramme zur LTW 2023 are not yet indexed in the embeddings DB. The 2023 PDFs are no longer linked from the live party websites (which currently feature 2026 draft programmes), and Wayback has no snapshots. The analyzer therefore falls back to bundesländer-übergreifende Grundsatzprogramme for BE Anträge until the 2023 PDFs are sourced manually. Refs #3. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 23:33:16 +02:00
aktiv=True,
anmerkung=(
Activate Berlin (PARDOK) — search-only MVP (#3) PortalaAdapter is now parameterizable and serves both LSA and Berlin from a single class. Berlin is activated as the third live bundesland (after NRW + LSA), with the deliberate caveat that the LTW 2023 Wahlprogramme are not yet indexed. PortalaAdapter refactor - Class attributes (bundesland, name, base_url, db_id, wahlperiode) moved into the constructor. New optional parameters: - portala_path: "/portal" for LSA, "/portala" for Berlin - document_type: "Antrag" for LSA, None for Berlin (BE's ETYPF index uses different value strings; the document_type subtree is dropped from the action.search.json tree) - pdf_url_prefix: "/files/" by default; absolute URLs in the hit list are passed through unchanged (Berlin embeds full starweb/adis/citat/... links) - date_window_days: 730 for LSA, 180 for BE (BE has ~10x more documents per WP, narrower window keeps payloads bounded) - _build_search_body builds the JSON tree dynamically: when document_type is None, the entire ETYPF/DTYPF/DART subtree is omitted, mirrored in the parsed/sref display strings as well. - _parse_hit_list_html now auto-detects between two formats: 1. LSA-style: <pre>$VAR1 = …</pre> Perl Data::Dumper records (existing parser, untouched). 2. Berlin-style: production HTML cards with efxRecordRepeater divs, h3 titles, h6 metadata lines containing the document type, drucksachen-id and date, plus a direct <a href="…pdf"> to the PDF on the same host. - Berlin extracts originator parties from the h6 line ("Antrag CDU, SPD" → ["CDU","SPD"], typ "Antrag") via the new word-boundary _normalize_fraktion regex. - _normalize_fraktion rewritten with regex word boundaries, fixing a long-standing bug where comma-separated fraction lists like "CDU, SPD" failed to match CDU. Also picks up BSW for the Brombeer/SPD-BSW landtage and "Senat von Berlin" as Landesregierung. bundeslaender.py - BE flipped to aktiv=True. anmerkung documents the Wahlprogramm- Lücke and the auto-detected hit-list format. Live verified against pardok.parlament-berlin.de: - WP 19 with 180-day date window returns 2962 hits, page 1 contains 5 records all with title, drucksache, date, PDF URL. - 19/3107 ("Kleingewässerprogramm") correctly extracted as Antrag of CDU+SPD; 19/3104-3106 as Vorlagen zur Beschlussfassung; 19/3108 as Vorlage zur Kenntnisnahme. - LSA still returns the same 5 current Anträge of März 2026 — no regression from the refactor. Known limitation (will be tracked as a follow-up issue) - Berlin Wahlprogramme zur LTW 2023 are not yet indexed in the embeddings DB. The 2023 PDFs are no longer linked from the live party websites (which currently feature 2026 draft programmes), and Wayback has no snapshots. The analyzer therefore falls back to bundesländer-übergreifende Grundsatzprogramme for BE Anträge until the 2023 PDFs are sourced manually. Refs #3. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 23:33:16 +02:00
"PARDOK = portala/eUI-Framework (gleiche Engine wie LSA-PADOKA, "
"unter /portala/ statt /portal/). Hit list arrives as production "
"HTML cards instead of LSA-style Perl Data::Dumper blocks — "
"PortalaAdapter auto-detects both formats. document_type=None "
"for BE because Berlin's ETYPF index uses different value strings "
"than LSA. Wahlprogramme zur LTW 2023 sind noch nicht indexiert "
"(Folge-Issue) — Analyse läuft daher mit Grundsatzprogramm-"
"Zitaten als Fallback. Open-Data-XML unter "
"parlament-berlin.de/dokumente/open-data ist eine alternative "
"Datenquelle, derzeit nicht verwendet."
),
),
"BB": Bundesland(
code="BB",
name="Brandenburg",
parlament_name="Landtag Brandenburg",
wahlperiode=8,
# Wahltag (statt Konstituierende Sitzung am 2024-10-23), damit
# die Geschäftsordnungs-Drucksachen der konstituierenden Sitzung
# in den Plausibilitäts-Check fallen (siehe #61 Bug 4).
wahlperiode_start="2024-09-22",
naechste_wahl="2029-09-23",
regierungsfraktionen=["SPD", "BSW"],
landtagsfraktionen=["SPD", "AfD", "CDU", "BSW"],
Activate Brandenburg + Rheinland-Pfalz via PortalaAdapter reuse (#27, #30, Phase 2) Riesige Überraschung aus dem BB-HAR-Trace: Brandenburg ist NICHT StarWeb wie in dokukratie und bundeslaender.py klassifiziert, sondern läuft auch auf dem portala/eUI-Backend. Endpoint /portal/browse.tt.json mit db_id=lbb.lissh. Das alte /starweb/LBB/ELVIS/-Frontend ist nur Legacy. Folgeprobing offenbarte: RP/opal.rlp.de läuft ebenfalls portala (db_id=rlp.lissh, 46759 hits in WP18), ebenso NI/HE/BB. Damit ist Phase 2 großteils KEIN StarWeb-Adapter-Bau, sondern PortalaAdapter- Wiederverwendung mit konfigurierbaren Parametern. Activated via Registry-Einträge: - "BB" → PortalaAdapter(base_url=parlamentsdokumentation.brandenburg.de, db_id=lbb.lissh, wahlperiode=8). Nutzt die BE-Card-Variante des Hit-Parsers (efxRecordRepeater). - "RP" → PortalaAdapter(base_url=opal.rlp.de, db_id=rlp.lissh, wahlperiode=18). NICHT mit dem NRW OPAL verwechseln — anderer Markenname, andere Engine. PortalaAdapter erweitert um zwei neue Konstruktor-Parameter mit backward-kompatiblen Defaults: - typ_filter: Optional[str] = "DOKDBE" Wenn None, wird die TYP=<value>-Klausel weggelassen. Manche Instanzen (HE/hlt.lis) lehnen DOKDBE ab. - omit_date_filter: bool = False Wenn True, wird der DAT/DDAT/SDAT-Term weggelassen. HE und ähnliche Instanzen haben andere Date-Field-Namen. Plus _parse_hit_list_cards Date-Regex erweitert: zusätzlich zum "vom DD.MM.YYYY"-Pattern (BE) jetzt auch "DD.MM.YYYY"-plain (BB schreibt Datum vor Drucksachen-Nummer ohne "vom"-Marker). Smoke-Test (lokal): BB q="": 5 hits in 5.9s BB q="Schule": 5 hits (Pflegeschulen, Genderverbot, Hochschulen) RP q="": 5 hits in 4.1s (Entlastung, Bildungschancen) RP q="Schule": 5 hits (Hochschulbau, G9-Gymnasien, Leistungsgerechtigkeit) bundeslaender.py: BB.doku_system "StarWeb"→"portala", RP analog, beide aktiv=True. Anmerkungen mit dem portala-Verweis und der Klarstellung "OPAL/RLP ≠ NRW OPAL" erweitert. NICHT in diesem Commit: - HE: portala-Backend (hlt.lis) ist erreichbar, aber das HE-Card- Layout ist anders (Title direkt im <h3> statt <h3><span>, kein <span class="h6"> für Meta) — eigener Parser-Pfad nötig, deferred. - NI: nilas.niedersachsen.de/portal/ ist eine Login-Page, das öffentliche Backend ist nicht zugänglich — deferred. - HB: kein /portal/-Endpoint, bleibt das alte StarWeb-Servlet — braucht eigenen HAR-Trace, deferred. - BB als StarWeb-Template (#27) ist hinfällig, weil BB portala ist. Phase 2 (3/6) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:59:28 +02:00
doku_system="portala",
doku_base_url="https://www.parlamentsdokumentation.brandenburg.de",
drucksache_format="8/1234",
dokukratie_scraper="bb",
Activate Brandenburg + Rheinland-Pfalz via PortalaAdapter reuse (#27, #30, Phase 2) Riesige Überraschung aus dem BB-HAR-Trace: Brandenburg ist NICHT StarWeb wie in dokukratie und bundeslaender.py klassifiziert, sondern läuft auch auf dem portala/eUI-Backend. Endpoint /portal/browse.tt.json mit db_id=lbb.lissh. Das alte /starweb/LBB/ELVIS/-Frontend ist nur Legacy. Folgeprobing offenbarte: RP/opal.rlp.de läuft ebenfalls portala (db_id=rlp.lissh, 46759 hits in WP18), ebenso NI/HE/BB. Damit ist Phase 2 großteils KEIN StarWeb-Adapter-Bau, sondern PortalaAdapter- Wiederverwendung mit konfigurierbaren Parametern. Activated via Registry-Einträge: - "BB" → PortalaAdapter(base_url=parlamentsdokumentation.brandenburg.de, db_id=lbb.lissh, wahlperiode=8). Nutzt die BE-Card-Variante des Hit-Parsers (efxRecordRepeater). - "RP" → PortalaAdapter(base_url=opal.rlp.de, db_id=rlp.lissh, wahlperiode=18). NICHT mit dem NRW OPAL verwechseln — anderer Markenname, andere Engine. PortalaAdapter erweitert um zwei neue Konstruktor-Parameter mit backward-kompatiblen Defaults: - typ_filter: Optional[str] = "DOKDBE" Wenn None, wird die TYP=<value>-Klausel weggelassen. Manche Instanzen (HE/hlt.lis) lehnen DOKDBE ab. - omit_date_filter: bool = False Wenn True, wird der DAT/DDAT/SDAT-Term weggelassen. HE und ähnliche Instanzen haben andere Date-Field-Namen. Plus _parse_hit_list_cards Date-Regex erweitert: zusätzlich zum "vom DD.MM.YYYY"-Pattern (BE) jetzt auch "DD.MM.YYYY"-plain (BB schreibt Datum vor Drucksachen-Nummer ohne "vom"-Marker). Smoke-Test (lokal): BB q="": 5 hits in 5.9s BB q="Schule": 5 hits (Pflegeschulen, Genderverbot, Hochschulen) RP q="": 5 hits in 4.1s (Entlastung, Bildungschancen) RP q="Schule": 5 hits (Hochschulbau, G9-Gymnasien, Leistungsgerechtigkeit) bundeslaender.py: BB.doku_system "StarWeb"→"portala", RP analog, beide aktiv=True. Anmerkungen mit dem portala-Verweis und der Klarstellung "OPAL/RLP ≠ NRW OPAL" erweitert. NICHT in diesem Commit: - HE: portala-Backend (hlt.lis) ist erreichbar, aber das HE-Card- Layout ist anders (Title direkt im <h3> statt <h3><span>, kein <span class="h6"> für Meta) — eigener Parser-Pfad nötig, deferred. - NI: nilas.niedersachsen.de/portal/ ist eine Login-Page, das öffentliche Backend ist nicht zugänglich — deferred. - HB: kein /portal/-Endpoint, bleibt das alte StarWeb-Servlet — braucht eigenen HAR-Trace, deferred. - BB als StarWeb-Template (#27) ist hinfällig, weil BB portala ist. Phase 2 (3/6) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:59:28 +02:00
aktiv=True,
anmerkung=(
"Kabinett Woidke IV (SPD-BSW) seit Dezember 2024. Knappe "
"Mehrheit (zwei Sitze). Doku-System ist NICHT StarWeb wie "
"ursprünglich klassifiziert (das alte /starweb/LBB/ELVIS/-"
"Frontend ist nur Legacy), sondern das moderne portala/eUI-"
"Backend auf /portal/browse.tt.json mit db_id=lbb.lissh. "
"Wiederverwendet PortalaAdapter aus #2/#3 (#27)."
),
),
"HB": Bundesland(
code="HB",
name="Bremen",
parlament_name="Bremische Bürgerschaft",
wahlperiode=21,
wahlperiode_start="2023-07-05",
naechste_wahl="2027-05-09",
regierungsfraktionen=["SPD", "GRÜNE", "LINKE"],
landtagsfraktionen=["SPD", "CDU", "GRÜNE", "LINKE", "AfD", "BiW"],
doku_system="StarWeb",
doku_base_url="https://paris.bremische-buergerschaft.de",
drucksache_format="21/1234",
dokukratie_scraper="hb",
anmerkung=(
"PARiS ist eine StarWeb-Skin auf bremischer Hardware — kein "
"eigenständiges System. Endpoint folgt dem Standard "
"/starweb/paris/servlet.starweb?path=paris/LISSH.web (siehe "
"dokukratie/hb.yml). Wiederverwendbar mit dem generischen "
"StarWebAdapter aus Issue #27. AfD durch Listenstreichung 2023 "
"nicht im Landtag, stattdessen Bürger in Wut (BiW). Wahltag 2027 "
"noch nicht festgesetzt."
),
),
"HH": Bundesland(
code="HH",
name="Hamburg",
parlament_name="Hamburgische Bürgerschaft",
wahlperiode=23,
wahlperiode_start="2025-03-26",
naechste_wahl="2030-03-03",
regierungsfraktionen=["SPD", "GRÜNE"],
landtagsfraktionen=["SPD", "CDU", "GRÜNE", "LINKE", "AfD"],
doku_system="ParlDok",
doku_base_url="https://www.buergerschaft-hh.de/parldok",
drucksache_format="23/1234",
dokukratie_scraper="hh",
aktiv=True,
anmerkung=(
"Wahl am 02.03.2025; Senat Tschentscher III seit 07.05.2025 "
"vereidigt. ParlDok 8.3.1 (J3S GmbH) — kompatibel mit der MV-"
"Variante (8.3.5), gleiches /parldok/Fulltext/Search-Schema. "
"Aktiv via ParLDokAdapter-Registry-Eintrag in #28."
),
),
"HE": Bundesland(
code="HE",
name="Hessen",
parlament_name="Hessischer Landtag",
wahlperiode=21,
wahlperiode_start="2024-01-18",
naechste_wahl="2028-10-22",
regierungsfraktionen=["CDU", "SPD"],
landtagsfraktionen=["CDU", "AfD", "SPD", "GRÜNE", "FDP"],
doku_system="StarWeb",
doku_base_url="https://starweb.hessen.de/starweb/LIS",
drucksache_format="21/1234",
dokukratie_scraper="he",
anmerkung="Wahltermin 2028 ist Schätzung.",
),
"MV": Bundesland(
code="MV",
name="Mecklenburg-Vorpommern",
parlament_name="Landtag Mecklenburg-Vorpommern",
wahlperiode=8,
wahlperiode_start="2021-10-26",
naechste_wahl="2026-09-20",
regierungsfraktionen=["SPD", "LINKE"],
landtagsfraktionen=["SPD", "AfD", "CDU", "LINKE", "GRÜNE", "FDP"],
doku_system="ParlDok",
doku_base_url="https://www.dokumentation.landtag-mv.de",
drucksache_format="8/1234",
dokukratie_scraper="mv",
Activate Mecklenburg-Vorpommern (ParlDok) — search-only MVP (#4) Adds a new ParLDokAdapter for ParlDok 8.x parliament documentation systems by J3S GmbH. MV becomes the fourth supported state alongside NRW, LSA and BE. Notable details: - ParlDok 8.x is a single-page app whose backend is a JSON API rooted at {base}/parldok/Fulltext/{Search,Resultpage}. The legacy ParLDok 5.x HTML POST form (parldok/formalkriterien) used by dokukratie's mv.yml has been deprecated by the LandtagMV upgrade to 8.3.5 and is no longer reachable via the old form fields — hence a new adapter rather than reusing the dokukratie scraper. - Two-stage pagination: Fulltext/Search returns the first 100 hits + a queryid; further pages come from Fulltext/Resultpage with {queryid, limit:{Start,Length}}. The Search endpoint silently ignores any non-zero Start, so single-stage offset pagination is not an option. - Server-side filter via facet_lp (type=10) on the configured WP; type=Antrag is filtered client-side because the facet_type value IDs are instance-specific and would require an extra Fulltext/Filter discovery call. ParlDok also returns the same Drucksache multiple times when it appears in several Vorgänge/Beratungen, so search() dedupes by lp/number. - Wahlprogramme zur LTW 26.09.2021 are not yet indexed (follow-up in #4) — analyses run with the federal Grundsatzprogramm fallback, same as Berlin until #10 lands. Drive-by cleanup of PortalaAdapter print() statements: switched to the module-level logger so adapter parser bugs no longer disappear into stdout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 08:19:48 +02:00
aktiv=True,
anmerkung=(
"ParlDok 8.3.5 (J3S GmbH) — moderne SPA, JSON-API unter "
"/parldok/Fulltext/Search. ParLDokAdapter (eigene Implementierung, "
"nicht portala-kompatibel). Die in dokukratie/mv.yml beschriebene "
"Legacy-HTML-Form (parldok/formalkriterien) ist mit dem 8.x-Upgrade "
"deprecated. Suche filtert via facet_lp=10/id=8 server-seitig auf "
"WP8, type=Antrag wird client-seitig gefiltert. Wahlprogramme zur "
"LTW 26.09.2021 sind noch nicht indexiert (Folge-Issue) — Analyse "
"läuft daher mit Grundsatzprogramm-Zitaten als Fallback. Wahltag "
"offiziell auf 20.09.2026 festgelegt."
),
),
"NI": Bundesland(
code="NI",
name="Niedersachsen",
parlament_name="Niedersächsischer Landtag",
wahlperiode=19,
wahlperiode_start="2022-11-08",
naechste_wahl="2027-10-10",
regierungsfraktionen=["SPD", "GRÜNE"],
landtagsfraktionen=["SPD", "CDU", "GRÜNE", "AfD"],
doku_system="StarWeb",
doku_base_url="https://www.landtag-niedersachsen.de",
drucksache_format="19/12345",
dokukratie_scraper="ni",
anmerkung=(
"Wahltermin Herbst 2027 (zwischen 11.07. und 03.10.2027) noch nicht festgesetzt; "
"geschätzt. Olaf Lies (SPD) seit 20.05.2025 Ministerpräsident."
),
),
"NRW": Bundesland(
code="NRW",
name="Nordrhein-Westfalen",
parlament_name="Landtag Nordrhein-Westfalen",
wahlperiode=18,
wahlperiode_start="2022-06-01",
naechste_wahl="2027-05-15",
regierungsfraktionen=["CDU", "GRÜNE"],
landtagsfraktionen=["CDU", "SPD", "GRÜNE", "FDP", "AfD"],
doku_system="OPAL",
doku_base_url="https://opal.landtag.nrw.de",
drucksache_format="18/12345",
dokukratie_scraper="nw",
aktiv=True,
anmerkung=(
"OPAL in NRW ist eine eigene Implementierung, nicht identisch mit dem "
"StarWeb-basierten OPAL in RLP. Wahltermin 2027 ist Schätzung."
),
),
"RP": Bundesland(
code="RP",
name="Rheinland-Pfalz",
parlament_name="Landtag Rheinland-Pfalz",
wahlperiode=18,
wahlperiode_start="2021-05-18",
naechste_wahl="2031-03-22",
regierungsfraktionen=["SPD", "GRÜNE", "FDP"],
landtagsfraktionen=["SPD", "CDU", "AfD", "GRÜNE", "FREIE WÄHLER", "FDP"],
Activate Brandenburg + Rheinland-Pfalz via PortalaAdapter reuse (#27, #30, Phase 2) Riesige Überraschung aus dem BB-HAR-Trace: Brandenburg ist NICHT StarWeb wie in dokukratie und bundeslaender.py klassifiziert, sondern läuft auch auf dem portala/eUI-Backend. Endpoint /portal/browse.tt.json mit db_id=lbb.lissh. Das alte /starweb/LBB/ELVIS/-Frontend ist nur Legacy. Folgeprobing offenbarte: RP/opal.rlp.de läuft ebenfalls portala (db_id=rlp.lissh, 46759 hits in WP18), ebenso NI/HE/BB. Damit ist Phase 2 großteils KEIN StarWeb-Adapter-Bau, sondern PortalaAdapter- Wiederverwendung mit konfigurierbaren Parametern. Activated via Registry-Einträge: - "BB" → PortalaAdapter(base_url=parlamentsdokumentation.brandenburg.de, db_id=lbb.lissh, wahlperiode=8). Nutzt die BE-Card-Variante des Hit-Parsers (efxRecordRepeater). - "RP" → PortalaAdapter(base_url=opal.rlp.de, db_id=rlp.lissh, wahlperiode=18). NICHT mit dem NRW OPAL verwechseln — anderer Markenname, andere Engine. PortalaAdapter erweitert um zwei neue Konstruktor-Parameter mit backward-kompatiblen Defaults: - typ_filter: Optional[str] = "DOKDBE" Wenn None, wird die TYP=<value>-Klausel weggelassen. Manche Instanzen (HE/hlt.lis) lehnen DOKDBE ab. - omit_date_filter: bool = False Wenn True, wird der DAT/DDAT/SDAT-Term weggelassen. HE und ähnliche Instanzen haben andere Date-Field-Namen. Plus _parse_hit_list_cards Date-Regex erweitert: zusätzlich zum "vom DD.MM.YYYY"-Pattern (BE) jetzt auch "DD.MM.YYYY"-plain (BB schreibt Datum vor Drucksachen-Nummer ohne "vom"-Marker). Smoke-Test (lokal): BB q="": 5 hits in 5.9s BB q="Schule": 5 hits (Pflegeschulen, Genderverbot, Hochschulen) RP q="": 5 hits in 4.1s (Entlastung, Bildungschancen) RP q="Schule": 5 hits (Hochschulbau, G9-Gymnasien, Leistungsgerechtigkeit) bundeslaender.py: BB.doku_system "StarWeb"→"portala", RP analog, beide aktiv=True. Anmerkungen mit dem portala-Verweis und der Klarstellung "OPAL/RLP ≠ NRW OPAL" erweitert. NICHT in diesem Commit: - HE: portala-Backend (hlt.lis) ist erreichbar, aber das HE-Card- Layout ist anders (Title direkt im <h3> statt <h3><span>, kein <span class="h6"> für Meta) — eigener Parser-Pfad nötig, deferred. - NI: nilas.niedersachsen.de/portal/ ist eine Login-Page, das öffentliche Backend ist nicht zugänglich — deferred. - HB: kein /portal/-Endpoint, bleibt das alte StarWeb-Servlet — braucht eigenen HAR-Trace, deferred. - BB als StarWeb-Template (#27) ist hinfällig, weil BB portala ist. Phase 2 (3/6) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:59:28 +02:00
doku_system="portala",
doku_base_url="https://opal.rlp.de",
drucksache_format="18/12345",
dokukratie_scraper="rp",
Activate Brandenburg + Rheinland-Pfalz via PortalaAdapter reuse (#27, #30, Phase 2) Riesige Überraschung aus dem BB-HAR-Trace: Brandenburg ist NICHT StarWeb wie in dokukratie und bundeslaender.py klassifiziert, sondern läuft auch auf dem portala/eUI-Backend. Endpoint /portal/browse.tt.json mit db_id=lbb.lissh. Das alte /starweb/LBB/ELVIS/-Frontend ist nur Legacy. Folgeprobing offenbarte: RP/opal.rlp.de läuft ebenfalls portala (db_id=rlp.lissh, 46759 hits in WP18), ebenso NI/HE/BB. Damit ist Phase 2 großteils KEIN StarWeb-Adapter-Bau, sondern PortalaAdapter- Wiederverwendung mit konfigurierbaren Parametern. Activated via Registry-Einträge: - "BB" → PortalaAdapter(base_url=parlamentsdokumentation.brandenburg.de, db_id=lbb.lissh, wahlperiode=8). Nutzt die BE-Card-Variante des Hit-Parsers (efxRecordRepeater). - "RP" → PortalaAdapter(base_url=opal.rlp.de, db_id=rlp.lissh, wahlperiode=18). NICHT mit dem NRW OPAL verwechseln — anderer Markenname, andere Engine. PortalaAdapter erweitert um zwei neue Konstruktor-Parameter mit backward-kompatiblen Defaults: - typ_filter: Optional[str] = "DOKDBE" Wenn None, wird die TYP=<value>-Klausel weggelassen. Manche Instanzen (HE/hlt.lis) lehnen DOKDBE ab. - omit_date_filter: bool = False Wenn True, wird der DAT/DDAT/SDAT-Term weggelassen. HE und ähnliche Instanzen haben andere Date-Field-Namen. Plus _parse_hit_list_cards Date-Regex erweitert: zusätzlich zum "vom DD.MM.YYYY"-Pattern (BE) jetzt auch "DD.MM.YYYY"-plain (BB schreibt Datum vor Drucksachen-Nummer ohne "vom"-Marker). Smoke-Test (lokal): BB q="": 5 hits in 5.9s BB q="Schule": 5 hits (Pflegeschulen, Genderverbot, Hochschulen) RP q="": 5 hits in 4.1s (Entlastung, Bildungschancen) RP q="Schule": 5 hits (Hochschulbau, G9-Gymnasien, Leistungsgerechtigkeit) bundeslaender.py: BB.doku_system "StarWeb"→"portala", RP analog, beide aktiv=True. Anmerkungen mit dem portala-Verweis und der Klarstellung "OPAL/RLP ≠ NRW OPAL" erweitert. NICHT in diesem Commit: - HE: portala-Backend (hlt.lis) ist erreichbar, aber das HE-Card- Layout ist anders (Title direkt im <h3> statt <h3><span>, kein <span class="h6"> für Meta) — eigener Parser-Pfad nötig, deferred. - NI: nilas.niedersachsen.de/portal/ ist eine Login-Page, das öffentliche Backend ist nicht zugänglich — deferred. - HB: kein /portal/-Endpoint, bleibt das alte StarWeb-Servlet — braucht eigenen HAR-Trace, deferred. - BB als StarWeb-Template (#27) ist hinfällig, weil BB portala ist. Phase 2 (3/6) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:59:28 +02:00
aktiv=True,
anmerkung=(
Activate Brandenburg + Rheinland-Pfalz via PortalaAdapter reuse (#27, #30, Phase 2) Riesige Überraschung aus dem BB-HAR-Trace: Brandenburg ist NICHT StarWeb wie in dokukratie und bundeslaender.py klassifiziert, sondern läuft auch auf dem portala/eUI-Backend. Endpoint /portal/browse.tt.json mit db_id=lbb.lissh. Das alte /starweb/LBB/ELVIS/-Frontend ist nur Legacy. Folgeprobing offenbarte: RP/opal.rlp.de läuft ebenfalls portala (db_id=rlp.lissh, 46759 hits in WP18), ebenso NI/HE/BB. Damit ist Phase 2 großteils KEIN StarWeb-Adapter-Bau, sondern PortalaAdapter- Wiederverwendung mit konfigurierbaren Parametern. Activated via Registry-Einträge: - "BB" → PortalaAdapter(base_url=parlamentsdokumentation.brandenburg.de, db_id=lbb.lissh, wahlperiode=8). Nutzt die BE-Card-Variante des Hit-Parsers (efxRecordRepeater). - "RP" → PortalaAdapter(base_url=opal.rlp.de, db_id=rlp.lissh, wahlperiode=18). NICHT mit dem NRW OPAL verwechseln — anderer Markenname, andere Engine. PortalaAdapter erweitert um zwei neue Konstruktor-Parameter mit backward-kompatiblen Defaults: - typ_filter: Optional[str] = "DOKDBE" Wenn None, wird die TYP=<value>-Klausel weggelassen. Manche Instanzen (HE/hlt.lis) lehnen DOKDBE ab. - omit_date_filter: bool = False Wenn True, wird der DAT/DDAT/SDAT-Term weggelassen. HE und ähnliche Instanzen haben andere Date-Field-Namen. Plus _parse_hit_list_cards Date-Regex erweitert: zusätzlich zum "vom DD.MM.YYYY"-Pattern (BE) jetzt auch "DD.MM.YYYY"-plain (BB schreibt Datum vor Drucksachen-Nummer ohne "vom"-Marker). Smoke-Test (lokal): BB q="": 5 hits in 5.9s BB q="Schule": 5 hits (Pflegeschulen, Genderverbot, Hochschulen) RP q="": 5 hits in 4.1s (Entlastung, Bildungschancen) RP q="Schule": 5 hits (Hochschulbau, G9-Gymnasien, Leistungsgerechtigkeit) bundeslaender.py: BB.doku_system "StarWeb"→"portala", RP analog, beide aktiv=True. Anmerkungen mit dem portala-Verweis und der Klarstellung "OPAL/RLP ≠ NRW OPAL" erweitert. NICHT in diesem Commit: - HE: portala-Backend (hlt.lis) ist erreichbar, aber das HE-Card- Layout ist anders (Title direkt im <h3> statt <h3><span>, kein <span class="h6"> für Meta) — eigener Parser-Pfad nötig, deferred. - NI: nilas.niedersachsen.de/portal/ ist eine Login-Page, das öffentliche Backend ist nicht zugänglich — deferred. - HB: kein /portal/-Endpoint, bleibt das alte StarWeb-Servlet — braucht eigenen HAR-Trace, deferred. - BB als StarWeb-Template (#27) ist hinfällig, weil BB portala ist. Phase 2 (3/6) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:59:28 +02:00
"OPAL in RLP läuft tatsächlich auf dem portala/eUI-Backend "
"(NICHT StarWeb wie ursprünglich klassifiziert), erreichbar "
"unter /portal/browse.tt.json mit db_id=rlp.lissh. "
"Wiederverwendet PortalaAdapter aus #2/#3 (#30). NICHT "
"verwechseln mit dem NRW OPAL — anderer Markenname, "
"andere Engine. Wahl zum 19. Landtag fand am 22.03.2026 "
"statt; Koalitionsverhandlungen CDU+SPD laufen, Kabinett "
"Schweitzer I geschäftsführend. Nach Konstituierung müssen "
"WP und Wahltermin aktualisiert werden."
),
),
"SL": Bundesland(
code="SL",
name="Saarland",
parlament_name="Landtag des Saarlandes",
wahlperiode=17,
wahlperiode_start="2022-04-25",
naechste_wahl="2027-04-18",
regierungsfraktionen=["SPD"],
landtagsfraktionen=["SPD", "CDU", "AfD"],
doku_system="Eigensystem",
doku_base_url="https://www.landtag-saar.de",
drucksache_format="17/1234",
dokukratie_scraper="sl",
anmerkung=(
"Einzige SPD-Alleinregierung in Deutschland. AfD-Status im 17. LT vor "
"produktiver Nutzung verifizieren."
),
),
"SN": Bundesland(
code="SN",
name="Sachsen",
parlament_name="Sächsischer Landtag",
wahlperiode=8,
wahlperiode_start="2024-10-01",
naechste_wahl="2029-09-02",
regierungsfraktionen=["CDU", "SPD"],
landtagsfraktionen=["CDU", "AfD", "BSW", "SPD", "LINKE", "GRÜNE"],
doku_system="Eigensystem",
doku_base_url="https://edas.landtag.sachsen.de",
drucksache_format="8/1234",
dokukratie_scraper="sn",
anmerkung=(
"Minderheitsregierung CDU+SPD (Kabinett Kretschmer III seit "
"18.12.2024). EDAS auf edas.landtag.sachsen.de ist eine "
"ASP.NET-Webforms-Anwendung mit __VIEWSTATE/__CALLBACKID-"
"Postbacks (siehe dokukratie/sn.yml) — NICHT ParlDok-kompatibel "
"mit MV/HH trotz älterer Wikipedia-Klassifikation. Eigener "
"Adapter notwendig (Issue #26)."
),
),
"LSA": Bundesland(
code="LSA",
name="Sachsen-Anhalt",
parlament_name="Landtag von Sachsen-Anhalt",
wahlperiode=8,
wahlperiode_start="2021-07-06",
naechste_wahl="2026-09-06",
regierungsfraktionen=["CDU", "SPD", "FDP"],
landtagsfraktionen=["CDU", "AfD", "LINKE", "SPD", "GRÜNE", "FDP"],
Add PortalaAdapter for PADOKA / Sachsen-Anhalt (#2) Adds a clean-room PortalaAdapter that talks to the eUI/portala framework behind PADOKA (Landtag Sachsen-Anhalt). Same engine powers Berlin's PARDOK; the same adapter will serve issue #3 once activated for BE. Reverse-engineering notes - The "PADOKA = StarWeb" assumption from issue #1 / dokukratie's st.yml is outdated. The Sachsen-Anhalt portal was migrated to the same eUI/portala SPA framework Berlin uses. The legacy starweb URL returns 503; the new entry point is /portal/browse.tt.html. - Search workflow is two-stage: 1. POST /portal/browse.tt.json with a JSON action body containing an Elasticsearch-style query tree under search.json. Returns a report_id plus hit count. 2. POST /portal/report.tt.html with {report_id, start, chunksize} returns the HTML hit list. Each record carries a Perl Data::Dumper block in a <pre> tag with the canonical metadata. - The query schema (sources, search.lines, search.json tree, report block) is taken from dokukratie/scrapers/portala.query.json (GPL-3.0) — only structure/selectors are reused, no Python code is ported. - DB id is "lsa.lissh"; the server validates this and rejects unknown interfaces with an explicit errormsg. - PDFs live under /files/drs/wp{N}/drs/d{nr}{xxx}.pdf and are served directly without any session cookie. What the adapter does - search() builds a date-window query (last ~24 months) for "Antrag" document type and returns the most recent hits. The user's free-text query is applied as a client-side title/Urheber filter (no fulltext search server-side yet — see "Limitations" below). - Hits are parsed from the Perl record dumps in the report HTML: - WEV06.main → title (Perl \x{xx} hex escapes decoded) - WEV32.5 → relative PDF path - WEV32.main → "Antrag <Urheber> <DD.MM.YYYY> Drucksache <b>X/YYYY</b>" - Fraktion strings are normalised to canonical codes (CDU, SPD, GRÜNE, FDP, AfD, LINKE, Landesregierung). - get_document() looks up a single Drucksache by re-running the search. - download_text() fetches the PDF and extracts text via PyMuPDF. - bundeslaender.py: LSA's doku_system corrected from "StarWeb" to "PARDOK", anmerkung updated with the migration story. Limitations (deliberate, MVP) - No server-side full-text search. The portala framework's sf index names for LSA full-text content are not yet known; tree mutations with sf=alAB return 0 hits. Client-side filter is "good enough" for the next ~24 months of Anträge (≈few hundred per WP). - LSA is still aktiv=False in bundeslaender.py — the adapter is dormant in production until issue #2's wahlprogramm ingest and frontend activation land. Verified live against padoka.landtag.sachsen-anhalt.de: - search(query="", limit=5) returned 5 current Anträge from März 2026 (LINKE + GRÜNE) with correct dates, fractions, titles and PDF URLs. - download_text("8/6790") returned 5051 chars of real Antragstext ("ICE-Halt für Salzwedel dauerhaft erhalten"). Refs #2. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 21:50:23 +02:00
doku_system="PARDOK",
doku_base_url="https://padoka.landtag.sachsen-anhalt.de",
drucksache_format="8/1234",
dokukratie_scraper="st",
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
aktiv=True,
anmerkung=(
"ISO-Code wäre ST; LSA ist im politischen Sprachgebrauch dominant. "
"Sven Schulze (CDU) seit 28.01.2026 MP nach Rücktritt Haseloff. "
Add PortalaAdapter for PADOKA / Sachsen-Anhalt (#2) Adds a clean-room PortalaAdapter that talks to the eUI/portala framework behind PADOKA (Landtag Sachsen-Anhalt). Same engine powers Berlin's PARDOK; the same adapter will serve issue #3 once activated for BE. Reverse-engineering notes - The "PADOKA = StarWeb" assumption from issue #1 / dokukratie's st.yml is outdated. The Sachsen-Anhalt portal was migrated to the same eUI/portala SPA framework Berlin uses. The legacy starweb URL returns 503; the new entry point is /portal/browse.tt.html. - Search workflow is two-stage: 1. POST /portal/browse.tt.json with a JSON action body containing an Elasticsearch-style query tree under search.json. Returns a report_id plus hit count. 2. POST /portal/report.tt.html with {report_id, start, chunksize} returns the HTML hit list. Each record carries a Perl Data::Dumper block in a <pre> tag with the canonical metadata. - The query schema (sources, search.lines, search.json tree, report block) is taken from dokukratie/scrapers/portala.query.json (GPL-3.0) — only structure/selectors are reused, no Python code is ported. - DB id is "lsa.lissh"; the server validates this and rejects unknown interfaces with an explicit errormsg. - PDFs live under /files/drs/wp{N}/drs/d{nr}{xxx}.pdf and are served directly without any session cookie. What the adapter does - search() builds a date-window query (last ~24 months) for "Antrag" document type and returns the most recent hits. The user's free-text query is applied as a client-side title/Urheber filter (no fulltext search server-side yet — see "Limitations" below). - Hits are parsed from the Perl record dumps in the report HTML: - WEV06.main → title (Perl \x{xx} hex escapes decoded) - WEV32.5 → relative PDF path - WEV32.main → "Antrag <Urheber> <DD.MM.YYYY> Drucksache <b>X/YYYY</b>" - Fraktion strings are normalised to canonical codes (CDU, SPD, GRÜNE, FDP, AfD, LINKE, Landesregierung). - get_document() looks up a single Drucksache by re-running the search. - download_text() fetches the PDF and extracts text via PyMuPDF. - bundeslaender.py: LSA's doku_system corrected from "StarWeb" to "PARDOK", anmerkung updated with the migration story. Limitations (deliberate, MVP) - No server-side full-text search. The portala framework's sf index names for LSA full-text content are not yet known; tree mutations with sf=alAB return 0 hits. Client-side filter is "good enough" for the next ~24 months of Anträge (≈few hundred per WP). - LSA is still aktiv=False in bundeslaender.py — the adapter is dormant in production until issue #2's wahlprogramm ingest and frontend activation land. Verified live against padoka.landtag.sachsen-anhalt.de: - search(query="", limit=5) returned 5 current Anträge from März 2026 (LINKE + GRÜNE) with correct dates, fractions, titles and PDF URLs. - download_text("8/6790") returned 5051 chars of real Antragstext ("ICE-Halt für Salzwedel dauerhaft erhalten"). Refs #2. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 21:50:23 +02:00
"PADOKA wurde von StarWeb auf das portala/eUI-Framework migriert "
"(gleiche Engine wie Berlin/PARDOK). dokukratie's st.yml ist veraltet. "
"Suche läuft via POST /portal/browse.tt.json + report.tt.html."
),
),
"SH": Bundesland(
code="SH",
name="Schleswig-Holstein",
parlament_name="Schleswig-Holsteinischer Landtag",
wahlperiode=20,
wahlperiode_start="2022-06-07",
naechste_wahl="2027-04-18",
regierungsfraktionen=["CDU", "GRÜNE"],
landtagsfraktionen=["CDU", "GRÜNE", "SPD", "FDP", "SSW"],
doku_system="StarWeb",
Activate Schleswig-Holstein via StarFinderCGIAdapter (#20, Phase 2) SH läuft auf der ältesten der vier Backend-Familien: Starfinder-CGI auf lissh.lvn.parlanet.de. URL-basiert (nicht stateful wie das moderne StarWeb-Servlet von BB/HE/NI/RP/HB), Latin-1-encoding, flat HTML-Tabelle als Hit-Format. Eigener Adapter weil das Schema fundamental anders ist als alles andere. Endpoint: http://lissh.lvn.parlanet.de/cgi-bin/starfinder/0 ?path=lisshfl.txt&id=FASTLINK&pass=&search=WP=20+AND+dtyp=antrag &format=WEBKURZFL Hit-Format pro <tr class="tabcol*">: <b>{TITLE}</b><br> Antrag {URHEBER} {DD.MM.YYYY} Drucksache <a href="{PDF}">{N/M}</a> Quelle: dokukratie/sh.yml + Live-Probing. Encoding: Server liefert iso-8859-1 ohne korrektes Content-Type- Header. Adapter dekodiert resp.content explizit als latin-1. SSW-Detection im _normalize_fraktion: SH ist das einzige BL mit SSW-Fraktion (von der 5%-Hürde befreit), pattern ist \\bSSW\\b analog zu \\bAfD\\b. Free-Text-Suche client-seitig (siehe #18) — server-side query- syntax mit (term) im starfinder-search-Param wird vom Server nicht als Volltext interpretiert, einheitlich mit allen anderen aktiven Adaptern. Smoke-Test (lokal): SH q="": 8 hits in 14.4s SH q="Schule": 8 hits in 14.8s (Schulentwicklung Westküste, Hochschulen, queere Vielfalt an Schule etc.) SH q="Klima": 8 hits (klimafreundlich, Klimafolgen, Strategischer Aktionsplan) SH q="Bildung": 8 hits (berufliche Bildung, Holocaust-Wissen) bundeslaender.py::SH.aktiv = True. doku_base_url auf lissh.lvn.parlanet.de korrigiert (ehemaliger landtag.ltsh.de- Eintrag passte nicht zum echten Endpoint). Damit ist Phase 2 (1/6) angefangen — als Nebenpfad, weil das StarWeb-Servlet (#27 BB als Template für 5 weitere) ohne HAR- Trace nicht sauber reverse-engineerbar war. Phase 2 (1/6) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:34:06 +02:00
doku_base_url="http://lissh.lvn.parlanet.de",
drucksache_format="20/1234",
dokukratie_scraper="sh",
Activate Schleswig-Holstein via StarFinderCGIAdapter (#20, Phase 2) SH läuft auf der ältesten der vier Backend-Familien: Starfinder-CGI auf lissh.lvn.parlanet.de. URL-basiert (nicht stateful wie das moderne StarWeb-Servlet von BB/HE/NI/RP/HB), Latin-1-encoding, flat HTML-Tabelle als Hit-Format. Eigener Adapter weil das Schema fundamental anders ist als alles andere. Endpoint: http://lissh.lvn.parlanet.de/cgi-bin/starfinder/0 ?path=lisshfl.txt&id=FASTLINK&pass=&search=WP=20+AND+dtyp=antrag &format=WEBKURZFL Hit-Format pro <tr class="tabcol*">: <b>{TITLE}</b><br> Antrag {URHEBER} {DD.MM.YYYY} Drucksache <a href="{PDF}">{N/M}</a> Quelle: dokukratie/sh.yml + Live-Probing. Encoding: Server liefert iso-8859-1 ohne korrektes Content-Type- Header. Adapter dekodiert resp.content explizit als latin-1. SSW-Detection im _normalize_fraktion: SH ist das einzige BL mit SSW-Fraktion (von der 5%-Hürde befreit), pattern ist \\bSSW\\b analog zu \\bAfD\\b. Free-Text-Suche client-seitig (siehe #18) — server-side query- syntax mit (term) im starfinder-search-Param wird vom Server nicht als Volltext interpretiert, einheitlich mit allen anderen aktiven Adaptern. Smoke-Test (lokal): SH q="": 8 hits in 14.4s SH q="Schule": 8 hits in 14.8s (Schulentwicklung Westküste, Hochschulen, queere Vielfalt an Schule etc.) SH q="Klima": 8 hits (klimafreundlich, Klimafolgen, Strategischer Aktionsplan) SH q="Bildung": 8 hits (berufliche Bildung, Holocaust-Wissen) bundeslaender.py::SH.aktiv = True. doku_base_url auf lissh.lvn.parlanet.de korrigiert (ehemaliger landtag.ltsh.de- Eintrag passte nicht zum echten Endpoint). Damit ist Phase 2 (1/6) angefangen — als Nebenpfad, weil das StarWeb-Servlet (#27 BB als Template für 5 weitere) ohne HAR- Trace nicht sauber reverse-engineerbar war. Phase 2 (1/6) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:34:06 +02:00
aktiv=True,
anmerkung=(
"SSW ist von der 5%-Hürde befreit. Doku-System ist die "
"alte Starfinder-CGI auf lissh.lvn.parlanet.de — URL-"
"basiert via "
"/cgi-bin/starfinder/0?path=lisshfl.txt&search=WP=20+AND+dtyp=antrag, "
"Latin-1-encoding. NICHT die moderne StarWeb-Servlet-"
"Variante (BB/HE/NI/RP/HB) — eigene Klasse "
"StarFinderCGIAdapter."
),
),
"TH": Bundesland(
code="TH",
name="Thüringen",
parlament_name="Thüringer Landtag",
wahlperiode=8,
wahlperiode_start="2024-10-01",
naechste_wahl="2029-09-01",
regierungsfraktionen=["CDU", "BSW", "SPD"],
landtagsfraktionen=["AfD", "CDU", "LINKE", "BSW", "SPD"],
doku_system="ParlDok",
Activate Thüringen via ParLDokAdapter reuse + filter widening (#25, Phase 1) Thüringen läuft auf parldok.thueringer-landtag.de mit ParlDok 8.3.5 (J3S GmbH) — exakt dieselbe Version wie MV. Aber TH packt seine Anträge unter zusammengesetzten type-Strings ("Antrag gemäß § 79 GO", "Antrag gemäß § 74 (2) GO") und kind="Vorlage" statt der MV-Variante kind="Drucksache"/type="Antrag". Strict-Match auf "Antrag" hat 0 Treffer geliefert. Lösung: ParLDokAdapter um zwei Konstruktor-Parameter erweitert: - document_typ_substring=True → Substring-Match auf type-Feld ("Antrag" matched "Antrag gemäß § 79 GO", "Alternativantrag" usw.) - kinds=["Drucksache", "Vorlage"] → erweiterte kind-Liste Defaults sind backward-kompatibel (Substring-Match aus, kinds nur Drucksache), sodass MV und HH unverändert weiterlaufen. _hit_matches_filters() als zentraler Filter-Helper extrahiert, search() und get_document() nutzen ihn — get_document() überspringt ihn allerdings, weil dort beliebige Drucksachen aufrufbar sein müssen, unabhängig vom search-Time-Filter. Hostname-Korrektur: parldok.thueringen.de redirected per 303 auf parldok.thueringer-landtag.de. doku_base_url in bundeslaender.py auf den neuen Host umgestellt. Smoke-Test (lokal): TH q="": 8 hits in 3.3s TH q="Schule": 2 hits in 25.7s (Lernmittelbeschaffung, Modernisierung Bund-Länder-Vereinbarung — beide Schul-bezogen) TH q="Klima": 0 hits (keine in den letzten 1000 Drucksachen) Damit ist Phase 1 (3/3) komplett. Nächstes Phase-2 Issue: #27 BB als StarWebAdapter-Template. Phase 1 (3/3) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:48:02 +02:00
doku_base_url="https://parldok.thueringer-landtag.de",
drucksache_format="8/1234",
dokukratie_scraper="th",
Activate Thüringen via ParLDokAdapter reuse + filter widening (#25, Phase 1) Thüringen läuft auf parldok.thueringer-landtag.de mit ParlDok 8.3.5 (J3S GmbH) — exakt dieselbe Version wie MV. Aber TH packt seine Anträge unter zusammengesetzten type-Strings ("Antrag gemäß § 79 GO", "Antrag gemäß § 74 (2) GO") und kind="Vorlage" statt der MV-Variante kind="Drucksache"/type="Antrag". Strict-Match auf "Antrag" hat 0 Treffer geliefert. Lösung: ParLDokAdapter um zwei Konstruktor-Parameter erweitert: - document_typ_substring=True → Substring-Match auf type-Feld ("Antrag" matched "Antrag gemäß § 79 GO", "Alternativantrag" usw.) - kinds=["Drucksache", "Vorlage"] → erweiterte kind-Liste Defaults sind backward-kompatibel (Substring-Match aus, kinds nur Drucksache), sodass MV und HH unverändert weiterlaufen. _hit_matches_filters() als zentraler Filter-Helper extrahiert, search() und get_document() nutzen ihn — get_document() überspringt ihn allerdings, weil dort beliebige Drucksachen aufrufbar sein müssen, unabhängig vom search-Time-Filter. Hostname-Korrektur: parldok.thueringen.de redirected per 303 auf parldok.thueringer-landtag.de. doku_base_url in bundeslaender.py auf den neuen Host umgestellt. Smoke-Test (lokal): TH q="": 8 hits in 3.3s TH q="Schule": 2 hits in 25.7s (Lernmittelbeschaffung, Modernisierung Bund-Länder-Vereinbarung — beide Schul-bezogen) TH q="Klima": 0 hits (keine in den letzten 1000 Drucksachen) Damit ist Phase 1 (3/3) komplett. Nächstes Phase-2 Issue: #27 BB als StarWebAdapter-Template. Phase 1 (3/3) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:48:02 +02:00
aktiv=True,
anmerkung=(
"Erste Brombeer-Koalition Deutschlands (CDU+BSW+SPD) als "
Activate Thüringen via ParLDokAdapter reuse + filter widening (#25, Phase 1) Thüringen läuft auf parldok.thueringer-landtag.de mit ParlDok 8.3.5 (J3S GmbH) — exakt dieselbe Version wie MV. Aber TH packt seine Anträge unter zusammengesetzten type-Strings ("Antrag gemäß § 79 GO", "Antrag gemäß § 74 (2) GO") und kind="Vorlage" statt der MV-Variante kind="Drucksache"/type="Antrag". Strict-Match auf "Antrag" hat 0 Treffer geliefert. Lösung: ParLDokAdapter um zwei Konstruktor-Parameter erweitert: - document_typ_substring=True → Substring-Match auf type-Feld ("Antrag" matched "Antrag gemäß § 79 GO", "Alternativantrag" usw.) - kinds=["Drucksache", "Vorlage"] → erweiterte kind-Liste Defaults sind backward-kompatibel (Substring-Match aus, kinds nur Drucksache), sodass MV und HH unverändert weiterlaufen. _hit_matches_filters() als zentraler Filter-Helper extrahiert, search() und get_document() nutzen ihn — get_document() überspringt ihn allerdings, weil dort beliebige Drucksachen aufrufbar sein müssen, unabhängig vom search-Time-Filter. Hostname-Korrektur: parldok.thueringen.de redirected per 303 auf parldok.thueringer-landtag.de. doku_base_url in bundeslaender.py auf den neuen Host umgestellt. Smoke-Test (lokal): TH q="": 8 hits in 3.3s TH q="Schule": 2 hits in 25.7s (Lernmittelbeschaffung, Modernisierung Bund-Länder-Vereinbarung — beide Schul-bezogen) TH q="Klima": 0 hits (keine in den letzten 1000 Drucksachen) Damit ist Phase 1 (3/3) komplett. Nächstes Phase-2 Issue: #27 BB als StarWebAdapter-Template. Phase 1 (3/3) aus Roadmap-Issue #49. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:48:02 +02:00
"Minderheitsregierung mit 44 von 88 Sitzen. Mario Voigt "
"(CDU) seit Dezember 2024 MP. ParlDok 8.3.5 (J3S GmbH) — "
"EXAKT dieselbe Version wie MV. ParLDokAdapter direkt "
"wiederverwendbar als Registry-Eintrag (#25). Achtung: "
"alter Hostname parldok.thueringen.de redirected per 303 "
"auf parldok.thueringer-landtag.de — neuer Hostname ist "
"der korrekte."
),
),
}
def get(code: str) -> Optional[Bundesland]:
"""Bundesland-Konfig per Code abrufen, oder None."""
return BUNDESLAENDER.get(code)
def aktive_bundeslaender() -> list[Bundesland]:
"""Alle aktuell aktiven (im Analyzer unterstützten) Bundesländer."""
return [bl for bl in BUNDESLAENDER.values() if bl.aktiv]
def alle_bundeslaender() -> list[Bundesland]:
"""Alle 16 Bundesländer (aktive zuerst, dann alphabetisch nach Name)."""
aktiv = sorted([bl for bl in BUNDESLAENDER.values() if bl.aktiv], key=lambda b: b.name)
inaktiv = sorted([bl for bl in BUNDESLAENDER.values() if not bl.aktiv], key=lambda b: b.name)
return aktiv + inaktiv