This commit is contained in:
team3
2026-07-04 03:25:02 +02:00
parent c4caf31ed0
commit 2f5d5b9ca1
11 changed files with 176 additions and 18 deletions

View File

@@ -297,3 +297,36 @@ async def test_writer_prompt_traegt_budget(testdb, tmp_path, monkeypatch):
monkeypatch.setattr(gb, "run_single_slot", fake_slot)
await gb._stage_writer(env, card)
assert str(gb._writer_budget(2)) in seen["prompt"] # 800 + 2×400
async def test_fakten_gate_schwelle(testdb, tmp_path, monkeypatch):
"""12 Claims → kein Fix-Rewrite (nur Log); ab GATE_FIX_MIN läuft der Fix."""
db = testdb
await db.upsert_guide_card(TOPIC, FMT, "alpha", "Alpha")
env = gb._Env(None, "g-g", TOPIC, FMT, "", tmp_path / "Guide.json", {"Alpha": []}, {}, "(q)", "spec")
md = "<!-- section: Alpha -->\n<!-- ausführlich -->\nText."
card = {"block_norm": "alpha", "block": "Alpha", "writer_rounds": 0, "md": md}
keys = []
async def fake_slot(ctx, label, *, key, prompt, role, capabilities, payload, timeout):
keys.append(key)
if "-gate-" in key:
return gb.OK, [{"text": "c1", "grund": ""}, {"text": "c2", "grund": ""}]
raise AssertionError("Fix darf unter der Schwelle nicht laufen")
monkeypatch.setattr(gb, "run_single_slot", fake_slot)
assert await gb._stage_fakten_gate(env, card)
assert all("-gate-" in k for k in keys)
async def test_load_subblocks_defaultet_levellose(testdb):
"""Consensus-Row ohne level fällt NICHT mehr raus — Default 'advanced'.
(Re-Run-Resume hinterließ 25 solcher Rows; der Writer verlor sie stumm.)"""
from guide import _load_subblocks
db = testdb
await db.put_subblock("t", "block", "mit level", "Block", "Mit Level",
level="beginner", status="consensus")
await db.put_subblock("t", "block", "ohne level", "Block", "Ohne Level", status="consensus")
subs = await _load_subblocks("t")
by_title = {s["title"]: s["level"] for s in subs["Block"]}
assert by_title == {"Mit Level": "beginner", "Ohne Level": "advanced"}

View File

@@ -63,3 +63,44 @@ def test_note_guide_kalibrierung():
assert qa.note({"fachlich_falsch": 0.1}, gq.NOTE_GEWICHTE_GUIDE) == 7.0
ohne = {"marker_fehlend": 0.0, "ziel_ohne_anker": 0.0}
assert qa.note(ohne, gq.NOTE_GEWICHTE_GUIDE) == 10.0
def test_marker_escaping_tolerant():
"""Escapte Titel (h\\~2\\~o) sind kein „Marker fehlt" — Writer und DB escapen verschieden."""
md = "<!-- ausführlich -->\n<!-- sub: beginner | ^ und ~ müssen escaped werden (h\\\\~2\\\\~o) -->\nText."
cards = [{"block": "Hoch", "block_norm": "hoch", "md": md}]
rel = {"hoch": {gq._norm_title("^ und ~ müssen escaped werden (h~2~o)")}}
assert gq.marker_fehlend(cards, rel) == []
async def test_fachlich_falsch_braucht_beide_bestaetiger(monkeypatch):
"""Befund zählt nur, wenn BEIDE Bestätiger zustimmen — Einzel-/Zweifach-Urteile
ließen die Note desselben Guides zwischen 2.0 und 6.6 springen."""
import agents
calls = {"n": 0}
async def fake_agent(key, prompt, timeout, **kw):
calls["n"] += 1
if "-fakten-3-" in key: # Bestätiger 2: nur #1 bleibt
return 0, '{"relevant": {"1": "ja"}}', ""
if "-fakten-2-" in key: # Bestätiger 1: #1 und #2
return 0, '{"relevant": {"1": "ja", "2": "ja"}}', ""
return 0, '{"relevant": {"1": "ja", "2": "ja", "3": "nein"}}', "" # Pass 1
monkeypatch.setattr(agents, "run_agent", fake_agent)
cards = [_card("Alpha", AUSF), _card("Beta", AUSF), _card("Gamma", AUSF)]
out = await gq._fachlich_falsch("t", cards)
assert out == ["Alpha"] and calls["n"] == 3
async def test_fachlich_falsch_ohne_verdacht_kein_zweiter_pass(monkeypatch):
import agents
calls = {"n": 0}
async def fake_agent(key, prompt, timeout, **kw):
calls["n"] += 1
return 0, '{"relevant": {"1": "nein", "2": "nein"}}', ""
monkeypatch.setattr(agents, "run_agent", fake_agent)
out = await gq._fachlich_falsch("t", [_card("Alpha", AUSF), _card("Beta", AUSF)])
assert out == [] and calls["n"] == 1

View File

@@ -505,3 +505,17 @@ async def test_crossblock_context_wins(testdb, tmp_path, monkeypatch):
assert alpha["payload"]["raw"].get("Alpha", []) == [] # Paket-Seite gefaltet
gamma_rows = {r["sub_norm"]: r["status"] for r in await db.list_subblocks(TOPIC, "gamma")}
assert gamma_rows[blocks._norm_title("Gleiche Aussage")] == "consensus" # Kontext unberührt
async def test_finalize_defaultet_level_nachzuegler(testdb, tmp_path):
"""Finalize klassifiziert level-/relevance-lose consensus-Rows (Default advanced/relevant)."""
db = testdb
await db.put_subblock(TOPIC, "alpha", "nachzuegler", "Alpha", "Nachzügler", status="consensus")
await db.kanban_upsert_card(TOPIC, "artefacts", "alpha", "ablock", "finalize", {})
files = {k: tmp_path / f"{k}.json" for k in
("sub_roh", "facts", "sidecar", "question_pattern", "artefakte")}
card = {"card_id": "alpha", "payload": {"title": "Alpha", "raw": {}, "facts": {},
"sidecar": {}, "pattern": {}, "artefacts": {}}}
await ba._proc_finalize(_ctx(), Flow(TOPIC, work_dir=tmp_path), files, [card])
row = next(r for r in await db.list_subblocks(TOPIC, "alpha"))
assert row["level"] == "advanced" and row["relevance"] == "relevant"