"""Phase 1: der Compliance-Check legt einen strukturierten v3-AgentOutput pro Thema in state['agent_outputs'][topic] ab (für die Ergebnis-Tabs). Offline + deterministisch: die einzige LLM-Stelle im registrierten ImpressumAgent ist `validate_present` (Semantic-Validator) — gemockt. """ from __future__ import annotations import asyncio import pytest # Impressum mit Name+Anschrift+Geschäftsführer, aber OHNE Email, Telefon, # Handelsregister, USt-IdNr → erzwingt Findings (alle mit norm + action). IMPRESSUM_TEXT = ( "Angaben gemäß § 5 TMG\n\n" "Musterfirma GmbH\n" "Musterstraße 1\n" "12345 Berlin\n\n" "Vertreten durch den Geschäftsführer: Max Mustermann\n\n" "Wir betreiben einen Online-Shop für Musterprodukte aller Art. " "Weitere Informationen finden Sie auf unserer Website.\n" ) @pytest.fixture(autouse=True) def _llm_offline(monkeypatch): """Semantic-Validator (LLM) neutralisieren → rein deterministischer Lauf.""" async def _no_validate(*_a, **_kw): return {} monkeypatch.setattr( "compliance.services.specialist_agents.impressum.agent.validate_present", _no_validate, raising=False, ) def test_run_agent_outputs_populates_structured_impressum(): from compliance.api.agent_check._agent_outputs import run_agent_outputs state = { "doc_texts": {"impressum": IMPRESSUM_TEXT}, "profile_dict": {"has_online_shop": True}, "req": None, "extracted_profile": {"company_name": "Musterfirma GmbH"}, "site_name": "musterfirma.de", "domain": "musterfirma.de", } asyncio.run(run_agent_outputs(state)) out = (state.get("agent_outputs") or {}).get("impressum") assert out is not None, "impressum AgentOutput muss im Ergebnis liegen" assert out["agent"] == "impressum" assert isinstance(out["findings"], list) # Unvollständiges Impressum → mind. ein Finding, jedes mit Abstellmaßnahme assert out["findings"], "erwarte Findings für ein unvollständiges Impressum" assert all(f.get("action") for f in out["findings"]), \ "jedes Finding trägt eine Abstellmaßnahme (action)" # Auditfest: Rechtsgrundlage + Quelle je Finding assert all(f.get("norm") for f in out["findings"]) assert all(f.get("sources") for f in out["findings"]) # Aggregat-Felder fürs Speedometer vorberechnet assert out["mc_total"] >= 1 # Linter-sauber: keine verbotenen Disclaimer-Begriffe im Output blob = str(out).lower() for term in ("rechtssicher", "garantiert", "gesetzeskonform"): assert term not in blob def test_run_agent_outputs_skips_short_text(): from compliance.api.agent_check._agent_outputs import run_agent_outputs state = { "doc_texts": {"impressum": "zu kurz"}, "profile_dict": {}, "req": None, } asyncio.run(run_agent_outputs(state)) assert not (state.get("agent_outputs") or {}).get("impressum")