aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthias Andreas Benkard <code@mail.matthias.benkard.de>2026-08-25 22:40:05 +0200
committerMatthias Andreas Benkard <code@mail.matthias.benkard.de>2026-08-25 22:40:05 +0200
commitff8e9837f11a1488dbcdf95fa47457ef74f864bb (patch)
tree97a7bf72ac5f796b0d7b7cfa26be3a02b87769f0 /src
parentf3e9ae405ee64c98684d99966d75bb90367adc44 (diff)
Die weite Suche behält den Vorrang, die Mehrdeutigkeit entscheidet der Verbund
„Die bisherige Nummer 18 wird Nummer 29 und nach der Angabe „Absatz 1“ werden die Wörter „oder Absatz 4“ eingefügt.“ Der Bußgeldkatalog des § 108 führt zweiunddreißig Nummern, und beinahe jede nennt einen „Absatz 1“; norm-weit aufgelöst trifft der Anker einundzwanzig Vorkommen. Der Befehl blieb deshalb liegen — zu Recht, aber unnötig: Gemeint war ersichtlich die soeben umnummerierte Einheit. Für eine Satzzeichen-Operation galt diese Auslegung schon, für eine Wortoperation ausdrücklich nicht. Das war keine Nachlässigkeit, sondern eine bewusste Entscheidung: Nicht jede Begleitklausel meint die umnummerierte Einheit, und wer sie stets dorthin zwänge, verlöre die Fälle, in denen sie anderswo greift. Die Regel ist deshalb nicht umzukehren, sondern zu verfeinern. Die weite Suche behält den Vorrang; erst wenn sie mehrere Fundstellen findet, entscheidet der engere Skopus. Findet sie gar keine, so meint der Befehl etwas anderes und bleibt liegen — der Rückfall greift allein bei Mehrdeutigkeit. Bleibt der Anker auch in der umnummerierten Einheit mehrdeutig, so steht die Mehrdeutigkeit im Protokoll und nicht die Begründung des zweiten Versuchs. Die Regel gehört zur Anwendung und nicht zur Erkennung. Ob ein Anker mehrdeutig ist, steht erst nach den neununddreißig vorangegangenen Punkten fest; der Erkenner sieht nur das Ausgangsgesetz, in dem es die Nummer 29 noch gar nicht gibt. Der Schritt trägt darum eine Rückfallstelle, die das Auffalten des Verbunds mitgibt — vorwärts und nur innerhalb desselben Verbunds. Nennt die Klausel eine Einheit derselben Art, wie die Umnummerierung sie vergibt, so wird nicht geraten. Damit ist der ganze Artikel 1 der GEG-Novelle selbsttätig angewandt: 119 von 119 Befehlen, kein Rest. Der Wortlaut der Nummer 29 gleicht der amtlichen Fassung (BJNR172810020.xml). Geprüft: 381 Tests (zuvor 378), darunter die drei Grenzen der Regel — Rückfall bei Mehrdeutigkeit, kein Rückfall bei fehlendem Zieltext, und Mehrdeutigkeit bleibt Mehrdeutigkeit. Change-Id: Id0d7080ba93ebad73fbcad42fe41c434b9a67e05
Diffstat (limited to 'src')
-rw-r--r--src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java18
-rw-r--r--src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java5
-rw-r--r--src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java97
-rw-r--r--src/test/java/eu/mulk/aendggner/EndToEndTest.java21
-rw-r--r--src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java114
5 files changed, 240 insertions, 15 deletions
diff --git a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java
index 7fc5e8a..a80e09a 100644
--- a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java
+++ b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java
@@ -40,7 +40,11 @@ public sealed interface Aenderungsbefehl {
/** „… werden die Wörter „A“ durch die Wörter „B“ ersetzt.“ */
record Ersetzung(
Stelle stelle, String alt, String neu, boolean jeweils, boolean amEnde, Provenienz provenienz)
- implements Aenderungsbefehl {}
+ implements Aenderungsbefehl {
+ public Ersetzung mitStelle(Stelle neueStelle) {
+ return new Ersetzung(neueStelle, alt, neu, jeweils, amEnde, provenienz);
+ }
+ }
/** „§ X wird wie folgt gefasst: „…““ */
record Neufassung(Stelle stelle, String neuerText, Provenienz provenienz)
@@ -66,7 +70,11 @@ public sealed interface Aenderungsbefehl {
/** „… werden nach dem Wort „A“ die Wörter „B“ eingefügt.“ */
record WoerterEinfuegung(Stelle stelle, WortAnker anker, String woerter, Provenienz provenienz)
- implements Aenderungsbefehl {}
+ implements Aenderungsbefehl {
+ public WoerterEinfuegung mitStelle(Stelle neueStelle) {
+ return new WoerterEinfuegung(neueStelle, anker, woerter, provenienz);
+ }
+ }
/**
* „Nach § 28 wird folgender § 28a eingefügt: „…““
@@ -111,7 +119,11 @@ public sealed interface Aenderungsbefehl {
/** „… werden die Wörter „A“ gestrichen.“ */
record Streichung(Stelle stelle, String woerter, Provenienz provenienz)
- implements Aenderungsbefehl {}
+ implements Aenderungsbefehl {
+ public Streichung mitStelle(Stelle neueStelle) {
+ return new Streichung(neueStelle, woerter, provenienz);
+ }
+ }
/** „Der bisherige Absatz 2 wird Absatz 3.“ */
record Umnummerierung(Stelle stelle, Stelle neu, Provenienz provenienz)
diff --git a/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java b/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java
index 192d244..c825a64 100644
--- a/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java
+++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java
@@ -1757,6 +1757,11 @@ final class BefehlErkenner {
// Nach einer Umnummerierung wird die Wortoperation nicht auf die neue Stelle festgenagelt: sie
// löst norm-weit auf (findet ihren Zieltext im umbenannten Absatz, ohne eine womöglich schon
// bestehende Zielnummer fälschlich zu treffen) — das übernehmen die Zweige weiter unten.
+ // Bleibt die weite Auflösung mehrdeutig, so entscheidet erst beim Anwenden die soeben
+ // umnummerierte Einheit (siehe BefehlAnwender.rueckfall). Dort und nicht hier gehört die
+ // Regel hin: Ob ein Anker mehrdeutig ist, steht erst nach den vorangegangenen Punkten fest —
+ // der Erkenner sieht nur das Ausgangsgesetz, in dem es die neue Bezeichnung noch gar nicht
+ // gibt.
if (REINE_WORT_OPERATION.matcher(rechts).lookingAt()
&& !(linksBefehl instanceof Umnummerierung)) {
var praefix0 = lokativerPraefix(links);
diff --git a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
index a46defb..56b610e 100644
--- a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
+++ b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
@@ -35,6 +35,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
/**
@@ -107,7 +108,29 @@ public final class BefehlAnwender {
ergebnisse[index] = angewandt(schritt.teil(), "(Gesetzesüberschrift)");
continue;
}
- ergebnisse[index] = wendeAn(normen, gliederungen, schritt.teil());
+ var ergebnis = wendeAn(normen, gliederungen, schritt.teil());
+ if (ergebnis.status() == Status.MANUELL_PRUEFEN
+ && ergebnis.grund() == Grund.MEHRDEUTIG
+ && schritt.rueckfallStelle() != null) {
+ var enger = mitStelle(schritt.teil(), schritt.rueckfallStelle());
+ // Der zweite Versuch ist gefahrlos: Jeder Zweig meldet den Fehlschlag, bevor er schreibt.
+ // Gelingt er nicht, so bleibt der erste Protokolleintrag stehen — die Mehrdeutigkeit ist
+ // der wahre Befund und darf nicht durch ein „nicht auffindbar“ der zweiten Auflösung
+ // verdeckt werden.
+ if (enger != null) {
+ var zweiter = wendeAn(normen, gliederungen, enger);
+ if (zweiter.status() == Status.ANGEWANDT) {
+ ergebnis =
+ new AngewandteAenderung(
+ schritt.teil(),
+ Status.ANGEWANDT,
+ zweiter.begruendung(),
+ zweiter.betroffeneEnbez(),
+ null);
+ }
+ }
+ }
+ ergebnisse[index] = ergebnis;
}
protokoll.addAll(verdichte(befehle, schritte, ergebnisse));
@@ -129,8 +152,17 @@ public final class BefehlAnwender {
* Protokolleintrag sein Ergebnis eingeht. Ein Verbund ({@link Sammelbefehl}) zerfällt in je einen
* Schritt pro Teilbefehl; jeder andere Befehl ist sein eigener einziger Schritt ({@code
* ganzerBefehl}).
+ *
+ * @param rueckfallStelle die Einheit, die eine vorangehende Umnummerierung desselben Verbunds
+ * soeben neu bezeichnet hat; {@code null} außerhalb eines Verbunds und vor der ersten
+ * Umnummerierung. Sie kommt nur zum Zuge, wenn die norm-weite Auflösung mehrdeutig bleibt
+ * (siehe {@link #anwenden}).
*/
- private record Schritt(int befehlIndex, Aenderungsbefehl teil, boolean ganzerBefehl) {}
+ private record Schritt(
+ int befehlIndex,
+ Aenderungsbefehl teil,
+ boolean ganzerBefehl,
+ @Nullable Stelle rueckfallStelle) {}
/** Faltet die Befehlsliste zur Schrittliste auf, in Dokumentreihenfolge. */
private static List<Schritt> schritte(List<Aenderungsbefehl> befehle) {
@@ -140,23 +172,78 @@ public final class BefehlAnwender {
if (befehl instanceof Sammelbefehl s) {
falte(s, i, schritte);
} else {
- schritte.add(new Schritt(i, befehl, true));
+ schritte.add(new Schritt(i, befehl, true, null));
}
}
return schritte;
}
private static void falte(Sammelbefehl befehl, int befehlIndex, List<Schritt> ziel) {
+ // Innerhalb eines Verbunds merkt sich das Auffalten die zuletzt gesehene Umnummerierung: Ihre
+ // neue Bezeichnung ist der Rückfall für die nachfolgenden Wortoperationen desselben Verbunds.
+ // Nur vorwärts und nur innerhalb dieses Verbunds — ein späterer Punkt des Dokuments hat mit
+ // ihr nichts zu schaffen.
+ Stelle zuletztUmnummeriert = null;
for (var teil : befehl.teilbefehle()) {
if (teil instanceof Sammelbefehl geschachtelt) {
falte(geschachtelt, befehlIndex, ziel);
- } else {
- ziel.add(new Schritt(befehlIndex, teil, false));
+ continue;
+ }
+ ziel.add(new Schritt(befehlIndex, teil, false, rueckfall(zuletztUmnummeriert, teil)));
+ if (teil instanceof Umnummerierung um && !um.neu().istLeer()) {
+ zuletztUmnummeriert = um.neu();
}
}
}
/**
+ * Die Stelle, auf die eine Begleitklausel zurückfällt, wenn ihre norm-weite Auflösung mehrdeutig
+ * bleibt: die soeben umnummerierte Einheit.
+ *
+ * <p>Der Vorrang bleibt bei der norm-weiten Auflösung, denn nicht jede Begleitklausel meint die
+ * umnummerierte Einheit — „Die bisherige Nr. 11 wird Nr. 12 und die Angabe ‚schriftliche‘ wird
+ * gestrichen“ kann sehr wohl anderswo greifen. Erst wenn die weite Suche mehrere Fundstellen
+ * findet, entscheidet der engere Skopus; findet sie gar keine, so meint der Befehl etwas anderes
+ * und bleibt zu Recht liegen.
+ *
+ * <p>Der Rückfall greift nur bei Wortoperationen — Strukturbefehle nennen ihren Skopus ohnehin —
+ * und nur, wenn die Klausel keine eigene feinere Einheit nennt: Wer „in Satz 3“ sagt, hat seinen
+ * Skopus bereits bestimmt.
+ */
+ private static @Nullable Stelle rueckfall(
+ @Nullable Stelle zuletztUmnummeriert, Aenderungsbefehl teil) {
+ if (zuletztUmnummeriert == null
+ || !(teil instanceof Ersetzung
+ || teil instanceof Streichung
+ || teil instanceof WoerterEinfuegung)) {
+ return null;
+ }
+ if (zuletztUmnummeriert.paragraph().isPresent()) {
+ return zuletztUmnummeriert;
+ }
+ // Die neue Bezeichnung tritt zum Rahmen der Klausel hinzu — aber nur, wenn dieser nicht
+ // selbst schon eine Einheit derselben Art nennt. „In Absatz 3 …“ neben einer Umnummerierung
+ // auf Absatz 8 ergäbe „Absatz 3 Absatz 8“; wo das droht, wird nicht geraten.
+ var vorhandeneArten =
+ teil.stelle().komponenten().stream().map(k -> k.getClass()).collect(Collectors.toSet());
+ if (zuletztUmnummeriert.komponenten().stream()
+ .anyMatch(k -> vorhandeneArten.contains(k.getClass()))) {
+ return null;
+ }
+ return teil.stelle().plus(zuletztUmnummeriert);
+ }
+
+ /** Derselbe Befehl, auf eine engere Stelle festgelegt. */
+ private static @Nullable Aenderungsbefehl mitStelle(Aenderungsbefehl befehl, Stelle stelle) {
+ return switch (befehl) {
+ case Ersetzung e -> e.mitStelle(stelle);
+ case Streichung st -> st.mitStelle(stelle);
+ case WoerterEinfuegung w -> w.mitStelle(stelle);
+ default -> null;
+ };
+ }
+
+ /**
* Anwendungsreihenfolge der Schritte. Sie folgt dem Dokument, mit einer Ausnahme:
* Umnummerierungen beziehen sich stets auf die ursprüngliche Zählung, nicht auf den Stand nach
* den vorangegangenen Punkten. Wer eine Bezeichnung räumt, muss daher vor den kommen, der sie neu
diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java
index 7a6dcee..41f30e5 100644
--- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java
+++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java
@@ -293,8 +293,8 @@ class EndToEndTest {
.filter(a -> a.status() == BefehlAnwender.Status.MANUELL_PRUEFEN)
.map(a -> a.befehl().provenienz().gliederungsPfad())
.toList();
- assertThat(manuellPfade).containsExactly("40. a) hh)");
- assertThat(anwendung.anzahlAngewandt()).isEqualTo(118);
+ assertThat(manuellPfade).isEmpty();
+ assertThat(anwendung.anzahlAngewandt()).isEqualTo(119);
// Die Kaskade des § 108 Absatz 1 geht lückenlos auf: 32 Nummern, keine doppelt, keine fehlend.
var nummern =
@@ -312,6 +312,13 @@ class EndToEndTest {
assertThat(nummern).hasSize(32).endsWith("32");
var neu = anwendung.neu();
+ // Die Begleitklausel der Nummer 18/29 hat allein dort gegriffen — der Wortlaut gleicht der
+ // amtlichen Nachfassung (BJNR172810020.xml, § 108 Absatz 1 Nummer 29).
+ var paragraph108 = neu.norm("§ 108").orElseThrow().absaetze().get(0).text();
+ assertThat(paragraph108)
+ .contains("29. entgegen § 96 Absatz 1 oder Absatz 4 eine Bestätigung nicht")
+ .contains("30. entgegen § 96 Absatz 5 Satz 2 eine Abrechnung nicht");
+
// Die Überschrift der Nummer 1 der Anlage 8 ist geändert — und nur sie: Der Titel der Anlage
// trägt seinen eigenen Wortlaut unversehrt, den Punkt 43. a) ihm gegeben hat.
var anlage8 = neu.norm("Anlage 8").orElseThrow();
@@ -1722,14 +1729,14 @@ class EndToEndTest {
assumeTrue(Files.exists(xml) && Files.exists(pdf), "GEG-Beispieldaten fehlen");
var vollstaendig = Pipeline.erzeugeSynopse(Pipeline.Auftrag.von(xml, List.of(pdf)));
- assertThat(vollstaendig.anzahlAngewandt()).isEqualTo(118);
- assertThat(vollstaendig.anzahlManuell()).isEqualTo(1);
+ assertThat(vollstaendig.anzahlAngewandt()).isEqualTo(119);
+ assertThat(vollstaendig.anzahlManuell()).isZero();
var anfang2024 =
Pipeline.erzeugeSynopse(
Pipeline.Auftrag.von(xml, List.of(pdf)).mitStichtag(LocalDate.of(2024, 1, 1)));
- assertThat(anfang2024.anzahlAngewandt()).isEqualTo(117);
- assertThat(anfang2024.anzahlManuell()).isEqualTo(1);
+ assertThat(anfang2024.anzahlAngewandt()).isEqualTo(118);
+ assertThat(anfang2024.anzahlManuell()).isZero();
assertThat(anfang2024.html())
.contains("Am Stichtag noch nicht in Kraft")
.contains("Tritt erst am 1. Oktober 2024 in Kraft");
@@ -1737,7 +1744,7 @@ class EndToEndTest {
var oktober2024 =
Pipeline.erzeugeSynopse(
Pipeline.Auftrag.von(xml, List.of(pdf)).mitStichtag(LocalDate.of(2024, 10, 1)));
- assertThat(oktober2024.anzahlAngewandt()).isEqualTo(118);
+ assertThat(oktober2024.anzahlAngewandt()).isEqualTo(119);
}
/**
diff --git a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java
index 0e186ad..a1f5cff 100644
--- a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java
+++ b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java
@@ -4,6 +4,7 @@ package eu.mulk.aendggner.anwendung;
import static org.assertj.core.api.Assertions.assertThat;
+import eu.mulk.aendggner.aenderung.Aenderungsbefehl;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Anfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Aufhebung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.BereichsUmnummerierung;
@@ -1777,4 +1778,117 @@ class BefehlAnwenderTest {
assertThat(ergebnis.protokoll().get(0).grund()).isEqualTo(Grund.NICHT_UNTERSTUETZT);
assertThat(ergebnis.neu().norm("Anlage 8").orElseThrow().titel()).isEqualTo("Anforderungen");
}
+
+ private static Gesetz bussgeldkatalog() {
+ return new Gesetz(
+ "TestG",
+ "Testgesetz",
+ "TestG",
+ List.of(
+ new Norm(
+ "§ 108",
+ "Bußgeldvorschriften",
+ null,
+ List.of(
+ new Absatz(
+ "1",
+ "17. entgegen § 90 Absatz 1 etwas tut,\n"
+ + "18. entgegen § 96 Absatz 1 etwas unterlässt,\n"
+ + "19. entgegen § 97 Absatz 1 etwas anderes tut,")),
+ false)));
+ }
+
+ private static Sammelbefehl verbund(Aenderungsbefehl... teile) {
+ return new Sammelbefehl(List.of(teile));
+ }
+
+ /**
+ * „Die bisherige Nummer 18 wird Nummer 29 und nach der Angabe ‚Absatz 1‘ werden die Wörter ‚oder
+ * Absatz 4‘ eingefügt.“ — Der Anker steht in jeder Nummer; norm-weit ist er mehrdeutig. Erst dann
+ * entscheidet die soeben umnummerierte Einheit.
+ */
+ @Test
+ void mehrdeutigeBegleitklauselFaelltAufDieUmnummerierteEinheitZurueck() {
+ var rahmen = stelle(new Stelle.Paragraph("108"), new Stelle.AbsatzNr("1"));
+ var befehl =
+ verbund(
+ new Umnummerierung(
+ rahmen.plus(stelle(new Stelle.NummerNr("18"))),
+ stelle(new Stelle.NummerNr("29")),
+ PROV),
+ new WoerterEinfuegung(
+ rahmen, new WortAnker.NachWoertern("Absatz 1"), "oder Absatz 4", PROV));
+
+ var ergebnis = BefehlAnwender.anwenden(bussgeldkatalog(), List.of(befehl));
+ assertThat(ergebnis.protokoll()).allMatch(a -> a.status() == Status.ANGEWANDT);
+
+ var text = ergebnis.neu().norm("§ 108").orElseThrow().absaetze().get(0).text();
+ // Allein die umnummerierte Nummer hat die Wörter bekommen.
+ assertThat(text).contains("29. entgegen § 96 Absatz 1 oder Absatz 4 etwas unterlässt,");
+ assertThat(text).contains("17. entgegen § 90 Absatz 1 etwas tut,");
+ assertThat(text).contains("19. entgegen § 97 Absatz 1 etwas anderes tut,");
+ }
+
+ /**
+ * Der Rückfall greift nur bei Mehrdeutigkeit, nie bei fehlendem Zieltext: Wer seinen Anker
+ * nirgends findet, meint etwas anderes — ihn in die umnummerierte Einheit zu zwingen wäre eine
+ * Falschanwendung, keine Verfeinerung.
+ */
+ @Test
+ void fehlenderZieltextFaelltNichtZurueck() {
+ var rahmen = stelle(new Stelle.Paragraph("108"), new Stelle.AbsatzNr("1"));
+ var befehl =
+ verbund(
+ new Umnummerierung(
+ rahmen.plus(stelle(new Stelle.NummerNr("18"))),
+ stelle(new Stelle.NummerNr("29")),
+ PROV),
+ new WoerterEinfuegung(
+ rahmen, new WortAnker.NachWoertern("Paragraph 1"), "oder Absatz 4", PROV));
+
+ var ergebnis = BefehlAnwender.anwenden(bussgeldkatalog(), List.of(befehl));
+ assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.MANUELL_PRUEFEN);
+ assertThat(ergebnis.neu().norm("§ 108").orElseThrow().absaetze().get(0).text())
+ .doesNotContain("oder Absatz 4");
+ }
+
+ /**
+ * Bleibt der Anker auch in der umnummerierten Einheit mehrdeutig, so bleibt der Befehl liegen —
+ * und mit der Begründung des <em>ersten</em> Versuchs: Die Mehrdeutigkeit ist der wahre Befund.
+ */
+ @Test
+ void mehrdeutigBleibtMehrdeutig() {
+ var gesetz =
+ new Gesetz(
+ "TestG",
+ "Testgesetz",
+ "TestG",
+ List.of(
+ new Norm(
+ "§ 108",
+ null,
+ null,
+ List.of(
+ new Absatz(
+ "1",
+ "17. entgegen § 90 Absatz 1 etwas tut,\n"
+ + "18. entgegen § 96 Absatz 1 und § 97 Absatz 1 etwas unterlässt,")),
+ false)));
+ var rahmen = stelle(new Stelle.Paragraph("108"), new Stelle.AbsatzNr("1"));
+ var befehl =
+ verbund(
+ new Umnummerierung(
+ rahmen.plus(stelle(new Stelle.NummerNr("18"))),
+ stelle(new Stelle.NummerNr("29")),
+ PROV),
+ new WoerterEinfuegung(
+ rahmen, new WortAnker.NachWoertern("Absatz 1"), "oder Absatz 4", PROV));
+
+ var ergebnis = BefehlAnwender.anwenden(gesetz, List.of(befehl));
+ assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.MANUELL_PRUEFEN);
+ assertThat(ergebnis.protokoll().get(0).grund()).isEqualTo(Grund.MEHRDEUTIG);
+ assertThat(ergebnis.protokoll().get(0).begruendung()).contains("mehrdeutig");
+ assertThat(ergebnis.neu().norm("§ 108").orElseThrow().absaetze().get(0).text())
+ .doesNotContain("oder Absatz 4");
+ }
}