aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Andreas Benkard <code@mail.matthias.benkard.de>2026-08-25 22:55:02 +0200
committerMatthias Andreas Benkard <code@mail.matthias.benkard.de>2026-08-25 22:55:02 +0200
commita231681883935e0bee2f453b2a4ef3d798ed3534 (patch)
treed7cff50c1dd9b70709e1d06a3a72507cd5bbbe51
parent20d8b08492bea77f42d019af5db66ef184f105b3 (diff)
Wer verweist, wird gelesen, auch wenn ihm nicht gefolgt wird
„Die Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8 Buchst. a geändert.“ Ein Befehl, der seinen Inhalt nicht nennt, sondern auf einen anderen Punkt desselben Artikels verweist. Er galt bislang als nicht erkannt. Zwei Prüfungen haben ergeben, dass die naheliegende Abhilfe nicht trägt. Die Inhaltsübersicht wird nicht selbsttätig mitgeführt — der Anwender rührt sie bei einer Umnummerierung oder Neufassung nicht an —, und das rheinland-pfälzische Stammgesetz führt überhaupt keine Inhaltsübersicht. Den Befehl als „bereits bewirkt“ zu quittieren wäre also aktenwidrig; ihn auszuführen verlangte, dass der Anwender die Befehlsliste zurückliest und das Ziel umdeutet („Überschrift des § 13“ wird zur Titelspalte einer Übersichtszeile). Das ist ein eigenes Vorhaben. Er wird deshalb gelesen und ausdrücklich als Grenze gerügt. Der Unterschied ist kein kosmetischer: Der Rest wandert von „Befehl nicht erkannt“ zu „Nicht unterstützt“ und damit in die Gruppe, die das Handbuch für die bewusst gezogenen Grenzen führt. Die Synopse sagt fortan, dass hier das Erzeugnis die Grenze zieht, und nennt dabei den Verweis; sie sagt nicht mehr, die Vorlage sei unverständlich. Das Muster ist auf den ganzen Satz verankert, damit ein bloß adverbiales „entsprechend“ nicht mitgerissen wird. Damit sind sämtliche 23 Befehle des rheinland-pfälzischen Heftes erschlossen. Geprüft: 388 Tests (zuvor 386). Change-Id: I70d5ac52676310bf9bc2c95ab921bd74155a16b7
-rw-r--r--README.md17
-rw-r--r--src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java15
-rw-r--r--src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java17
-rw-r--r--src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java18
-rw-r--r--src/test/java/eu/mulk/aendggner/EndToEndTest.java24
-rw-r--r--src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java30
6 files changed, 109 insertions, 12 deletions
diff --git a/README.md b/README.md
index 538f10a..c894884 100644
--- a/README.md
+++ b/README.md
@@ -339,7 +339,15 @@ Streichen und Umnummerierung.
15. Verb-Rahmen, deren Unterpunkte allein die Fundstelle tragen („Es werden
ersetzt: … in § 35 Absatz 3 die Angabe „X“ jeweils durch die Angabe „Y“,“),
sowie
-16. die Neufassung der Gesetzesüberschrift.
+16. die Neufassung der Gesetzesüberschrift sowie
+17. die Verweisung auf einen anderen Punkt desselben Artikels („Die
+ Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8 Buchst. a
+ geändert“). Sie wird gelesen, aber nicht ausgeführt: Die sinngemäße
+ Übertragung setzte einen Rückgriff auf die Befehlsliste und eine Umdeutung
+ des Ziels voraus, die das Erzeugnis nicht leistet. Gelesen zu werden ist
+ gleichwohl mehr als gar nichts — die Rüge sagt alsdann, dass hier das
+ Erzeugnis die Grenze zieht, und nicht, dass die Vorlage unverständlich sei
+ (§ 1 Absatz 5).
(3) Landesrechtliche Befehlsformen bestimmt ergänzend § 13.
@@ -613,9 +621,10 @@ gleichwohl vier allgemeine Funde gebracht: die Nebenform „die Worte“ für â€
Wörter“, den Seitenfuß des dortigen Gesetzblattes, der im Inhaltsstrom das
Zitat einer Neufassung zerschneidet, den Strichpunkt samt Halbsatz-Anfügung
(§ 7 Absatz 2 Nummer 13) und den bezugspunktlosen Chapeau-Lokator (§ 7 Absatz 2
-Nummer 14). Offen bleibt allein die Verweisung auf einen anderen Punkt desselben
-Artikels („Die Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8
-Buchst. a geändert“).
+Nummer 14). Auch die Verweisung auf einen anderen
+Punkt desselben Artikels (§ 7 Absatz 2 Nummer 17) stammt von dort; sie wird
+gelesen und ausdrücklich als Grenze gerügt. Sämtliche 23 Befehle des Heftes sind
+damit erschlossen.
(5) Welche Konvention welches Land beisteuert, welche Stammfassungen woher
stammen und was noch offen ist, verzeichnet
diff --git a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java
index 47bca25..3138eeb 100644
--- a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java
+++ b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java
@@ -239,4 +239,19 @@ public sealed interface Aenderungsbefehl {
/** Fallback für alles, was der Parser nicht versteht — muss manuell geprüft werden. */
record UnbekannterBefehl(Stelle stelle, String originalText, Provenienz provenienz)
implements Aenderungsbefehl {}
+
+ /**
+ * „Die Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8 Buchst. a geändert.“
+ *
+ * <p>Ein Befehl, der seinen Inhalt nicht selbst nennt, sondern auf einen anderen Punkt desselben
+ * Artikels verweist. Er wird erkannt, aber nicht angewandt: Die sinngemäße Übertragung setzte
+ * voraus, dass der Anwender die Befehlsliste zurückliest und das Ziel umdeutet („Überschrift des
+ * § 13“ → Titelspalte der Übersichtszeile). Erkannt zu werden ist gleichwohl mehr als gar nichts
+ * — die Rüge sagt dann, dass das Erzeugnis die Grenze zieht, und nicht, dass die Vorlage
+ * unverständlich sei.
+ *
+ * @param verweis der Wortlaut der Verweisung („Nummer 8 Buchst. a“).
+ */
+ record VerweisenderBefehl(Stelle stelle, String verweis, Provenienz provenienz)
+ implements Aenderungsbefehl {}
}
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 ef49b7b..f1cece5 100644
--- a/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java
+++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java
@@ -17,6 +17,7 @@ import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Streichung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturEinfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturErsetzung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Umnummerierung;
+import eu.mulk.aendggner.aenderung.Aenderungsbefehl.VerweisenderBefehl;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WoerterEinfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortAnker;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortlautVoranstellung;
@@ -520,6 +521,15 @@ final class BefehlErkenner {
private static final Pattern HALBSATZ = Pattern.compile("Halbsatz(?: \\d+[a-z]?)?");
+ // „Die Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8 Buchst. a geändert.“ — ein
+ // Befehl, der seinen Inhalt nicht nennt, sondern auf einen anderen Punkt verweist. Verankert auf
+ // den ganzen Satz, damit ein bloß adverbiales „entsprechend“ nicht mitgerissen wird; ohne
+ // verschachtelte Quantoren und daher für die Mustersuche kostenneutral.
+ private static final Pattern VERWEISENDE_AENDERUNG =
+ Pattern.compile(
+ "^Die Inhaltsübersicht wird entsprechend (?:der|dem) "
+ + "(?:vorstehenden |vorgenannten |nachstehenden )?(.+?) geändert\\.$");
+
private static final Pattern EBENE_BEZEICHNUNG =
Pattern.compile(
"^(?:(?:§|Art\\.) (\\d+[a-z]?)|(?:Absatz|Abs\\.) (\\d+[a-z]?)|Satz(?: (\\d+[a-z]?))?|Sätze"
@@ -880,6 +890,13 @@ final class BefehlErkenner {
Matcher m;
+ // Die Verweisung auf einen anderen Punkt desselben Artikels. Sie steht ganz vorn, weil sie
+ // den vollen Satz beansprucht und sonst von der Neufassung an sich gezogen würde.
+ if ((m = VERWEISENDE_AENDERUNG.matcher(text)).matches()) {
+ return Optional.of(
+ new VerweisenderBefehl(mitInhaltsuebersicht(kontext), m.group(1).strip(), provenienz));
+ }
+
// Inhaltsübersichts-Angaben zuerst prüfen, bevor NEUFASSUNG/STRUKTUR_ERSETZUNG die Phrase
// strukturell (aber mit unparsbarer Stelle) an sich ziehen.
if ((m = INHALTSUEBERSICHT_ANGABE.matcher(text)).matches()) {
diff --git a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
index 64c6564..8d9b7e7 100644
--- a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
+++ b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
@@ -18,6 +18,7 @@ import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturEinfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturErsetzung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Umnummerierung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.UnbekannterBefehl;
+import eu.mulk.aendggner.aenderung.Aenderungsbefehl.VerweisenderBefehl;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WoerterEinfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortAnker;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortlautVoranstellung;
@@ -667,6 +668,20 @@ public final class BefehlAnwender {
if (befehl instanceof UnbekannterBefehl) {
return manuell(befehl, Grund.NICHT_ERKANNT, "Befehl nicht erkannt.");
}
+ // Gelesen, aber bewusst nicht ausgeführt. Die Weiche steht vor der Inhaltsübersichts-Weiche,
+ // damit die Rüge den Verweis nennt und nicht bloß die allgemeine Grenze jener Norm: Die
+ // sinngemäße Übertragung eines anderen Punktes setzte einen Rückgriff auf die Befehlsliste und
+ // eine Umdeutung des Ziels voraus („Überschrift des § 13“ → Titelspalte der Übersichtszeile),
+ // die dieser Anwender nicht leistet. Sie zu erraten wäre schlimmer, als sie zu benennen.
+ if (befehl instanceof VerweisenderBefehl v) {
+ return manuell(
+ befehl,
+ Grund.NICHT_UNTERSTUETZT,
+ "Der Befehl verweist auf „"
+ + v.verweis()
+ + "“ desselben Artikels; die sinngemäße Übertragung auf die Inhaltsübersicht ist"
+ + " nicht umgesetzt.");
+ }
// Sammelbefehle vor den Spezialweichen dispatchen (jeder Teil wird einzeln geroutet).
if (befehl instanceof Sammelbefehl s) {
return wendeSammelAn(normen, gliederungen, s);
@@ -724,6 +739,9 @@ public final class BefehlAnwender {
wendeGliederungsUeberschriftenAn(normen, gliederungen, g);
case Sammelbefehl s -> wendeSammelAn(normen, gliederungen, s);
case UnbekannterBefehl u -> manuell(befehl, Grund.NICHT_ERKANNT, "Befehl nicht erkannt.");
+ // Oben abgefangen; die Weiche muss ihn gleichwohl kennen.
+ case VerweisenderBefehl v ->
+ manuell(befehl, Grund.NICHT_UNTERSTUETZT, "Verweisender Befehl.");
};
} catch (RuntimeException e) {
return manuell(befehl, Grund.FEHLGESCHLAGEN, "Anwendung fehlgeschlagen: " + e);
diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java
index d0273ad..8cd867e 100644
--- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java
+++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java
@@ -10,6 +10,7 @@ import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Ersetzung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Sammelbefehl;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturEinfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.UnbekannterBefehl;
+import eu.mulk.aendggner.aenderung.Aenderungsbefehl.VerweisenderBefehl;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortAnker;
import eu.mulk.aendggner.aenderung.parse.AenderungsantragParser;
import eu.mulk.aendggner.aenderung.parse.AenderungsgesetzParser;
@@ -19,6 +20,7 @@ import eu.mulk.aendggner.aenderung.parse.SuperskriptModus;
import eu.mulk.aendggner.aenderung.parse.TextBereiniger;
import eu.mulk.aendggner.aenderung.parse.ZitatExtraktor;
import eu.mulk.aendggner.anwendung.BefehlAnwender;
+import eu.mulk.aendggner.anwendung.Grund;
import eu.mulk.aendggner.anwendung.Nachfassungsabgleich;
import eu.mulk.aendggner.gesetz.Absatz;
import eu.mulk.aendggner.gesetz.Gesetz;
@@ -1889,14 +1891,20 @@ class EndToEndTest {
assertThat(befehlAn(parseErgebnis, "5. a) aa)")).isInstanceOf(Sammelbefehl.class);
assertThat(befehlAn(parseErgebnis, "7. a) aa)")).isInstanceOf(Ersetzung.class);
- // Eine benannte Grenze bleibt: die Verweisung auf einen anderen Punkt desselben Artikels
- // („Die Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8 Buchst. a geändert“).
- var unerkannt =
- parseErgebnis.befehle().stream()
- .filter(b -> b instanceof UnbekannterBefehl)
- .map(b -> b.provenienz().gliederungsPfad())
- .toList();
- assertThat(unerkannt).containsExactly("12.");
+ // Kein Befehl des Heftes bleibt mehr ungelesen.
+ assertThat(parseErgebnis.befehle()).noneMatch(b -> b instanceof UnbekannterBefehl);
+
+ // Die Verweisung auf einen anderen Punkt desselben Artikels wird gelesen, aber bewusst nicht
+ // ausgeführt. Der Unterschied ist kein kosmetischer: Die Synopse sagt fortan, dass das
+ // Erzeugnis hier die Grenze zieht, und nicht, dass die Vorlage unverständlich sei.
+ var verweisung = befehlAn(parseErgebnis, "12.");
+ assertThat(verweisung).isInstanceOf(VerweisenderBefehl.class);
+ assertThat(((VerweisenderBefehl) verweisung).verweis()).isEqualTo("Nummer 8 Buchst. a");
+
+ var anwendung = BefehlAnwender.anwenden(gesetz, List.of(verweisung));
+ assertThat(anwendung.protokoll().get(0).grund()).isEqualTo(Grund.NICHT_UNTERSTUETZT);
+ assertThat(anwendung.protokoll().get(0).begruendung())
+ .contains("verweist auf „Nummer 8 Buchst. a“");
}
private static Aenderungsbefehl befehlAn(
diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java
index 80234b8..327c8db 100644
--- a/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java
+++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java
@@ -15,6 +15,7 @@ import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Streichung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturEinfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturErsetzung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Umnummerierung;
+import eu.mulk.aendggner.aenderung.Aenderungsbefehl.VerweisenderBefehl;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WoerterEinfuegung;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortAnker;
import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortlautZuAbsatz;
@@ -1514,4 +1515,33 @@ class BefehlErkennerTest {
assertThat(ersetzung.alt()).isEqualTo(";");
assertThat(ersetzung.neu()).isEqualTo(",");
}
+
+ /**
+ * Die Verweisung auf einen anderen Punkt desselben Artikels wird gelesen, aber nicht ausgeführt.
+ * Erkannt zu werden ist gleichwohl mehr als gar nichts: Die Rüge sagt dann, dass das Erzeugnis
+ * die Grenze zieht, und nicht, dass die Vorlage unverständlich sei.
+ */
+ @Test
+ void erkenntDieVerweisungAufEinenAnderenPunkt() {
+ var befehl =
+ erkenne(
+ "Die Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8 Buchst. a geändert.",
+ Stelle.LEER);
+
+ assertThat(befehl).containsInstanceOf(VerweisenderBefehl.class);
+ var verweisung = (VerweisenderBefehl) befehl.orElseThrow();
+ assertThat(verweisung.verweis()).isEqualTo("Nummer 8 Buchst. a");
+ assertThat(verweisung.stelle().betrifftInhaltsuebersicht()).isTrue();
+ }
+
+ /** Ein bloß adverbiales „entsprechend“ wird davon nicht mitgerissen. */
+ @Test
+ void adverbialesEntsprechendIstKeineVerweisung() {
+ var befehl =
+ erkenne(
+ "In § 5 werden die Wörter „entsprechend der Anlage“ durch die Wörter „nach der"
+ + " Anlage“ ersetzt.",
+ Stelle.LEER);
+ assertThat(befehl).containsInstanceOf(Ersetzung.class);
+ }
}