update
This commit is contained in:
@@ -703,6 +703,39 @@ async def board_snapshot(topic: str, format_name: str, limit: int = 20) -> dict:
|
||||
return {"columns": columns, "qa_guide": note_guide}
|
||||
|
||||
|
||||
async def repair_karten(topic: str, format_name: str) -> list[str]:
|
||||
"""QA-Befund-getriebenes Guide-Repair: Karten, die im jüngsten Guide-QA-Report
|
||||
Befunde tragen, gehen zurück auf `pruefer` (md bleibt) — Prüfer+Fix beheben gezielt,
|
||||
generate_guide resumt die offenen Karten und misst am Ende neu. Pendant zum
|
||||
Blocks-Repair („Score unter 10 muss einen Fix-Pfad haben"). → betroffene Blocktitel."""
|
||||
import qa as qa_mod
|
||||
tdir = qa_mod.QA_DIR / topic
|
||||
reports = sorted(tdir.glob("guide-*.json"), key=lambda p: p.stat().st_mtime) if tdir.is_dir() else []
|
||||
rep = _json_file(reports[-1]) if reports else None
|
||||
if not rep:
|
||||
return []
|
||||
cards = {c["block_norm"]: c for c in await db.list_guide_cards(topic, format_name)}
|
||||
norms: set[str] = set()
|
||||
for e in rep.get("marker_fehlend", []): # "Block · sub"
|
||||
norms.add(_norm_title(str(e).split(" · ")[0]))
|
||||
for e in rep.get("ziel_ohne_anker", []): # "block_norm · (id) text"
|
||||
norms.add(str(e).split(" · ")[0])
|
||||
for e in rep.get("laengen_ausreisser", []): # {"block": titel}
|
||||
norms.add(_norm_title(e.get("block", "") if isinstance(e, dict) else str(e)))
|
||||
for e in rep.get("lesbarkeit", []): # "Block: hinweis"
|
||||
norms.add(_norm_title(str(e).split(":")[0]))
|
||||
for t in rep.get("fachlich_falsch", []) or []:
|
||||
norms.add(_norm_title(str(t)))
|
||||
for e in rep.get("redundanz", []): # {"a": "Block: absatz", "b": …}
|
||||
for seite in ("a", "b"):
|
||||
norms.add(_norm_title(str(e.get(seite, "")).split(":")[0]))
|
||||
betroffen = []
|
||||
for n in sorted(norms & set(cards)):
|
||||
await db.set_guide_card(topic, format_name, n, stage="pruefer", status="open", gate_info="")
|
||||
betroffen.append(cards[n]["block"])
|
||||
return betroffen
|
||||
|
||||
|
||||
async def reset_card(topic: str, format_name: str, block_norm: str, ab_stage: int) -> bool:
|
||||
"""Reset ONE guide card to a stage (single-card variant of reset_from_stage):
|
||||
fields re-zeroed, md only wiped for writer(2) and earlier, lernziele only for 0."""
|
||||
|
||||
@@ -9,9 +9,9 @@ from fastapi import APIRouter, HTTPException
|
||||
from fastapi.responses import Response
|
||||
|
||||
from agents import active_agents, provider_available
|
||||
from config import PROJECTS_DIR, UNI_DIR, PROVIDERS
|
||||
from config import DEFAULT_PROVIDER, PROJECTS_DIR, UNI_DIR, PROVIDERS
|
||||
from database import (
|
||||
create_guide, delete_guide, get_guide, list_guides,
|
||||
create_guide, delete_guide, get_guide, list_guides, update_guide,
|
||||
create_topic, list_topics as db_list_topics, delete_topic,
|
||||
list_block_progress, get_block_progress, set_open_question,
|
||||
set_block_score_and_streak,
|
||||
@@ -681,6 +681,27 @@ async def get_guide_board(topic: str, format: str = "Guide"):
|
||||
return snap
|
||||
|
||||
|
||||
@router.post("/guides/board/repair")
|
||||
async def repair_guide_board(req: GuideBoardResetRequest):
|
||||
"""Befunde beheben fürs Guide-Board: Karten mit QA-Befunden zurück auf `pruefer`,
|
||||
dann resumt generate_guide die offenen Karten (Prüfer+Fix) und misst neu."""
|
||||
import guide_board
|
||||
topic = req.topic.strip()
|
||||
guide = next((g for g in await list_guides()
|
||||
if g["topic"] == topic and g["format"] == req.format), None)
|
||||
if guide is None:
|
||||
raise HTTPException(404, "Kein Guide für dieses Topic/Format")
|
||||
if guide["status"] in ("queued", "generating"):
|
||||
return {"ok": True, "status": "generating", "betroffen": []}
|
||||
betroffen = await guide_board.repair_karten(topic, req.format)
|
||||
if betroffen:
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
await update_guide(guide["id"], status="queued", progress="Repair…", updated_at=now)
|
||||
asyncio.create_task(generate_guide(guide["id"], topic, req.format,
|
||||
guide.get("instructions") or "", DEFAULT_PROVIDER))
|
||||
return {"ok": True, "betroffen": betroffen}
|
||||
|
||||
|
||||
@router.post("/guides/board/reset")
|
||||
async def reset_guide_board(req: GuideBoardResetRequest):
|
||||
"""Reset cards from a stage onward — without generation (pendant to blocks reset-stage)."""
|
||||
|
||||
@@ -417,3 +417,29 @@ async def test_laengen_trigger_startet_fix(testdb, tmp_path, monkeypatch):
|
||||
card.update(stage="fix", gate_info=(await db.list_guide_cards(TOPIC, FMT))[0]["gate_info"])
|
||||
assert await gb._stage_fix(env, card)
|
||||
assert "Länge" in seen["auftraege"] and str(gb._writer_budget(1)) in seen["auftraege"]
|
||||
|
||||
|
||||
async def test_repair_karten_setzt_befundkarten_auf_pruefer(testdb, tmp_path, monkeypatch):
|
||||
"""Guide-Repair: Karten mit QA-Befunden (alle Befundklassen-Formate) → pruefer,
|
||||
md bleibt; Karten ohne Befund unangetastet. Kein Report → leere Liste."""
|
||||
import json as _json
|
||||
import qa as qa_mod
|
||||
db = testdb
|
||||
monkeypatch.setattr(qa_mod, "QA_DIR", tmp_path / "qa")
|
||||
for n in ("alpha", "beta", "gamma"):
|
||||
await db.upsert_guide_card(TOPIC, FMT, n, n.title())
|
||||
await db.set_guide_card(TOPIC, FMT, n, stage="done", status="ok", md="<!-- section: X -->\nText")
|
||||
assert await gb.repair_karten(TOPIC, FMT) == [] # kein Report
|
||||
tdir = tmp_path / "qa" / TOPIC
|
||||
tdir.mkdir(parents=True)
|
||||
(tdir / "guide-20260705-000000.json").write_text(_json.dumps({
|
||||
"marker_fehlend": ["Alpha · sub eins"],
|
||||
"fachlich_falsch": ["Beta"],
|
||||
"ziel_ohne_anker": [], "laengen_ausreisser": [], "redundanz": [], "lesbarkeit": [],
|
||||
}), encoding="utf-8")
|
||||
betroffen = await gb.repair_karten(TOPIC, FMT)
|
||||
assert sorted(betroffen) == ["Alpha", "Beta"]
|
||||
cards = {c["block_norm"]: c for c in await db.list_guide_cards(TOPIC, FMT)}
|
||||
assert cards["alpha"]["stage"] == cards["beta"]["stage"] == "pruefer"
|
||||
assert cards["alpha"]["md"] # Text bleibt — der Prüfer arbeitet auf dem Bestand
|
||||
assert cards["gamma"]["stage"] == "done"
|
||||
|
||||
Reference in New Issue
Block a user