From 14ec52a1070285a12a6bc5a0f4859996d468b59e Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sat, 22 Aug 2026 16:41:57 +0200 Subject: =?UTF-8?q?Die=20Einr=C3=BCckung=20tr=C3=A4gt=20die=20Gliederung,?= =?UTF-8?q?=20nicht=20blo=C3=9F=20das=20Satzbild?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die vorangegangene Fassung hatte zwei Mängel festgehalten, aber nicht behoben: Der Block aus „Nach Nr. 4 werden die folgenden Nrn. 5 bis 7 eingefügt“ trat ans Ende des Absatzes statt hinter die Nr. 4, und die Heilung des Weißraums nach einer Streichung verkürzte die Einrückung der Aufzählungszeilen. Beide wiegen schwerer als alles sonst Offene, denn sie führen zu einem falschen Ergebnis, ohne es anzuzeigen: Der Befehl gilt als angewandt, der Abschnitt „Manuell prüfen“ schweigt, und allein der Wortlaut weicht ab. Damit war das Leitprinzip des Erzeugnisses an dieser Stelle verfehlt. Bei der Behebung hat sich ergeben, dass die beiden nicht nebeneinanderstanden, sondern eine Ursache teilten. Die Neufassung einer Nummer oder eines Buchstabens setzte ihren Wortlaut ohne Einrückung, also in die erste Spalte. Der Zeilenblock einer Aufzählungsmarke reicht aber so weit, wie tiefer eingerückt wird; eine in der ersten Spalte stehende Zeile nimmt daher den gesamten Rest des Absatzes als ihre Kindzeilen an. Der nachfolgende Einfügebefehl fand seinen Anker mithin am Ende des Absatzes und stand richtig, wo er falsch stand. Die Einrückung ist im kanonischen Klartext kein Satzbild, sondern die Zugehörigkeit einer Zeile zu ihrer Einheit; die Neufassung setzt sie nunmehr wie die Ersetzung, und die Heilung nach einer Streichung glättet allein die Naht, an der Text herausgenommen wurde. Die zeilenweise Gegenprobe an der amtlichen Nachfassung hat darüber hinaus zwei Abweichungen gezeigt, die keine Mängel der Reihenfolge waren. Zum einen hielt der leere Platzhalter „7. (aufgehoben)“ eine Bezeichnung, die der eingefügte Block neu vergibt; er weicht fortan, wie er es bei der Umnummerierung auf eine weggefallene Bezeichnung längst tut. Verdrängt wird dabei nur ein Platzhalter, niemals ein Wortlaut — der Platzhalter des Absatzes 2, den kein Befehl anrührt, bleibt stehen. Zum anderen führt der Satz des Gesetzblatts zwischen der Marke einer Aufzählungszeile und ihrem Text die Tabulatorspalte des Setzers, der kanonische Klartext dagegen ein Leerzeichen; ohne dessen Rückführung trügen gerade die neu gesetzten Zeilen ein anderes Satzbild als die unberührten. Artikel 56 Absatz 1 des Bayerischen Jagdgesetzes gleicht damit in Aufbau und Wortlaut der amtlichen Nachfassung. Die beiden Zusicherungen des Akzeptanztests, die den Mangel festhielten, sind umgekehrt; drei Prüfungen der zugrunde liegenden Regeln treten hinzu. Dreihundertfünfzehn Testfälle bestehen, und keine der gepinnten Zahlen der übrigen Belegfälle hat sich geändert. Die Browserfassung ist übersetzt worden und bleibt auslieferbar; ihr Lauf im Browser ist mangels verbundener Erweiterung nicht in Augenschein genommen worden. Co-Authored-By: Claude Opus 5 Change-Id: I89b2fafa3e2185dbd6abfe0aa6b7bbbd04f6828f --- src/test/java/eu/mulk/aendggner/EndToEndTest.java | 33 +++++--- .../aendggner/anwendung/BefehlAnwenderTest.java | 96 ++++++++++++++++++++++ 2 files changed, 117 insertions(+), 12 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 865afe6..fe0ab21 100644 --- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java +++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java @@ -271,8 +271,9 @@ class EndToEndTest { // vorrücken, ihre Begleitänderungen aber an ihrer Dokumentstelle bleiben — die Wortfolge // „schriftliche“ etwa steht erst nach dem vorangehenden Punkt nur noch einmal im // Artikel und ist damit eindeutig. - // „Kein Rest“ heißt: jeder Befehl hat gegriffen. Es heißt nicht, dass die Norm in allem der - // amtlichen Nachfassung gleicht — was daran noch fehlt, steht weiter unten an Art. 56. + // „Kein Rest“ heißt zunächst nur: jeder Befehl hat gegriffen. Dass Art. 56 Abs. 1 darüber + // hinaus in Aufbau und Wortlaut der amtlichen Nachfassung gleicht, prüfen die + // Zusicherungen weiter unten. var anwendung = BefehlAnwender.anwenden(gesetz, parseErgebnis.befehle()); assertThat(anwendung.protokoll()).hasSameSizeAs(parseErgebnis.befehle()); var manuellPfade = @@ -298,16 +299,24 @@ class EndToEndTest { // Abs. 2 Nr. 12 Buchst. b führt ihre Marke allein auf der Zeile — sie ist trotzdem auflösbar. assertThat(art56.absaetze().get(1).text()).contains("(§ 2 Abs. 3 BJagdG)"); - // Offen bleibt an dieser Norm eine Frage, die mit der Reihenfolge nichts zu tun hat und schon - // vorher so stand: Der eingefügte Block „Nach Nr. 4 werden die folgenden Nrn. 5 bis 7 - // eingefügt“ landet am Ende des Absatzes statt hinter der Nr. 4, und der leere Platzhalter - // „7. (aufgehoben)“ der Altfassung bleibt zwischen den Nrn. 9 und 10 stehen. Beides ist hier - // festgehalten, damit es nicht unbemerkt bleibt — der Befehl gilt als angewandt, die Stellung - // seines Blocks ist aber falsch. - assertThat(katalog).contains("7. (aufgehoben)"); - assertThat(katalog.indexOf("5.\t den Verboten des Art. 29 Abs. 2")) - .as("die eingefügten Nrn. 5 bis 7 stehen (noch) hinter der Nr. 16") - .isGreaterThan(katalog.indexOf("16.")); + // Der Block aus „Nach Nr. 4 werden die folgenden Nrn. 5 bis 7 eingefügt“ steht an seinem Platz + // — zwischen der Nr. 4 und der Nr. 8 — und nicht mehr am Ende des Absatzes. Dass er dort + // landete, lag an der Neufassung der Nr. 4 einen Punkt zuvor: Sie setzte ihren Wortlaut ohne + // Einrückung, worauf der Zeilenblock der Nr. 4 bis ans Absatzende reichte (er reicht so weit, + // wie tiefer eingerückt wird). + assertThat(katalog.indexOf(" 5. den Verboten des Art. 29 Abs. 2")) + .as("die eingefügten Nrn. 5 bis 7 stehen zwischen der Nr. 4 und der Nr. 8") + .isGreaterThan(katalog.indexOf(" 4. entgegen Art. 29 Abs. 1")) + .isLessThan(katalog.indexOf(" 8. entgegen Art. 31 Abs. 2")); + // Der leere Platzhalter „7. (aufgehoben)“ der Altfassung weicht dem eingefügten Block, weil + // dieser dieselbe Bezeichnung vergibt — dieselbe Regel wie bei der Umnummerierung auf eine + // weggefallene Bezeichnung. Verdrängt wird dabei nur ein Platzhalter, nie ein Wortlaut: Der + // Platzhalter „1. (aufgehoben)“ des Abs. 2, den kein Befehl anrührt, bleibt unberührt stehen. + assertThat(katalog).doesNotContain("(aufgehoben)"); + assertThat(art56.absaetze().get(1).text()).contains("1. (aufgehoben)"); + // Die Einrückung der Aufzählungszeilen übersteht die Streichungen des Hefts: Sie wird nicht + // mehr von der Leerzeichen-Heilung mitgenommen, die nur noch die Naht der Streichung glättet. + assertThat(katalog).contains("\n 12. ohne Begleitung").doesNotContain("\n 12. "); // Art. 29a Abs. 5 trägt nach der Kaskade die neue Behördenbezeichnung und den eingefügten Satz. var art29a = anwendung.neu().norm("Art. 29a").orElseThrow(); diff --git a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java index 7e7da85..212a037 100644 --- a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java +++ b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java @@ -1192,6 +1192,102 @@ class BefehlAnwenderTest { .isEqualTo("Zweck dieses Gesetzes ist die Erprobung, auch in Teilen,."); } + /** + * Ein Katalog, wie ihn das Stammgesetz führt: Aufzählungszeilen auf zwei Leerzeichen, darunter + * ein weggefallener Platzhalter. + */ + private static Gesetz katalog() { + return new Gesetz( + "TestG", + "Gesetz zur Erprobung", + "Testgesetz", + List.of( + new Norm( + "§ 1", + "Zweck", + null, + List.of( + new Absatz( + "1", + "Erprobt wird, wer\n" + + " 1. Befehle erkennt,\n" + + " 2. Befehle schriftlich anwendet,\n" + + " 3. (weggefallen)\n" + + " 4. Ergebnisse prüft.")), + false)), + List.of()); + } + + /** + * Die Neufassung einer Nummer setzt ihren Wortlaut auf die Einrückung der alten Einheit. Ohne sie + * stünde die Zeile in Spalte 0 und der Zeilenblock ihrer Marke reichte bis ans Absatzende — ein + * nachfolgender Einfügebefehl träte dann an die falsche Stelle. + */ + @Test + void neufassungEinerNummerBehaeltDieEinrueckung() { + var befehl = + new Neufassung( + stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("1"), new Stelle.NummerNr("2")), + "2. Befehle anwendet,", + PROV); + + var ergebnis = BefehlAnwender.anwenden(katalog(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "§ 1", 0)) + .contains("\n 2. Befehle anwendet,\n") + .doesNotContain("\n2. "); + } + + /** + * Die Heilung des Weißraums nach einer Streichung glättet die Naht und sonst nichts: Die + * Einrückung der Aufzählungszeilen bleibt, wie sie war. + */ + @Test + void streichungLaesstDieEinrueckungUnberuehrt() { + var befehl = + new Streichung( + stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("1")), "schriftlich ", PROV); + + var ergebnis = BefehlAnwender.anwenden(katalog(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "§ 1", 0)) + .isEqualTo( + "Erprobt wird, wer\n" + + " 1. Befehle erkennt,\n" + + " 2. Befehle anwendet,\n" + + " 3. (weggefallen)\n" + + " 4. Ergebnisse prüft."); + } + + /** + * Vergibt ein eingefügter Block eine Bezeichnung, die ein leerer Platzhalter noch hält, so weicht + * dieser — dieselbe Regel wie bei der Umnummerierung auf eine weggefallene Bezeichnung. + */ + @Test + void eingefuegterBlockVerdraengtDenWeggefallenenPlatzhalter() { + var befehl = + new StrukturEinfuegung( + stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("1"), new Stelle.NummerNr("2")), + false, + Ebene.NUMMER, + "3", + "3. Befehle ordnet,", + PROV); + + var ergebnis = BefehlAnwender.anwenden(katalog(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "§ 1", 0)) + .isEqualTo( + "Erprobt wird, wer\n" + + " 1. Befehle erkennt,\n" + + " 2. Befehle schriftlich anwendet,\n" + + " 3. Befehle ordnet,\n" + + " 4. Ergebnisse prüft."); + } + private static String absatzText(Gesetz gesetz, String enbez, int index) { return gesetz.norm(enbez).orElseThrow().absaetze().get(index).text(); } -- cgit v1.2.1