Die Umnummerierungs-Kaskade war keine Grenze, sondern drei Mängel

Die mehrschrittige Umnummerierungssequenz galt bislang als wesenseigene Grenze:
Ihre Folgeänderungen gingen in den Abschnitt „Manuell prüfen“, im bayerischen
Belegfall drei von 154 Anweisungen (48. a) ee), 48. a) gg), 48. b) cc), sämtlich
aus der Neunummerierung des Bußgeldkatalogs in Art. 56 BayJG). Die Prüfung gegen
die amtliche Nachfassung zeigt, dass es keine Grenze war, sondern drei
voneinander unabhängige Mängel. Erst die Diagnose vor jeder Änderung — die
Begründungen der drei Fälle ausgeben — hat sie getrennt; die Vermutung, alles
sei eine Frage der Reihenfolge, traf nur auf einen von ihnen zu.

Geordnet werden nun Schritte statt Befehle (BefehlAnwender). Ein Verbund aus
Umnummerierung und Begleitänderung trägt zwei gegenläufige zeitliche Ansprüche:
Die Umnummerierung gehört vor denjenigen, der ihre Bezeichnung neu besetzt, die
Begleitänderung an ihre Stelle im Dokument, denn sie setzt die vorangegangenen
Punkte als vollzogen voraus. Bisher setzte sich der erste Anspruch für die ganze
Einheit durch. Bei gg) — „Die bisherige Nr. 11 wird Nr. 12 und die Angabe
„schriftliche“ wird gestrichen“ — stand die Angabe vorgezogen noch zweimal im
Artikel und war zu Recht mehrdeutig; an ihrer Dokumentstelle hat ee) die zweite
Fundstelle längst ersetzt. Die Befehlsliste wird dazu vor der Anwendung zu
Schritten aufgefaltet (je Teilbefehl einer); protokolliert wird unverändert je
Befehl, ein Verbund gilt nur als angewandt, wenn jeder Teil gegriffen hat.

Die Ordnungsregel selbst bleibt wörtlich dieselbe („wer eine Bezeichnung räumt,
kommt vor dem, der sie neu besetzt“), wird aber erst jetzt vollständig
durchgesetzt. Bisher rückte ein Befehl nur einmal vor seinen ersten
Kollisionspartner; auf Schritten zerreißt das die Ketten — von „Nr. 15 wird
Nr. 16“, „Nrn. 13 und 14 werden Nrn. 14 und 15“, „nach Nr. 12 wird Nr. 13
eingefügt“ zog die Einfügung nur das letzte Glied vor sich her. An die Stelle
tritt eine Tiefensuche auf der Dokumentordnung: vor jedem Schritt erst rekursiv
seine Räumer, eine ringförmige Abhängigkeit bricht ab. Kein Kahn mit „frühester
bereiter Knoten“ — der zieht unbeteiligte Schritte vor und bricht genau die
Begleitänderung wieder.

Die beiden übrigen Mängel lagen anderswo:

* Das Muster der lokativen Klausel (BefehlErkenner) schloss mit einer
  Wortgrenze. Hinter einem abgekürzten Bezeichnungswort steht aber schon der
  Abkürzungspunkt, und zwischen ihm und dem Leerzeichen liegt keine Wortgrenze;
  der Klausel entging deshalb jede Kurzform („in Abs. 2 …“, „in Buchst. b …“).
  Die unabgekürzten Formen trafen zu, weshalb es nie auffiel.

* Der StellenAufloeser verlangte hinter der Aufzählungsmarke Text auf derselben
  Zeile. Eine Einheit, die sich vollständig in ihre Untergliederung ergießt,
  führt ihre Marke allein (Art. 56 Abs. 2 Nr. 12 BayJG, darunter nur die
  Buchstaben a und b) und galt als nicht auffindbar.

Der bayerische Belegfall steht damit auf 154 angewandten Anweisungen ohne Rest
(zuvor 151), die Ausschussfassung der Beschlussempfehlung zum GEG auf 68 statt
67 — dort greift nun eine Bereichs-Umnummerierung in § 108, die vorher nur ihr
erstes Glied vorziehen konnte; § 108 liegt jedoch in der bekannten Zone, in der
das Beispiel-XML eine andere Fassung ist als die vorausgesetzte, taugt also
nicht als Beleg. Belegt ist die Ordnung an Art. 29a und Art. 56 BayJG und an den
Kaskaden des WDR-Gesetzes. Alle übrigen Bezugszahlen des Bundes und der Länder
sind unverändert; 304 Prüfungen laufen durch.

