Files
creator/AUFTRAG-inventar-fix.md
2026-07-05 23:03:00 +02:00

12 KiB
Raw Blame History

Auftrag: Inventar-Pipeline reparieren — zu viele, fehlende und schlecht benannte Bausteine

Kontext

Das Thema aak (Uni-Quelle uni/aak: Skript + Serien + Klausuren + Hausaufgaben) erzeugte 108 Bausteine. Soll-Abgleich mit dem Skript ergibt: sinnvoll wären ~6070 (davon ~4045 Skript-Kern). Der letzte QA-Lauf (storage/qa/aak/20260705-201016.json) zeigt 36 % Dubletten-Verdacht bei Note 10.0 und Lücken-Quote 0.0 — obwohl Kernkonzepte fehlen.

Zahlenfluss des Laufs (aus storage/topics/aak/arbeit/inventar-*.json): ~1150 Roh-Nennungen (24 Chunks × 2 Research-Pässe) → 203 Kandidaten → Filter degradiert 69, Recheck holt 17 zurück → 134 → Dedup prüft 183 Paare, merged nur 17 (9 %) → 117 → Gruppierung: 5 Umbrellas, 17 Umbrella-Merges per Type-Gate verworfen → Supplement +4 → 108.

Die Pipeline-Stages stehen in inventory_stages (backend/board_inventory.py:1614). Alle Zeilennummern unten beziehen sich auf den Branch refactor inkl. der offenen (uncommitteten) Diffs — siehe „Leitplanken".

Befund: sechs Root Causes

