diff options
Diffstat (limited to 'src')
12 files changed, 268 insertions, 26 deletions
diff --git a/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java b/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java index 12a152e..fe29437 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java @@ -144,7 +144,35 @@ public record Stelle(List<Komponente> komponenten) { return komponenten.stream() .filter(Gliederungseinheit.class::isInstance) .map(Gliederungseinheit.class::cast) - .anyMatch(g -> !istAnlagenArt(g.art())); + .anyMatch(g -> !istAnlagenArt(g.art()) && !istAnlagenEinheitsArt(g.art())); + } + + /** + * Die benannte Einheit einer Anlage („Ausbildungsabschnitt 1“), falls vorhanden. + * + * <p>Sie gliedert nicht das Gesetz, sondern die Anlage, und wird — wie deren Nummern — als eigene + * Norm geführt, deren Bezeichnung die Anlage voranstellt („Anlage 1 Ausbildungsabschnitt 1“). + */ + public Optional<Gliederungseinheit> anlagenEinheit() { + return komponenten.stream() + .filter(Gliederungseinheit.class::isInstance) + .map(Gliederungseinheit.class::cast) + .filter(g -> istAnlagenEinheitsArt(g.art())) + .findFirst(); + } + + /** + * Trägt die Art den Bau einer benannten Anlagen-Einheit? Buchstaben <em>vor</em> dem Wortstamm + * sind verlangt: „Ausbildungsabschnitt“ trifft, „Abschnitt“ nicht — der gliedert das Gesetz. + */ + private static boolean istAnlagenEinheitsArt(String art) { + // „Unterabschnitt“ endet zwar auf den Wortstamm, gliedert aber das Gesetz und ist keine + // Einheit einer Anlage; ebenso der schlichte „Abschnitt“. + if (art.equalsIgnoreCase("Abschnitt") || art.equalsIgnoreCase("Unterabschnitt")) { + return false; + } + int stelle = art.length() - "abschnitt".length(); + return stelle > 0 && art.regionMatches(true, stelle, "abschnitt", 0, "abschnitt".length()); } /** Die enbez der adressierten Anhang-/Anlagen-Norm („Anhang“, „Anlage 2“), falls vorhanden. */ 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 dc12398..1d0685b 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java @@ -484,7 +484,7 @@ final class BefehlErkenner { Pattern.compile( "^(?:Der bisherige |Die bisherige |Das bisherige )?(.+?) wird (?:zu )?(?:der |die |das )?" + "(§|Art\\.|Absatz|Abs\\.|Satz|Nummer|Nr\\.|Buchstabe|Buchst\\." - + "|Teil|Abschnitt|Unterabschnitt|Buch|Kapitel|Anlage) " + + "|Teil|Abschnitt|Unterabschnitt|Buch|Kapitel|Anlage|\\p{L}+abschnitt) " + "(\\d+[a-z]?)\\.$"); // „Die bisherigen Absätze 2 bis 4 werden zu den Absätzen 3 bis 5.“ bzw. „Die bisherigen Nummern 4 @@ -722,7 +722,7 @@ final class BefehlErkenner { Pattern.compile( "^(?:Der bisherige |Die bisherige |Das bisherige )?(.+?) wird (?:zu )?" + "(§|Art\\.|Absatz|Abs\\.|Satz|Nummer|Nr\\.|Buchstabe|Buchst\\." - + "|Teil|Abschnitt|Unterabschnitt|Buch|Kapitel|Anlage)" + + "|Teil|Abschnitt|Unterabschnitt|Buch|Kapitel|Anlage|\\p{L}+abschnitt)" // Der Wächter „(?!wird |werden )“ ist nötig: ohne ihn verschlänge die Untereinheit // in der schlichten Form („Abs. 3 wird Abs. 2 und wird wie folgt geändert:“) das // Verb und wäre als Stelle unparsbar. @@ -2194,7 +2194,15 @@ final class BefehlErkenner { case "Buchstabe", "Buchst." -> new Stelle.BuchstabeNr(nummer); case "Teil", "Abschnitt", "Unterabschnitt", "Buch", "Kapitel", "Anlage" -> new Stelle.Gliederungseinheit(ebene, nummer); - default -> throw new IllegalArgumentException("Unbekannte Ebene: " + ebene); + // Die benannte Einheit einer Anlage („Ausbildungsabschnitt 5“) — sie gliedert die Anlage, + // nicht das Gesetz, und wird wie deren Nummern als eigene Norm geführt. + default -> { + if (!ebene.regionMatches(true, Math.max(0, ebene.length() - 9), "abschnitt", 0, 9) + || ebene.length() <= 9) { + throw new IllegalArgumentException("Unbekannte Ebene: " + ebene); + } + yield new Stelle.Gliederungseinheit(ebene, nummer); + } }; } diff --git a/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java b/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java index f6e7360..e772846 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java @@ -230,6 +230,18 @@ public final class StellenParser { i++; } default -> { + // Die benannte Einheit einer Anlage: „Im Ausbildungsabschnitt 1 …“. Sie steht nicht in + // der Liste der Gliederungsarten, weil ihr Name der Anlage gehört und nicht dem Gesetz; + // erkannt wird sie an ihrem Bau (siehe istAnlagenEinheit). + if (istAnlagenEinheit(wort)) { + var wert = naechstesWort(woerter, i); + if (wert != null && NUMMER_WERT.matcher(wert).matches()) { + komponenten.add(new Stelle.Gliederungseinheit(anlagenEinheitsArt(wort), wert)); + i++; + continue; + } + return Optional.empty(); + } // Ordinal vor der Gliederungsart: „zum zweiten Abschnitt“, „des 2. Abschnitts“. var ordinal = ordinalZahl(wort); var art = ordinal != null ? naechstesWort(woerter, i) : null; @@ -573,6 +585,29 @@ public final class StellenParser { }; } + /** + * Die benannte Einheit einer Anlage („Ausbildungsabschnitt 1“ des Ausbildungsrahmenplans). + * + * <p>Erkannt wird sie an ihrem Bau und nicht an einer Wortliste: Jede Anlage darf ihre Einheiten + * nennen, wie sie will, und eine Liste wäre am nächsten Land wieder unvollständig. Verlangt sind + * Buchstaben <em>vor</em> dem Wortstamm — „Ausbildungsabschnitt“ trifft, „Abschnitt“ nicht, denn + * der gliedert das Gesetz und ist anderswo geregelt. + */ + private static final Pattern ANLAGEN_EINHEIT = + Pattern.compile("^(\\p{L}+abschnitt)(?:s|e|es|en)?$", Pattern.CASE_INSENSITIVE); + + private static boolean istAnlagenEinheit(String wort) { + // „Unterabschnitt“ endet auf den Wortstamm, gliedert aber das Gesetz; er ist oben abgehandelt + // und darf hier nicht noch einmal zugreifen. + return !istGliederungsArt(wort) && ANLAGEN_EINHEIT.matcher(wort).matches(); + } + + /** Der Nominativ Singular der benannten Einheit („Ausbildungsabschnitts“ → „…abschnitt“). */ + private static String anlagenEinheitsArt(String wort) { + var treffer = ANLAGEN_EINHEIT.matcher(wort); + return treffer.matches() ? treffer.group(1) : wort; + } + /** Normalisiert Genitiv-/Pluralformen der Gliederungsart auf den Nominativ Singular. */ private static String gliederungsArt(String wort) { return switch (wort) { diff --git a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java index eb69423..a73ab77 100644 --- a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java +++ b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java @@ -2217,6 +2217,38 @@ public final class BefehlAnwender { return angewandt(befehl, enbezNeu); } + // „Der bisherige Ausbildungsabschnitt 5 wird zu Ausbildungsabschnitt 6.“ — die benannte + // Einheit einer Anlage ist eine eigene Norm; umnummeriert wird deren Bezeichnung. Der Befehl + // nennt nur die Einheit, die Norm heißt aber „Anlage 1 Ausbildungsabschnitt 6“: Die Anlage + // steht im Bestand und wird von dort übernommen, nicht aus dem Befehl erraten. + var altEinheit = befehl.stelle().anlagenEinheit(); + var neuEinheit = befehl.neu().anlagenEinheit(); + if (altEinheit.isPresent() && neuEinheit.isPresent()) { + var ergebnis = StellenAufloeser.aufloese(gesetzAus(normen), befehl.stelle()); + if (ergebnis instanceof StellenAufloeser.Ergebnis.NichtGefunden nicht) { + return manuell(befehl, nicht.grund(), nicht.begruendung()); + } + var idx = ((StellenAufloeser.Ergebnis.Gefunden) ergebnis).fundstelle().normIndex(); + var enbezAlt = normen.get(idx).enbez(); + var alteBezeichnung = altEinheit.get().bezeichnung(); + if (!enbezAlt.endsWith(alteBezeichnung)) { + return manuell( + befehl, + Grund.BESTAND_WIDERSPRICHT, + "„" + enbezAlt + "“ trägt nicht die Bezeichnung „" + alteBezeichnung + "“."); + } + var enbezNeu = + enbezAlt.substring(0, enbezAlt.length() - alteBezeichnung.length()) + + neuEinheit.get().bezeichnung(); + if (!enbezNeu.equals(enbezAlt) + && StellenAufloeser.normIndex(gesetzAus(normen), enbezNeu) >= 0) { + return manuell( + befehl, Grund.BESTAND_WIDERSPRICHT, enbezNeu + " existiert bereits im Gesetz."); + } + normen.set(idx, normen.get(idx).mitEnbez(enbezNeu)); + return angewandt(befehl, enbezNeu); + } + var altAbsatz = befehl.stelle().absatz(); var neuAbsatz = befehl.neu().absatz(); // Nur wenn der Absatz selbst das Umnummerierungsziel ist — bei „Satz 5 wird Satz 4“ stammt diff --git a/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java b/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java index 32d9c8b..f9d4ff2 100644 --- a/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java +++ b/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java @@ -64,6 +64,16 @@ final class StellenAufloeser { stelle = stelle.ohne(nummer.get()); } } + // Ebenso die benannte Einheit einer Anlage („Anlage 1 Ausbildungsabschnitt 1“): Sie gliedert + // nicht das Gesetz, sondern die Anlage, und der Ausbildungsrahmenplan führt sie so. + var einheit = stelle.anlagenEinheit(); + if (einheit.isPresent()) { + var alsNorm = enbez + " " + einheit.get().bezeichnung(); + if (normIndex(gesetz, alsNorm) >= 0) { + enbez = alsNorm; + stelle = stelle.ohne(einheit.get()); + } + } } else { return new Ergebnis.NichtGefunden( "Stelle nennt keinen Paragraphen: " + stelle.anzeigeText(), diff --git a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextAusgeber.java b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextAusgeber.java index 3a82945..74d6e11 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextAusgeber.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextAusgeber.java @@ -40,7 +40,9 @@ public final class LandesRechtTextAusgeber { * Anlagen-Norm stellt den Bezug schon her. */ private static final Pattern ANLAGEN_NUMMER = - Pattern.compile("^(?:Anlage|Anhang)(?:\\s+\\d+[a-z]?)?\\s+((?:Nummer|Nr\\.)\\s+\\d+[a-z]?)$"); + Pattern.compile( + "^(?:Anlage|Anhang)(?:\\s+\\d+[a-z]?)?" + + "\\s+((?:Nummer|Nr\\.|\\p{L}+abschnitt)\\s+\\d+[a-z]?)$"); private LandesRechtTextAusgeber() {} diff --git a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java index 7f7e2f4..b93ef5d 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java @@ -149,6 +149,16 @@ final class LandesRechtTextParser { "^((?:\\(X+\\) )?(?:§§|Artt\\.) \\S.*?) {2}(\\((?:weggefallen|aufgehoben)\\))$"); /** + * Eine benannte Einheit innerhalb einer Anlage: die Nummer eines Zuständigkeitskatalogs („Nummer + * 6“) ebenso wie der Abschnitt eines Ausbildungsrahmenplans („Ausbildungsabschnitt 1“). + * + * <p>Die zweite Form ist nicht als „Abschnitt“ zu lesen: Ein Abschnitt gliedert das Gesetz, + * innerhalb einer Anlage gliedert nichts mehr. Verlangt sind deshalb Buchstaben <em>vor</em> dem + * Wortstamm — „Ausbildungsabschnitt“ trifft, „Abschnitt“ nicht. + */ + private static final String ANLAGEN_EINHEIT = "(?:Nummer|Nr\\.|\\p{L}+abschnitt)\\s+\\d+[a-z]?"; + + /** * Der Kopf einer Nummer innerhalb einer Anlage („Nummer 6“). Die Nummern eines * Zuständigkeitskatalogs sind keine Aufzählungsglieder, sondern eigene Einheiten mit eigener * Absatzzählung — das Landesrechtsportal führt jede als eigene Einzelnorm, und die @@ -157,7 +167,7 @@ final class LandesRechtTextParser { * voranstellt: „Anlage Nummer 6“. */ private static final Pattern ANLAGEN_NUMMER_KOPF = - Pattern.compile("^(?:Nummer|Nr\\.)\\s+(\\d+[a-z]?)\\s*$"); + Pattern.compile("^(" + ANLAGEN_EINHEIT + ")\\s*$"); private static final Pattern WEGGEFALLEN_TITEL = Pattern.compile("^\\((?:aufgehoben|weggefallen)\\)$"); @@ -331,8 +341,7 @@ final class LandesRechtTextParser { } else if (neueAnlagenNummer) { // „Anlage Nummer 6“ — die Anlage selbst bleibt als Norm vor ihnen stehen; trägt sie // keinen eigenen Wortlaut, so ist sie eben leer. - normEnbez = - (anlagenEnbez != null ? anlagenEnbez + " " : "") + "Nummer " + anlagenNummer.group(1); + normEnbez = (anlagenEnbez != null ? anlagenEnbez + " " : "") + anlagenNummer.group(1); normTitel = null; } else if (neueNorm) { normEnbez = normKopf.group(1) + " " + normKopf.group(2); 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 |
