Files
creator2/tests/test_artefakte.py
2026-07-12 16:13:50 +02:00

82 lines
4.3 KiB
Python

"""Ebene 2: Quellen-Referenz-Guard — Karten müssen ohne den Quelltext
funktionieren (Lauf 8: 17 verifizierte Karten fragten „was steht im Beleg")."""
import artefakte
import db
import llm
from conftest import run_anlegen, topic_anlegen
def test_referenz_muster_trifft_nur_referenzen():
schlecht = [
{"frage": "Welchen Namen trägt die Technik, die im Beleg erwähnt wird?",
"antwort": "k-Enumeration.", "text": ""},
{"frage": "Was ist MAX-3-SAT?",
"antwort": "Aus dem Beleg geht nur hervor, dass es in Hausaufgabe 13.1 vorkommt.",
"text": ""},
{"frage": "Welche Aufgabe wird in Aufgabe 1 gestellt?", "antwort": "x", "text": ""},
{"frage": "Wie groß ist |V'|?", "antwort": "Laut Musterlösung genau |V|.", "text": ""},
]
gut = [ # Fachwörter dürfen NICHT matchen (generisch bleiben)
{"frage": "Was ist eine aussagenlogische Belegung?",
"antwort": "Eine Zuordnung von Wahrheitswerten zu Variablen.", "text": ""},
{"frage": "Was verbindet ein Fluss mit Quelle und Senke?",
"antwort": "Er belegt jede Kante mit einem Wert unter der Kapazität.", "text": ""},
]
assert all(artefakte._referenziert_quelle(k) for k in schlecht)
assert not any(artefakte._referenziert_quelle(k) for k in gut)
async def test_nur_ohne_sieht_fehlende_flashcard():
"""Ein lebendes Beispiel darf die Flashcard-Nachgenerierung nicht blockieren."""
topic = topic_anlegen("fcfehlt")
a = db.insert("atome", topic=topic, titel="X", typ="begriff", definition="d",
status="neu", soll_id=1, braucht=db.j([]))
b = db.insert("atome", topic=topic, titel="Y", typ="begriff", definition="d",
status="neu", soll_id=1, braucht=db.j([]))
# a: nur ein Beispiel, keine Flashcard → muss nachgeneriert werden
db.insert("artefakte", atom_id=a, typ="beispiel", status="verifiziert",
inhalt=db.j({"text": "Beispiel"}))
# b: verifizierte Flashcard → versorgt, nicht mehr in nur_ohne
db.insert("artefakte", atom_id=b, typ="flashcard", status="verifiziert",
inhalt=db.j({"frage": "F", "antwort": "A"}))
ids = [x["id"] for c in artefakte._chunks(topic, nur_ohne=True) for x in c]
assert ids == [a]
async def test_reverify_ausfall_laesst_kandidat(monkeypatch):
"""Re-Verify-Ausfall (kein Urteil zur id) → Kandidat bleibt, nicht verworfen."""
import fake_agents
topic = topic_anlegen("reverify")
run = run_anlegen(topic)
a = db.insert("atome", topic=topic, titel="X", typ="begriff", definition="d",
status="neu", braucht=db.j([]))
k = db.insert("artefakte", atom_id=a, typ="flashcard", status="kandidat",
inhalt=db.j({"frage": "Was ist X?", "antwort": "Y", "text": ""}))
# Fix liefert saubere Karte; Re-Verify antwortet ohne Eintrag zur id → kein Urteil
monkeypatch.setitem(fake_agents._HANDLER, "Artefakt-Fix",
lambda p: {"frage": "Was ist X?", "antwort": "Y", "text": ""})
monkeypatch.setitem(fake_agents._HANDLER, "Artefakt-Verify", lambda p: [])
ctx = llm.Kontext(run, topic, "minimax")
ctx.ebene = "artefakte"
await artefakte._fixen(ctx, db.one("SELECT * FROM artefakte WHERE id=?", (k,)),
["mangel"], {"id": a})
assert db.one("SELECT status FROM artefakte WHERE id=?", (k,))["status"] == "kandidat"
async def test_guard_verwirft_kandidat_und_repair_kann_nachlegen():
topic = topic_anlegen("guard")
run = run_anlegen(topic)
a = db.insert("atome", topic=topic, titel="X", typ="begriff", definition="d",
status="neu", braucht=db.j([]))
k = db.insert("artefakte", atom_id=a, typ="flashcard", status="kandidat",
inhalt=db.j({"frage": "Was steht im Beleg?", "antwort": "x", "text": ""}))
ctx = llm.Kontext(run, topic, "minimax")
ctx.ebene = "artefakte"
atom = db.one("SELECT * FROM atome WHERE id=?", (a,))
await artefakte._verifizieren(ctx, [atom]) # Guard greift VOR dem Panel
assert db.one("SELECT status FROM artefakte WHERE id=?", (k,))["status"] == "verworfen"
# verworfene zählen nicht als versorgt: Repair generiert für das Atom nach
chunks = artefakte._chunks(topic, nur_ohne=True)
assert [x["id"] for c in chunks for x in c] == [a]