| """Welche Norm eine Frage entscheidet — kuratiert statt erraten. |
| |
| Dieselbe Bauweise wie die vier Listenmodule (`amrl_substitution`, |
| `amrl_austauschbarkeit`, `amrl_biosimilars`, `amrl_otc`), aber eine Ebene höher. |
| Die Listen sichern die **Stoffebene**: steht ein Wirkstoff auf einer Anlage. |
| Dieses Modul sichert die **Normebene**: welche Vorschrift eine Frage überhaupt |
| beantwortet. |
| |
| Der Anlass war eine Livemessung mit fünf normbezogenen Fragen — keine nannte |
| einen Wirkstoff, alle vier Lookups meldeten deshalb planmäßig `nicht_pruefbar`, |
| und zwei Antworten nannten die falsche maßgebliche Norm: |
| |
| OTC zu Lasten der GKV beantwortet mit § 31 Abs. 1 SGB V. Diese Norm |
| gewährt den Anspruch aber nur, „soweit die |
| Arzneimittel nicht nach § 34 … ausgeschlossen |
| sind“ — sie verweist auf die Antwort, sie ist sie |
| nicht. Entschieden wird die Frage von § 34 Abs. 1. |
| |
| Zuweisungsverbot beantwortet mit § 360 Abs. 2 SGB V, einer |
| Ausnahmeklausel zur E-Rezept-Pflicht. Das Ergebnis |
| stimmte zufällig, die Herleitung war verkehrt herum. |
| Das Verbot steht in § 31 Abs. 1 Satz 6. |
| |
| Beide Male standen die richtigen Normen im Index. Das Retrieval hat sie nicht |
| gefunden, weil Ähnlichkeit zur Frage etwas anderes ist als Einschlägigkeit — und |
| kein Ähnlichkeitsmaß kann den Unterschied kennen. Deshalb dieselbe Antwort wie |
| bei den Listen: eine kuratierte Tabelle und eine Substring-Prüfung, kein Modell. |
| |
| Das Register tut zwei Dinge: |
| |
| 1. **Pflichtabruf.** `pflichtabruf()` benennt Korpus, Container, § und Absatz |
| der tragenden Normen. Der `FederatedRetriever` holt sie unabhängig vom |
| Ähnlichkeitswettbewerb — die entscheidende Norm steht damit im Kontext, auch |
| wenn sie sich schlecht einbettet. |
| |
| 2. **Abgleich und Richtigstellung.** `pruefe()` liest den Abschnitt |
| „Maßgebliche Norm“ der fertigen Antwort. Fehlt ein Glied der Kette, wird es |
| nachgetragen. Steht dort eine Vorschrift, die die Frage nicht entscheidet, |
| setzt `in_antwort_einsetzen()` die Abschnitte „Kurzantwort“ und „Maßgebliche |
| Norm“ neu. |
| |
| **Warum die Antwort neu gesetzt und nicht nur ergänzt wird.** Die erste Fassung |
| hängte den richtigen Befund unter die falsche Antwort. Damit standen beide |
| nebeneinander und nichts im Text sagte, welcher gilt — dieselbe Lage, die |
| `amrl_substitution.antwort_mit_befunden` für die Listen und |
| `corpus_amendments.reconcile_negative_answer` für spätere Änderungen auflöst, |
| und sie wird hier genauso aufgelöst. |
| |
| **Eine Richtigstellung, die den Widerspruch stehen lässt, ist keine.** Der |
| Ausdruck vom 20.08.2026 zeigte die zweite Fassung von außen: die Antwort zur |
| Austauschbarkeit von Darreichungsformen begann mit der Meldung, das Modell habe |
| danebengelegen, setzte Kurzantwort und maßgebliche Norm neu — und ließ darunter |
| den vollständigen Wortlaut des verworfenen § 40c AM-RL stehen, mitsamt seinem |
| Quellenmarker und als erste Quelle der Liste. Angekündigt wurde das im Text |
| sogar („können sich noch auf die verworfene Vorschrift beziehen“); aufgelöst |
| wurde es nicht. Drei Dinge folgen daraus, und alle drei stehen unten im Code: |
| |
| * Der Hinweis steht **hinter** der Antwort, nicht davor (`in_antwort_einsetzen`). |
| * Absätze, die die verworfene Vorschrift **zitieren**, fallen weg; ihre |
| Erwähnung im Wortlaut einer anderen Norm bleibt (`_ohne_verworfene_bloecke`). |
| * Der neu gesetzte Normabschnitt übernimmt die Quellenmarker, die das Modell |
| denselben Vorschriften gegeben hat (`_marker_je_norm`) — sonst verlöre gerade |
| die richtiggestellte Norm ihren Beleg. |
| |
| **Die `kernaussage` ist die Grenze dieses Moduls.** Sie gibt wieder, was die |
| tragende Norm sagt — sie subsumiert nicht. „Vertragsärzte dürfen nicht zuweisen“ |
| steht im Gesetz; ob eine konkrete Praxis zugewiesen hat, entscheidet dieses |
| Modul nicht und darf es nicht entscheiden. Alles Fallbezogene bleibt beim |
| Modell, dessen übrige Abschnitte unangetastet stehen bleiben. |
| |
| **Bedingte Einträge gegen Übergenauigkeit.** Eine Norm, ein Hinweis oder ein |
| Fehlgriff kann an Signale gebunden werden (`nur_bei`, `nicht_bei`). Ohne das |
| trug die OTC-Antwort für eine erwachsene Versicherte den Hinweis auf Kinder bis |
| 12, und die allgemeine Frage nach Darreichungsformen bekam § 40c AM-RL |
| aufgeladen, der nur biotechnologisch hergestellte Arzneimittel betrifft. Ein |
| Register, das zu jeder Frage alles nennt, verwischt den Hauptfall. |
| |
| **Die Grenze des Registers ist Absicht.** Es enthält nur Fälle, die in der |
| Auswertung tatsächlich falsch beantwortet wurden. Jeder Eintrag ist eine |
| Rechtsbehauptung, die gepflegt werden muss; ein Register, das |
| „vorsichtshalber“ jede denkbare Frage abdeckt, ist bei der nächsten Novelle |
| stiller Ballast. Trifft kein Anker, ist der Befund `nicht_pruefbar` und die |
| Pipeline verhält sich wie zuvor. |
| |
| **Der Lifestyle-Anker ist derselbe Fehler an einer zweiten Stelle.** Auch die |
| Frage nach der Erstattungsfähigkeit von Sildenafil, Wegovy oder Champix wurde |
| auf § 31 SGB V gestützt statt auf § 34 Abs. 1 Satz 7 SGB V. Er steht neben dem |
| OTC-Anker, weil beide aus § 34 Abs. 1 kommen und trotzdem verschiedene |
| Ausschlüsse sind: Satz 1 schließt nach der Verschreibungspflicht aus, Satz 7 nach |
| der Zweckbestimmung. Zwei Dinge trägt nur dieser Anker. Erstens hat der |
| Ausschluss genau eine Ausnahme — die Tabakentwöhnung nach § 34 Abs. 2 SGB V, |
| § 14a AM-RL, Anlage IIa —, und sie hängt an `nur_bei=_TABAK`, weil sie in einer |
| Frage nach Sildenafil nichts zu suchen hat. Zweitens führt der Weg über den |
| medizinisch begründeten Einzelfall hier *nicht* hinaus: § 16 Abs. 5 AM-RL öffnet |
| sich wörtlich nur für die nach § 16 Abs. 1 und 2 ausgeschlossenen Arzneimittel. |
| Das steht in der `kernaussage`, aber bewusst **nicht** als `Fehlgriff` — der |
| Listenblock von `amrl_lifestyle` schreibt denselben Satz in seiner Verneinung |
| („… greift hier nicht“), und ein Muster auf `§ 16` schlüge an einer Antwort an, |
| die gerade das Richtige sagt. |
| |
| **Die Fundstellen sind gegen den Index geprüft**, nicht aus dem Gedächtnis |
| notiert: `container_id`, `section_id` und `subsection` stammen aus der |
| Chunk-Metadata der laufenden Collections. `tests/test_norm_anchors.py` hält das |
| nach — ein Anker, der auf nichts zeigt, ist schlimmer als kein Anker. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import re |
| from dataclasses import dataclass, field |
| from typing import Any, Dict, List, Optional, Tuple |
|
|
| |
| |
| |
|
|
| |
| |
| |
| Signalsatz = Tuple[Tuple[str, ...], ...] |
|
|
|
|
| @dataclass(frozen=True) |
| class Bedingung: |
| """Wann ein Eintrag zur Frage gehört — und wann er nur Ballast wäre.""" |
|
|
| nur_bei: Tuple[str, ...] = () |
| nicht_bei: Tuple[str, ...] = () |
|
|
| def gilt(self, haystack: str) -> bool: |
| if self.nur_bei and not any(_trifft(s, haystack) for s in self.nur_bei): |
| return False |
| if self.nicht_bei and any(_trifft(s, haystack) for s in self.nicht_bei): |
| return False |
| return True |
|
|
|
|
| @dataclass(frozen=True) |
| class Norm: |
| """Eine Vorschrift, so wie sie zu zitieren und so wie sie zu finden ist. |
| |
| `zitat` ist die Form, in der die Antwort sie nennen soll. Die übrigen Felder |
| sind die Adresse im Index; sie sind leer, wenn die Norm nicht indiziert ist |
| (ApoG, Technische Anlagen, AM-RL-Anlagen). Eine nicht indizierte Norm wird |
| benannt, aber nicht abgerufen — sonst behauptete der Pflichtabruf einen |
| Bestand, den es nicht gibt. |
| """ |
|
|
| zitat: str |
| corpus_id: str = "" |
| container_id: str = "" |
| section_id: str = "" |
| |
| |
| absatz: str = "" |
| tragend: bool = True |
| warum: str = "" |
| wenn: Bedingung = Bedingung() |
| |
| |
| |
| |
| |
| |
| |
| |
| chunks: int = 0 |
|
|
| @property |
| def abrufbar(self) -> bool: |
| return bool(self.corpus_id and self.section_id) |
|
|
| def als_ziel(self, max_chunks: int = 2) -> Dict[str, Any]: |
| """Die Adresse als schlichtes dict — der Retriever kennt dieses Modul nicht.""" |
| return { |
| "corpus_id": self.corpus_id, |
| "container_id": self.container_id, |
| "section_id": self.section_id, |
| "subsection": self.absatz, |
| "max_chunks": self.chunks or max_chunks, |
| "zitat": self.zitat, |
| } |
|
|
|
|
| @dataclass(frozen=True) |
| class Fehlgriff: |
| """Eine Vorschrift, die zu dieser Frage regelmäßig fälschlich genannt wird. |
| |
| Zwei Sorten, und die Unterscheidung entscheidet, wann angeschlagen wird: |
| |
| `nur_ohne_tragende=True` — die Vorschrift *gehört* in die Antwort, nur nicht |
| als die entscheidende. § 31 SGB V ist in einer OTC-Antwort die Anspruchs- |
| norm; ein Fehler ist sie erst, wenn sie **statt** § 34 dasteht. |
| |
| `nur_ohne_tragende=False` — die Vorschrift ist zu eng oder zu speziell und |
| stört auch neben der richtigen Norm. § 40c AM-RL betrifft ausschließlich |
| biotechnologisch hergestellte Arzneimittel; in einer allgemeinen Frage nach |
| Darreichungsformen verengt er die Antwort auf einen Sonderfall. |
| |
| `im_kurzabschnitt=True` — das Muster wird gegen die **Kurzantwort** geprüft, |
| nicht gegen den Normabschnitt. Manche Fehler stehen nicht in der Wahl der |
| Vorschrift, sondern in ihrer Zusammenfassung: die OTC-Kurzantwort nennt die |
| richtige Norm (§ 34) und fasst ihre Absätze trotzdem falsch zusammen. Ein |
| solcher Fehlgriff treibt keine Blockentfernung (`_ohne_verworfene_bloecke`); |
| er löst allein die Neusetzung der Kurzantwort aus der `kernaussage` aus. |
| """ |
|
|
| muster: str |
| warum: str |
| nur_ohne_tragende: bool = True |
| im_kurzabschnitt: bool = False |
| wenn: Bedingung = Bedingung() |
|
|
|
|
| @dataclass(frozen=True) |
| class Hinweis: |
| """Was eine richtige Antwort nicht verschweigen darf — soweit es der Fall aufwirft.""" |
|
|
| text: str |
| wenn: Bedingung = Bedingung() |
|
|
|
|
| @dataclass(frozen=True) |
| class Kernaussage: |
| """Eine Kurzantwort für einen Teilfall, die die allgemeine verdrängt. |
| |
| Der Anlass ist gemessen: die Frage nach einem **zehnjährigen** Kind mit einer |
| OTC-Verordnung bekam am 21.08.2026 die allgemeine Kurzantwort — „zu Lasten |
| der GKV verordnungsfähig nur, soweit … Anlage I …". Für ein Kind bis zum |
| vollendeten 12. Lebensjahr ist das falsch: der Ausschluss greift dort gar |
| nicht, und die Liste entscheidet nichts. |
| |
| Ein Hinweis am Ende reichte dafür nicht. Er stünde unter einer Kurzantwort, |
| die das Gegenteil sagt — dieselbe Lage, die `in_antwort_einsetzen` für die |
| Richtigstellung auflöst, eine Ebene tiefer. Deshalb verdrängt die bedingte |
| Kernaussage die allgemeine, statt neben ihr zu stehen. |
| """ |
|
|
| text: str |
| wenn: Bedingung = Bedingung() |
|
|
|
|
| @dataclass(frozen=True) |
| class Anker: |
| """Ein Fragetyp und die Normenkette, die ihn entscheidet.""" |
|
|
| key: str |
| thema: str |
| signale: Tuple[Signalsatz, ...] |
| normen: Tuple[Norm, ...] |
| |
| |
| kernaussage: str = "" |
| |
| |
| kernaussagen: Tuple[Kernaussage, ...] = () |
| fehlgriffe: Tuple[Fehlgriff, ...] = () |
| hinweise: Tuple[Hinweis, ...] = () |
|
|
| def trifft(self, haystack: str) -> bool: |
| return any( |
| all(any(_trifft(s, haystack) for s in gruppe) for gruppe in satz) |
| for satz in self.signale |
| ) |
|
|
| def geltende_normen(self, haystack: str) -> Tuple[Norm, ...]: |
| return tuple(n for n in self.normen if n.wenn.gilt(haystack)) |
|
|
| def tragende(self, haystack: str) -> Tuple[Norm, ...]: |
| return tuple(n for n in self.geltende_normen(haystack) if n.tragend) |
|
|
| def geltende_hinweise(self, haystack: str) -> Tuple[str, ...]: |
| return tuple(h.text for h in self.hinweise if h.wenn.gilt(haystack)) |
|
|
| def geltende_kernaussage(self, haystack: str) -> str: |
| for eintrag in self.kernaussagen: |
| if eintrag.wenn.gilt(haystack): |
| return eintrag.text |
| return self.kernaussage |
|
|
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| _MARKE_ERWACHSEN = "__alter_ab_18__" |
| _MARKE_KIND = "__alter_bis_11__" |
| _MARKE_MINDERJAEHRIG = "__alter_bis_17__" |
|
|
| |
| |
| _ZAHLWORT: Dict[str, int] = { |
| "ein": 1, "eine": 1, "einem": 1, "einjährig": 1, |
| "zwei": 2, "drei": 3, "vier": 4, "fünf": 5, "fuenf": 5, "sechs": 6, |
| "sieben": 7, "acht": 8, "neun": 9, "zehn": 10, "elf": 11, "zwölf": 12, |
| "zwoelf": 12, "dreizehn": 13, "vierzehn": 14, "fünfzehn": 15, |
| "fuenfzehn": 15, "sechzehn": 16, "siebzehn": 17, "achtzehn": 18, |
| "neunzehn": 19, "zwanzig": 20, |
| } |
|
|
| |
| |
| |
| |
| _ALTER_RX = ( |
| re.compile(r"(\d{1,3})\s*-?\s*j[äa]hrig"), |
| re.compile(r"(\d{1,3})\s+jahre?\s+alt"), |
| re.compile(r"([a-zäöüß]+)j[äa]hrig"), |
| re.compile(r"([a-zäöüß]+)\s+jahre?\s+alt"), |
| ) |
|
|
|
|
| def alter_in_jahren(question: str) -> Optional[int]: |
| """Das Alter, das die Frage nennt — oder None. |
| |
| Gefunden wird das **erste** Alter. Eine Frage mit zwei Altersangaben ist |
| ein Sachverhalt, den das Register nicht entscheidet; dann trägt es lieber |
| das erste und der Fachanwender sieht die Marke im Befund. |
| """ |
| text = " ".join(str(question or "").lower().split()) |
| for erkenner in _ALTER_RX: |
| treffer = erkenner.search(text) |
| if not treffer: |
| continue |
| roh = treffer.group(1) |
| if roh.isdigit(): |
| jahre = int(roh) |
| else: |
| jahre = _ZAHLWORT.get(roh, _ZAHLWORT.get(roh.rstrip("e"), -1)) |
| if 0 <= jahre <= 120: |
| return jahre |
| return None |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| _VERNEINT = re.compile( |
| r"\b(?:nicht|kein\w*)\s+(?:zur\s+herstellung\s+(?:einer\s+)?)?" |
| r"(?:parenteral\w*)(?:\s+zubereitung\w*)?" |
| ) |
|
|
|
|
| def _alterssignale(question: str) -> str: |
| jahre = alter_in_jahren(question) |
| if jahre is None: |
| return "" |
| marken = [] |
| if jahre >= 18: |
| marken.append(_MARKE_ERWACHSEN) |
| else: |
| marken.append(_MARKE_MINDERJAEHRIG) |
| if jahre < 12: |
| marken.append(_MARKE_KIND) |
| return " " + " ".join(marken) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| _ERWACHSEN = ("erwachsen", "volljährig", "volljaehrig", "rentner", _MARKE_ERWACHSEN) |
|
|
| |
| |
| |
| _ZU_LASTEN = ( |
| "zu lasten", |
| "zulasten", |
| "kasse", |
| "gkv", |
| "erstattung", |
| "erstattungsfähig", |
| "erstattungsfaehig", |
| "verordnungsfähig", |
| "verordnungsfaehig", |
| "kassenrezept", |
| "verordnet werden", |
| "verordnen", |
| ) |
|
|
| |
| |
| |
| |
| _SELBST_ZAHLEN = ( |
| "privatrezept", |
| "grünes rezept", |
| "gruenes rezept", |
| "grüne rezept", |
| "selbstzahler", |
| "selbst zahlen", |
| "selbst bezahlen", |
| "ausgeschlossen", |
| ) |
|
|
| |
| _BIOLOGISCH = ("biolog", "biosimilar", "biotechnolog", "referenzarzneimittel", "§ 40c", "40c") |
|
|
| |
| |
| |
| _PARENTERAL = ( |
| "parenteral", |
| "zytostatik", |
| "antineoplast", |
| "applikationsfertig", |
| "unmittelbaren ärztlichen anwendung", |
| "unmittelbaren aerztlichen anwendung", |
| "zubereitung aus fertigarzneimitteln", |
| ) |
|
|
| |
| |
| |
| |
| _LIFESTYLE_GEBIETE = ( |
| "erektil", |
| "dysfunktion", |
| "sexuelle potenz", |
| "sexuellen potenz", |
| "sexuellen verlangen", |
| "sexuellen verlangens", |
| "potenzmittel", |
| "libido", |
| "raucherentwöhn", |
| "raucherentwoehn", |
| "tabakentwöhn", |
| "tabakentwoehn", |
| "tabakabhängig", |
| "tabakabhaengig", |
| "nikotinabhängig", |
| "nikotinabhaengig", |
| "rauchstopp", |
| "abmagerung", |
| "appetitzügl", |
| "appetitzuegl", |
| "zügelung des appetits", |
| "zuegelung des appetits", |
| "gewichtsreduktion", |
| "gewichtsabnahme", |
| "gewichtsregulierung", |
| "regulierung des körpergewichts", |
| "regulierung des koerpergewichts", |
| "abnehmspritze", |
| "adipositas", |
| "übergewicht", |
| "uebergewicht", |
| "haarwuchs", |
| "haarausfall", |
| "verbesserung des aussehens", |
| "kosmetisch", |
| "schlaf-wach-rhythmus", |
| ) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| _LIFESTYLE_LEITFAELLE = ( |
| "sildenafil", |
| "viagra", |
| "tadalafil", |
| "cialis", |
| "vardenafil", |
| "levitra", |
| "avanafil", |
| "alprostadil", |
| "dapoxetin", |
| "semaglutid", |
| "wegovy", |
| "liraglutid", |
| "saxenda", |
| "tirzepatid", |
| "mounjaro", |
| "orlistat", |
| "xenical", |
| "mysimba", |
| "finasterid", |
| "propecia", |
| "minoxidil", |
| "regaine", |
| "vareniclin", |
| "champix", |
| "zyban", |
| "cytisin", |
| ) |
|
|
| |
| |
| |
| _TABAK = ( |
| "raucherentwöhn", |
| "raucherentwoehn", |
| "tabakentwöhn", |
| "tabakentwoehn", |
| "tabakabhängig", |
| "tabakabhaengig", |
| "nikotinabhängig", |
| "nikotinabhaengig", |
| "rauchstopp", |
| "raucher", |
| "rauchen", |
| "tabak", |
| "nikotin", |
| "nicotin", |
| "vareniclin", |
| "champix", |
| "zyban", |
| "cytisin", |
| ) |
|
|
| |
| |
| _AKTEURE = ( |
| "arzt", |
| "ärzt", |
| "aerzt", |
| "praxis", |
| "krankenkasse", |
| "kasse", |
| "verordner", |
| "vertragsarzt", |
| ) |
|
|
|
|
| ANKER: Tuple[Anker, ...] = ( |
| Anker( |
| key="otc_zu_lasten_gkv", |
| thema="Nicht verschreibungspflichtiges Arzneimittel zu Lasten der GKV", |
| signale=( |
| ( |
| ( |
| "nicht verschreibungspflichtig", |
| "nicht-verschreibungspflichtig", |
| "nicht rezeptpflichtig", |
| "rezeptfrei", |
| "freiverkäuflich", |
| "freiverkaeuflich", |
| "otc", |
| ), |
| _ZU_LASTEN, |
| ), |
| ), |
| kernaussage=( |
| "Nicht verschreibungspflichtige Arzneimittel sind nach § 34 Abs. 1 Satz 1 SGB V " |
| "von der Versorgung ausgeschlossen. Zu Lasten der GKV verordnungsfähig sind sie " |
| "nur, soweit der Gemeinsame Bundesausschuss sie in § 12 und Anlage I der AM-RL " |
| "als Therapiestandard bei der Behandlung einer schwerwiegenden Erkrankung " |
| "ausweist und der Vertragsarzt sie für diese Erkrankung mit Begründung verordnet." |
| ), |
| kernaussagen=( |
| Kernaussage( |
| |
| |
| |
| |
| |
| text=( |
| "Der Ausschluss des § 34 Abs. 1 Satz 1 SGB V gilt hier nicht: nach " |
| "§ 34 Abs. 1 Satz 5 Nr. 1 SGB V sind versicherte Kinder bis zum " |
| "vollendeten 12. Lebensjahr von ihm ausgenommen, § 12 Abs. 12 AM-RL " |
| "wiederholt das für die Richtlinie. Ein Eintrag in Anlage I ist " |
| "deshalb keine Voraussetzung der Verordnungsfähigkeit — die Anlage " |
| "führt die Ausnahmen **vom** Ausschluss, und der greift in diesem " |
| "Fall nicht. Zu prüfen bleibt die Verordnung im Übrigen, nicht die " |
| "Liste." |
| ), |
| wenn=Bedingung(nur_bei=(_MARKE_KIND,)), |
| ), |
| ), |
| normen=( |
| Norm( |
| zitat="§ 34 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 34", |
| absatz="1", |
| warum=( |
| "Satz 1 schließt nicht verschreibungspflichtige Arzneimittel von der " |
| "Versorgung aus, Satz 2 ermächtigt den G-BA zu den Ausnahmen." |
| ), |
| ), |
| Norm( |
| zitat="§ 12 AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 12", |
| warum=( |
| "Setzt die Ermächtigung des § 34 Abs. 1 Satz 2 um und regelt nach " |
| "Absatz 10 abschließend, wann ausnahmsweise verordnet werden darf." |
| ), |
| ), |
| Norm( |
| zitat="AM-RL Anlage I", |
| warum=( |
| "Führt die ausnahmsweise verordnungsfähigen Stoffe samt Indikation. " |
| "Die konkrete Verordnungsfähigkeit ist an ihr zu prüfen." |
| ), |
| ), |
| Norm( |
| zitat="§ 31 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 31", |
| absatz="1", |
| tragend=False, |
| warum=( |
| "Anspruchsnorm — gewährt die Versorgung ausdrücklich nur, soweit sie " |
| "nicht nach § 34 ausgeschlossen ist. Gehört in die Antwort, " |
| "entscheidet sie aber nicht." |
| ), |
| ), |
| ), |
| fehlgriffe=( |
| Fehlgriff( |
| muster=r"§\s*31\b", |
| warum=( |
| "§ 31 Abs. 1 Satz 1 SGB V gewährt den Anspruch nur, „soweit die " |
| "Arzneimittel nicht nach § 34 oder durch Richtlinien nach § 92 " |
| "Absatz 1 Satz 2 Nummer 6 ausgeschlossen sind“. Die Norm verweist " |
| "auf die Antwort; die Ausschlussentscheidung trifft § 34." |
| ), |
| ), |
| Fehlgriff( |
| |
| |
| |
| |
| |
| |
| |
| muster=( |
| r"(?is)nicht zu (?:den|einer)\b.{0,80}ausgeschlossen" |
| r".{0,120}(abführmittel|abfuehrmittel|reisekrankheit|erkältung" |
| r"|erkaeltung|rachentherapeutika|grippal)" |
| ), |
| warum=( |
| "Die in § 34 Abs. 1 Satz 5 ff. SGB V genannten Gruppen (Erkältungs- " |
| "und Grippemittel, Mund- und Rachentherapeutika, Abführmittel, Mittel " |
| "gegen Reisekrankheit) sind ein eigener Ausschluss bestimmter " |
| "verschreibungspflichtiger Arzneimittel für Erwachsene — nicht der " |
| "Negativmaßstab der OTC-Ausnahme. Ob ein nicht verschreibungspflichtiges " |
| "Arzneimittel ausnahmsweise verordnungsfähig ist, entscheidet allein " |
| "§ 12 in Verbindung mit Anlage I der AM-RL; ein nicht " |
| "verschreibungspflichtiges Abführmittel etwa kann für eine dort " |
| "gelistete schwerwiegende Erkrankung verordnungsfähig sein." |
| ), |
| nur_ohne_tragende=False, |
| im_kurzabschnitt=True, |
| wenn=Bedingung( |
| nicht_bei=( |
| "abführmittel", |
| "abfuehrmittel", |
| "reisekrankheit", |
| "rachentherapeutika", |
| ) |
| ), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| text=( |
| "Neben Anlage I bleibt verordnungsfähig, was § 12 AM-RL gesondert regelt: " |
| "Begleitmedikation, die die Fachinformation des Hauptarzneimittels " |
| "voraussetzt (Absatz 7), die Behandlung schwerwiegender unerwünschter " |
| "Arzneimittelwirkungen (Absatz 8) und Arzneimittel der Anthroposophie und " |
| "Homöopathie für die dort gelisteten Indikationsgebiete (Absatz 6)." |
| ), |
| ), |
| Hinweis( |
| |
| |
| |
| |
| |
| text=( |
| "Für versicherte Kinder bis zum vollendeten 12. Lebensjahr " |
| "(§ 34 Abs. 1 Satz 5 Nr. 1 SGB V) und Jugendliche mit " |
| "Entwicklungsstörungen bis zum vollendeten 18. Lebensjahr " |
| "(§ 34 Abs. 1 Satz 5 Nr. 2 SGB V) gilt der Ausschluss überhaupt " |
| "nicht; § 12 Abs. 12 AM-RL wiederholt das für die Richtlinie." |
| ), |
| wenn=Bedingung(nicht_bei=_ERWACHSEN), |
| ), |
| ), |
| ), |
| Anker( |
| key="lifestyle_arzneimittel", |
| thema="Arzneimittel zur Erhöhung der Lebensqualität (Lifestyle-Arzneimittel)", |
| |
| |
| |
| |
| signale=( |
| (("lifestyle", "life-style", "erhöhung der lebensqualität", "erhoehung der lebensqualitaet"),), |
| (_LIFESTYLE_GEBIETE, (*_ZU_LASTEN, *_SELBST_ZAHLEN)), |
| (_LIFESTYLE_LEITFAELLE, (*_ZU_LASTEN, *_SELBST_ZAHLEN)), |
| ), |
| kernaussage=( |
| "Arzneimittel, bei deren Anwendung eine Erhöhung der Lebensqualität im Vordergrund " |
| "steht, sind nach § 34 Abs. 1 Satz 7 SGB V von der Versorgung ausgeschlossen; Satz 8 " |
| "nennt die Anwendungsgebiete — erektile Dysfunktion, Anreizung sowie Steigerung der " |
| "sexuellen Potenz, Raucherentwöhnung, Abmagerung, Zügelung des Appetits, Regulierung " |
| "des Körpergewichts und Verbesserung des Haarwuchses. Das Nähere regelt § 14 AM-RL, " |
| "dessen Absatz 2 das erste Gebiet zu den sexuellen Dysfunktionen weitet; welche " |
| "Fertigarzneimittel und Anwendungsgebiete darunterfallen, stellt Anlage II der AM-RL " |
| "zusammen. Der Ausschluss beruht damit auf dem Gesetz selbst: der medizinisch " |
| "begründete Einzelfall nach § 16 Abs. 5 AM-RL öffnet sich wörtlich nur für die nach " |
| "§ 16 Abs. 1 und 2 ausgeschlossenen Arzneimittel und trägt hier nicht. Die einzige " |
| "Ausnahme ist die Tabakentwöhnung: bei festgestellter schwerer Tabakabhängigkeit " |
| "besteht nach § 34 Abs. 2 SGB V, § 14a AM-RL Anspruch auf eine einmalige Versorgung " |
| "mit den in Anlage IIa geführten Arzneimitteln im Rahmen evidenzbasierter Programme." |
| ), |
| normen=( |
| Norm( |
| zitat="§ 34 Abs. 1 Satz 7 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 34", |
| absatz="1", |
| warum=( |
| "Satz 7 schließt Arzneimittel aus, bei deren Anwendung eine Erhöhung der " |
| "Lebensqualität im Vordergrund steht; Satz 8 zählt die Anwendungsgebiete " |
| "auf, Satz 9 verweist auf die Richtlinien nach § 92 Abs. 1 Satz 2 Nr. 6. " |
| "Das ist ein anderer Ausschluss als der des Satzes 1 und hängt nicht an der " |
| "Verschreibungspflicht." |
| ), |
| ), |
| Norm( |
| zitat="§ 14 AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 14", |
| warum=( |
| "Führt Satz 7 aus: Absatz 1 umschreibt die ausgeschlossenen Arzneimittel " |
| "nach ihrer Zweckbestimmung, Absatz 2 wiederholt die Anwendungsgebiete, " |
| "Absatz 3 stellt sie in Anlage II zusammen." |
| ), |
| ), |
| Norm( |
| zitat="AM-RL Anlage II", |
| warum=( |
| "Die Übersicht der ausgeschlossenen Fertigarzneimittel und Anwendungsgebiete " |
| "— hier entscheidet sich die Frage nach dem einzelnen Arzneimittel. Nicht " |
| "indiziert, aber als deterministischer Lookup vorhanden (amrl_lifestyle)." |
| ), |
| ), |
| Norm( |
| zitat="§ 34 Abs. 2 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 34", |
| absatz="2", |
| warum=( |
| "Der einzige Weg an dem Ausschluss vorbei: Versicherte mit festgestellter " |
| "schwerer Tabakabhängigkeit haben Anspruch auf eine einmalige Versorgung mit " |
| "Arzneimitteln zur Tabakentwöhnung im Rahmen evidenzbasierter Programme; " |
| "erneut frühestens drei Jahre nach Abschluss der Behandlung." |
| ), |
| wenn=Bedingung(nur_bei=_TABAK), |
| ), |
| Norm( |
| zitat="§ 14a AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 14a", |
| warum=( |
| "Setzt § 34 Abs. 2 um: Absatz 1 hält den Ausschluss nach § 34 Abs. 1 Satz 7 " |
| "ff. SGB V ausdrücklich fest, Absatz 2 gewährt die Ausnahme, Absatz 3 nennt " |
| "Anlage IIa und die Voraussetzungen, unter denen eine schwere " |
| "Tabakabhängigkeit festgestellt ist." |
| ), |
| wenn=Bedingung(nur_bei=_TABAK), |
| ), |
| Norm( |
| zitat="AM-RL Anlage IIa", |
| warum=( |
| "Führt die zur Tabakentwöhnung ausnahmsweise verordnungsfähigen Arzneimittel " |
| "— hier entscheidet sich, ob die Ausnahme den Wirkstoff erfasst. Nicht " |
| "indiziert, aber als deterministischer Lookup vorhanden " |
| "(amrl_tabakentwoehnung)." |
| ), |
| wenn=Bedingung(nur_bei=_TABAK), |
| ), |
| Norm( |
| zitat="§ 31 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 31", |
| absatz="1", |
| tragend=False, |
| warum=( |
| "Anspruchsnorm — gewährt die Versorgung ausdrücklich nur, soweit sie nicht " |
| "nach § 34 ausgeschlossen ist. Gehört in die Antwort, entscheidet sie aber " |
| "nicht." |
| ), |
| ), |
| ), |
| fehlgriffe=( |
| Fehlgriff( |
| |
| |
| muster=r"§\s*31\b", |
| warum=( |
| "§ 31 Abs. 1 Satz 1 SGB V gewährt den Anspruch nur, „soweit die Arzneimittel " |
| "nicht nach § 34 oder durch Richtlinien nach § 92 Absatz 1 Satz 2 Nummer 6 " |
| "ausgeschlossen sind“. Für Arzneimittel zur Erhöhung der Lebensqualität " |
| "trifft diese Ausschlussentscheidung § 34 Abs. 1 Satz 7." |
| ), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| |
| |
| |
| |
| text=( |
| "Der Ausschluss nach § 34 Abs. 1 Satz 7 SGB V trifft auch " |
| "verschreibungspflichtige Arzneimittel: er hängt nicht an der " |
| "Verschreibungspflicht wie der des Satzes 1, sondern an der " |
| "Zweckbestimmung (§ 14 Abs. 1 AM-RL)." |
| ), |
| ), |
| Hinweis( |
| |
| |
| text=( |
| "Zur Tabakentwöhnung besteht die eine gesetzliche Ausnahme: Versicherte mit " |
| "festgestellter schwerer Tabakabhängigkeit haben nach § 34 Abs. 2 SGB V, " |
| "§ 14a AM-RL Anspruch auf eine einmalige Versorgung im Rahmen " |
| "evidenzbasierter Programme; die dafür verordnungsfähigen Arzneimittel führt " |
| "Anlage IIa. Ob die Voraussetzungen vorliegen, ist eine ärztliche " |
| "Feststellung nach § 14a Abs. 3 AM-RL und keine Auskunft dieses Registers." |
| ), |
| wenn=Bedingung(nur_bei=_TABAK), |
| ), |
| ), |
| ), |
| Anker( |
| key="apothekenwahl_zuweisung", |
| thema="Freie Apothekenwahl und Zuweisungsverbot", |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| signale=( |
| ( |
| ( |
| "zuweis", |
| "zuführ", |
| "zufuehr", |
| "zuleiten", |
| "makeln", |
| "makelverbot", |
| "apothekenwahl", |
| "freie wahl", |
| "freier wahl", |
| "frei wähl", |
| "frei waehl", |
| "bestimmte apotheke", |
| "bestimmten apotheke", |
| "bestimmter apotheke", |
| "bestimmte apotheken", |
| "welcher apotheke", |
| "welche apotheke", |
| ), |
| ("apotheke", "apotheken", "leistungserbringer"), |
| ), |
| ( |
| ( |
| "vorgeb", |
| "vorschreib", |
| "beeinfluss", |
| "steuer", |
| "lenken", |
| "nahelegen", |
| "nahe legen", |
| "empfehl", |
| "verweis", |
| "aussuchen", |
| "auswählen", |
| "auswaehlen", |
| ), |
| ("apotheke", "apotheken"), |
| _AKTEURE, |
| ), |
| ( |
| ( |
| "an eine apotheke", |
| "an die apotheke", |
| "an eine bestimmte apotheke", |
| "an bestimmte apotheken", |
| "zu einer apotheke", |
| "zu einer bestimmten apotheke", |
| "in eine bestimmte apotheke", |
| ), |
| _AKTEURE, |
| ), |
| ), |
| kernaussage=( |
| "Nein. Versicherte wählen die Apotheke frei (§ 31 Abs. 1 Satz 5 SGB V). " |
| "Vertragsärzte und Krankenkassen dürfen sie weder dahin beeinflussen, " |
| "Verordnungen bei einer bestimmten Apotheke einzulösen, noch Verordnungen " |
| "unmittelbar oder mittelbar bestimmten Apotheken zuweisen (Satz 6); für " |
| "elektronische Verordnungen gilt nichts anderes (Satz 7). Ausgenommen ist nur, " |
| "was gesetzlich anders bestimmt ist oder was aus medizinischen Gründen im " |
| "Einzelfall als Empfehlung geboten ist." |
| ), |
| normen=( |
| Norm( |
| zitat="§ 31 Abs. 1 Satz 5 bis 7 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 31", |
| absatz="1", |
| warum=( |
| "Satz 5 gibt den Versicherten die freie Apothekenwahl, Satz 6 verbietet " |
| "Vertragsärzten und Krankenkassen Beeinflussung und Zuweisung, Satz 7 " |
| "erstreckt beides ausdrücklich auf elektronische Verordnungen." |
| ), |
| ), |
| Norm( |
| zitat="§ 11 ApoG", |
| tragend=False, |
| warum=( |
| "Spiegelt das Verbot auf der Seite der Apotheke (Absprachen mit " |
| "Ärzten). Nicht indiziert — die Antwort kann es benennen, nicht " |
| "zitieren." |
| ), |
| ), |
| ), |
| fehlgriffe=( |
| Fehlgriff( |
| muster=r"§\s*360\b", |
| warum=( |
| "§ 360 SGB V regelt die Pflicht zur elektronischen Verordnung. Aus der " |
| "technischen Ausgestaltung des E-Rezepts folgt kein Zuweisungsverbot — " |
| "es steht in § 31 Abs. 1 Satz 6 und gilt nach Satz 7 auch für " |
| "elektronische Verordnungen." |
| ), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| text=( |
| "Das Verbot ist ein Verbot, nicht bloß eine fehlende Erlaubnis: § 31 " |
| "Abs. 1 Satz 6 SGB V untersagt Beeinflussung und Zuweisung ausdrücklich. " |
| "Eine Antwort, die nur feststellt, es gebe keine Berechtigung, verfehlt " |
| "die Rechtslage." |
| ), |
| ), |
| ), |
| ), |
| Anker( |
| key="sonderkennzeichen", |
| thema="PZN oder Sonderkennzeichen in der Abrechnung", |
| signale=( |
| ( |
| ( |
| "sonderkennzeichen", |
| "sonder-pzn", |
| "sonderpzn", |
| "pseudo-pzn", |
| "pseudopzn", |
| "sonder-kennzeichen", |
| ), |
| ), |
| ), |
| kernaussage=( |
| "Zu übermitteln ist die Pharmazentralnummer des tatsächlich abgegebenen " |
| "Fertigarzneimittels (§ 300 Abs. 1 Nr. 1 SGB V, § 2 Abs. 1 " |
| "Arzneimittelabrechnungsvereinbarung). Ein Sonderkennzeichen ist zu verwenden, " |
| "soweit die Technische Anlage 1 zur Vereinbarung für den konkreten Abgabe- oder " |
| "Abrechnungssachverhalt eines vorsieht. Ob es die Produkt-PZN ersetzt oder einen " |
| "zusätzlichen Sachverhalt abbildet, richtet sich nach der dortigen Regelung." |
| ), |
| normen=( |
| Norm( |
| zitat="§ 2 Abs. 1 Arzneimittelabrechnungsvereinbarung", |
| corpus_id="amabrv", |
| container_id="Vertrag", |
| section_id="§ 2", |
| absatz="1", |
| warum=( |
| "Bestimmt das bundeseinheitliche Kennzeichen nach § 300 Abs. 3 Satz 1 " |
| "Nr. 1 SGB V und rechnet die Sonderkennzeichen der Technischen Anlage 1 " |
| "ausdrücklich dazu." |
| ), |
| ), |
| Norm( |
| zitat="§ 300 Abs. 1 und 3 SGB V", |
| corpus_id="sgb5", |
| container_id="Zehntes Kapitel", |
| section_id="§ 300", |
| absatz="1", |
| warum=( |
| "Verpflichtet die Apotheke, das Kennzeichen maschinenlesbar zu " |
| "übertragen, und ist die Ermächtigungsgrundlage der Vereinbarung." |
| ), |
| ), |
| Norm( |
| zitat="Technische Anlage 1 zur Arzneimittelabrechnungsvereinbarung", |
| tragend=False, |
| warum=( |
| "Führt die einzelnen Sonderkennzeichen und bestimmt, für welchen " |
| "Sachverhalt welches gilt. Nicht indiziert — die Vereinbarung verweist " |
| "darauf, das Verzeichnis selbst liegt nicht vor." |
| ), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| text=( |
| "Maßgeblich ist das **abgegebene**, nicht das verordnete Fertigarzneimittel. " |
| "Bei einer Ersetzung fallen beide auseinander." |
| ), |
| ), |
| Hinweis( |
| text=( |
| "Welches Sonderkennzeichen im Einzelfall gilt, steht in der Technischen " |
| "Anlage 1 und nicht in der Vereinbarung selbst. Sie ist nicht Teil des " |
| "indizierten Bestandes; die Antwort kann die Regel nennen, nicht das " |
| "einzelne Kennzeichen." |
| ), |
| ), |
| ), |
| ), |
| Anker( |
| key="rabatt_vor_import", |
| thema="Abgaberangfolge: Rabattarzneimittel und preisgünstiger Import", |
| signale=( |
| ( |
| ("import", "reimport", "re-import", "parallelimport", "parallelvertrieb"), |
| ( |
| "rabatt", |
| "130a", |
| "rabattvertrag", |
| "rabattarzneimittel", |
| "rabattbegünstigt", |
| "rabattbeguenstigt", |
| ), |
| ), |
| ), |
| kernaussage=( |
| "Vorrang hat das rabattbegünstigte Fertigarzneimittel; die Abgabe eines " |
| "preisgünstigen Imports tritt dahinter zurück (§ 11 Abs. 1 Rahmenvertrag, " |
| "§ 129 Abs. 1 Satz 8 SGB V). Von der Abgaberangfolge darf nur unter den " |
| "Voraussetzungen der §§ 10 bis 14 Rahmenvertrag abgewichen werden, insbesondere " |
| "bei Nichtverfügbarkeit oder bei ordnungsgemäß geltend gemachten pharmazeutischen " |
| "Bedenken. Welches Arzneimittel dann abzugeben ist, richtet sich nach dem " |
| "Auswahlbereich des § 9 und der weiteren Rangfolge." |
| ), |
| normen=( |
| Norm( |
| zitat="§ 10 Rahmenvertrag", |
| corpus_id="rv129", |
| container_id="Vertrag", |
| section_id="§ 10", |
| warum=( |
| "Die Abgaberangfolge selbst: die Auswahl ist nach Maßgabe der §§ 11 bis " |
| "14 zu treffen. Ohne diese Norm wird eine Rangfolge behauptet, ohne die " |
| "Vorschrift zu nennen, die sie anordnet." |
| ), |
| ), |
| Norm( |
| zitat="§ 11 Abs. 1 Rahmenvertrag", |
| corpus_id="rv129", |
| container_id="Vertrag", |
| section_id="§ 11", |
| absatz="1", |
| warum=( |
| "Vorrang der Rabattverträge: vorrangig ist ein Fertigarzneimittel " |
| "abzugeben, für das ein Rabattvertrag nach § 130a Abs. 8 SGB V besteht." |
| ), |
| ), |
| Norm( |
| zitat="§ 129 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Viertes Kapitel", |
| section_id="§ 129", |
| absatz="1", |
| warum=( |
| "Satz 1 Nr. 2 begründet die Importabgabepflicht samt Preisabstand; " |
| "Satz 8 ordnet an, dass die Abgabe eines Rabattarzneimittels ihr " |
| "vorgeht. Das ist die gesetzliche Grundlage der Rangfolge." |
| ), |
| ), |
| Norm( |
| zitat="§ 13 Rahmenvertrag", |
| corpus_id="rv129", |
| container_id="Vertrag", |
| section_id="§ 13", |
| |
| |
| |
| chunks=1, |
| warum="Führt die Abgabe preisgünstiger Importe nach § 9 im Einzelnen aus.", |
| ), |
| Norm( |
| zitat="§ 14 Rahmenvertrag", |
| corpus_id="rv129", |
| container_id="Vertrag", |
| section_id="§ 14", |
| |
| |
| |
| chunks=1, |
| warum=( |
| "Regelt abschließend, wann von der Abgaberangfolge abgewichen werden " |
| "darf. Eine Antwort, die nur sagt, die vorrangige Abgabe sei „nicht " |
| "möglich“, bleibt ohne diese Tatbestände unbestimmt." |
| ), |
| ), |
| ), |
| fehlgriffe=( |
| Fehlgriff( |
| |
| |
| |
| |
| muster=r"§\s*14\s+Abs(?:atz|\.)?\s*5", |
| warum=( |
| "§ 14 Abs. 5 Rahmenvertrag gilt nur in den Fällen des § 129 Abs. 2a " |
| "und 2b SGB V. Ohne einen dieser Tatbestände trägt er die allgemeine " |
| "Abweichung von der Abgaberangfolge nicht; maßgeblich sind dann die " |
| "§§ 10 bis 14 Rahmenvertrag im Übrigen — insbesondere Nichtverfügbarkeit " |
| "und ordnungsgemäß geltend gemachte pharmazeutische Bedenken." |
| ), |
| nur_ohne_tragende=False, |
| wenn=Bedingung( |
| nicht_bei=( |
| "abs. 2a", |
| "absatz 2a", |
| "abs 2a", |
| "absätze 2a", |
| "absaetze 2a", |
| "abs. 2b", |
| "absatz 2b", |
| "2a und 2b", |
| ) |
| ), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| |
| text=( |
| "§ 129 Abs. 1 Satz 9 SGB V nimmt biotechnologisch hergestellte und " |
| "antineoplastische Arzneimittel zur parenteralen Anwendung von der " |
| "Importabgabepflicht aus." |
| ), |
| wenn=Bedingung( |
| nur_bei=( |
| "parenteral", |
| "zytostatik", |
| "antineoplast", |
| "biotechnolog", |
| "biolog", |
| "zubereitung", |
| ) |
| ), |
| ), |
| ), |
| ), |
| Anker( |
| key="darreichungsform_austausch", |
| thema="Austauschbarkeit von Darreichungsformen", |
| signale=( |
| ( |
| ("darreichungsform",), |
| ( |
| "austausch", |
| "austauschbar", |
| "ersetz", |
| "aut idem", |
| "aut-idem", |
| "substitu", |
| "abweichen", |
| "abgeben statt", |
| "anstelle", |
| "andere", |
| "anderer", |
| "unterschiedlich", |
| ), |
| ), |
| ), |
| kernaussage=( |
| "Eine andere Darreichungsform darf abgegeben werden, wenn beide Formen nach " |
| "§ 9 Abs. 3 Buchst. d Rahmenvertrag in Verbindung mit § 40 und Anlage VII Teil A " |
| "der AM-RL austauschbar sind. Die Austauschbarkeit folgt aus der Zuordnung in " |
| "Anlage VII Teil A, nicht aus einer Ähnlichkeit der Formen; Einzeldosis- und " |
| "Mehrdosenbehältnis sind untereinander nicht austauschbar. Daneben müssen die " |
| "übrigen Kriterien des § 9 Abs. 3 erfüllt sein: gleicher Wirkstoff, identische " |
| "Wirkstärke, identische Packungsgröße und Zulassung für ein gleiches " |
| "Anwendungsgebiet." |
| ), |
| normen=( |
| Norm( |
| zitat="§ 9 Abs. 3 Buchst. d Rahmenvertrag", |
| corpus_id="rv129", |
| container_id="Vertrag", |
| section_id="§ 9", |
| absatz="3", |
| warum=( |
| "Nennt die Kriterien: identische Bezeichnung heißt gleich; austauschbar " |
| "ist, was Anlage VII Teil A der AM-RL benennt; Einzeldosis- und " |
| "Mehrdosenbehältnis sind nicht austauschbar; bei Importen zählt die Form " |
| "des Referenzarzneimittels. Buchstaben a bis c und e bis f nennen die " |
| "übrigen Voraussetzungen des Austauschs." |
| ), |
| ), |
| Norm( |
| zitat="§ 129 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Viertes Kapitel", |
| section_id="§ 129", |
| absatz="1", |
| warum=( |
| "Satz 2 verlangt neben der gleichen oder austauschbaren Darreichungsform " |
| "Identität in Wirkstärke und Packungsgröße sowie die Zulassung für ein " |
| "gleiches Anwendungsgebiet. Die Austauschbarkeit der Form ist also nur " |
| "eine von mehreren Voraussetzungen." |
| ), |
| ), |
| Norm( |
| zitat="§ 40 AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 40", |
| warum=( |
| "Die Hinweise des G-BA nach § 129 Abs. 1a Satz 1 SGB V selbst, mit " |
| "Anlage VII Teil A als Fundstelle." |
| ), |
| ), |
| Norm( |
| zitat="AM-RL Anlage VII Teil A", |
| warum=( |
| "Die Liste der austauschbaren Darreichungsformen — hier entscheidet sich " |
| "die Frage. Nicht indiziert, aber als deterministischer Lookup vorhanden " |
| "(amrl_austauschbarkeit)." |
| ), |
| ), |
| Norm( |
| zitat="§ 40c Abs. 1 AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 40c", |
| tragend=False, |
| warum=( |
| "Zusätzliche Regelungen zu den Darreichungsformen — aber nur für " |
| "biotechnologisch hergestellte biologische Arzneimittel." |
| ), |
| wenn=Bedingung(nur_bei=_BIOLOGISCH), |
| ), |
| ), |
| fehlgriffe=( |
| Fehlgriff( |
| |
| |
| muster=r"§\s*40c\b", |
| warum=( |
| "§ 40c AM-RL betrifft ausschließlich biotechnologisch hergestellte " |
| "biologische Arzneimittel. Für die allgemeine Austauschbarkeit von " |
| "Darreichungsformen ist § 40 in Verbindung mit Anlage VII Teil A " |
| "maßgeblich; § 40c tritt nur hinzu, wenn ein biologisches Arzneimittel " |
| "betroffen ist." |
| ), |
| nur_ohne_tragende=False, |
| wenn=Bedingung(nicht_bei=_BIOLOGISCH), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| text=( |
| "Ohne beide konkret benannten Darreichungsformen lässt sich die " |
| "Zugehörigkeit zu einer Gruppe der Anlage VII Teil A nicht feststellen — " |
| "und damit die Frage nicht abschließend beantworten." |
| ), |
| ), |
| ), |
| ), |
| Anker( |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| key="abgabe_nicht_verordnungsfaehig", |
| thema="Abgabe eines nicht verordnungsfähigen Arzneimittels zu Lasten der GKV", |
| signale=( |
| ( |
| ( |
| "nicht verordnungsfähig", |
| "nicht verordnungsfaehig", |
| "nicht verordnungsfähiges", |
| "nicht verordnungsfaehiges", |
| "verordnungsausschluss", |
| "verordnungseinschränkung", |
| "verordnungseinschraenkung", |
| "von der versorgung ausgeschlossen", |
| "ausgeschlossenes arzneimittel", |
| "anlage iii", |
| ), |
| ( |
| "abgeben", |
| "abgabe", |
| "beliefer", |
| "einlösen", |
| "einloesen", |
| "zu lasten", |
| "zulasten", |
| "abrechn", |
| "retax", |
| "vergütungsanspruch", |
| "verguetungsanspruch", |
| ), |
| ), |
| ), |
| kernaussage=( |
| "Der Anspruch der Versicherten besteht nach § 31 Abs. 1 Satz 1 SGB V nur, " |
| "soweit das Arzneimittel nicht nach § 34 SGB V oder durch die Richtlinien " |
| "nach § 92 Abs. 1 Satz 2 Nr. 6 SGB V ausgeschlossen ist. Die arzneimittel" |
| "rechtliche Zulassung und die Verschreibungspflicht sagen darüber nichts: " |
| "sie betreffen die Verkehrsfähigkeit, nicht die sozialrechtliche " |
| "Verordnungsfähigkeit zu Lasten der GKV. Ausgeschlossen oder eingeschränkt " |
| "wird auf Grundlage des § 92 Abs. 1 Satz 1 Halbsatz 3 SGB V in Verbindung " |
| "mit § 16 Abs. 1 und 2 AM-RL; die so erfassten Arzneimittel sind in " |
| "Anlage III der AM-RL zusammengestellt. Für die durch Richtlinie " |
| "ausgeschlossenen Arzneimittel eröffnet § 31 Abs. 1 Satz 4 SGB V die " |
| "Verordnung im medizinisch begründeten Einzelfall mit Begründung; adressiert " |
| "ist dort der Vertragsarzt. Der Vergütungsanspruch der Apotheke entsteht " |
| "nach § 6 Abs. 1 Satz 1 Rahmenvertrag mit der Belieferung einer gültigen " |
| "ordnungsgemäßen vertragsärztlichen Verordnung." |
| ), |
| normen=( |
| Norm( |
| zitat="§ 31 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 31", |
| absatz="1", |
| chunks=1, |
| warum=( |
| "Satz 1 trägt den Anspruch samt Ausschlussvorbehalt — „soweit die " |
| "Arzneimittel nicht nach § 34 oder durch Richtlinien nach § 92 Absatz 1 " |
| "Satz 2 Nummer 6 ausgeschlossen sind“. Satz 4 eröffnet für die durch " |
| "Richtlinie ausgeschlossenen Arzneimittel die Verordnung im medizinisch " |
| "begründeten Einzelfall." |
| ), |
| ), |
| Norm( |
| zitat="§ 34 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 34", |
| absatz="1", |
| chunks=1, |
| warum=( |
| "Der zweite der beiden Ausschlusswege, die § 31 Abs. 1 Satz 1 nennt. " |
| "Wer nur den Richtlinienweg nennt, gibt die Grundregel unvollständig " |
| "wieder." |
| ), |
| ), |
| |
| |
| |
| |
| |
| |
| |
| |
| Norm( |
| zitat="§ 92 Abs. 1 Satz 1 Halbsatz 3 SGB V", |
| corpus_id="sgb5", |
| container_id="Viertes Kapitel", |
| section_id="§ 92", |
| absatz="1", |
| chunks=1, |
| warum=( |
| "Die gesetzliche Ermächtigung, die Verordnung von Arzneimitteln " |
| "einzuschränken oder auszuschließen, „wenn die Unzweckmäßigkeit " |
| "erwiesen oder eine andere, wirtschaftlichere Behandlungsmöglichkeit " |
| "mit vergleichbarem diagnostischen oder therapeutischen Nutzen " |
| "verfügbar ist“. Die Vorbemerkung der Anlage III nimmt genau diesen " |
| "Halbsatz in Verbindung mit § 16 Abs. 1 und 2 AM-RL in Bezug." |
| ), |
| ), |
| |
| |
| |
| |
| |
| |
| |
| Norm( |
| zitat="§ 16 Abs. 1 AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 16", |
| absatz="1", |
| chunks=1, |
| warum=( |
| "„Verordnungseinschränkungen und -ausschlüsse von Arzneimitteln nach " |
| "§ 92“ — die Konkretisierung des Richtlinienwegs. Absatz 1 nennt die " |
| "drei Gründe: fehlender Nutzen, fehlende medizinische Notwendigkeit, " |
| "fehlende Wirtschaftlichkeit." |
| ), |
| ), |
| Norm( |
| zitat="§ 16 Abs. 2 AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 16", |
| absatz="2", |
| chunks=1, |
| warum=( |
| "Die Regelbeispiele, wann diese Voraussetzungen zutreffen — " |
| "Unzweckmäßigkeit, wirtschaftlichere Behandlungsmöglichkeit, fehlende " |
| "medizinische Notwendigkeit, nichtmedikamentöse Alternative, fixe " |
| "Kombination statt Monopräparat. Anlage III ist die Fundstelle, in der " |
| "die so ausgeschlossenen Arzneimittel zusammengestellt sind." |
| ), |
| ), |
| Norm( |
| zitat="§ 6 Abs. 1 Rahmenvertrag", |
| corpus_id="rv129", |
| container_id="Vertrag", |
| section_id="§ 6", |
| absatz="1", |
| chunks=1, |
| warum=( |
| "Die Abgabeebene, nach der gefragt ist: Satz 1 lässt den " |
| "Vergütungsanspruch der Apotheke „mit Belieferung einer gültigen " |
| "ordnungsgemäßen vertragsärztlichen Verordnung“ entstehen. Ohne diese " |
| "Norm beantwortet die Antwort die Verordnungsfrage und nicht die " |
| "gestellte." |
| ), |
| ), |
| Norm( |
| zitat="AM-RL Anlage III", |
| tragend=False, |
| warum=( |
| "Führt die eingeschränkten und ausgeschlossenen Arzneimittel. Nicht " |
| "indiziert, aber als deterministischer Lookup vorhanden " |
| "(amrl_verordnungsausschluss)." |
| ), |
| ), |
| ), |
| hinweise=( |
| |
| |
| |
| |
| |
| |
| |
| Hinweis( |
| text=( |
| "Die Ermächtigung für Anlage III ist § 92 Abs. 1 Satz 1 Halbsatz 3 " |
| "SGB V in Verbindung mit § 16 Abs. 1 und 2 AM-RL — nicht § 92 Abs. 1 " |
| "Satz 2 Nr. 6 SGB V. Satz 2 Nr. 6 ermächtigt dazu, überhaupt eine " |
| "Arzneimittel-Richtlinie zu erlassen; Satz 1 Halbsatz 3 dazu, die " |
| "Verordnung von Arzneimitteln einzuschränken oder auszuschließen. " |
| "§ 31 Abs. 1 Satz 1 SGB V verweist auf die Richtlinie, die " |
| "Vorbemerkung der Anlage III auf die Einschränkungsermächtigung." |
| ), |
| ), |
| Hinweis( |
| text=( |
| "Die arzneimittelrechtliche Zulassung und die Verschreibungspflicht " |
| "entscheiden die Frage nicht: sie betreffen die Verkehrsfähigkeit " |
| "nach dem Arzneimittelrecht. Die sozialrechtliche " |
| "Verordnungsfähigkeit zu Lasten der GKV ist davon getrennt zu " |
| "prüfen." |
| ), |
| ), |
| Hinweis( |
| text=( |
| "Ob das konkrete Arzneimittel betroffen ist, entscheidet Anlage III der " |
| "AM-RL. Anders als bei der Substitutions-Ausschlussliste trägt dort die " |
| "Negativauskunft nicht: die Anlage ist eine Übersicht und nennt sich " |
| "nirgends abschließend." |
| ), |
| ), |
| Hinweis( |
| text=( |
| "Die Verordnung im medizinisch begründeten Einzelfall steht nach der " |
| "Vorbemerkung der Anlage III nur bei den Rechtsfolgen 3 bis 6 offen — " |
| "nicht bei einem gesetzlichen Ausschluss." |
| ), |
| ), |
| ), |
| ), |
| Anker( |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| key="biosimilar_austausch", |
| thema="Austausch eines biologischen Referenzarzneimittels durch ein Biosimilar", |
| signale=( |
| ( |
| ("biosimilar", "biotechnolog", "biologische", "biologisches", "referenzarzneimittel"), |
| ( |
| "austausch", |
| "austauschbar", |
| "ersetz", |
| "substitu", |
| "abgeben", |
| "abgabe", |
| "aut idem", |
| "aut-idem", |
| ), |
| ), |
| ), |
| kernaussage=( |
| "Vor dem Austausch sind zwei Ebenen zu prüfen. Allgemein gelten die " |
| "Voraussetzungen des § 129 Abs. 1 Satz 2 SGB V und des § 9 Abs. 3 " |
| "Rahmenvertrag: gleicher Wirkstoff, identische Wirkstärke, identische " |
| "Packungsgröße, Zulassung für ein gleiches Anwendungsgebiet und gleiche oder " |
| "austauschbare Darreichungsform. Besonders gilt für biotechnologisch " |
| "hergestellte biologische Fertigarzneimittel § 40c AM-RL: das abzugebende " |
| "Arzneimittel muss nach Anlage VIIa dem verordneten Referenzarzneimittel " |
| "zugeordnet sein, bei gleicher gemeldeter Darreichungsform muss zusätzlich " |
| "das in der Fachinformation angegebene Behältnis übereinstimmen, und die " |
| "Ersetzung darf vom verordnenden Arzt nicht ausgeschlossen sein. Für ein " |
| "unverändert abgegebenes Fertigarzneimittel gilt § 40c, nicht § 40b — der " |
| "betrifft die parenterale Zubereitung zur unmittelbaren ärztlichen Anwendung." |
| ), |
| normen=( |
| |
| |
| |
| Norm( |
| zitat="§ 40c AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 40c", |
| chunks=2, |
| warum=( |
| "Die Spezialnorm für den Austausch biotechnologisch hergestellter " |
| "biologischer **Fertigarzneimittel** durch die Apotheke. Absatz 1 " |
| "nennt die Abgabekriterien samt Behältnisgleichheit, Absatz 3 die " |
| "Zuordnung von Referenzarzneimittel und Biosimilar über Anlage VIIa." |
| ), |
| wenn=Bedingung(nicht_bei=_PARENTERAL), |
| ), |
| Norm( |
| zitat="§ 129 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Viertes Kapitel", |
| section_id="§ 129", |
| absatz="1", |
| chunks=1, |
| warum=( |
| "Die allgemeinen Voraussetzungen jeder Ersetzung: Satz 2 verlangt " |
| "Identität in Wirkstärke und Packungsgröße, eine gleiche oder " |
| "austauschbare Darreichungsform und die Zulassung für ein gleiches " |
| "Anwendungsgebiet." |
| ), |
| ), |
| Norm( |
| zitat="§ 9 Abs. 3 Rahmenvertrag", |
| corpus_id="rv129", |
| container_id="Vertrag", |
| section_id="§ 9", |
| absatz="3", |
| chunks=1, |
| warum=( |
| "Der Auswahlbereich, in dem die allgemeinen Kriterien für die Abgabe " |
| "ausgeführt sind. Buchstabe a stellt Biologika und Bezug nehmend " |
| "zugelassene Arzneimittel ausdrücklich wirkstoffgleich und verweist " |
| "für die Auswahl auf § 40c AM-RL." |
| ), |
| ), |
| Norm( |
| zitat="AM-RL Anlage VIIa", |
| warum=( |
| "Die Zuordnung von Referenzarzneimittel und Biosimilar — hier " |
| "entscheidet sich, ob überhaupt ausgetauscht werden darf. Nicht " |
| "indiziert, aber als deterministischer Lookup vorhanden " |
| "(amrl_biosimilars)." |
| ), |
| ), |
| Norm( |
| zitat="§ 40b AM-RL", |
| corpus_id="amrl", |
| container_id="Richtlinie", |
| section_id="§ 40b", |
| chunks=1, |
| warum=( |
| "Die Parallelvorschrift für parenterale Zubereitungen aus " |
| "Fertigarzneimitteln zur unmittelbaren ärztlichen Anwendung — in " |
| "einem solchen Fall die tragende Norm, sonst gar keine." |
| ), |
| wenn=Bedingung(nur_bei=_PARENTERAL), |
| ), |
| ), |
| fehlgriffe=( |
| Fehlgriff( |
| |
| |
| |
| muster=r"§\s*40b\b", |
| warum=( |
| "§ 40b AM-RL verpflichtet zur Ersetzung nur, „wenn es sich um eine " |
| "parenterale Zubereitung aus Fertigarzneimitteln zur unmittelbaren " |
| "ärztlichen Anwendung handelt“. Wird das Fertigarzneimittel " |
| "unverändert an die versicherte Person abgegeben, ist § 40c AM-RL " |
| "die maßgebliche Vorschrift; § 40b bleibt als Abgrenzung richtig, " |
| "als tragende Norm dieses Falls nicht." |
| ), |
| nur_ohne_tragende=False, |
| wenn=Bedingung(nicht_bei=_PARENTERAL), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| text=( |
| "Die Abgrenzung entscheidet die Abgabekonstellation, nicht das " |
| "Arzneimittel: § 40c AM-RL gilt für das unverändert abgegebene " |
| "Fertigarzneimittel, § 40b AM-RL für das Fertigarzneimittel, das zu " |
| "einer parenteralen Zubereitung zur unmittelbaren ärztlichen " |
| "Anwendung verarbeitet wird." |
| ), |
| ), |
| Hinweis( |
| text=( |
| "Ohne das konkrete Referenzarzneimittel lässt sich die Zuordnung in " |
| "Anlage VIIa nicht feststellen — und ohne sie ist die Frage nicht " |
| "abschließend zu beantworten." |
| ), |
| ), |
| ), |
| ), |
| Anker( |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| key="medikationsplan_aktualisierung", |
| thema="Aktualisierung des Medikationsplans durch die Apotheke", |
| signale=( |
| ( |
| ("medikationsplan",), |
| ( |
| "aktualisier", |
| "fortschreib", |
| "ergänz", |
| "ergaenz", |
| "ändern", |
| "aendern", |
| "pflegen", |
| "eintrag", |
| "elektronisch", |
| "muss", |
| "darf", |
| ), |
| ), |
| ), |
| kernaussage=( |
| "Die Apotheke hat den Medikationsplan nach § 31a Abs. 3 Satz 2 SGB V bei der " |
| "Abgabe eines Arzneimittels auf Wunsch des Versicherten zu aktualisieren, " |
| "soweit die Abgabe eine Aktualisierung erforderlich macht. Für den " |
| "elektronischen Medikationsplan nach § 334 Abs. 1 Satz 2 Nr. 4 SGB V besteht " |
| "der Anspruch nach § 31a Abs. 3 Satz 3 SGB V, wenn der Versicherte der " |
| "abgebenden Apotheke den Zugriff erlaubt; gespeichert wird die Aktualisierung " |
| "nach Satz 5 nur, sofern der Versicherte das wünscht. Seit die elektronische " |
| "Patientenakte nach § 342 Abs. 1 Satz 2 SGB V zur Verfügung steht, ist die " |
| "Aktualisierung und Speicherung nach § 31a Abs. 3a SGB V eine Pflicht, soweit " |
| "der Versicherte dem Zugriff nicht widersprochen hat." |
| ), |
| normen=( |
| Norm( |
| zitat="§ 31a SGB V", |
| corpus_id="sgb5", |
| container_id="Drittes Kapitel", |
| section_id="§ 31a", |
| chunks=2, |
| warum=( |
| "Absatz 3 Satz 2 begründet die Aktualisierung durch die Apotheke auf " |
| "Wunsch des Versicherten, Satz 3 den darüber hinausgehenden Anspruch " |
| "beim elektronischen Medikationsplan, Satz 5 die Speicherung. Absatz 3a " |
| "macht aus dem Anspruch eine Pflicht, sobald die elektronische " |
| "Patientenakte zur Verfügung steht. Ohne Absatz gefasst, weil die " |
| "Antwort auf Absatz 1, 3 und 3a zugleich beruht." |
| ), |
| ), |
| Norm( |
| zitat="§ 334 Abs. 1 SGB V", |
| corpus_id="sgb5", |
| container_id="Elftes Kapitel", |
| section_id="§ 334", |
| absatz="1", |
| chunks=1, |
| warum=( |
| "Satz 2 Nr. 4 ist der elektronische Medikationsplan — die Norm, auf die " |
| "§ 31a für die zweite Hälfte der Frage verweist. Sie steht im Elften " |
| "Kapitel und wird von einer Frage nach der Apotheke nicht gefunden." |
| ), |
| ), |
| ), |
| hinweise=( |
| Hinweis( |
| |
| |
| text=( |
| "Der Anspruch auf den Medikationsplan setzt nach § 31a Abs. 1 Satz 1 " |
| "SGB V voraus, dass der Versicherte gleichzeitig mindestens drei " |
| "verordnete Arzneimittel anwendet; erstellt wird er vom Vertragsarzt, " |
| "die Apotheke aktualisiert ihn." |
| ), |
| ), |
| ), |
| ), |
| ) |
|
|
|
|
| |
| |
| |
|
|
| def _norm(text: str) -> str: |
| return " ".join(str(text or "").lower().split()) |
|
|
|
|
| def _haystack(question: str) -> str: |
| """Die Frage, wie das Register sie liest — samt der Marken aus dem Alter. |
| |
| Getrennt von `_norm`, weil `_trifft` auch die **Signale** normalisiert: ein |
| Signal hat kein Alter, und eine Anreicherung dort wäre nur Rauschen. |
| """ |
| text = _norm(question) |
| if not text: |
| return text |
| text = _VERNEINT.sub(" ", text) |
| return f"{text}{_alterssignale(text)}" |
|
|
|
|
| |
| |
| |
| _KURZ = 4 |
|
|
|
|
| def _trifft(signal: str, haystack: str) -> bool: |
| signal = _norm(signal) |
| if not signal: |
| return False |
| if len(signal) <= _KURZ and signal.isalnum(): |
| return re.search(rf"(?<![\wäöüß]){re.escape(signal)}(?![\wäöüß])", haystack) is not None |
| return signal in haystack |
|
|
|
|
| def passende_anker(question: str) -> List[Anker]: |
| """Alle Anker, bei denen mindestens ein Signalsatz vollständig trifft.""" |
| haystack = _haystack(question) |
| if not haystack: |
| return [] |
| return [anker for anker in ANKER if anker.trifft(haystack)] |
|
|
|
|
| def pflichtabruf(question: str, *, max_chunks: int = 2) -> List[Dict[str, Any]]: |
| """Adressen der tragenden Normen, die unabhängig vom Ranking zu holen sind. |
| |
| Bewusst schlichte dicts: der `FederatedRetriever` soll dieses Modul nicht |
| importieren müssen. Er bekommt eine Liste von Zielen und weiß nicht, dass |
| dahinter eine Rechtsbehauptung steht. |
| """ |
| haystack = _haystack(question) |
| ziele: List[Dict[str, Any]] = [] |
| gesehen = set() |
| for anker in passende_anker(question): |
| for norm in anker.tragende(haystack): |
| if not norm.abrufbar: |
| continue |
| schluessel = (norm.corpus_id, norm.container_id, norm.section_id, norm.absatz) |
| if schluessel in gesehen: |
| continue |
| gesehen.add(schluessel) |
| ziele.append(norm.als_ziel(max_chunks=max_chunks)) |
| return ziele |
|
|
|
|
| def pflicht_korpora(question: str) -> List[str]: |
| """Korpora, die eine Frage erreichen muss, auch ohne im Text genannt zu sein. |
| |
| Das schließt die Lücke, die „Sonderkennzeichen“ aufgedeckt hat: das Wort |
| nennt kein Korpus, die Regelung steht aber in der Abrechnungsvereinbarung — |
| und deren 106 Chunks verlieren im Ähnlichkeitswettbewerb gegen 6.670 des |
| SGB V. Ein zweites Alias-Register braucht es dafür nicht: die Anker nennen |
| ihr Korpus bereits. |
| """ |
| out: List[str] = [] |
| for ziel in pflichtabruf(question): |
| if ziel["corpus_id"] not in out: |
| out.append(ziel["corpus_id"]) |
| return out |
|
|
|
|
| def anlagen_geprueft(question: str) -> bool: |
| """Nennt ein Anker eine AM-RL-Anlage als Fundstelle? |
| |
| Für den Reichweiten-Hinweis: er meldete die AM-RL-Anlagen als ungeprüft, |
| während die Antwort sich zwei Absätze darüber auf Anlage VII Teil A berief. |
| """ |
| haystack = _haystack(question) |
| return any( |
| "anlage" in norm.zitat.lower() and "am-rl" in norm.zitat.lower() |
| for anker in passende_anker(question) |
| for norm in anker.geltende_normen(haystack) |
| ) |
|
|
|
|
| |
| |
| |
|
|
| @dataclass |
| class Befund: |
| status: str |
| anker: List[Anker] = field(default_factory=list) |
| fehlend: List[Norm] = field(default_factory=list) |
| genannt: List[Norm] = field(default_factory=list) |
| erwartet: List[Norm] = field(default_factory=list) |
| fehlgriffe: List[Fehlgriff] = field(default_factory=list) |
| hinweise: List[str] = field(default_factory=list) |
| kernaussage: str = "" |
| grund: str = "" |
|
|
| @property |
| def ist_belastbar(self) -> bool: |
| return self.status in {"abweichung", "unvollstaendig", "bestaetigt"} |
|
|
| @property |
| def korrigiert(self) -> bool: |
| """Der Fall, in dem die Hauptantwort neu gesetzt wird.""" |
| return self.status == "abweichung" |
|
|
| def to_dict(self) -> Dict[str, Any]: |
| return { |
| "status": self.status, |
| "anker": [a.key for a in self.anker], |
| "erwartete_normen": [n.zitat for n in self.erwartet], |
| "genannt": [n.zitat for n in self.genannt], |
| "fehlend": [n.zitat for n in self.fehlend], |
| "fehlgriffe": [f.muster for f in self.fehlgriffe], |
| "grund": self.grund, |
| } |
|
|
|
|
| |
| |
| |
| |
| _NORM_UEBERSCHRIFT = "Maßgebliche Norm" |
| _KURZ_UEBERSCHRIFT = "Kurzantwort" |
|
|
| _UEBERSCHRIFT_RE = re.compile( |
| r"^\s*#*\s*(Kurzantwort|Maßgebliche\s+Norm(?:\(en\))?|Wortlaut(?:\s*/\s*Kriterien)?|" |
| r"Einordnung|Ausnahmen|Ergebnis|Heilungen|Retaxationsgrenzen)\s*:?\s*$", |
| re.I, |
| ) |
|
|
|
|
| def _abschnitte(answer: str) -> List[Tuple[Optional[str], List[str]]]: |
| """(Überschrift | None, Zeilen) in Reihenfolge. Der erste Block trägt None.""" |
| blocks: List[Tuple[Optional[str], List[str]]] = [] |
| heading: Optional[str] = None |
| body: List[str] = [] |
| for line in (answer or "").split("\n"): |
| treffer = _UEBERSCHRIFT_RE.match(line) |
| if treffer is None: |
| body.append(line) |
| continue |
| blocks.append((heading, body)) |
| heading, body = " ".join(treffer.group(1).split()), [] |
| blocks.append((heading, body)) |
| return blocks |
|
|
|
|
| def _ist(heading: Optional[str], name: str) -> bool: |
| return bool(heading) and str(heading).lower().startswith(name.lower()) |
|
|
|
|
| def normabschnitt(answer: str) -> str: |
| """Der Text unter „Maßgebliche Norm“, oder die ganze Antwort ohne den Abschnitt. |
| |
| Der Rückfall auf die ganze Antwort ist kein Notbehelf: nennt das Modell die |
| Norm nur in der Kurzantwort, ist sie genannt. Geprüft wird, ob die tragende |
| Norm überhaupt vorkommt — nicht, ob sie unter der richtigen Überschrift steht. |
| """ |
| for heading, body in _abschnitte(answer): |
| if _ist(heading, _NORM_UEBERSCHRIFT): |
| return "\n".join(body) |
| return answer or "" |
|
|
|
|
| def kurzabschnitt(answer: str) -> str: |
| """Der Text unter „Kurzantwort“ — oder leer, wenn es den Abschnitt nicht gibt. |
| |
| Anders als `normabschnitt` fällt das **nicht** auf die ganze Antwort zurück: |
| ein Fehlgriff `im_kurzabschnitt` sucht gezielt die Zusammenfassung, und ein |
| Rückfall würde ihn auch im Wortlaut anschlagen lassen, der die Norm richtig |
| zitiert. |
| """ |
| for heading, body in _abschnitte(answer): |
| if _ist(heading, _KURZ_UEBERSCHRIFT): |
| return "\n".join(body) |
| return "" |
|
|
|
|
| |
| |
| |
| |
| _PARAGRAF_RE = re.compile(r"§+\s*(\d+[a-z]?)") |
| |
| _ANLAGE_RE = re.compile(r"anlage\s+([ivx]+[a-z]?|\d+[a-z]?)(?:\s+teil\s+([ab]))?", re.I) |
|
|
|
|
| def _paragrafen(text: str) -> set: |
| return {m.group(1).lower() for m in _PARAGRAF_RE.finditer(text or "")} |
|
|
|
|
| def _anlagen(text: str) -> set: |
| return { |
| (m.group(1).lower(), (m.group(2) or "").lower()) for m in _ANLAGE_RE.finditer(text or "") |
| } |
|
|
|
|
| def _adresse(zitat: str) -> Optional[tuple]: |
| """Die vergleichbare Kennung eines Zitats: ('§', '34') oder ('anlage', 'vii', 'a').""" |
| anlage = _ANLAGE_RE.search(zitat or "") |
| if anlage and "§" not in (zitat or ""): |
| return ("anlage", anlage.group(1).lower(), (anlage.group(2) or "").lower()) |
| paragraf = _PARAGRAF_RE.search(zitat or "") |
| return ("§", paragraf.group(1).lower()) if paragraf else None |
|
|
|
|
| def _genannt_in(zitat: str, text: str) -> bool: |
| adresse = _adresse(zitat) |
| if adresse is None: |
| return False |
| if adresse[0] == "anlage": |
| return (adresse[1], adresse[2]) in _anlagen(text) |
| return adresse[1] in _paragrafen(text) |
|
|
|
|
| def pruefe(question: str = "", answer: str = "") -> Befund: |
| """Nennt die Antwort die Norm, die das Register für maßgeblich hält?""" |
| anker = passende_anker(question) |
| if not anker: |
| return Befund(status="nicht_pruefbar", grund="kein_anker") |
|
|
| haystack = _haystack(question) |
| tragende = [n for a in anker for n in a.tragende(haystack)] |
| hinweise = [h for a in anker for h in a.geltende_hinweise(haystack)] |
| kernaussage = "\n\n".join( |
| text for text in (a.geltende_kernaussage(haystack) for a in anker) if text |
| ) |
|
|
| if not tragende: |
| return Befund(status="nicht_pruefbar", anker=anker, grund="anker_ohne_tragende_norm") |
| if not (answer or "").strip(): |
| return Befund(status="nicht_pruefbar", anker=anker, grund="keine_antwort") |
|
|
| abschnitt = normabschnitt(answer) |
| genannt = [n for n in tragende if _genannt_in(n.zitat, abschnitt) or _genannt_in(n.zitat, answer)] |
| fehlend = [n for n in tragende if n not in genannt] |
|
|
| gemeinsam = dict( |
| anker=anker, erwartet=tragende, genannt=genannt, fehlend=fehlend, |
| hinweise=hinweise, kernaussage=kernaussage, |
| ) |
|
|
| |
| |
| |
| kurz = kurzabschnitt(answer) |
| tragend_im_abschnitt = any(_genannt_in(n.zitat, abschnitt) for n in tragende) |
| fehlgriffe = [ |
| f |
| for a in anker |
| for f in a.fehlgriffe |
| if f.wenn.gilt(haystack) |
| and re.search(f.muster, kurz if f.im_kurzabschnitt else abschnitt) |
| and not (f.nur_ohne_tragende and tragend_im_abschnitt) |
| ] |
|
|
| if fehlgriffe or not genannt: |
| return Befund( |
| status="abweichung", |
| grund="falsche_norm" if fehlgriffe else "tragende_norm_fehlt", |
| fehlgriffe=fehlgriffe, |
| **gemeinsam, |
| ) |
| if fehlend: |
| return Befund(status="unvollstaendig", grund="normenkette_unvollstaendig", **gemeinsam) |
| return Befund(status="bestaetigt", **gemeinsam) |
|
|
|
|
| |
| |
| |
|
|
| _EINLEITUNG = "Maßgebliche Norm — Abgleich mit dem kuratierten Normregister" |
|
|
| |
| |
| |
| |
| |
| _KORREKTUR_EINLEITUNG = "Hinweis zum Normabgleich" |
|
|
| |
| |
| |
| |
| _RESTVERWEIS = ( |
| "Die übrigen Abschnitte stammen unverändert vom Modell und nehmen diese Vorschrift " |
| "stellenweise noch in Bezug." |
| ) |
|
|
| |
| |
| |
| _MARKER_RE = re.compile(r"\[Quellen?\s+\d+(?:\s*,\s*\d+)*\]") |
|
|
|
|
| def _normzeilen(normen: List[Norm], *, einzug: str = " ", marker: Optional[Dict[tuple, str]] = None) -> List[str]: |
| zeilen: List[str] = [] |
| for norm in normen: |
| adresse = _adresse(norm.zitat) |
| beleg = (marker or {}).get(adresse) if adresse else None |
| zeilen.append(f"{einzug}{norm.zitat} {beleg}" if beleg else f"{einzug}{norm.zitat}") |
| if norm.warum: |
| zeilen.append(f"{einzug} {norm.warum}") |
| return zeilen |
|
|
|
|
| def _marker_je_norm(abschnitt: str) -> Dict[tuple, str]: |
| """Welchen Quellenmarker das Modell neben welche Vorschrift gesetzt hat. |
| |
| Die Richtigstellung ersetzt den Normabschnitt durch die Zitate des Registers |
| — und das Register führt keine Belege. Im Ausdruck vom 20.08.2026 stand die |
| richtiggestellte maßgebliche Norm deshalb ganz ohne Quellenverweis, während |
| die verworfene Vorschrift ihren Marker behielt und die Quellenliste anführte. |
| Wo das Modell dieselbe Vorschrift belegt hat, wandert der Marker mit. |
| |
| Übernommen wird nur aus Segmenten mit genau einer Fundstelle und genau einem |
| Marker. „§ 300 Abs. 3 SGB V in Verbindung mit § 2 der Abrechnungs- |
| vereinbarung — [Quelle 1]" nennt zwei Vorschriften und einen Beleg; welcher |
| zu welcher gehört, steht nicht im Text, und ein geratener Beleg wäre |
| schlimmer als keiner. |
| """ |
| out: Dict[tuple, str] = {} |
| for segment in re.split(r"[;\n]", abschnitt or ""): |
| marker = _MARKER_RE.findall(segment) |
| if len(marker) != 1: |
| continue |
| ohne_marker = _MARKER_RE.sub(" ", segment) |
| adressen = {("§", p) for p in _paragrafen(ohne_marker)} |
| adressen |= {("anlage", a, b) for a, b in _anlagen(ohne_marker)} |
| if len(adressen) != 1: |
| continue |
| out.setdefault(next(iter(adressen)), marker[0]) |
| return out |
|
|
|
|
| def _ohne_verworfene_bloecke(text: str, fehlgriffe: List[Fehlgriff]) -> str: |
| """Die Zitatblöcke der verworfenen Vorschrift aus dem Modelltext nehmen. |
| |
| Der Anlass steht im Ausdruck vom 20.08.2026: die Richtigstellung setzte |
| Kurzantwort und maßgebliche Norm neu, ließ darunter aber den vollständigen |
| Wortlaut des verworfenen § 40c AM-RL stehen — mitsamt seinem Quellenmarker — |
| und kündigte den Widerspruch im Text auch noch an. Wer die Antwort las, |
| musste selbst entscheiden, welche der beiden Vorschriften gilt. |
| |
| Entfernt wird ein Absatz nur, wenn seine **erste** Zeile die verworfene |
| Vorschrift nennt: dann ist der Absatz ein Zitat von ihr. Steht sie mitten in |
| einem Absatz, gehört sie zum Wortlaut einer anderen Norm — § 9 Abs. 3 |
| Buchst. d Rahmenvertrag verweist in seinem letzten Spiegelstrich selbst auf |
| § 40c —, und dieser Wortlaut ist richtig zitiert und bleibt stehen. |
| |
| Eine Abschnittsüberschrift schützt ihren Absatz: Text unter einer eigenen |
| Überschrift zu löschen hieße, den Abschnitt zu entscheiden, und dafür ist |
| das Register nicht zuständig. |
| |
| `im_kurzabschnitt`-Fehlgriffe bleiben außen vor: sie beanstanden keine |
| zitierte Vorschrift, sondern die Zusammenfassung, und ihr Muster ist ein |
| Satzmuster, kein Fundstellenmuster — es dürfte hier keinen Absatz löschen. |
| """ |
| fehlgriffe = [f for f in fehlgriffe if not f.im_kurzabschnitt] |
| if not fehlgriffe or not (text or "").strip(): |
| return text |
|
|
| muster = [re.compile(f.muster) for f in fehlgriffe] |
| behalten: List[str] = [] |
| for absatz in re.split(r"\n[ \t]*\n", text): |
| erste = next((zeile for zeile in absatz.split("\n") if zeile.strip()), "") |
| if not erste or _UEBERSCHRIFT_RE.match(erste): |
| behalten.append(absatz) |
| continue |
| if any(m.search(erste) for m in muster): |
| continue |
| behalten.append(absatz) |
| return "\n\n".join(a for a in behalten if a.strip()) |
|
|
|
|
| def _nimmt_noch_bezug(text: str, fehlgriffe: List[Fehlgriff]) -> bool: |
| """Argumentiert der verbliebene Modelltext noch aus der verworfenen Vorschrift? |
| |
| Gefragt ist nur nach dem Text, der **stehen bleibt**. „Kurzantwort" und |
| „Maßgebliche Norm" werden ohnehin neu gesetzt; was dort noch steht, ist |
| gleich weg und kein Restbezug. |
| |
| Der Abschnitt „Wortlaut / Kriterien" zählt ebenfalls nicht mit. Er gibt |
| Normtext wieder, und dass eine Vorschrift auf eine andere verweist, ist dann |
| keine Aussage des Modells, sondern die des Gesetzgebers: § 9 Abs. 3 |
| Buchst. d Rahmenvertrag nennt § 40c in seinem letzten Spiegelstrich selbst. |
| Ein Hinweis auf einen „Restbezug" wäre dort eine Warnung vor dem richtigen |
| Zitat. |
| """ |
| fehlgriffe = [f for f in fehlgriffe if not f.im_kurzabschnitt] |
| if not fehlgriffe: |
| return False |
| ersetzt = (_KURZ_UEBERSCHRIFT, _NORM_UEBERSCHRIFT, "Wortlaut") |
| rest = "\n".join( |
| "\n".join(body) |
| for heading, body in _abschnitte(text) |
| if not any(_ist(heading, name) for name in ersetzt) |
| ) |
| return any(re.search(f.muster, rest) for f in fehlgriffe) |
|
|
|
|
| def befund_block(befund: Befund, *, restverweis: bool = False) -> str: |
| """Der Textblock, den die Antwort bekommt. Leer, wenn nichts zu sagen ist. |
| |
| **Ein `Hinweis` hängt nicht daran, dass die Antwort falsch war.** Bis zum |
| 21.08.2026 gab dieser Block nur bei `abweichung` und `unvollstaendig` etwas |
| zurück; eine im Übrigen richtige Antwort bekam die Hinweise nicht. Das |
| widerspricht dem, wofür sie da sind — „was eine richtige Antwort nicht |
| verschweigen darf". Gemessen an zwei Läufen derselben Frage: im ersten |
| fehlte ein Kettenglied und der Hinweis auf die Altersausnahme kam mit, im |
| zweiten war die Kette vollständig und derselbe Hinweis blieb weg. |
| """ |
| if befund.status == "bestaetigt": |
| hinweise = list(befund.hinweise) |
| if not hinweise: |
| return "" |
| themen = ", ".join(a.thema for a in befund.anker) |
| return "\n".join([f"{_KORREKTUR_EINLEITUNG} ({themen}):", *hinweise]) |
|
|
| if befund.status not in {"abweichung", "unvollstaendig"}: |
| return "" |
|
|
| themen = ", ".join(a.thema for a in befund.anker) |
| zeilen: List[str] = [] |
|
|
| if befund.status == "abweichung": |
| zeilen.append(f"{_KORREKTUR_EINLEITUNG} ({themen}):") |
| if befund.fehlgriffe: |
| if any(not f.im_kurzabschnitt for f in befund.fehlgriffe): |
| zeilen.append( |
| "Kurzantwort und maßgebliche Norm oben stammen aus dem kuratierten " |
| "Normregister; die zunächst herangezogene Vorschrift entscheidet diese " |
| "Frage nicht." |
| ) |
| else: |
| zeilen.append( |
| "Kurzantwort und maßgebliche Norm oben stammen aus dem kuratierten " |
| "Normregister; die ursprüngliche Fassung hat die maßgeblichen " |
| "Regelungen unzutreffend zusammengefasst." |
| ) |
| for fehlgriff in befund.fehlgriffe: |
| zeilen.append(f" {fehlgriff.warum}") |
| else: |
| zeilen.append( |
| "Kurzantwort und maßgebliche Norm oben stammen aus dem kuratierten " |
| "Normregister; die ursprüngliche Fassung nannte die tragende Vorschrift " |
| "nicht." |
| ) |
| if restverweis: |
| zeilen.append(_RESTVERWEIS) |
| else: |
| zeilen.append(f"{_EINLEITUNG} ({themen}):") |
| zeilen.append("Zur Normenkette gehört außerdem:") |
| zeilen.extend(_normzeilen(befund.fehlend)) |
|
|
| for hinweis in befund.hinweise: |
| zeilen.append(hinweis) |
|
|
| return "\n".join(zeilen) |
|
|
|
|
| def _normabschnitt_text(befund: Befund, marker: Optional[Dict[tuple, str]] = None) -> str: |
| return "\n".join(_normzeilen(befund.erwartet, einzug="", marker=marker)) |
|
|
|
|
| def in_antwort_einsetzen(answer: str, befund: Befund) -> str: |
| """Befund und Antwort zusammenführen. |
| |
| Zwei Wege, und der Unterschied ist der Punkt: |
| |
| * `unvollstaendig` — die Antwort ist im Übrigen richtig, ihr fehlt ein Glied |
| der Kette. Der Nachtrag hängt unten an und lässt sie stehen. |
| * `abweichung` — die Antwort steht auf der falschen Vorschrift. Dann genügt |
| ein Nachtrag nicht: er stünde neben der falschen Antwort, und nichts im |
| Text sagte, welcher gilt. „Kurzantwort" und „Maßgebliche Norm" werden |
| deshalb neu gesetzt. |
| |
| **Die Antwort führt in beiden Fällen, nicht der Werkstattbericht.** Bis zum |
| 20.08.2026 stand der Richtigstellungsblock *über* der Antwort: der Leser |
| bekam zuerst zu lesen, dass das Modell danebengelegen habe, und erst danach, |
| was gilt. Der Block wandert deshalb ans Ende, zu den übrigen Hinweisen — |
| die Kurzantwort steht wieder oben, wo sie hingehört. |
| |
| Die übrigen Abschnitte bleiben Modelltext. Sie umzuschreiben hieße, den Fall |
| zu entscheiden, und das ist nicht Aufgabe eines Normregisters. Entfernt |
| werden nur die Absätze, die die verworfene Vorschrift zitieren — siehe |
| `_ohne_verworfene_bloecke`. |
| """ |
| if befund.status not in {"abweichung", "unvollstaendig", "bestaetigt"}: |
| return answer |
|
|
| text = (answer or "").strip() |
|
|
| if befund.status != "abweichung": |
| |
| |
| block = befund_block(befund) |
| if not block: |
| return answer |
| return f"{text}\n\n{block}" if text else block |
|
|
| |
| |
| |
| marker = _marker_je_norm(normabschnitt(text)) |
| text = _ohne_verworfene_bloecke(text, befund.fehlgriffe) |
| block = befund_block(befund, restverweis=_nimmt_noch_bezug(text, befund.fehlgriffe)) |
|
|
| blocks = _abschnitte(text) |
| hat_schema = any( |
| _ist(h, _KURZ_UEBERSCHRIFT) or _ist(h, _NORM_UEBERSCHRIFT) for h, _ in blocks |
| ) |
| if not hat_schema: |
| |
| |
| |
| |
| |
| |
| |
| |
| kopf: List[str] = [] |
| if befund.kernaussage: |
| kopf.append(f"{_KURZ_UEBERSCHRIFT}:\n{befund.kernaussage}") |
| kopf.append(f"{_NORM_UEBERSCHRIFT}:\n{_normabschnitt_text(befund, marker)}") |
| return "\n\n".join([t for t in (*kopf, text, block) if t.strip()]) |
|
|
| teile: List[str] = [] |
| norm_gesetzt = False |
| for heading, body_lines in blocks: |
| body = "\n".join(body_lines).strip() |
| if heading is None: |
| if body: |
| teile.append(body) |
| elif _ist(heading, _KURZ_UEBERSCHRIFT) and befund.kernaussage: |
| teile.append(f"{heading}:\n{befund.kernaussage}") |
| elif _ist(heading, _NORM_UEBERSCHRIFT): |
| teile.append(f"{heading}:\n{_normabschnitt_text(befund, marker)}") |
| norm_gesetzt = True |
| elif body: |
| teile.append(f"{heading}:\n{body}") |
| |
| |
| |
| |
|
|
| if not norm_gesetzt: |
| |
| |
| einfuegen = 1 if teile and teile[0].startswith(_KURZ_UEBERSCHRIFT) else 0 |
| teile.insert(einfuegen, f"{_NORM_UEBERSCHRIFT}:\n{_normabschnitt_text(befund, marker)}") |
|
|
| return "\n\n".join(t for t in teile if t.strip()) + f"\n\n{block}" |
|
|