From 702e7a6333a1367aa4ecd3247aa44a4d641cb405 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Mon, 8 Jun 2026 18:24:01 +0200 Subject: [PATCH] =?UTF-8?q?fix(impressum):=20Pattern=20fasst=20Gesch=C3=A4?= =?UTF-8?q?ftsf=C3=BChrung/Vorstand/Inhaber?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Safetykon-Bug: 'Geschäftsführung:' (Sammelbegriff für GF einer GmbH) matched das alte Pattern 'Geschäftsführer' nicht — False-Positive IMPRESSUM-AGENT-VERTRETUNGSBERECHTIGTE_LABEL_KORREKT. Pattern erweitert: Geschäftsführer|Geschäftsführung|Geschäftsführerin + Vorstand|Vorstandsvorsitzender + Inhaber|persönlich haftend. Test test_safetykon_geschaeftsfuehrung_passes ergänzt (11/11 grün). frontend: SlotCard zeigt jetzt Badge bei 0/0/0-Slots ('Dokument konnte nicht geladen werden') statt silent-fail, + bei 0 Findings ein 'alle MCs OK'-Badge. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../sdk/agent/_components/AgentTestTab.tsx | 14 ++++++++++++ .../specialist_agents/impressum/mcs.py | 15 ++++++++----- .../tests/test_specialist_impressum_v2.py | 22 +++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx b/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx index 4dc40fde..2488e738 100644 --- a/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx +++ b/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx @@ -288,6 +288,10 @@ function SlotCard({ slot, output, runId }: { }) { const [showAll, setShowAll] = useState(false) const visibleFindings = showAll ? output.findings : output.findings.slice(0, 8) + const wasSkipped = output.mc_total > 0 && + output.mc_ok === 0 && output.mc_na === 0 && + output.mc_high === 0 && output.mc_medium === 0 && output.mc_low === 0 + const allGreen = !wasSkipped && output.findings.length === 0 return (
@@ -295,6 +299,16 @@ function SlotCard({ slot, output, runId }: { {output.duration_ms} ms · confidence {(output.confidence * 100).toFixed(0)}% + {wasSkipped && ( + + Dokument konnte nicht geladen werden (leer/zu kurz) + + )} + {allGreen && ( + + Keine Findings — alle anwendbaren MCs OK + + )} diff --git a/backend-compliance/compliance/services/specialist_agents/impressum/mcs.py b/backend-compliance/compliance/services/specialist_agents/impressum/mcs.py index f7d1a04e..7e00bb26 100644 --- a/backend-compliance/compliance/services/specialist_agents/impressum/mcs.py +++ b/backend-compliance/compliance/services/specialist_agents/impressum/mcs.py @@ -103,8 +103,11 @@ MCS: tuple[MC, ...] = ( severity_if_missing="HIGH", patterns=( re.compile( - r"(?:Gesch(?:ae|ä)ftsf(?:ue|ü)hrer|" - r"Vertretungsberechtigt|vertreten\s+durch)" + r"(?:Gesch(?:ae|ä)ftsf(?:ue|ü)hr(?:er|ung|erin)|" + r"Vorstand(?:svorsitzend(?:er|e))?|" + r"Vertretungsberechtigt|vertreten\s+durch|" + r"Inhaber(?:in)?|" + r"Pers(?:ö|oe)nlich\s+haftend)" r"\s*[:.\s]", re.IGNORECASE, ), @@ -121,9 +124,11 @@ MCS: tuple[MC, ...] = ( norm="§ 5 Abs. 1 Nr. 1 TMG (Deutsch-Pflicht, gerichtsfest)", severity_if_missing="MEDIUM", patterns=(re.compile( - r"(?:Gesch(?:ae|ä)ftsf(?:ue|ü)hrer|" - r"Vorstand|" - r"Vertretungsberechtigt|vertreten\s+durch)" + r"(?:Gesch(?:ae|ä)ftsf(?:ue|ü)hr(?:er|ung|erin)|" + r"Vorstand(?:svorsitzend(?:er|e))?|" + r"Vertretungsberechtigt|vertreten\s+durch|" + r"Inhaber(?:in)?|" + r"Pers(?:ö|oe)nlich\s+haftend)" r"\s*[:.\s]", re.IGNORECASE, ),), diff --git a/backend-compliance/tests/test_specialist_impressum_v2.py b/backend-compliance/tests/test_specialist_impressum_v2.py index 7bc0beb4..a2754836 100644 --- a/backend-compliance/tests/test_specialist_impressum_v2.py +++ b/backend-compliance/tests/test_specialist_impressum_v2.py @@ -78,6 +78,28 @@ def test_tesla_missing_german_label(monkeypatch): assert "ust_id" in field_ids +def test_safetykon_geschaeftsfuehrung_passes(monkeypatch): + """Geschäftsführung (statt -führer) muss als deutsches Label akzeptiert + werden — sonst False-Positive bei SafetyKon GmbH und ähnlichen.""" + async def _no_cascade(*a, **kw): return None, [] + monkeypatch.setattr( + "compliance.services.specialist_agents.impressum.agent.cascade", + _no_cascade, + ) + txt = ( + "SafetyKon GmbH\nMerzhauser Str. 144\n79100 Freiburg\n" + "Telefon: 0761/48 98 09 01\nE-Mail: info@safetykon.de\n" + "Geschäftsführung: Dr. Oliver Kirchwehm\n" + "Handelsregister AG Freiburg HRB 709859\n" + "USt-Id: DE288952921\n" + ) + agent = ImpressumAgent() + out = _run(agent.evaluate(AgentInput(doc_type="impressum", text=txt))) + field_ids = {f.field_id for f in out.findings} + assert "vertretungsberechtigte" not in field_ids + assert "vertretungsberechtigte_label_korrekt" not in field_ids + + def test_full_impressum_has_no_basic_findings(monkeypatch): async def _no_cascade(*a, **kw): return None, []