From d51e3dad33edb14c048372c035b635313d7a1dc9 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Fri, 28 Aug 2026 08:36:29 +0200 Subject: Die Anlage gliedert sich nach eigener Wahl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Korpuslauf sollte klären, woran die Anlagen-Reste liegen, und hat die Frage anders beantwortet als erwartet: Unter den 116 liegengebliebenen Befehlen des Korpus ist kein einziger ein Tabellenproblem. Die Annahme, die vier mecklenburgischen Reste scheiterten an fehlender Tabellenunterstützung, war unrichtig. Beschafft man das Ursprungsheft (GVOBl. M-V 2016 Nr. 12, über das Internet-Archiv, weil der Wirt einer Skriptabfrage nicht antwortet), so zeigt sich: Der Ausbildungsrahmenplan ist keine Tabelle, sondern gegliederter Fließtext — je Abschnitt eine Kopfzeile, die Ausbildungsstelle, die Dauer und eine Spiegelstrichliste. Er fehlte in der Stammfassung, das war alles. Eine Anlage gliedert sich nach eigener Wahl. Neben den Nummern eines Zuständigkeitskatalogs kennt das Erzeugnis deshalb fortan die benannte Einheit und führt sie wie jene als eigene Norm, deren Bezeichnung die Anlage voranstellt: „Anlage 1 Ausbildungsabschnitt 1“. Erkannt wird sie an ihrem Bau und nicht an einer Wortliste — verlangt sind Buchstaben vor dem Wortstamm —, denn jede Anlage darf ihre Einheiten nennen, wie sie will, und eine Liste wäre am nächsten Land wieder unvollständig. Leser und Ausgeber tragen sie (der Rundlauf geht auf), der Stellenparser nimmt sie als Stellenangabe, der Auflöser setzt sie mit der Anlage zur Normbezeichnung zusammen, und der Anwender benennt sie um. Dabei ist ein stiller Fehler zutage getreten: Die Umnummerierung lief für alles, was weder Paragraph noch Absatz noch Aufzählungsmarke noch Satz war, in den Auffangzweig „keine Textänderung nötig“ und meldete Erfolg, ohne etwas zu tun. Erst der Belegfall hat das gezeigt. Von den vier mecklenburgischen Resten sind zwei erledigt (22 statt 20 von 24 Befehlen). Die beiden übrigen haben benannte Gründe: Der eine fügt einen ganzen Ausbildungsabschnitt ein — eine neue Norm innerhalb einer Anlage setzt das Erzeugnis nicht —, der andere verweist auf einen Anhang des ändernden Gesetzes, der nicht vorliegt. Die Anlage 2 (Vordruck des Befähigungsberichts) bleibt aus demselben Grund fort; sie ist der einzige echte Tabellensatz des ganzen Korpus. Die Grundlinie hat sich sogleich bewährt: Die Erweiterung kostete einen Befehl, der zuvor angewandt wurde — „Die Überschrift zu Unterabschnitt 4 wird gestrichen“ des GEG-Entwurfs fiel aus dem Gliederungszweig, weil auch „Unterabschnitt“ auf den Wortstamm endet. Der Korpuslauf rügte das im selben Durchgang („angewandte Befehle 86 statt 87“), und zwar in einem anderen Land und einem anderen Dokument, wo keine Einzelprüfung es bemerkt hätte. Die Grenze ist gezogen und durch zwei Prüffälle gepinnt. Geprüft: mvnw verify (445 Testfälle) und reuse lint (214/214) gehen durch. Der Akzeptanzfall pinnt 35 statt 29 Normen und 22 statt 20 angewandte Befehle; die Grundlinie des Korpuslaufs ist auf 1289 statt 1287 angewandter Befehle fortgeschrieben. Co-Authored-By: Claude Opus 5 Change-Id: I3e6046c3a91ecc45406058b367ec5a9a19c84967 --- src/test/java/eu/mulk/aendggner/EndToEndTest.java | 34 ++++++++++++--- .../aenderung/parse/StellenParserTest.java | 20 +++++++++ .../MecklenburgVorpommern/APOAmtsTA-MV-alt.txt | 51 ++++++++++++++++++++++ .../sampledata/MecklenburgVorpommern/SOURCES | 45 +++++++++++++++---- .../resources/sampledata/korpus-grundlinie.tsv | 4 +- 5 files changed, 136 insertions(+), 18 deletions(-) (limited to 'src/test') diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java index 34bc8e6..ea014b0 100644 --- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java +++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java @@ -1931,8 +1931,12 @@ class EndToEndTest { var gesetz = new eu.mulk.aendggner.gesetz.land.LandesRechtLoader().load(alt); assertThat(gesetz.jurabk()).isEqualTo("APOAmtsTA M-V"); - // Die Inhaltsübersicht ist eine Norm gleichen Namens; dazu die 28 Paragraphen. - assertThat(gesetz.normen()).hasSize(29); + // Die Inhaltsübersicht ist eine Norm gleichen Namens; dazu die 28 Paragraphen, die Anlage 1 + // (Ausbildungsrahmenplan) und deren fünf Ausbildungsabschnitte, die das Portal wie die Nummern + // eines Zuständigkeitskatalogs als eigene Einheiten führt. + assertThat(gesetz.normen()).hasSize(35); + assertThat(gesetz.norm("Anlage 1 Ausbildungsabschnitt 1")).isPresent(); + assertThat(gesetz.norm("Anlage 1 Ausbildungsabschnitt 5")).isPresent(); var text = TextBereiniger.bereinige(new PatchTextExtraktor().extrahiere(pdf)); // Kolumnentitel und Seitenfuß stehen im Inhaltsstrom, und zwar mitten im Befehlstext. @@ -1945,7 +1949,7 @@ class EndToEndTest { assertThat(parseErgebnis.befehle()).hasSize(24); var anwendung = BefehlAnwender.anwenden(gesetz, parseErgebnis.befehle()); - assertThat(anwendung.anzahlAngewandt()).isEqualTo(20); + assertThat(anwendung.anzahlAngewandt()).isEqualTo(22); // Die Nummern 2 und 3 entfallen, die Nummern 4 bis 6 rücken auf 2 bis 4 — ohne Platzhalter, // denn sie stehen am Ende ihres Blockes nicht. @@ -1965,15 +1969,31 @@ class EndToEndTest { assertThat(anwendung.neu().norm("Inhaltsübersicht").orElseThrow().absaetze().get(0).text()) .contains("§ 10 | Ausbildungsnachweise"); - // Übrig bleiben allein die vier Befehle, die die Anlagen betreffen: Die Stammfassung führt sie - // nicht mit (Tabellen und Vordrucke), und der elfte Befehl verweist auf einen Anhang des - // Änderungsgesetzes. + // Die benannte Einheit der Anlage trägt die Wortersetzung … + assertThat( + anwendung + .neu() + .norm("Anlage 1 Ausbildungsabschnitt 1") + .orElseThrow() + .absaetze() + .get(0) + .text()) + .startsWith("Das für das Veterinärwesen zuständige Ministerium") + .doesNotContain("Ministerium für Landwirtschaft, Umwelt und Verbraucherschutz"); + // … und die Umnummerierung trifft ihre Bezeichnung, nicht ihren Wortlaut. + assertThat(anwendung.neu().norm("Anlage 1 Ausbildungsabschnitt 6")).isPresent(); + assertThat(anwendung.neu().norm("Anlage 1 Ausbildungsabschnitt 5")).isEmpty(); + + // Übrig bleiben zwei Befehle, beide mit benanntem Grund: Nummer 10 Buchstabe b fügt einen + // ganzen Ausbildungsabschnitt ein — eine neue Norm innerhalb einer Anlage, die das Erzeugnis + // nicht setzt —, und Nummer 11 verweist auf einen Anhang des ändernden Gesetzes, der nicht + // vorliegt. Was nicht vorliegt, lässt sich nicht anwenden. var offen = anwendung.protokoll().stream() .filter(a -> a.status() == BefehlAnwender.Status.MANUELL_PRUEFEN) .map(a -> a.befehl().provenienz().gliederungsPfad()) .toList(); - assertThat(offen).containsExactly("10. a)", "10. b)", "10. c)", "11."); + assertThat(offen).containsExactly("10. b)", "11."); } private static Aenderungsbefehl befehlZu( diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java index 13e4442..6c34b8c 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java @@ -152,4 +152,24 @@ class StellenParserTest { // Ein Wort, das bloß so anfängt, ist keiner. assertThat(StellenParser.istNurChapeau("In der Einleitungsformel")).isFalse(); } + + @Test + void benannteEinheitEinerAnlage() { + // „Im Ausbildungsabschnitt 1 …“ — der Ausbildungsrahmenplan gliedert sich in benannte + // Einheiten, die das Portal wie eigene Normen führt. + var stelle = StellenParser.parse("Ausbildungsabschnitt 1").orElseThrow(); + assertThat(stelle.anzeigeText()).isEqualTo("Ausbildungsabschnitt 1"); + assertThat(stelle.anlagenEinheit()).isPresent(); + assertThat(stelle.betrifftEchteGliederung()).isFalse(); + } + + @Test + void unterabschnittBleibtGliederungDesGesetzes() { + // Er endet auf denselben Wortstamm, gliedert aber das Gesetz und ist keine Einheit einer + // Anlage. Ohne diese Grenze fiele „Die Überschrift zu Unterabschnitt 4 wird gestrichen“ aus + // dem Gliederungszweig heraus. + var stelle = StellenParser.parse("Unterabschnitt 4").orElseThrow(); + assertThat(stelle.anlagenEinheit()).isEmpty(); + assertThat(stelle.betrifftEchteGliederung()).isTrue(); + } } diff --git a/src/test/resources/sampledata/MecklenburgVorpommern/APOAmtsTA-MV-alt.txt b/src/test/resources/sampledata/MecklenburgVorpommern/APOAmtsTA-MV-alt.txt index 32a5bd0..c8749d7 100644 --- a/src/test/resources/sampledata/MecklenburgVorpommern/APOAmtsTA-MV-alt.txt +++ b/src/test/resources/sampledata/MecklenburgVorpommern/APOAmtsTA-MV-alt.txt @@ -216,3 +216,54 @@ Für Veterinärreferendarinnen und Veterinärreferendare mit Behinderungen sind Abschnitt 4 Schlussvorschriften § 28 Inkrafttreten, Außerkrafttreten Diese Verordnung tritt am 1. Oktober 2016 in Kraft. Gleichzeitig tritt die Ausbildungs- und Prüfungsordnung höherer Veterinärdienst vom 29. Dezember 1997 (GVOBl. M-V 1998 S. 85), die zuletzt durch Artikel 3 Absatz 8 des Gesetzes vom 1. Dezember 2008 (GVOBl. M-V S. 461, 464) geändert worden ist, außer Kraft. +Anlage 1 +Ausbildungsrahmenplan +(zu § 7 Absatz 3, § 12 Absatz 3) +Die Lernziele und Lerninhalte richten sich nach dem Modulsystem der Länderarbeitsgemeinschaft Verbraucherschutz. +Ausbildungsabschnitt 1 +Ministerium für Landwirtschaft, Umwelt und Verbraucherschutz +Dauer: 7 Monate +Ausbildungsinhalte: + - Aufbau und Funktion der Verwaltung, insbesondere der Veterinärverwaltung, + - Aufgaben der Dienst- und Fachaufsicht, Einblick in die laufenden Geschäftsvorgänge, Verwaltungs- und Haushaltsrecht, Bearbeitung von Vorgängen, Fertigung von Vermerken, Vorlagen, Schreiben, Berichten und Halten von Vorträgen, + - Erstellung von Entwürfen für Verordnungen, Verfügungen, Genehmigungen, Zulassungen, Obergutachten; konkrete Durchführung der Fachaufsicht bezüglich des Vollzuges des Tierseuchen-, Lebensmittel-, Tierschutz-, Arzneimittel-, Betäubungsmittel-, Heilmittelwerbe-, Futtermittel-, Tierische Nebenprodukte-Beseitigungs- und Abfallrechtes, + - Teilnahme an dem Lehrgang für technische Referendare, der einen Gesamtüberblick über die wesentlichen Aufgaben der allgemeinen und der landwirtschaftlichen Verwaltung gibt, Schulung im Vortrag während dieses Lehrganges. +Ausbildungsabschnitt 2 +Veterinär- und Lebensmittelüberwachungsamt +Dauer: 6 Monate +Ausbildungsinhalte: + - allgemeine und spezielle Tierseuchenbekämpfungsmaßnahmen bei anzeigepflichtigen Tierseuchen und meldepflichtigen Tierkrankheiten, Tiergesundheit, Tierseuchenprophylaxe, Beseitigung tierischer Nebenprodukte, + - Überwachung der Erzeugung, Herstellung, Be- und Verarbeitung und des Inverkehrbringens von Lebensmitteln, Bedarfsgegenständen und Kosmetika, + - Beteiligung an der Fortbildung von Hilfskräften, + - Vorbereitung, Durchführung und Nachbereitung tierschutzrechtlicher Kontrollen, erforderlichenfalls Anordnung und Durchführung von Maßnahmen zur Behebung vorliegender und zur Vermeidung zukünftiger Verstöße, + - Berechnung und Erhebung von Veterinärverwaltungskosten, + - Aufgaben im Strahlenschutz und Katastrophenschutz, + - Einweisung in die Aufgaben als Sachverständiger vor Gericht, + - Koordination der behördlichen Zusammenarbeit, insbesondere mit der Ordnungsbehörde und der Staatsanwaltschaft sowie mit praktizierenden Tierärzten, Fachorganisationen und -verbänden. +Ausbildungsabschnitt 3 +Landesamt für Landwirtschaft, Lebensmittelsicherheit und Fischerei +Dauer: 4 Monate +Ausbildungsinhalte: + - Vertiefung der Kenntnisse bezüglich Untersuchungsverfahren zur Diagnostik von Tierseuchen, Tierkrankheiten und Zoonosen, + - Grundsätze der Probenplanung unter Berücksichtigung des Risikokonzeptes und Überwachungsprogrammen, Datenmeldung, + - risikoorientierte Untersuchung und Beurteilung nach dem Lebensmittel-, Bedarfsgegenstände- und Kosmetikrecht, + - Untersuchungen und Beurteilungen nach dem Arzneimittel-, Betäubungsmittel- und Futtermittelrecht, + - Überwachung der tierärztlichen Hausapotheken, der Herstellung und des Einsatzes von Fütterungsarzneimitteln, + - Probeentnahmen im Rahmen der Tierarzneimittelüberwachung, + - Aufgaben der veterinärmedizinischen Bauhygiene, + - Erstellung von Stellungnahmen und Gutachten, + - Bearbeitung von Zulassungs- und Genehmigungsverfahren, + - Grundsätze des Tierschutzrechts und des Tierversuchswesens, + - Inhalt und praktische Anwendung des Tierische Nebenprodukte-Beseitigungsrechts. +Ausbildungsabschnitt 4 +Veterinär- und Lebensmittelüberwachungsamt, Sachgebiet Schlachttier- und Fleischuntersuchung und Hygieneüberwachung +Dauer: 2 Monate +Ausbildungsinhalte: + - amtliche Überwachung von Frischfleisch, Überprüfungs- und Inspektionsaufgaben, Genusstauglichkeitskennzeichnung und Maßnahmen im Anschluss an die Kontrollen, + - Überwachung von Schlachttiertransporten, Kontrolle der Anlieferung der Tiere, gegebenenfalls tierschutzgerechte Tötung, Unterbringung der Tiere und Zutrieb zur Betäubung, Betäubungs- und Tötungsverfahren, + - Beseitigung von tierischen Nebenprodukten. +Ausbildungsabschnitt 5 +Fachseminar +Dauer: 3 Monate +Ausbildungsinhalte: + - Vertiefung der aufgabenbezogenen wissenschaftlichen Kenntnisse und der Kenntnisse im allgemeinen Verwaltungsrecht und in Teilen des besonderen Verwaltungsrechtes diff --git a/src/test/resources/sampledata/MecklenburgVorpommern/SOURCES b/src/test/resources/sampledata/MecklenburgVorpommern/SOURCES index f821362..af7a157 100644 --- a/src/test/resources/sampledata/MecklenburgVorpommern/SOURCES +++ b/src/test/resources/sampledata/MecklenburgVorpommern/SOURCES @@ -77,12 +77,39 @@ Beispieldaten Mecklenburg-Vorpommern — Herkunft und Aufbereitung - Hochgestellte Fußnotenziffern an den Artikel-Überschriften des Mantelgesetzes („Änderung der … amtstierärztlicher Dienst⁴⁴“). -5. Benannte Grenzen - Vier der 24 Befehle bleiben liegen, sämtlich die *Anlagen* betreffend: - Nummer 10 Buchstaben a bis c ändern die Anlage 1 (Ausbildungsrahmenplan) über - deren „Ausbildungsabschnitte“, Nummer 11 ersetzt die Anlage 2 durch eine - Fassung, die im *Anhang des Änderungsgesetzes* steht. Die Anlagen sind - Tabellen und Vordrucke; der kanonische Klartext hat für sie keine Form, und - sie sind in der Stammfassung deshalb nicht mitgeführt. Der Verweis auf einen - Anhang des ändernden Gesetzes ist überdies eine Form, die das Erzeugnis nicht - auflöst. +5. Die Anlage 1 (nachgetragen am 28.08.2026) + Die Stammfassung führt seither den Ausbildungsrahmenplan (Anlage 1) mit. Er + steht im Ursprungsheft GVOBl. M-V 2016 Nr. 12 auf den Seiten 498 bis 500 und + ist über das Internet-Archiv beschafft worden, weil der Wirt regierung-mv.de + einer Skriptabfrage nicht antwortet: + https://web.archive.org/web/20220302185826/https://www.regierung-mv.de/static/ + Regierungsportal/Justizministerium/Inhalte/Rechtliches/GVOBI.M-V/Dateien/ + GVOBl_1245663.pdf (abgerufen am 28.08.2026). + + Der Befund dabei ist wichtiger als der Nachtrag selbst: **Die Anlage 1 ist + keine Tabelle.** Sie ist gegliederter Fließtext — je Ausbildungsabschnitt eine + Kopfzeile, die Ausbildungsstelle, die Dauer und eine Spiegelstrichliste der + Inhalte. Der kanonische Klartext trägt sie unverändert; die frühere Annahme, + die Anlagen ließen sich nur als Tabellen führen, trifft allein auf die Anlage 2 + zu (Vordruck des Befähigungsberichts mit den Spalten Wertung, Wertigkeit, + Einzelergebnis). + + Aufbereitet mit `--extract-only`: Kopfzeilen ohne Doppelpunkt, Spiegelstriche + als „ - “ eingerückt, der Kolumnentitel („Nr. 12 Tag der Ausgabe …“) entfernt. + Die fünf Ausbildungsabschnitte werden — wie die Nummern des Berliner + Zuständigkeitskatalogs — als eigene Normen geführt: „Anlage 1 + Ausbildungsabschnitt 1“ bis „… 5“. + +6. Benannte Grenzen + Zwei der 24 Befehle bleiben liegen: + - Nummer 10 Buchstabe b fügt einen ganzen Ausbildungsabschnitt ein. Eine neue + Norm *innerhalb* einer Anlage setzt das Erzeugnis nicht; die Einfügung ganzer + Einheiten ist an den §-Kopf gebunden. + - Nummer 11 ersetzt die Anlage 2 durch eine Fassung, die im *Anhang des + Änderungsgesetzes* steht. Der Verweis auf einen Anhang des ändernden Gesetzes + wird nicht aufgelöst, und die neue Fassung liegt damit nicht vor. Was nicht + vorliegt, lässt sich nicht anwenden. + + Die Anlage 2 selbst ist aus demselben Grund nicht nachgetragen: Sie ist ein + Vordruck, ihr einziger Befehl ersetzt sie ohnehin ganz, und ihre Form wäre die + einzige im ganzen Beispielkorpus, für die der kanonische Klartext keine hat. diff --git a/src/test/resources/sampledata/korpus-grundlinie.tsv b/src/test/resources/sampledata/korpus-grundlinie.tsv index 60da4f6..b5b360c 100644 --- a/src/test/resources/sampledata/korpus-grundlinie.tsv +++ b/src/test/resources/sampledata/korpus-grundlinie.tsv @@ -1,4 +1,4 @@ -# Grundlinie des Korpuslaufs (§ 6d des Handbuchs), Stand 28. August 2026. +# Grundlinie des Korpuslaufs (§ 6d des Handbuchs), Stand 28. August 2026 (zweite Fassung des Tages). # # Jede Zeile hält fest, was ein Auftrag der Liste „korpus.tsv“ zu diesem Zeitpunkt hergegeben hat. # Der Lauf wird dagegen gehalten (KorpusberichtTest, „--grundlinie“): Gerügt wird allein, was @@ -34,7 +34,7 @@ TH-KiGaFinVO 10 10 0 0 - - - - - - BB-FraktG 4 4 0 0 24 24 0 0 0 - HH-GutachterausschussVO 21 17 4 0 10 14 0 0 4 Befehl nicht erkannt:2; Stelle nicht auffindbar:1; Zieltext nicht vorhanden:1 HB-BerufsfachschulVO 41 37 4 0 26 29 1 0 2 Befehl nicht erkannt:3; Fundstelle mehrdeutig:1 -MV-APOAmtsTA 24 20 4 0 - - - - - Befehl nicht erkannt:4 +MV-APOAmtsTA 24 22 2 0 - - - - - Befehl nicht erkannt:2 RP-UKAPOGS 23 9 14 0 - - - - - Stelle nicht auffindbar:2; Zieltext nicht vorhanden:10; Bestand widerspricht dem Befehl:2 GEG-GModG-RegE 97 87 10 0 - - - - - Befehl nicht erkannt:6; Stelle nicht auffindbar:2; Zieltext nicht vorhanden:2 GEG-Beschlussempfehlung 119 70 49 0 - - - - - Befehl nicht erkannt:1; Stelle nicht auffindbar:3; Zieltext nicht vorhanden:40; Fundstelle mehrdeutig:1; Bestand widerspricht dem Befehl:4 -- cgit v1.2.1