Der Schnitt aus CLAUDE.md ist durchgehalten: - Fetch (deterministisch, kein LLM): marktguru-Adapter mit geprüftem Ortsbezug (zipCode), Wochen-Cache, robots.txt-Respekt, ehrlicher Regel-4- Abbruch bei fehlendem Beleg statt Krücke. - Kategorisierung (einziger LLM-Ort): geschlossene Liste + Daten-Integrität als Code erzwungen; austauschbar via Protokoll (OpenRouter/Anthropic), mit Drosselung/Retry und ehrlichem Abbruch. - FastAPI-Web-UI als dünne Schicht: Modellauswahl (Liste/Suche/Refresh), Live-Fortschritt, gruppierte Ergebnisse mit Filtern, Ergebnis-Cache. - 36 Tests gegen die Architektur-Regeln (kein Auffüllen, Abbruch, Integrität, geschlossene Liste, Unsicherheit, Schnitt) und die Web-Schicht. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
41 lines
1.4 KiB
Python
41 lines
1.4 KiB
Python
"""Regel 4: Abbruch statt stiller Drift -- mit Schwelle, Ursache, Vorschlag."""
|
|
|
|
import pytest
|
|
|
|
from angebote.fehler import AbbruchFehler
|
|
from angebote.fetch import aufloesen_ort, hole_angebote
|
|
from tests.fakes import FakeQuelle, beispiel_angebot
|
|
|
|
|
|
def test_unaufloesbarer_ort_bricht_ab():
|
|
with pytest.raises(AbbruchFehler) as exc:
|
|
aufloesen_ort("Hintertupfingen")
|
|
e = exc.value
|
|
# Der Abbruch ist brauchbar: alle drei Felder sind belegt.
|
|
assert e.schwelle and e.ursache and e.vorschlag
|
|
assert "PLZ" in e.vorschlag
|
|
|
|
|
|
def test_plz_wird_direkt_aufgeloest():
|
|
ort = aufloesen_ort("60487")
|
|
assert ort.plz == "60487"
|
|
|
|
|
|
def test_bekannter_ortsname_wird_aufgeloest():
|
|
ort = aufloesen_ort("Frankfurt")
|
|
assert ort.plz and ort.plz.isdigit()
|
|
|
|
|
|
def test_keine_quelle_deckt_ort_ab_bricht_ab():
|
|
with pytest.raises(AbbruchFehler) as exc:
|
|
hole_angebote("60487", [FakeQuelle("woanders", [], deckt=False)])
|
|
assert exc.value.schwelle == "Ortsabdeckung"
|
|
|
|
|
|
def test_adapter_abbruch_propagiert_nicht_kaschiert():
|
|
# Eine Quelle, die ihren Ortsbezug nicht herstellen kann, bricht ab --
|
|
# der Orchestrator schluckt das NICHT zu einem leeren Ergebnis.
|
|
fehler = AbbruchFehler("Quelle X", "Ortsbezug nicht verifiziert", "andere Quelle")
|
|
quelle = FakeQuelle("kaputt", [beispiel_angebot()], fehler=fehler)
|
|
with pytest.raises(AbbruchFehler):
|
|
hole_angebote("60487", [quelle])
|