From baba0d857d975ebc7e2d43aea2c92f56c948b312 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Fri, 18 Sep 2026 22:07:05 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20verbleibendes=20contradicts=5Ftask=20na?= =?UTF-8?q?ch=20Korrektur=20macht=20Ergebnis=20unzuverl=C3=A4ssig?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _unresolved prüft jetzt auch, ob die LLM-Prüfung nach allen Korrekturrunden noch ein fehlerhaftes Annahmen-Urteil trägt (contradicts_task, stricter_than_task, weaker_than_task). Ist das der Fall, wird das Ergebnis als unzuverlässig markiert und der Solver nicht gestartet (wie bei falscher Zielgröße). Anlass: Portfoliomanagement – Prüfung erkannte x als Stückzahl statt als Betrag (contradicts_task), 2 Korrekturrunden reparierten es nicht, aber der Solver lief als reliable=True. Die Prüfung war wirksam, die Pipeline behandelte den Befund aber nicht als Zuverlässigkeitsproblem. 439 Tests grün. --- TextToModel.py | 9 +++++++++ tests/test_pipeline.py | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/TextToModel.py b/TextToModel.py index ba171a3..77f87d9 100644 --- a/TextToModel.py +++ b/TextToModel.py @@ -138,6 +138,15 @@ def _unresolved(attempt: dict) -> List[str]: if not attempt["review"].objective_check.matches: oc = attempt["review"].objective_check problems.append(f"Zielfunktion passt nicht zur Frage (gefragt: {oc.asked_quantity}; modelliert: {oc.modeled_quantity})") + # Eine Annahme, die auch nach allen Korrekturrunden noch dem Text widerspricht (contradicts_task), + # die Lösung stärker einschränkt (stricter_than_task) oder mehr zulässt (weaker_than_task), macht + # das Ergebnis unzuverlässig – der Solver rechnet ein falsches Modell. Beobachtet am + # Portfoliomanagement: Prüfung erkannte x als Stückzahl statt als Betrag (contradicts_task), + # aber 2 Korrekturrunden reparierten es nicht, der Solver lief als reliable=True. + faulty = {"contradicts_task", "stricter_than_task", "weaker_than_task"} + for check in attempt["review"].checks: + if check.verdict.value in faulty: + problems.append(f"Prüfung: Annahme {check.verdict.value} – {check.unclear_point[:120]}") problems += [f"[{i.code}] {i.message}" for i in attempt["issues"] if i.severity == CheckSeverity.ERROR] return problems diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 9a5864d..67920f0 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -115,6 +115,19 @@ def test_better_earlier_attempt_wins_over_worse_restart(): assert result.solver_run is not None # Zielgröße passt -> Solver läuft, Ergebnis aber als unzuverlässig markiert +def test_persistent_contradicted_assumption_is_unreliable(): + # beobachtet am Portfoliomanagement: Prüfung erkannte x als Stückzahl statt als Betrag + # (contradicts_task), aber die Korrektur reparierte es nicht. Der Solver lief als reliable=True. + # Ein verbleibendes contradicts_task nach allen Runden muss das Ergebnis unzuverlässig machen. + from test_review import make_review + contradicts = make_review(verdict="contradicts_task") + session = FakeSession(specs=[HALLUCINATED] * 3, reviews=[contradicts] * 3, + codes=[SolverCode(code=STRUCTURED_CODE)]) + result = run_pipeline("Aufgabe", session=session, max_revisions=2, max_restarts=0) + assert not result.reliable + assert any("Prüfung: Annahme contradicts_task" in i for i in result.reliability_issues) + + def test_no_restart_when_disabled(): session = FakeSession(specs=[HALLUCINATED] * 3, reviews=[MISMATCH] * 3) result = run_pipeline("Aufgabe", session=session, max_revisions=2, max_restarts=0)