aboutsummaryrefslogtreecommitdiff
path: root/FASSUNGEN.txt
Commit message (Collapse)AuthorAgeFilesLines
* Quellformate jenseits des verkündeten GesetzesMatthias Andreas Benkard11 days1-0/+144
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Bisher nahm ÄndGgner nur verkündete Artikelgesetze und Gesetzentwürfe an, ohne den Unterschied zu kennen. Dokumente, die einen Entwurf ändern statt ein Gesetz, lieferten still null Befehle. Neu: * Dokumentart-Erkennung aus dem Rohtext (DokumentErkenner, DokumentArt, DokumentKopf) — vor der Bereinigung, weil gerade die Drucksachenköpfe als Kolumnentitel wegfallen. Erkannt wird nie am Dateinamen: Die Beispieldaten enthalten eine Datei namens Beschlussempfehlung, die in Wahrheit ein Entschließungsantrag ist. Dokumente ohne Befehle erzeugen jetzt eine benannte Warnung statt stiller Leere. * Änderungsanträge (AenderungsantragParser, EntwurfsPatcher): Der Antrag wird auf den Entwurfstext angewandt, der geänderte Entwurf danach wie gewohnt auf das Stammgesetz — eine komponierte Synopse. Drucksachen- und Gesetzesstellen bleiben getrennte Typen; die Zuordnung Antrag→Entwurf läuft über die Drucksachennummer, nicht über die Argumentreihenfolge. Der 1910 Zeilen große BefehlAnwender bleibt unberührt. * Beschlussempfehlungen werden erkannt und mit Begründung übergangen, die den brauchbaren Entwurf beim Namen nennt. Die Spaltentrennung der Zusammenstellung ist gebaut (FontgroessenFilter.Spalte, koordinatenbasiert am Steg) und belegt: Die linke Spalte ergibt Befehl für Befehl den Regierungsentwurf. Die rechte Spalte bleibt bewusst offen — sie vermerkt „unverändert“ auch zeilenweise innerhalb zitierter Blöcke, ihre Anführungszeichen gehen daher nicht auf; nötig ist die zeilenweise Zuordnung beider Spalten über die gemeinsame Grundlinie. Die Synopse kennzeichnet eine Entwurfsfassung als solche. 296 Tests grün (vorher 269); alle gepinnten Akzeptanzzahlen unverändert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Change-Id: I0001d25fcbd9969fc06eea675edc4326ce2e02f9
* Support unnumbered named Anlagen; strip control charactersMatthias Andreas Benkard2026-07-261-6/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Investigating "Anlagen as amendment target" corrected the diagnosis from yesterday: Anlagen are supported. In gii-XML they are norms of their own ("Anlage 8", "Anhang"), Stelle.anlagenEnbez() resolves them, and the GEG sample applies annex-targeted commands — only two of its fifty manual entries touch annexes, both for content reasons. What actually failed in Berlin was narrower, and is fixed: * A law with a single annex names it after the provision it belongs to ("Die Anlage zu § 2 Absatz 4 Satz 1"). StellenParser demanded a number after "Anlage" and rejected the phrase, so the article's frame command went unrecognised and its items lost their context. The annex now carries the designation "Anlage", like "Anhang". The naming suffix is skipped deliberately: read along, the "§ 2" inside it would become the target and the wrong norm would be amended. * C0 control characters are now stripped. Berlin's enumeration indent carries a U+0007 that sits invisibly in front of the command and made its start-of-line anchor miss. * Command verbs torn apart by a stray space in the official typesetting ("ein gefügt" for "eingefügt") are rejoined, restricted to sequences that are not valid German word order. Three of Article 1's four commands are now recognised. The fourth places the new unit by a word anchor ("Vor den Wörtern … wird folgender Absatz 5 eingefügt"), which StrukturEinfuegung cannot express; that and the inability of the plain-text stem format to carry an Anlage at all are recorded in Landesrecht-Beispiele.adoc. 231 tests green; all pinned figures unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Change-Id: Ic5804bf343dd5d8ce435c07b8f882ca0372890d2
* Berlin column spike: stream order already reads correctlyMatthias Andreas Benkard2026-07-261-0/+54
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The plan assumed the two-column Berlin gazette would need x-coordinate column detection. It does not: the content stream already emits the left column fully before the right one, so commands come out in reading order. The test pins that finding. What does go wrong there is different, and two parts of it are fixed: * The article's amendment formula carries its own target ("§ 2 Satz 1 des Gesetzes zur Errichtung … wird wie folgt geändert"), but the following items never inherited it. The pattern's leading \b could never match before "§" — a non-word character needs a word character in front of it — so the paragraph branch was dead code and only the Bavarian "Art." branch ever fired. * The running page header is not a line of its own; it sits inside the body text of the following column, so it has to be cut out rather than dropped as a column title. Two blockers remain and are recorded rather than papered over: Article 1 amends an *Anlage* with its own numbering, which the model does not carry (the same gap that shelved Baden-Württemberg), and full-width frames (title block, imprint) sit elsewhere in the stream than on the page, which would need a real XY-cut. Stems are unobtainable either way — gesetze.berlin.de is an authenticated juris app like the Schleswig- Holstein portal. 229 tests green; all pinned figures unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Change-Id: I4619dbe96a023d61104d7107a9a34533123d1bc5
* Support the two Lower Saxony insertion forms; NEFG now applies fullyMatthias Andreas Benkard2026-07-251-0/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The NEFG acceptance case left two commands as "check manually". Both are now supported, so Lower Saxony applies 7 of 7 with no remainder. * Lower Saxony cites inserted paragraphs with a space before the sub number ("§ 2 a"); the rest of German legal usage writes "§ 2a", which is what the Stelle and level parsers expect. TextBereiniger now pulls the form together, leaving enumeration markers of the amendment act alone ("… nach § 8 c) In Absatz 2 …"). * "In Kapitel 4 wird nach § 12 der folgende neue § 13 angefügt" — the division only names the section the new paragraph lands in; the anchor governs the position, as in the plain form. The optional "neue" is now accepted in both. Applying that insertion needed one more thing: the paragraph it creates is only vacated by the *following* command ("Der bisherige § 13 wird § 14"), so in document order the two collided and the insertion was rejected. "Bisherig" denotes the state before the amendment, so the renumbering logically precedes the reoccupation and is now pulled ahead. The log still lists commands in the order of the amendment act. 226 tests green; all other pinned figures unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Change-Id: I0e2ea5b0389f8002157eeb8471800da51febe739
* Add North Rhine-Westphalia TMZ-Gesetz acceptance caseMatthias Andreas Benkard2026-07-251-8/+58
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Article 3 of the 22. Rundfunkänderungsgesetz (GV. NRW. 2026 S. 202) amends the Telemedienzuständigkeitsgesetz. All four commands apply cleanly, and the result matches the official consolidated version of 1 April 2026. recht.nrw.de turned out to be the one remaining state portal that serves consolidated laws as server-rendered HTML, with the version history encoded in the URL date prefix — so the pre-amendment stem (27 Apr 2022) was directly obtainable. Two fixes were needed: * LandesRechtTextParser read the parenthesised title suffix wholly as the abbreviation. State laws routinely carry both short title and abbreviation there ("(Telemedienzuständigkeitsgesetz – TMZ-Gesetz)"), and the amendment act cites the short title, so article selection never matched. The parser now splits at the dash. * ZitatExtraktor swallowed the rest of the document when a closing quotation mark is missing in the official text (Article 2 no. 11 here), which hid Articles 3 to 5 entirely. An amendment act never quotes across an article heading, so an open quotation is now closed before a bare "Artikel N" line, with a warning. Quoted paragraphs are unaffected: Bavarian norm heads read "Art. N". 223 tests green; all previously pinned figures unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Change-Id: I78470075d9be2433966b821b6fe1e21808996c46
* Add Schleswig-Holstein extraction case and three cleanup fixesMatthias Andreas Benkard2026-07-251-0/+66
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The GVOBl. Schl.-H. amendment act (Kommunalrecht, 2026/27) brings three conventions the tool had not seen: * a running two-line page header that sits between articles and glued itself onto the following article heading, * superscript footnote markers on article headings ("Artikel 1 ¹)"), which defeated the article split, and * ragged-right typesetting, where the geometric margin detection finds no alignment cluster and reports full lines as hard line ends, so a trailing hyphen was never joined. All three are fixed in TextBereiniger; the hyphen rule now trusts the extractor's trailing-space signal over the geometric class. A full acceptance test is not possible: the Schleswig-Holstein law portal serves document bodies only through an authenticated API, and the last freely archived consolidated Gemeindeordnung (14 Nov 2022) predates the amended § 34a. The new test therefore covers everything up to and including command recognition; the blocker is recorded in Landesrecht-Beispiele.adoc. 219 tests green; Bund/Bayern/Sachsen/Niedersachsen figures unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Change-Id: I9b3ab8a756372504b51c4d410b491fded255da96
* Add Lower Saxony NEFG acceptance case and two parser robustness fixesMatthias Andreas Benkard2026-07-241-0/+36
| | | | | | | | | | | | | | | | | | | | | | | | | | | Second §-structured Landesrecht case for wave six: the Lower Saxony ELER Support Act (NEFG, unchanged since 2022, derived from the two-column Nds. GVBl 2022 No. 33) plus the amending act of 28 Jan 2026 (Nds. GVBl 2026 No. 10). Five of seven commands apply — both "erhält folgende Fassung" re-enactments (§ 1(1), § 2), the citation replacement in § 1(5), the words insertion in § 6(1), and the § 13 → § 14 renumbering. - LandesRechtTextParser: a norm head no longer accepts a title ending in a full stop, so a cross-reference sentence at line start ("§ 7 GAPInVeKoSG findet entsprechend Anwendung.") is not misread as a norm head "§ 7" (which had made the monotonicity check swallow the norms in between). - TextBereiniger: strip the Lower Saxony GVBl running footer and publisher line. The footer sat between two enumerated items and otherwise attached to the preceding re-enactment quote, defeating its end-of-sentence anchor. - Add sampledata/Niedersachsen/NEFG-alt.txt and EndToEndTest.nefgAcceptance. Two insertion forms remain documented residues (manuell prüfen): inserting a §-block with a space-separated sub-number ("§ 2 a") and a chapter-scoped §-block insertion ("In Kapitel 4 wird nach § 12 … angefügt"). 221 tests green; federal, Bavarian and Saxon pinned numbers unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Change-Id: Ie23eee1f596ec8eecc6a73f6ce585a22e73ec6c9
* Add Saxony SächsBeamtVG acceptance case (first non-Bavarian Landesrecht)Matthias Andreas Benkard2026-07-241-0/+47
| | | | | | | | | | | | | | | | | | | | | | Complete the first §-structured Landesrecht acceptance case for wave six: the Saxon Civil Servants' Pension Act (SächsBeamtVG) in its 1 Feb 2025 version plus the amending act of 13 April 2026 (SächsGVBl. S. 134). All five commands are recognised and applied without residue — the amount replacements in § 47 and the re-enactment of § 80(1) sentence 2. - LandesRechtTextParser: recognise arabic, keyword-first structural headings ("Abschnitt 1", "Unterabschnitt 2", "Teil 3") via GLIEDERUNG_ARABISCH, in addition to Bavaria's roman "I. Abschnitt" form. Bavaria behaviour unchanged. - TextBereiniger: strip the footer of revosax full-text output (REVOSAX_FUSS, "https://…revosax… Fassung vom … Seite N von M"). - Add the consolidated pre-amendment stem as canonical plaintext (sampledata/Sachsen/SaechsBeamtVG-alt.txt, derived from the archived revosax full text) and EndToEndTest.saechsBeamtVgAcceptance (5 applied, 0 manual). 220 tests green; federal and Bavarian pinned numbers unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Change-Id: I8e878bc9506f24028cf643a873de000f3d066d64
* Generalize Bavarian loader to a shared Landesrecht loaderMatthias Andreas Benkard2026-07-191-0/+53
| | | | | | | | | | | | | | | | | | | | | | | | | | | Prepare wave six (Landesrecht of the remaining Länder) by lifting the Bavaria-specific stem-law loader to a shared one. Unlike Bavaria (Art./§ inversion), the other Länder structure their stem laws in §, so the loader must handle both sigils. - Move gesetz/bayern/{BayRechtLoader,BayRechtTextParser} to gesetz/land/{LandesRechtLoader,LandesRechtTextParser}; the norm head now matches "§ N" as well as "Art. N" and derives the sigil per norm from the match. Cross-reference keywords in the norm head are excluded only as whole words (so a title "Satzungen" no longer trips on "Satz"), and the juris abbreviation may be multi-token ("(GO NRW)"). - Derive the superscript mode data-drivenly from the loaded stem law (Superskript.traegtSatznummern) instead of from "is it gii-XML": Bavaria and Lower Saxony keep their amtliche Satznummern, the Bund and Länder without official sentence numbering drop them. - Recognize the neufassung idiom "erhält/erhalten folgende Fassung" (Schleswig- Holstein, Niedersachsen) via a NEUFASSUNG_VERB building block, additive to "wird/werden wie folgt gefasst". Federal and Bavarian behaviour is unchanged (219 tests green, pinned acceptance numbers UWG 19/0, GEG 66/53, GEG-GModG 90/9, IfSG 42/24, BayJG 149/154 hold). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Change-Id: I55a70a7932bf657a2346ca70f3fa05e173bf80ad
* Support Bavarian state law (BayJG) with Art./§ inversion and superscriptsMatthias Andreas Benkard2026-07-191-8/+165
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Extend ÄndGgner from federal-only to Bavarian state law. Bavarian base laws are structured in Artikel while their amending acts are structured in Paragraphen (inverted from the Bund); official sentence numbers and footnote markers are carried as Unicode superscripts (¹²³, ⁶)). - Generalise Stelle.Paragraph to carry a sigil ("§" or "Art.") and route it through recogniser, applier and resolver (bit-identical Bund output). - Superscript pipeline: geometric detection in FontgroessenFilter (SuperskriptModus BEHALTEN), Superskript util, exact sentence splitting in SatzTeiler, label-based sentence resolution. - BayRechtLoader/BayRechtTextParser for gesetze-bayern.de PDF/plaintext. - §-structured amending acts, GVBl/Landtag column titles, non-breaking spaces, the GVBl continuation quote; Bavarian command forms (footnote aufhebung, Satznummerierung streichung, Wortlaut forms, Halbsatz, gapping chains). Acceptance (EndToEndTest.bayJgGvblAcceptance): the pre-2026 BayJG fassung (BayJG-alt.txt, reconstructed from Wayback single-article snapshots) with GVBl 6/2026 §§ 1-2 applied — 154 commands, 0 unknown, 149 applied automatically, 5 pinned residuals (follow-up edits inside two multi-step renumbering sequences in Art. 29a and Art. 56). Application-side fixes surfaced by the acceptance run (all Bund-safe): sentence-start superscript before §; sentence boundaries = {0} ∪ {each number ≥ 2}; gapping scope inheritance for bare word operations; footnote definition lines hidden from word operations; absatz aufhebung marks "(weggefallen)" keeping its number, and absatz renumbering overwrites an empty placeholder (weggefallen/gegenstandslos) target. 211 tests green (mvnw verify); federal reference numbers unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Change-Id: Iebae4c17ca90755c5fd36251362042f3d5796fd0
* Classify line ends by alignment clusters and canonicalize definition listsMatthias Andreas Benkard2026-07-191-21/+45
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The percentile-based right-margin estimate from the previous commit misclassified two real-world layouts: at the column switch of the two-column old-BGBl format a window contains both column margins, so the 90th percentile returned the right column's margin and marked every left-column soft wrap as deliberate (vetoing hyphen mending, IfSG 2020: "Impf- surveillance"); and series of equally wide centered "Artikel N" headings in draft bills formed the top of their window's distribution, so they counted as full-width and were reflowed into the following line, breaking teileInArtikel's line anchor (ProdHaftG RegE). Classify against alignment clusters instead: a line end is soft when at least five window lines end within 4 pt of it (the justified block's own margin), hard when such a cluster runs at least 10 pt above it, unclassified otherwise. Structure anchors ("Artikel 2", "§ 19", bare Gliederung labels) are always exempt from reflow since equal-width heading series still form sham clusters. Also flush the pending line end-X at page ends — without it, the first line of the next page inherited the previous page's footer geometry and was misclassified (UWG: "Artikel 2" swallowed the closing provisions). Markerless joins additionally never cross into a following enumeration marker line ("...vorgesehen und" + "d) die Überwachung" no longer glues to "undd)"), a text-level veto that also works without geometry. On the base-law side, ContentFlattener now separates sibling <LA> elements within a <DD> — the short-label/definition pairs of the UWG Anhang and § 2 IfSG were previously glued without any separator ("Irreführung über Unternehmereigenschaftdie unwahre Angabe...") in both synopsis columns. The continuation line is indented two spaces deeper than its enumeration line so StellenAufloeser.zeilenBlock keeps it inside the unit's block ("Anhang Nummer 31 Buchstabe b"). BefehlAnwender writes the same canonical shape when inserting or recasting quoted units (rueckeZitatEin), so XML-derived and PDF-derived items agree: " 2a. Stichwort" + " Definitionstext". Verified by mvnw verify (179 tests, 7 new) and a before/after sweep of all 21 sample law/amendment combinations: applied/manual counts are unchanged throughout (UWG 19/0, GEG-BGBl 66/53, GModG-RegE 77/20, IfSG-0645 42/24, ...), no marker characters leak into the HTML output. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Change-Id: Ib7faae1bc5c59bda83f648a579af16a4c77e4285
* Classify line breaks geometrically via PDFBox coordinates and support list ↵Matthias Andreas Benkard2026-07-171-27/+25
| | | | | | | | | | | | | | | | | | | | | | | indentation Replaces the heuristic character-count full-width check with real geometric layout analysis. FontgroessenFilter collects the right-edge X coordinate of the text runs on each page and classifies line endings against the local 90th percentile of page margins (using a 20-line sliding window) into soft, hard, or unclassified breaks. TextBereiniger uses this classification to reflow only soft line wraps (WEICH) and keep deliberate ones (HART or UNBEKANNT). Also aligns quote normalization and GII-XML flattening to indent continuation lines in lists (e.g., hanging definitions in UWG Anhang): - BefehlAnwender.normalisiereZitatText applies to single-unit Neufassung and indents continuation lines deeper (4 spaces) than list items (2 spaces). - ContentFlattener generates the same structure for sibling <LA> elements inside <DD>. This ensures the paragraph parser correctly groups these lines as child lines. Change-Id: I1fd7039d4933a273cc2dc55f958d34b439e2302c
* Fix markerless line-break join gluing whole words without a spaceMatthias Andreas Benkard2026-07-171-0/+56
| | | | | | | | | | | | | | | | | | | | | | | | TextBereiniger.verbindeUmbrueche assumed any letter-ending, no-trailing-space line followed by a lowercase continuation was a hyphen-less mid-word split (PDF extraction artifact) and joined it with zero separator. That assumption breaks for deliberate word-boundary breaks, e.g. the short-label/hanging- indent definition format in the UWG Anhang ("...Nachhaltigkeitssiegels" + "das Anbringen..."), producing glued words in the rendered synopsis. Gate the markerless join on the candidate line reaching a locally-typical "full column width" (90th percentile in a ±20-line window), since automatic wraps always land near the column edge while deliberate breaks don't. The window is local rather than document-wide because some source PDFs mix column widths within one document (narrower Regelungstext vs. wider Begründung), which a global statistic would otherwise penalize. Also route the single-unit Neufassung fallback through the existing normalisiereZitatText normalization, matching its sibling code paths, so that internal line breaks now more often preserved by the fix above don't leak into the HTML output as spurious line breaks instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Change-Id: I0a79f22f9286cd4a90eea32bad9b54cb4a082cf4
* Support Anhang/Anlage targets, Inhaltsübersicht Angabe commands, and ↵Matthias Andreas Benkard2026-07-161-0/+90
| | | | | | | | | | | | | | Gliederungs-Überschriften insertion/replacement Fourth enablement wave: Anhänge/Anlagen resolve as ordinary norm targets with nested Nummer/Buchstabe block resolution, InhaltsuebersichtAnwender applies Angabe commands automatically, GliederungsUeberschriften handles inserting and replacing structural headings, the law's own heading can be recast, and FontgroessenFilter now determines body text per page instead of document-wide. Sample data (UWG/AGG/ProdHaftG) now applies with 0 manual cases. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Change-Id: I1a76750afbecfa1aae734bcdabc91470a28420ca
* Support range structure replacement, struct renumbering, and multi-paragraph ↵Matthias Andreas Benkard2026-07-151-0/+81
| | | | | | | | | | | | blocks Adds bisStelle to StrukturErsetzung for coordinated target ranges, recognizes deletion/renumbering of whole structural units (paragraphs and Gliederung entries), and handles insertion/replacement of multi-paragraph blocks split on §-headings. Updates FASSUNGEN.txt accordingly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Change-Id: I637cc5effbe32c094e62c070b63c470149a77c85
* Add FASSUNGEN.txt version registerMatthias Andreas Benkard2026-07-131-0/+134
Record the changes of the "Fassung vom 13.7.2026" in bureaucratic legal German, mirroring the amendment-act style the tool itself processes. Convention: add a dated section (newest first) for every day the code changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Change-Id: Ib39e4f78405b33b439be006325e2c310b72b1511