Aktualisierung der AM-RL-Module und Retrieval-Logik
Browse files
src/__pycache__/norm_anchors.cpython-311.pyc
ADDED
|
Binary file (90.7 kB). View file
|
|
|
src/norm_anchors.py
CHANGED
|
@@ -196,11 +196,19 @@ class Fehlgriff:
|
|
| 196 |
stört auch neben der richtigen Norm. § 40c AM-RL betrifft ausschließlich
|
| 197 |
biotechnologisch hergestellte Arzneimittel; in einer allgemeinen Frage nach
|
| 198 |
Darreichungsformen verengt er die Antwort auf einen Sonderfall.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
"""
|
| 200 |
|
| 201 |
muster: str
|
| 202 |
warum: str
|
| 203 |
nur_ohne_tragende: bool = True
|
|
|
|
| 204 |
wenn: Bedingung = Bedingung()
|
| 205 |
|
| 206 |
|
|
@@ -659,6 +667,41 @@ ANKER: Tuple[Anker, ...] = (
|
|
| 659 |
"auf die Antwort; die Ausschlussentscheidung trifft § 34."
|
| 660 |
),
|
| 661 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 662 |
),
|
| 663 |
hinweise=(
|
| 664 |
Hinweis(
|
|
@@ -1106,7 +1149,10 @@ ANKER: Tuple[Anker, ...] = (
|
|
| 1106 |
corpus_id="rv129",
|
| 1107 |
container_id="Vertrag",
|
| 1108 |
section_id="§ 13",
|
| 1109 |
-
|
|
|
|
|
|
|
|
|
|
| 1110 |
warum="Führt die Abgabe preisgünstiger Importe nach § 9 im Einzelnen aus.",
|
| 1111 |
),
|
| 1112 |
Norm(
|
|
@@ -1114,7 +1160,10 @@ ANKER: Tuple[Anker, ...] = (
|
|
| 1114 |
corpus_id="rv129",
|
| 1115 |
container_id="Vertrag",
|
| 1116 |
section_id="§ 14",
|
| 1117 |
-
|
|
|
|
|
|
|
|
|
|
| 1118 |
warum=(
|
| 1119 |
"Regelt abschließend, wann von der Abgaberangfolge abgewichen werden "
|
| 1120 |
"darf. Eine Antwort, die nur sagt, die vorrangige Abgabe sei „nicht "
|
|
@@ -1122,6 +1171,35 @@ ANKER: Tuple[Anker, ...] = (
|
|
| 1122 |
),
|
| 1123 |
),
|
| 1124 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1125 |
hinweise=(
|
| 1126 |
Hinweis(
|
| 1127 |
# Ohne Fallbezug ist das ein Sonderfall und gehört nicht in die Kette.
|
|
@@ -1909,6 +1987,20 @@ def normabschnitt(answer: str) -> str:
|
|
| 1909 |
return answer or ""
|
| 1910 |
|
| 1911 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1912 |
# „§ 34 Abs. 1 SGB V“ soll auch auf „§ 34 SGB V“ und „§ 34 Absatz 1“ passen: das
|
| 1913 |
# Modell schreibt die Norm selten genau so, wie das Register sie führt. Geprüft
|
| 1914 |
# wird deshalb nur der Paragraf — der Absatz ist eine Genauigkeit, die eine
|
|
@@ -1976,13 +2068,14 @@ def pruefe(question: str = "", answer: str = "") -> Befund:
|
|
| 1976 |
# Ein Fehlgriff der Sorte „gehört dazu, nur nicht als die entscheidende Norm"
|
| 1977 |
# zählt nur, wenn keine tragende Norm neben ihm steht. § 31 SGB V gehört in
|
| 1978 |
# eine OTC-Antwort — nur eben nicht als die Norm, die den Ausschluss trifft.
|
|
|
|
| 1979 |
tragend_im_abschnitt = any(_genannt_in(n.zitat, abschnitt) for n in tragende)
|
| 1980 |
fehlgriffe = [
|
| 1981 |
f
|
| 1982 |
for a in anker
|
| 1983 |
for f in a.fehlgriffe
|
| 1984 |
if f.wenn.gilt(haystack)
|
| 1985 |
-
and re.search(f.muster, abschnitt)
|
| 1986 |
and not (f.nur_ohne_tragende and tragend_im_abschnitt)
|
| 1987 |
]
|
| 1988 |
|
|
@@ -2084,7 +2177,12 @@ def _ohne_verworfene_bloecke(text: str, fehlgriffe: List[Fehlgriff]) -> str:
|
|
| 2084 |
Eine Abschnittsüberschrift schützt ihren Absatz: Text unter einer eigenen
|
| 2085 |
Überschrift zu löschen hieße, den Abschnitt zu entscheiden, und dafür ist
|
| 2086 |
das Register nicht zuständig.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2087 |
"""
|
|
|
|
| 2088 |
if not fehlgriffe or not (text or "").strip():
|
| 2089 |
return text
|
| 2090 |
|
|
@@ -2115,6 +2213,7 @@ def _nimmt_noch_bezug(text: str, fehlgriffe: List[Fehlgriff]) -> bool:
|
|
| 2115 |
Ein Hinweis auf einen „Restbezug" wäre dort eine Warnung vor dem richtigen
|
| 2116 |
Zitat.
|
| 2117 |
"""
|
|
|
|
| 2118 |
if not fehlgriffe:
|
| 2119 |
return False
|
| 2120 |
ersetzt = (_KURZ_UEBERSCHRIFT, _NORM_UEBERSCHRIFT, "Wortlaut")
|
|
@@ -2153,11 +2252,18 @@ def befund_block(befund: Befund, *, restverweis: bool = False) -> str:
|
|
| 2153 |
if befund.status == "abweichung":
|
| 2154 |
zeilen.append(f"{_KORREKTUR_EINLEITUNG} ({themen}):")
|
| 2155 |
if befund.fehlgriffe:
|
| 2156 |
-
|
| 2157 |
-
|
| 2158 |
-
|
| 2159 |
-
|
| 2160 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2161 |
for fehlgriff in befund.fehlgriffe:
|
| 2162 |
zeilen.append(f" {fehlgriff.warum}")
|
| 2163 |
else:
|
|
|
|
| 196 |
stört auch neben der richtigen Norm. § 40c AM-RL betrifft ausschließlich
|
| 197 |
biotechnologisch hergestellte Arzneimittel; in einer allgemeinen Frage nach
|
| 198 |
Darreichungsformen verengt er die Antwort auf einen Sonderfall.
|
| 199 |
+
|
| 200 |
+
`im_kurzabschnitt=True` — das Muster wird gegen die **Kurzantwort** geprüft,
|
| 201 |
+
nicht gegen den Normabschnitt. Manche Fehler stehen nicht in der Wahl der
|
| 202 |
+
Vorschrift, sondern in ihrer Zusammenfassung: die OTC-Kurzantwort nennt die
|
| 203 |
+
richtige Norm (§ 34) und fasst ihre Absätze trotzdem falsch zusammen. Ein
|
| 204 |
+
solcher Fehlgriff treibt keine Blockentfernung (`_ohne_verworfene_bloecke`);
|
| 205 |
+
er löst allein die Neusetzung der Kurzantwort aus der `kernaussage` aus.
|
| 206 |
"""
|
| 207 |
|
| 208 |
muster: str
|
| 209 |
warum: str
|
| 210 |
nur_ohne_tragende: bool = True
|
| 211 |
+
im_kurzabschnitt: bool = False
|
| 212 |
wenn: Bedingung = Bedingung()
|
| 213 |
|
| 214 |
|
|
|
|
| 667 |
"auf die Antwort; die Ausschlussentscheidung trifft § 34."
|
| 668 |
),
|
| 669 |
),
|
| 670 |
+
Fehlgriff(
|
| 671 |
+
# Gemessen am realen Lauf: die Kurzantwort nannte die richtige Norm
|
| 672 |
+
# (§ 34), machte aber die in § 34 Abs. 1 Satz 5 ff. genannten Gruppen
|
| 673 |
+
# zum Negativmaßstab der OTC-Ausnahme („… nicht zu den ausgeschlossenen
|
| 674 |
+
# Gruppen wie Abführmittel … gehört“). Das vermischt zwei Regelungs-
|
| 675 |
+
# komplexe. Der Fehlgriff sucht deshalb die Kurzantwort, nicht den
|
| 676 |
+
# Normabschnitt, und feuert nicht, wenn die Frage selbst eine der
|
| 677 |
+
# Gruppen benennt (dann ist ihre Nennung sachgerecht).
|
| 678 |
+
muster=(
|
| 679 |
+
r"(?is)nicht zu (?:den|einer)\b.{0,80}ausgeschlossen"
|
| 680 |
+
r".{0,120}(abführmittel|abfuehrmittel|reisekrankheit|erkältung"
|
| 681 |
+
r"|erkaeltung|rachentherapeutika|grippal)"
|
| 682 |
+
),
|
| 683 |
+
warum=(
|
| 684 |
+
"Die in § 34 Abs. 1 Satz 5 ff. SGB V genannten Gruppen (Erkältungs- "
|
| 685 |
+
"und Grippemittel, Mund- und Rachentherapeutika, Abführmittel, Mittel "
|
| 686 |
+
"gegen Reisekrankheit) sind ein eigener Ausschluss bestimmter "
|
| 687 |
+
"verschreibungspflichtiger Arzneimittel für Erwachsene — nicht der "
|
| 688 |
+
"Negativmaßstab der OTC-Ausnahme. Ob ein nicht verschreibungspflichtiges "
|
| 689 |
+
"Arzneimittel ausnahmsweise verordnungsfähig ist, entscheidet allein "
|
| 690 |
+
"§ 12 in Verbindung mit Anlage I der AM-RL; ein nicht "
|
| 691 |
+
"verschreibungspflichtiges Abführmittel etwa kann für eine dort "
|
| 692 |
+
"gelistete schwerwiegende Erkrankung verordnungsfähig sein."
|
| 693 |
+
),
|
| 694 |
+
nur_ohne_tragende=False,
|
| 695 |
+
im_kurzabschnitt=True,
|
| 696 |
+
wenn=Bedingung(
|
| 697 |
+
nicht_bei=(
|
| 698 |
+
"abführmittel",
|
| 699 |
+
"abfuehrmittel",
|
| 700 |
+
"reisekrankheit",
|
| 701 |
+
"rachentherapeutika",
|
| 702 |
+
)
|
| 703 |
+
),
|
| 704 |
+
),
|
| 705 |
),
|
| 706 |
hinweise=(
|
| 707 |
Hinweis(
|
|
|
|
| 1149 |
corpus_id="rv129",
|
| 1150 |
container_id="Vertrag",
|
| 1151 |
section_id="§ 13",
|
| 1152 |
+
# Die Frage nennt den Import ausdrücklich; ohne § 13 als maßgebliche
|
| 1153 |
+
# Norm fehlt die Vorschrift, die seine Abgabe regelt. Ein Chunk genügt:
|
| 1154 |
+
# der Anker soll ihn benennen und knapp belegen, nicht ausbreiten.
|
| 1155 |
+
chunks=1,
|
| 1156 |
warum="Führt die Abgabe preisgünstiger Importe nach § 9 im Einzelnen aus.",
|
| 1157 |
),
|
| 1158 |
Norm(
|
|
|
|
| 1160 |
corpus_id="rv129",
|
| 1161 |
container_id="Vertrag",
|
| 1162 |
section_id="§ 14",
|
| 1163 |
+
# Die Frage fragt ausdrücklich nach der Abweichung von der Rangfolge;
|
| 1164 |
+
# § 14 ist die Vorschrift, die sie regelt, und gehört damit in die
|
| 1165 |
+
# maßgeblichen Normen. Ein Chunk hält das Abrufbudget schmal.
|
| 1166 |
+
chunks=1,
|
| 1167 |
warum=(
|
| 1168 |
"Regelt abschließend, wann von der Abgaberangfolge abgewichen werden "
|
| 1169 |
"darf. Eine Antwort, die nur sagt, die vorrangige Abgabe sei „nicht "
|
|
|
|
| 1171 |
),
|
| 1172 |
),
|
| 1173 |
),
|
| 1174 |
+
fehlgriffe=(
|
| 1175 |
+
Fehlgriff(
|
| 1176 |
+
# Gemessen am realen Lauf: die Antwort stützte die allgemeine Abweichung
|
| 1177 |
+
# auf § 14 Abs. 5 und zitierte „In den Fällen des § 129 Absätze 2a und
|
| 1178 |
+
# 2b SGB V …“, obwohl die Frage keinen dieser Tatbestände nennt. Der
|
| 1179 |
+
# Fehlgriff feuert deshalb nur, wenn die Frage 2a/2b nicht aufwirft.
|
| 1180 |
+
muster=r"§\s*14\s+Abs(?:atz|\.)?\s*5",
|
| 1181 |
+
warum=(
|
| 1182 |
+
"§ 14 Abs. 5 Rahmenvertrag gilt nur in den Fällen des § 129 Abs. 2a "
|
| 1183 |
+
"und 2b SGB V. Ohne einen dieser Tatbestände trägt er die allgemeine "
|
| 1184 |
+
"Abweichung von der Abgaberangfolge nicht; maßgeblich sind dann die "
|
| 1185 |
+
"§§ 10 bis 14 Rahmenvertrag im Übrigen — insbesondere Nichtverfügbarkeit "
|
| 1186 |
+
"und ordnungsgemäß geltend gemachte pharmazeutische Bedenken."
|
| 1187 |
+
),
|
| 1188 |
+
nur_ohne_tragende=False,
|
| 1189 |
+
wenn=Bedingung(
|
| 1190 |
+
nicht_bei=(
|
| 1191 |
+
"abs. 2a",
|
| 1192 |
+
"absatz 2a",
|
| 1193 |
+
"abs 2a",
|
| 1194 |
+
"absätze 2a",
|
| 1195 |
+
"absaetze 2a",
|
| 1196 |
+
"abs. 2b",
|
| 1197 |
+
"absatz 2b",
|
| 1198 |
+
"2a und 2b",
|
| 1199 |
+
)
|
| 1200 |
+
),
|
| 1201 |
+
),
|
| 1202 |
+
),
|
| 1203 |
hinweise=(
|
| 1204 |
Hinweis(
|
| 1205 |
# Ohne Fallbezug ist das ein Sonderfall und gehört nicht in die Kette.
|
|
|
|
| 1987 |
return answer or ""
|
| 1988 |
|
| 1989 |
|
| 1990 |
+
def kurzabschnitt(answer: str) -> str:
|
| 1991 |
+
"""Der Text unter „Kurzantwort“ — oder leer, wenn es den Abschnitt nicht gibt.
|
| 1992 |
+
|
| 1993 |
+
Anders als `normabschnitt` fällt das **nicht** auf die ganze Antwort zurück:
|
| 1994 |
+
ein Fehlgriff `im_kurzabschnitt` sucht gezielt die Zusammenfassung, und ein
|
| 1995 |
+
Rückfall würde ihn auch im Wortlaut anschlagen lassen, der die Norm richtig
|
| 1996 |
+
zitiert.
|
| 1997 |
+
"""
|
| 1998 |
+
for heading, body in _abschnitte(answer):
|
| 1999 |
+
if _ist(heading, _KURZ_UEBERSCHRIFT):
|
| 2000 |
+
return "\n".join(body)
|
| 2001 |
+
return ""
|
| 2002 |
+
|
| 2003 |
+
|
| 2004 |
# „§ 34 Abs. 1 SGB V“ soll auch auf „§ 34 SGB V“ und „§ 34 Absatz 1“ passen: das
|
| 2005 |
# Modell schreibt die Norm selten genau so, wie das Register sie führt. Geprüft
|
| 2006 |
# wird deshalb nur der Paragraf — der Absatz ist eine Genauigkeit, die eine
|
|
|
|
| 2068 |
# Ein Fehlgriff der Sorte „gehört dazu, nur nicht als die entscheidende Norm"
|
| 2069 |
# zählt nur, wenn keine tragende Norm neben ihm steht. § 31 SGB V gehört in
|
| 2070 |
# eine OTC-Antwort — nur eben nicht als die Norm, die den Ausschluss trifft.
|
| 2071 |
+
kurz = kurzabschnitt(answer)
|
| 2072 |
tragend_im_abschnitt = any(_genannt_in(n.zitat, abschnitt) for n in tragende)
|
| 2073 |
fehlgriffe = [
|
| 2074 |
f
|
| 2075 |
for a in anker
|
| 2076 |
for f in a.fehlgriffe
|
| 2077 |
if f.wenn.gilt(haystack)
|
| 2078 |
+
and re.search(f.muster, kurz if f.im_kurzabschnitt else abschnitt)
|
| 2079 |
and not (f.nur_ohne_tragende and tragend_im_abschnitt)
|
| 2080 |
]
|
| 2081 |
|
|
|
|
| 2177 |
Eine Abschnittsüberschrift schützt ihren Absatz: Text unter einer eigenen
|
| 2178 |
Überschrift zu löschen hieße, den Abschnitt zu entscheiden, und dafür ist
|
| 2179 |
das Register nicht zuständig.
|
| 2180 |
+
|
| 2181 |
+
`im_kurzabschnitt`-Fehlgriffe bleiben außen vor: sie beanstanden keine
|
| 2182 |
+
zitierte Vorschrift, sondern die Zusammenfassung, und ihr Muster ist ein
|
| 2183 |
+
Satzmuster, kein Fundstellenmuster — es dürfte hier keinen Absatz löschen.
|
| 2184 |
"""
|
| 2185 |
+
fehlgriffe = [f for f in fehlgriffe if not f.im_kurzabschnitt]
|
| 2186 |
if not fehlgriffe or not (text or "").strip():
|
| 2187 |
return text
|
| 2188 |
|
|
|
|
| 2213 |
Ein Hinweis auf einen „Restbezug" wäre dort eine Warnung vor dem richtigen
|
| 2214 |
Zitat.
|
| 2215 |
"""
|
| 2216 |
+
fehlgriffe = [f for f in fehlgriffe if not f.im_kurzabschnitt]
|
| 2217 |
if not fehlgriffe:
|
| 2218 |
return False
|
| 2219 |
ersetzt = (_KURZ_UEBERSCHRIFT, _NORM_UEBERSCHRIFT, "Wortlaut")
|
|
|
|
| 2252 |
if befund.status == "abweichung":
|
| 2253 |
zeilen.append(f"{_KORREKTUR_EINLEITUNG} ({themen}):")
|
| 2254 |
if befund.fehlgriffe:
|
| 2255 |
+
if any(not f.im_kurzabschnitt for f in befund.fehlgriffe):
|
| 2256 |
+
zeilen.append(
|
| 2257 |
+
"Kurzantwort und maßgebliche Norm oben stammen aus dem kuratierten "
|
| 2258 |
+
"Normregister; die zunächst herangezogene Vorschrift entscheidet diese "
|
| 2259 |
+
"Frage nicht."
|
| 2260 |
+
)
|
| 2261 |
+
else:
|
| 2262 |
+
zeilen.append(
|
| 2263 |
+
"Kurzantwort und maßgebliche Norm oben stammen aus dem kuratierten "
|
| 2264 |
+
"Normregister; die ursprüngliche Fassung hat die maßgeblichen "
|
| 2265 |
+
"Regelungen unzutreffend zusammengefasst."
|
| 2266 |
+
)
|
| 2267 |
for fehlgriff in befund.fehlgriffe:
|
| 2268 |
zeilen.append(f" {fehlgriff.warum}")
|
| 2269 |
else:
|