Der Akzeptanztest hält zwei Mängel fest, die er nicht behebt. Beide bestanden
schon zuvor, was ein Lauf gegen den Ausgangsstand belegt:

* Der Block aus „Nach Nr. 4 werden die folgenden Nrn. 5 bis 7 eingefügt“ tritt
  an das Ende des Absatzes statt hinter die Nr. 4, und der leere Platzhalter
  „7. (aufgehoben)“ der Altfassung bleibt zwischen den Nrn. 9 und 10 stehen.
  Dass jede Anweisung greift, heißt eben nicht, dass die Norm in allem der
  amtlichen Nachfassung gleicht; der Test sagt das ausdrücklich.

* Die Heilung doppelter Leerzeichen nach einer Streichung wirkt auf den
  gesamten Zieltext und verkürzt dabei die Einrückung der Aufzählungszeilen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Id61babe60226d27b5c05ff971927d61713b01781
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 bda8e94..e63cfd8 100644
--- a/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java
+++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java
@@ -587,11 +587,16 @@
   // „nach Satz 2 wird …“). Sie erbt nach einer Umnummerierung deren neue Bezeichnung als Kontext.
   // Wortanker („nach der Angabe „…““) zählen ausdrücklich nicht dazu: sie suchen ihren Text
   // normweit und dürfen nicht auf die neue Bezeichnung festgenagelt werden.
+  // Der Abschluss ist „kein Buchstabe mehr“ und nicht \b: hinter einem abgekürzten
+  // Bezeichnungswort steht bereits der Abkürzungspunkt, und zwischen ihm und dem folgenden
+  // Leerzeichen liegt keine Wortgrenze — mit \b entginge der Klausel jede bayerische
+  // Kurzform („in Abs. 2 …“, „in Buchst. b …“). Vor der Ausschreibung steht die Kurzform
+  // nur dann zurück, wenn diese länger passt (Alternativen sind absteigend geordnet).
   private static final Pattern LOKATIVE_KLAUSEL =
       Pattern.compile(
           "(?:in|im|nach|vor) (?:dem |der |den )?"
               + "(?:Satzteil|Satz|Sätze[n]?|Absatz|Abs\\.|Absätze[n]?|Nummer[n]?|Nrn?\\."
-              + "|Buchstabe[n]?|Buchst\\.|Halbsatz)\\b");
+              + "|Buchstabe[n]?|Buchst\\.|Halbsatz)(?!\\p{L})");
 
   // „In <Stelle> wird nach den Wörtern «1» ein Komma eingefügt.“ (Satzzeichen statt Wörter
   // einfügen)
diff --git a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
index b8540c5..32350ff 100644
--- a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
+++ b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java
@@ -73,20 +73,25 @@
     var protokoll = new ArrayList<AngewandteAenderung>();
     String neuerLangtitel = null;
 
