aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md21
-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
6 files changed, 257 insertions, 19 deletions
diff --git a/README.md b/README.md
index 3e4e980..84889b9 100644
--- a/README.md
+++ b/README.md
@@ -212,7 +212,7 @@ java -jar target/aendggner-0.1.0-SNAPSHOT.jar \
**`--stichtag <JJJJ-MM-TT>`**
: Die an diesem Tage geltende Fassung erzeugen. Tritt das Änderungsgesetz
gestaffelt in Kraft, so bleiben die an jenem Tage noch nicht geltenden Befehle
- unangewandt und werden gesondert ausgewiesen (§ 8 Absatz 5). Ohne diese Angabe
+ unangewandt und werden gesondert ausgewiesen (§ 8 Absatz 6). Ohne diese Angabe
werden alle Befehle angewandt.
**`--neufassung <file>`**
@@ -325,7 +325,9 @@ Streichen und Umnummerierung.
12. Verbünde aus Umnummerierung und Folgeänderung („§ 50 wird zu § 38 und wird
wie folgt geändert“, „Die bisherige Nr. 7 wird Nr. 5 und das Komma wird durch
das Wort „und“ ersetzt“). Eine Satzzeichen-Operation meint dabei stets die
- soeben umnummerierte Einheit, weil ihr Zieltext nichts unterscheidet;
+ soeben umnummerierte Einheit, weil ihr Zieltext nichts unterscheidet; eine
+ Wortoperation dagegen löst zunächst norm-weit auf und fällt erst dann auf jene
+ Einheit zurück, wenn die weite Suche mehrdeutig bleibt (§ 8 Absatz 5);
13. Verb-Rahmen, deren Unterpunkte allein die Fundstelle tragen („Es werden
ersetzt: … in § 35 Absatz 3 die Angabe „X“ jeweils durch die Angabe „Y“,“),
sowie
@@ -371,7 +373,17 @@ Verschoben wird stets nur nach vorn.
angewandt, wenn jeder seiner Teile gegriffen hat; sonst nennt die Meldung den
Teil und den Grund.
-(5) Ein Änderungsgesetz tritt nicht notwendig auf einen Schlag in Kraft. Der
+(5) Bleibt die Begleitklausel eines Verbunds bei norm-weiter Auflösung mehrdeutig,
+so entscheidet die soeben umnummerierte Einheit. Der Vorrang bleibt bei der weiten
+Suche, denn nicht jede Begleitklausel meint jene Einheit; findet sie gar keine
+Fundstelle, so meint der Befehl etwas anderes und bleibt zu Recht liegen — nur die
+Mehrdeutigkeit wird durch den engeren Skopus aufgelöst. Bleibt der Anker auch dort
+mehrdeutig, so steht die Mehrdeutigkeit im Protokoll und nicht die Begründung des
+zweiten Versuchs. Diese Regel gehört zur Anwendung und nicht zur Erkennung: Ob ein
+Anker mehrdeutig ist, steht erst nach den vorangegangenen Punkten fest — beim Lesen
+gibt es die neue Bezeichnung noch gar nicht.
+
+(6) Ein Änderungsgesetz tritt nicht notwendig auf einen Schlag in Kraft. Der
Schlussartikel wird deshalb gelesen und jeder Befehl der besondersten Anordnung
zugeordnet, die ihn erfasst („Artikel 1 Nummer 2 Buchstabe c tritt am 19. Juni
2026 in Kraft“); im Übrigen gilt die Grundregel. Mit dem Schalter `--stichtag`
@@ -420,7 +432,8 @@ gemeldet.
(5) Auf den Beispieldaten (§ 17 Absatz 2) werden hiernach alle Befehle der
Fassungen des Bundesgesetzblattes und der aktuellen Entwürfe angewandt; für
-UWG, AGG und ProdHaftG verbleibt kein Befehl zur Prüfung von Hand. Im Übrigen
+UWG, AGG, ProdHaftG und — seit dieser Welle — für den Artikel 1 der GEG-Novelle
+mit seinen 119 Befehlen verbleibt kein Befehl zur Prüfung von Hand. Im Übrigen
gilt § 1 Absatz 4.
(6) Bleibt die Aufbereitung im Einzelfall fehlerhaft, so ist nach § 6 Absatz 2
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");
+ }
}