R1 — Extraktion erlaubt Beweisschritt-Granularität (Hauptursache „zu viele")

  • templates/Prompt/Blocks-Research.md erklärt „named theorems with their own statement" und jede „standalone REDUCTION" zum eigenen Baustein. templates/Prompt/Blocks-Source-Uni.md nennt „formulas and theorems" als Zielkategorie, ohne Granularitätsgrenze.
  • Folge im aak-Lauf: 14 Beweisschritt-/Beweis-Objekt-Bausteine (z. B. Type-I, Schedule D*, Gewichtsfunktion d2, Zick-Zack-Tour, Optimaler Rundweg OPT((Kn,d2)) = n, 3-SAT ≤ K-COLOR: G=(V,E) Konstruktion) und 8 Bausteine für EIN Konzept („untere Schranken via ETH": Lower Bound via k/n/|E|/|T| + 4 weitere).
  • Verstärker: _is_named_statement (backend/blocks.py:1355) schützt alles mit Reduktions-Syntax vor Demotion — auch Konstruktionsdetails wie …: G=(V,E) Konstruktion.

R2 — Quellen-Nummern als Titel, Reparaturstufe greift nicht (Hauptursache „Benennung")

  • Research-Pässe übernehmen Skript-Nummerierungen als Titel („Satz 7.13", „Bemerkung 7.22", „Definition 6.19"). 6 finale Bausteine tragen reine Satz-/Bemerkungs-Nummern.
  • _REFERENCE_RE (backend/blocks.py:1022) matcht nur nackte Referenzen („Bemerkung 7.22"), NICHT „Satz 7.13 (Christofides)" oder „Satz 7.6: Kriterium für Eulerschen Kreis" — die laufen als „gute" Titel durch.
  • Rename ist Best-Effort: In clarify wird nur umbenannt, wenn ein Judge freiwillig rename liefert (backend/board_inventory.py:663). Beispiel Cluster 08c52a84: Judge j1 schlug für „Bemerkung 7.22" den korrekten Konzeptnamen vor („Untere Schranke für FPTAS …"), die Aggregation verwarf ihn.
  • Singletons überspringen Naming komplett: _choose_title läuft nur bei len(rows) > 1 (backend/board_inventory.py:725 und :802).

R3 — Titel-Split zerschneidet Namen (abgeschnittene Titel)

  • _title = entry.split(" — ")[0] (backend/textkit.py:35) + aggressives _norm_dash (backend/textkit.py:77): ein en-Dash MIT einseitigem Space innerhalb eines Titels wird zum Separator → Split mitten im Titel.
  • Es gibt keine Klammer-Balance-Prüfung und keinen Repair. Ergebnis: Aε-Algorithmus (Güte 1+ε, Laufzeit O(n3 und N P via nicht-deterministische Turingmaschine (Definition 6. liefen wortwörtlich bis done.
  • (Die 60-Zeichen-Kürzung in backend/board_artefacts.py:81 betrifft nur Ordnernamen, nicht Titel — kein Fix nötig.)

R4 — Dedup-Dämme brechen (36 % Verdacht überleben)

  • Merge braucht Einstimmigkeit zweier Judges (if ja1 and ja2, backend/board_inventory.py:1200); „uneinig" → kein Merge, kein Tiebreak.
  • Parameter-Familien werden als Paare je einzeln mit „nein" beschieden (Lower Bound via kn|E||T|, alle QA-Jaccard 1.0).
  • Kandidaten-Generierung verpasst Komposita: _canonical_key (backend/blocks.py:1118) trennt „Cliquenproblem" nicht in „Clique"+Stopwort → „Clique" vs. „Cliquenproblem (k-Clique)" wird ggf. nie Judge-Kandidat.
  • Type-Gate der Gruppierung verwarf 17 Umbrella-Merges (grund: "type-gate" in inventar-gruppierung.json) — exakt die späteren QA-Dubletten (Approximations-Grundbegriffe, Type-I/II+Schedule-Objekte, NP-Definitionen).
  • Filter-Recheck holte 17 korrekte Degradierungen zurück (ueberstimmt/floor_veto in inventar-filter-535eb84c.json) — darunter die komplette Lower-Bound-Familie.

R5 — Echte Lücken trotz Quote 0.0 (Ursache „fehlende")

  • Fehlend im aak-Inventar: SAT/Satz von Cook-Levin (zentralster Satz), MGA (Güte 2), Sahni-PTAS Ak, Satz von Lawler, Satz 6.16 (P=NP-Kriterium), Lastfunktion (Def 7.26, per Supplement teilweise nachgeholt).
  • QA-Lücken sind token-basiert (backend/qa.py:163): 108 übergranulare Bausteine decken jede Sektion irgendwie ab → Konzeptlücken unsichtbar, Supplement (_proc_gap_check) ergänzt zu wenig.
  • Verlust-Vektor upstream: clarify verlangt für Einzel-Reader-Funde Einstimmigkeit aller Judges (accept = v >= len(outs), backend/board_inventory.py:657) — ein einziges „nein" verwirft einen real existierenden Fund als failed-quorum.

R6 — QA-Note ist blind für das Problem

  • NOTE_GEWICHTE (backend/qa.py:40) enthält keine Dubletten. 36 % Verdacht + Verschlechterung zum Vorlauf (+0.06) ergeben trotzdem Note 10.0.

Maßnahmen (priorisiert; M1M3 = Ursachen, M4M5 = Dämme, M6 = Messung)

M1 — Titel-Hygiene, deterministisch

  1. _norm_dash/Titel-Split klammer-bewusst machen: Dash innerhalb offener Klammer ist KEIN Separator. Nach dem Split: unbalancierte Klammern → Titel reparieren (bevorzugt: Split rückgängig / nächsten Separator nehmen).
  2. _REFERENCE_RE erweitern: auch Satz 7.13 (Christofides), Satz 7.6: Kriterium …, … (Definition 6.19) erkennen. Deterministischer Strip: Referenz-Präfix/Suffix entfernen, Konzeptrest behalten („Satz 7.6: Kriterium für Eulerschen Kreis" → „Kriterium für Eulerschen Kreis"). Reine Nummern ohne Konzeptrest („Bemerkung 7.22") → Rename-PFLICHT (Judge muss Konzeptnamen liefern, sonst bleibt die Karte vor done hängen bzw. wird saniert), statt Best-Effort.
  3. Naming/Sanierung auch für Singletons erzwingen, wenn Titel _is_reference, klammer-unbalanciert oder >80 Zeichen ist (board_inventory.py:725, :802, _sanierung_noetig :492).

M2 — Granularitätsgrenze in den Prompts

  1. Blocks-Research.md + Blocks-Source-Uni.md (und Geschwister Blocks-Source-*.md): Negativ-Liste ergänzen — KEINE eigenen Bausteine sind: einzelne Beweisschritte, Hilfskonstruktionen/Beweis-Objekte (Hilfs-Schedules, Gewichtsfunktionen, konstruierte Touren), berechnete Einzel-Instanzen, Parameter-Instanzen desselben Arguments (dieselbe Technik „via k / via n / via |E|" = EIN Baustein). Solche Inhalte gehören als Aspekt in den Eltern-Baustein.
  2. Titel-Regel in beide Naming-Prompts (Blocks-Naming.md, Blocks-Klaerung.md, Blocks-Sanierung.md): Titel ist der KONZEPTNAME; Quellen-Nummerierungen („Satz 7.13") sind als Titel verboten, dürfen aber in der Beschreibung stehen.
  3. Sätze bleiben erlaubt als Baustein, wenn sie ein eigenständig prüfbares Ergebnis sind (Cook-Levin, Christofides) — benannt nach dem Ergebnis, nicht der Nummer.

M3 — Fragment-Filter nachschärfen

  1. _is_named_statement (blocks.py:1355) verengen: Reduktions-Syntax mit Konstruktions-Suffix (Doppelpunkt/Zusatz NACH der Relation, z. B. …≤ K-COLOR: G=(V,E) Konstruktion) ist NICHT geschützt, sondern fragment-verdächtig.
  2. Recheck-Overturn erschweren: ueberstimmt nur bei einstimmigem Recheck-Panel statt Mehrheit (board_inventory.py:1031). Beleg: 15 von 17 zurückgeholten Karten waren spätere QA-Dubletten.
  3. Parameter-Varianten als Verdacht markieren: Titel-Paare, die sich nur durch ein Parameter-Token unterscheiden (via k/via n/via |E|), in _filter_suspect bzw. als eigene Familien-Heuristik aufnehmen → Filter-/Dedup-Kandidat.

M4 — Dedup-Recall erhöhen (ohne Fehlmerge-Risiko aufzugeben)

  1. Die drei offenen Diffs (Richtungs-Guard _direction_conflict, Judge-Kanal-Guard, Dedup-Prompt-Zeile) BEHALTEN — sie sind Teil der Lösung.
  2. Tiebreak statt Veto: bei 1-1-Judge-Split (uneinig, board_inventory.py:1200) einen dritten Judge entscheiden lassen.
  3. Familien-Kollaps: Cluster von ≥3 Titeln, die sich nur im Parameter-Token unterscheiden, als EIN Merge-Fall (ein Judge-Call für die Familie) statt n² Einzelpaare.
  4. _canonical_key (blocks.py:1118): Kompositum-Suffix „…problem" auch verklebt abtrennen („Cliquenproblem" → Stamm + Stopwort), damit solche Paare Kandidaten werden. Generisch halten (Suffix-Regel, keine Wortliste pro Domäne).
  5. Type-Gate der Gruppierung (_GROUP_STANDALONE-Pfad) lockern: Umbrella-Merge nicht allein wegen gemischter Content-Typen (Definition+Satz+Algorithmus) verwerfen, wenn das Judge-Panel die Gruppe bestätigt hat. Die 17 verworfenen Fälle aus inventar-gruppierung.json sind der Prüfmaßstab.
  6. NICHT anfassen: die Varianten-Regel „k-X ≠ X / Max-X ≠ X" im Dedup-Prompt und das 2-Judge-Panel für klare Fälle. Bisher 0 Fehlmerges — das muss so bleiben.

M5 — Lücken schließen

  1. clarify-Quorum für Einzel-Reader-Funde von Einstimmigkeit auf Mehrheit senken (board_inventory.py:657) ODER abgelehnte Funde als Fragment aufbewahren statt rejected, damit gap_check/Supplement sie wiederfinden kann.
  2. Gap-Check konzeptbasiert ergänzen: benannte Ergebnisse des Korpus (Sätze/Definitionen mit eigener Aussage, Abschnittsüberschriften) gegen das Inventar prüfen, nicht nur Token-Abdeckung. Ein benanntes Kernresultat ohne zugeordneten Baustein = Lücke → Supplement-Kandidat.
  3. Prüffälle für aak (müssen nach einem Neulauf existieren): SAT/Cook-Levin, MGA, Sahni-PTAS Ak, Satz von Lawler, P=NP-Kriterium (Satz 6.16).

M6 — QA ehrlich machen

  1. dubletten_verdacht in NOTE_GEWICHTE aufnehmen (qa.py:40), damit die Note das Nutzerproblem abbildet.
  2. Optional: konzeptbasierte Lücken (aus M5.2) als eigene QA-Quote ausweisen.

Leitplanken

  • Generisch bleiben: keine aak-/Komplexitätstheorie-Sonderregeln in Pipeline oder Prompts. aak ist nur der Prüffall. Alle Heuristiken müssen für beliebige Themen tragen.
  • YAGNI: kleine, gezielte Diffs; bestehende Muster (Judge-Panels, Schema-Parser, Kanban-Stages) wiederverwenden; nichts Neues bauen, was eine Prompt-Zeile löst.
  • Offene Diffs behalten: backend/blocks.py, backend/board_inventory.py, templates/Prompt/Blocks-Dedup.md enthalten uncommittete Änderungen (Richtungs-Guard). Nicht verwerfen, darauf aufbauen.
  • Niemals git commit oder git push — der Nutzer committet selbst.
  • Fehlmerge-Bilanz: Recall-Erhöhungen (M4) dürfen keine falschen Merges einführen. Jede Lockerung braucht einen Judge-Beleg-Pfad; deterministische Auto-Merges bleiben streng.
  • Keine Echtläufe ohne Freigabe: make qa TOPIC=aak mit LLM-Judges und komplette Neuläufe kosten Tokens — nur nach Rückfrage beim Nutzer starten.

Validierung (in dieser Reihenfolge)

  1. pytest in backend/ — bestehende Tests dürfen nicht brechen; für M1 (Titel-Split, Referenz-Regex) und M4.4 (_canonical_key) gezielte Unit-Tests ergänzen (Fixtures: die realen Schadensfälle aus diesem Auftrag).
  2. make test-e2e — Fake-E2E (backend/fake_agents.py) muss grün bleiben; Störfall-Matrix ggf. um Referenz-Titel und unbalancierte Klammern erweitern.
  3. QA-Fehler-Injektion (Muster siehe QA-Modul-Tests): injizierte Satz-Nummern-Titel, Parameter-Familien und Konzeptlücken müssen von den geänderten Checks erkannt werden.
  4. Erst nach Nutzer-Freigabe: Neulauf aak + make qa TOPIC=aak. Erfolgskriterien:
    • Baustein-Anzahl ~6070 (statt 108),
    • dubletten_verdacht < 0.10 (statt 0.361),
    • die 5 Prüffall-Konzepte aus M5.3 existieren,
    • kein Titel matcht die erweiterte Referenz-Erkennung, keine unbalancierten Klammern,
    • Lücken-/Fremd-Quote nicht schlechter als der Referenzlauf 20260705-201016.json.