From 5203e9407979dbb920bc796ee457ce7c12911ef9 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sun, 23 Aug 2026 16:00:25 +0200 Subject: Die Anlage wird eine Norm, ihre Nummern noch nicht MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Klartext-Parser trägt fortan Anlagen: „Anlage“, „Anlage 2“ und „Anhang“ eröffnen eine eigene Norm, deren Bezeichnung genau so lautet wie im gii-XML, und vom ersten Anlagenkopf an gehört alles Folgende zu ihr — ihre inneren Überschriften gliedern nicht mehr das Gesetz, und ein Paragraph, den sie zitieren, eröffnet keine Norm. Berlin ist damit zur Hälfte belegt. Artikel 2 des Änderungsgesetzes schreibt das LAF-Errichtungsgesetz vollständig fort; alle fünf Normen gleichen danach der amtlichen Fassung vom 12. Juni 2026. Artikel 1 bleibt bei der Erkennung, und der Grund ist benannt statt umgangen: Fünf seiner sechs Befehle zielen auf Einheiten der Anlage, die dort als Überschriften stehen — „Nummer 6“, „Nummer 23“, „Nummer 31“ —, während der Stellenauflöser eine Aufzählungsmarke „6.“ sucht, die im Text der Anlage vielfach vorkommt. Die Gegenprobe belegt es: Werden die Überschriften versuchsweise in Marken umgeschrieben, steigt die Zahl der angewandten Befehle von zwei auf drei, mehrdeutig bleibt der Rest. Die Nummern einer Anlage brauchen einen eigenen Rang zwischen Norm und Absatz. Solange er fehlt, bringt die Beilage von zweimal 380 kB Stammfassung keinen Prüfgewinn; ihr Bezugsweg steht in „Berlin/SOURCES“ und führt in zwei Abrufen wieder dorthin. Dort ist auch der zweite Berliner Befund festgehalten: Das Portal setzt die amtlichen Satznummern als angeklebte Ziffern statt als Superskripte. Geprüft durch „mvnw verify“: 328 Tests, keine bestehende gepinnte Zahl bewegt, REUSE-Konformität 165 von 165. Co-Authored-By: Claude Opus 5 Change-Id: Ifdda599a8c641ce66d0370b2a027f556adb4d86d --- src/test/java/eu/mulk/aendggner/EndToEndTest.java | 27 +++++++------- .../gesetz/land/LandesRechtTextParserTest.java | 41 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 13 deletions(-) (limited to 'src/test/java/eu') diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java index df80a04..8fa50f5 100644 --- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java +++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java @@ -782,12 +782,12 @@ class EndToEndTest { * Spaltenspikes fest — die Spaltenreihenfolge des Inhaltsstroms ist bereits die Lesereihenfolge, * eine koordinatenbasierte Spaltenerkennung ist dafür nicht nötig. * - *

Kein voller Akzeptanztest: gesetze.berlin.de ist wie das schleswig-holsteinische Portal eine - * anmeldepflichtige juris-Anwendung, die Stammfassungen sind daraus nicht zu beschaffen. Artikel - * 1 ändert zudem eine *Anlage*; anlagenbezogene Befehle wendet ÄndGgner an (siehe GEG), doch der - * {@link eu.mulk.aendggner.gesetz.land.LandesRechtTextParser} kennt nur „§“- und „Art.“-Normköpfe - * — eine handgepflegte Stammfassung könnte diese Anlage nicht tragen (dieselbe Grenze, an der - * Baden-Württemberg zurückgestellt wurde). + *

Artikel 2 (LAF-Errichtungsgesetz) ist ein voller Akzeptanzfall: beide Befehle angewandt, + * alle fünf Normen gleich der amtlichen Nachfassung. Für Artikel 1 (ASOG) reicht die Prüfung bis + * zur Befehlserkennung. Fünf seiner sechs Befehle zielen auf die Anlage, deren Einheiten + * dort nicht als Aufzählungsmarken, sondern als Überschriften gesetzt sind („Nummer 6“, „Nummer + * 23“); sie brauchen einen eigenen Rang zwischen Norm und Absatz, den das Datenmodell noch nicht + * führt. Die Begründung im einzelnen steht in {@code Berlin/SOURCES}. */ @Test void asogLafAendGBerlin() throws Exception { @@ -807,13 +807,11 @@ class EndToEndTest { // Artikel 2 trägt sein Ziel in der Änderungsformel („§ 2 Satz 1 des Gesetzes zur Errichtung // …“); beide Punkte erben es als Kontext. - var laf = - new Gesetz( - "LAF-ErrichtungsG", - "Gesetz zur Errichtung eines Landesamtes für Flüchtlingsangelegenheiten und" - + " Unterbringung", - null, - List.of()); + var altLaf = SAMPLEDATA.resolve("Berlin/LAF-ErrG-alt.txt"); + assumeTrue(Files.exists(altLaf), "Berliner Stammfassung fehlt"); + var laf = new eu.mulk.aendggner.gesetz.land.LandesRechtLoader().load(altLaf); + // Dieses Gesetz führt kein Inhaltsverzeichnis; der Wortlaut beginnt beim ersten Normkopf. + assertThat(laf.normen()).hasSize(5); var ergebnis = new AenderungsgesetzParser().parse(text, laf, null); assertThat(ergebnis.artikel()).containsExactly("2"); assertThat(ergebnis.befehle()).hasSize(2); @@ -858,6 +856,9 @@ class EndToEndTest { // am nächsten Aufzählungspunkt verschlänge das offene Zitat die Punkte cc) und c). assertThat(ZitatExtraktor.extrahiere(text).warnungen()) .anyMatch(w -> w.startsWith("Zitat vor dem Aufzählungspunkt „cc)“ nicht geschlossen")); + + // Artikel 2 wird vollständig angewandt und gleicht danach der amtlichen Nachfassung. + pruefeGegenNachfassung(laf, ergebnis, "Berlin/LAF-ErrG-neu.txt"); } /** diff --git a/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java b/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java index e0cb1fc..bed8f9e 100644 --- a/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java +++ b/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java @@ -258,4 +258,45 @@ class LandesRechtTextParserTest { org.assertj.core.groups.Tuple.tuple("1.", "Der Rundfunkrat")); assertThat(gesetz.norm("§ 15").orElseThrow().gliederung().titel()).isEqualTo("Der Rundfunkrat"); } + + /** + * Eine Anlage ist eine eigene Norm; ihre enbez lautet genau wie im gii-XML („Anlage“, „Anlage 2“, + * „Anhang“), damit {@code Stelle.anlagenEnbez()} sie unverändert trifft. Alles hinter ihrem Kopf + * gehört zu ihr: Ihre inneren Überschriften gliedern nicht das Gesetz, und ein Paragraph, den sie + * zitiert, eröffnet keine Norm. Nur eine weitere Anlage beendet sie. + */ + @Test + void erkenntAnlagenAlsEigeneNormen() { + var gesetz = + LandesRechtTextParser.parse( + """ + Beispielgesetz + (BeispG) + Vom 1. Januar 2020 + Erster Abschnitt Allgemeines + § 1 Zweck + (1) Dieses Gesetz dient der Erprobung. + Anlage + Zuständigkeitskatalog + (zu § 1 Absatz 1) + Erster Abschnitt Aufgaben der Behörden + (1) Die erste Aufgabe. + (2) Die zweite Aufgabe; § 1 bleibt unberührt. + Anlage 2 + Muster + (1) Das Muster. + """); + + assertThat(gesetz.normen()) + .extracting(eu.mulk.aendggner.gesetz.Norm::enbez) + .containsExactly("§ 1", "Anlage", "Anlage 2"); + // Die Überschrift innerhalb der Anlage ist Inhalt, keine Gliederung des Gesetzes. + assertThat(gesetz.gliederungen()) + .extracting(Gliederung::bezeichnung) + .containsExactly("Erster Abschnitt"); + assertThat(gesetz.norm("Anlage").orElseThrow().gesamtText()) + .contains("Erster Abschnitt Aufgaben der Behörden") + .contains("§ 1 bleibt unberührt"); + assertThat(gesetz.norm("Anlage 2").orElseThrow().gesamtText()).contains("Das Muster"); + } } -- cgit v1.2.1