-    // Angewandt wird in Sachreihenfolge, protokolliert in der Reihenfolge des Änderungsgesetzes.
-    var ergebnisse = new AngewandteAenderung[befehle.size()];
-    for (int index : anwendungsReihenfolge(befehle)) {
-      var befehl = befehle.get(index);
+    // Angewandt wird schrittweise in Sachreihenfolge, protokolliert befehlsweise in der
+    // Reihenfolge des Änderungsgesetzes.
+    var schritte = schritte(befehle);
+    var ergebnisse = new AngewandteAenderung[schritte.size()];
+    for (int index : anwendungsReihenfolge(schritte)) {
+      var schritt = schritte.get(index);
       // „Die Überschrift wird wie folgt gefasst / durch die folgende Überschrift ersetzt“ auf
-      // oberster Ebene meint die Überschrift des Gesetzes selbst.
-      if (befehl instanceof Neufassung n && istNurUeberschrift(n.stelle())) {
+      // oberster Ebene meint die Überschrift des Gesetzes selbst — innerhalb eines Verbunds
+      // dagegen nie, dort steht sie für die Überschrift der Einheit, die der Verbund betrifft.
+      if (schritt.ganzerBefehl()
+          && schritt.teil() instanceof Neufassung n
+          && istNurUeberschrift(n.stelle())) {
         neuerLangtitel = n.neuerText().replaceAll("\\s+", " ").strip();
-        ergebnisse[index] = angewandt(befehl, "(Gesetzesüberschrift)");
+        ergebnisse[index] = angewandt(schritt.teil(), "(Gesetzesüberschrift)");
         continue;
       }
-      ergebnisse[index] = wendeAn(normen, gliederungen, befehl);
+      ergebnisse[index] = wendeAn(normen, gliederungen, schritt.teil());
     }
-    protokoll.addAll(Arrays.asList(ergebnisse));
+    protokoll.addAll(verdichte(befehle, schritte, ergebnisse));
 
     var neu = alt.mitNormen(normen).mitGliederungen(gliederungen);
     if (neuerLangtitel != null) {
@@ -96,46 +101,160 @@
   }
 
   /**
-   * Reihenfolge, in der die Befehle anzuwenden sind: grundsätzlich die des Änderungsgesetzes.
-   *
-   * <p>Eine Umnummerierung „Der bisherige § 13 wird § 14“ wird jedoch vor eine vorangehende
-   * Einfügung gezogen, die denselben Paragraphen neu besetzt („In Kapitel 4 wird nach § 12 der
-   * folgende neue § 13 angefügt“). „Bisherig“ bezeichnet den Stand vor der Änderung; die
-   * Umnummerierung geht der Neubesetzung sachlich also voraus. In der Textreihenfolge angewandt
-   * liefen beide Befehle dagegen auf zwei Paragraphen gleicher Bezeichnung hinaus.
+   * Ein einzeln anzuwendender Schritt: der Teilbefehl selbst und der Index des Befehls, in dessen
+   * 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}).
    */
+  private record Schritt(int befehlIndex, Aenderungsbefehl teil, boolean ganzerBefehl) {}
+
+  /** Faltet die Befehlsliste zur Schrittliste auf, in Dokumentreihenfolge. */
+  private static List<Schritt> schritte(List<Aenderungsbefehl> befehle) {
+    var schritte = new ArrayList<Schritt>(befehle.size());
+    for (int i = 0; i < befehle.size(); i++) {
+      var befehl = befehle.get(i);
+      if (befehl instanceof Sammelbefehl s) {
+        falte(s, i, schritte);
+      } else {
+        schritte.add(new Schritt(i, befehl, true));
+      }
+    }
+    return schritte;
+  }
+
+  private static void falte(Sammelbefehl befehl, int befehlIndex, List<Schritt> ziel) {
+    for (var teil : befehl.teilbefehle()) {
+      if (teil instanceof Sammelbefehl geschachtelt) {
+        falte(geschachtelt, befehlIndex, ziel);
+      } else {
+        ziel.add(new Schritt(befehlIndex, teil, false));
+      }
+    }
+  }
+
   /**
-   * Anwendungsreihenfolge der Befehle. 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 besetzt — sonst
-   * trüge das Gesetz vorübergehend zwei gleich bezeichnete Einheiten und die Fundstelle wäre
-   * mehrdeutig. Aus dieser einen Regel folgt beides: die absteigende Reihenfolge einer
-   * aufsteigenden Kaskade („Abs. 3 wird 4“, „Abs. 4 wird 5“, …) und der Vorrang einer
+   * 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
+   * besetzt — sonst trüge das Gesetz vorübergehend zwei gleich bezeichnete Einheiten und die
+   * Fundstelle wäre mehrdeutig. Aus dieser einen Regel folgt beides: die absteigende Reihenfolge
+   * einer aufsteigenden Kaskade („Abs. 3 wird 4“, „Abs. 4 wird 5“, …) und der Vorrang einer
    * Umnummerierung vor einer Einfügung, die deren Bezeichnung neu vergibt.
    *
-   * <p>Verschoben wird stets nur nach vorn: ein Befehl rückt vor den ersten, mit dem er kollidiert.
-   * So bleibt jede Folgeänderung hinter der Umnummerierung, auf deren neue Bezeichnung sie zeigt
-   * („Der bisherige Absatz 3 wird Absatz 4 und wie folgt geändert: …“).
+   * <p>Verschoben wird stets nur nach vorn, und wer vorrückt, nimmt mit, was ihm selbst vorausgehen
+   * muss: Vor jedem Schritt laufen erst diejenigen, die ihm eine Bezeichnung räumen, und vor diesen
+   * wiederum die ihren. Ohne diese Mitnahme zerrisse eine Kette wie „Nr. 15 wird Nr. 16“, „Nrn. 13
+   * und 14 werden die Nrn. 14 und 15“, „nach Nr. 12 wird Nr. 13 eingefügt“: die Einfügung zöge nur
+   * das letzte Glied vor sich, und dieses beträfe eine Bezeichnung, die noch besetzt ist. Ein
+   * Schritt ohne solche Voraussetzung bleibt dagegen an seinem Platz — daran hängt, dass eine
+   * Begleitänderung ihre Dokumentstelle behält.
+   *
+   * <p>Geordnet werden <em>Schritte</em> und nicht Befehle, weil ein Verbund aus Umnummerierung und
+   * Begleitänderung zwei gegenläufige zeitliche Ansprüche in einer Einheit trägt: Die
+   * Umnummerierung gehört nach vorn, ihre Begleitänderung aber an ihre Dokumentstelle, denn sie
+   * setzt die vorangegangenen Punkte als vollzogen voraus. „Die bisherige Nr. 11 wird Nr. 12 und
+   * die Angabe „schriftliche“ wird gestrichen“ (BayJG Art. 56 Abs. 1) trifft nach vorn gezogen noch
+   * zwei Fundstellen und wäre mehrdeutig; an seinem Platz belassen genau eine, weil der vorherige
+   * Punkt die andere längst ersetzt hat.
    */
-  private static List<Integer> anwendungsReihenfolge(List<Aenderungsbefehl> befehle) {
-    var reihenfolge = new ArrayList<Integer>(befehle.size());
-    for (int i = 0; i < befehle.size(); i++) {
-      reihenfolge.add(i);
+  private static List<Integer> anwendungsReihenfolge(List<Schritt> schritte) {
+    int anzahl = schritte.size();
+    var raeumt = new ArrayList<Set<String>>(anzahl);
+    var belegt = new ArrayList<Set<String>>(anzahl);
+    for (var schritt : schritte) {
+      raeumt.add(geraeumteBezeichnungen(schritt.teil()));
+      belegt.add(belegteBezeichnungen(schritt.teil()));
     }
-    for (int j = 0; j < befehle.size(); j++) {
-      var raeumt = geraeumteBezeichnungen(befehle.get(j));
-      if (raeumt.isEmpty()) {
-        continue;
-      }
-      for (int i = 0; i < j; i++) {
-        if (belegteBezeichnungen(befehle.get(i)).stream().anyMatch(raeumt::contains)) {
-          reihenfolge.remove(Integer.valueOf(j));
-          reihenfolge.add(reihenfolge.indexOf(i), j);
-          break;
+    var reihenfolge = new ArrayList<Integer>(anzahl);
+    // 0 = offen, 1 = in Arbeit (Zyklus-Bremse), 2 = eingereiht.
+    var stand = new byte[anzahl];
+    for (int i = 0; i < anzahl; i++) {
+      reiheEin(i, stand, raeumt, belegt, reihenfolge);
+    }
+    return reihenfolge;
+  }
+
+  /**
+   * Reiht den Schritt ein, nachdem alle Schritte eingereiht sind, die ihm eine seiner Bezeichnungen
+   * räumen. Eine ringförmige Abhängigkeit — zwei Schritte, die einander räumen — bricht an der
+   * Marke „in Arbeit“ ab; die beteiligten Schritte behalten dann ihre Dokumentreihenfolge.
+   */
+  private static void reiheEin(
+      int schritt,
+      byte[] stand,
+      List<Set<String>> raeumt,
+      List<Set<String>> belegt,
+      List<Integer> reihenfolge) {
+    if (stand[schritt] != 0) {
+      return;
+    }
+    stand[schritt] = 1;
+    var eigene = belegt.get(schritt);
+    if (!eigene.isEmpty()) {
+      for (int vorgaenger = 0; vorgaenger < stand.length; vorgaenger++) {
+        if (vorgaenger != schritt && raeumt.get(vorgaenger).stream().anyMatch(eigene::contains)) {
+          reiheEin(vorgaenger, stand, raeumt, belegt, reihenfolge);
         }
       }
     }
-    return reihenfolge;
+    stand[schritt] = 2;
+    reihenfolge.add(schritt);
+  }
+
+  /**
+   * Verdichtet die Schrittergebnisse zu je einem Protokolleintrag pro Befehl. Ein Verbund gilt nur
+   * dann als angewandt, wenn jeder seiner Teile griff; sonst nennt die Begründung die gescheiterten
+   * Teile in ihrer Reihenfolge im Verbund.
+   */
+  private static List<AngewandteAenderung> verdichte(
+      List<Aenderungsbefehl> befehle, List<Schritt> schritte, AngewandteAenderung[] ergebnisse) {
+    var protokoll = new ArrayList<AngewandteAenderung>(befehle.size());
+    int schritt = 0;
+    for (int i = 0; i < befehle.size(); i++) {
+      int von = schritt;
+      while (schritt < schritte.size() && schritte.get(schritt).befehlIndex() == i) {
+        schritt++;
+      }
+      if (von == schritt) {
+        // Ein Verbund ohne Teilbefehle — nichts anzuwenden, aber auch nichts zu verschweigen.
+        protokoll.add(manuell(befehle.get(i), "Verbund ohne Teilbefehle."));
+        continue;
+      }
+      if (schritte.get(von).ganzerBefehl()) {
+        protokoll.add(ergebnisse[von]);
+        continue;
+      }
+      protokoll.add(
+          verbund(befehle.get(i), Arrays.asList(ergebnisse).subList(von, schritt), schritte, von));
+    }
+    return protokoll;
+  }
+
+  private static AngewandteAenderung verbund(
+      Aenderungsbefehl befehl,
+      List<AngewandteAenderung> teilErgebnisse,
+      List<Schritt> schritte,
+      int von) {
+    var betroffene = new LinkedHashSet<String>();
+    var fehler = new ArrayList<String>();
+    for (int k = 0; k < teilErgebnisse.size(); k++) {
+      var ergebnis = teilErgebnisse.get(k);
+      betroffene.addAll(ergebnis.betroffeneEnbez());
+      if (ergebnis.status() != Status.ANGEWANDT) {
+        fehler.add(
+            "Teil "
+                + (k + 1)
+                + " ("
+                + schritte.get(von + k).teil().stelle().anzeigeText()
+                + "): "
+                + ergebnis.begruendung());
+      }
+    }
+    if (fehler.isEmpty()) {
+      return new AngewandteAenderung(befehl, Status.ANGEWANDT, "", betroffene);
+    }
+    return new AngewandteAenderung(
+        befehl, Status.MANUELL_PRUEFEN, String.join(" ", fehler), betroffene);
   }
 
   /** Bezeichnungen, die ein Befehl freigibt — die Ausgangsstellen seiner Umnummerierungen. */
@@ -1486,39 +1605,20 @@
    * zusammen. Nur wenn alle Teile gelingen, gilt der Befehl als angewandt; sonst wird er zur
    * manuellen Prüfung markiert (bereits angewandte Teile bleiben wirksam).
    */
+  /**
+   * Ein Verbund, der erst hier auftaucht (in einem anderen Verbund geschachtelt), wird für sich
+   * genommen aufgefaltet und geordnet. Der Regelfall — der Verbund als eigener Gliederungspunkt —
+   * ist dagegen schon in {@link #anwenden} aufgefaltet und läuft nie hier durch.
+   */
   private static AngewandteAenderung wendeSammelAn(
       List<Norm> normen, List<Gliederung> gliederungen, Sammelbefehl befehl) {
-    var betroffene = new LinkedHashSet<String>();
-    var fehler = new ArrayList<String>();
-    // Auch innerhalb eines Verbunds gilt die Bezeichnungs-Reihenfolge: „Die bisherigen Nrn. 13 und
-    // 14 werden die Nrn. 14 und 15“ zerfällt in zwei Umnummerierungen, die aufsteigend angewandt
-    // eine doppelte Nr. 14 erzeugten.
-    var teile = befehl.teilbefehle();
-    var meldungen = new String[teile.size()];
-    for (int index : anwendungsReihenfolge(teile)) {
-      var teil = teile.get(index);
-      var ergebnis = wendeAn(normen, gliederungen, teil);
-      betroffene.addAll(ergebnis.betroffeneEnbez());
-      if (ergebnis.status() != Status.ANGEWANDT) {
-        meldungen[index] =
-            "Teil "
-                + (index + 1)
-                + " ("
-                + teil.stelle().anzeigeText()
-                + "): "
-                + ergebnis.begruendung();
-      }
+    var schritte = new ArrayList<Schritt>(befehl.teilbefehle().size());
+    falte(befehl, 0, schritte);
+    var ergebnisse = new AngewandteAenderung[schritte.size()];
+    for (int index : anwendungsReihenfolge(schritte)) {
+      ergebnisse[index] = wendeAn(normen, gliederungen, schritte.get(index).teil());
     }
-    for (var meldung : meldungen) {
-      if (meldung != null) {
-        fehler.add(meldung);
-      }
-    }
-    if (fehler.isEmpty()) {
-      return new AngewandteAenderung(befehl, Status.ANGEWANDT, "", betroffene);
-    }
-    return new AngewandteAenderung(
-        befehl, Status.MANUELL_PRUEFEN, String.join(" ", fehler), betroffene);
+    return verbund(befehl, Arrays.asList(ergebnisse), schritte, 0);
   }
 
   // --- Gemeinsame Helfer ---------------------------------------------------------------------
diff --git a/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java b/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java
index ff77279..d2fe02a 100644
--- a/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java
+++ b/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java
@@ -252,7 +252,10 @@
    */
   private static SatzTeiler.@Nullable SatzBereich zeilenBlock(
       String text, String labelRegex, SatzTeiler.SatzBereich suchbereich) {
-    var muster = Pattern.compile("(?m)^([ \\t]*)" + labelRegex + "[ \\t].*$");
+    // Der Text hinter dem Label ist wahlfrei: eine Aufzählungseinheit, die sich vollständig in
+    // ihre Untergliederung ergießt, führt ihre Marke allein auf der Zeile (BayJG Art. 56 Abs. 2
+    // Nr. 12 — darunter nur die Buchstaben a und b). Ihr Block sind dann eben nur die Kindzeilen.
+    var muster = Pattern.compile("(?m)^([ \\t]*)" + labelRegex + "(?:[ \\t].*)?$");
     var matcher = muster.matcher(text).region(suchbereich.von(), suchbereich.bis());
     SatzTeiler.SatzBereich gefunden = null;
     int einrueckung = 0;
diff --git a/src/main/resources/sampledata/Landesrecht-Beispiele.adoc b/src/main/resources/sampledata/Landesrecht-Beispiele.adoc
index be70dfc..4de907f 100644
--- a/src/main/resources/sampledata/Landesrecht-Beispiele.adoc
+++ b/src/main/resources/sampledata/Landesrecht-Beispiele.adoc
@@ -232,10 +232,16 @@
   angefasst — ein Sammelheft mit mehreren Verkündungen, also zugleich ein Test der Artikel-/
   Verkündungsauswahl.
 . *Berlin, ganzseitenbreite Rahmen* (XY-Cut) — die letzte offene Layout-Frage, siehe „Noch offen“.
+. *Stellung eines eingefügten Blocks* — seit die Umnummerierungs-Kaskade des BayJG aufgeht, ist
+  dies der sichtbare Rest an Art. 56: „Nach Nr. 4 werden die folgenden Nrn. 5 bis 7 eingefügt“ gilt
+  als angewandt, der Block tritt aber ans Ende des Absatzes statt hinter die Nr. 4, und der leere
+  Platzhalter „7. (aufgehoben)“ bleibt zwischen den Nrn. 9 und 10 stehen. Beides ist im
+  Akzeptanztest festgehalten, damit es nicht unbemerkt bleibt.
 
 Regressionsschutz: `./mvnw verify` prüft die bestehenden Belegfälle mit. Gepinnt ist dabei nicht
 überall dieselbe Art von Zahl — für UWG, AGG und ProdHaftG, dass *kein* Befehl manuell bleibt; für
-das BayJG die 154 erkannten Befehle und namentlich die drei Umnummerierungs-Residuen; für Sachsen,
+das BayJG die 154 erkannten Befehle, die vollständige Anwendung und den Wortlaut des
+Bußgeldkatalogs an drei Stellen; für Sachsen,
 Niedersachsen und die vier NRW-Artikel die vollständige Anwendung bis auf das eine benannte
 Residuum im WDR-Gesetz; für Schleswig-Holstein, Berlin und Hessen die vollständige *Erkennung*
 (dort 21 Befehle). Wer eine dieser Zahlen