10 KiB
10 KiB
Bezahlte Lektionen aus creator (Vorgänger)
Extrahiert 2026-07-09 aus dem alten Code. Format: Regel — Grund (Beleg alt: Datei:Zeile). Diese Regeln sind Anforderungen an creator2, kein übernommener Code.
Infra-Fehler
- Infra-Fehler (429/Timeout/Netz) getrennt von Inhaltsfehlern zählen — sonst frisst ein 429 die inhaltlichen Restarts und der Lauf läuft fail-open weiter (pipeline.py:80).
- Erschöpfte Infra-Retries ⇒ Lauf-PAUSE (fortsetzbar), nie Teilergebnis — Quorum verhungerte sonst still (pipeline.py:304).
- Retries + Backoff zentral: 3×, 8/16/32 s (config.py:180).
- Stall-Hedge: genau EIN Zwilling nach Schwelle, erster valider gewinnt — Stalls verbrannten 160–230 s Timeout (pipeline.py:225).
- Hedge-Schwelle = max(90 s, timeout/2) — pauschale 90 s hedgten gesunde lange Calls (pipeline.py:196).
- Judge-Timeouts eng (p50 6–72 s), Retry heilt in Sekunden (config.py:201).
- Prozessgruppen-Kill (killpg + start_new_session) — CLI-Kinder hielten sonst Pipes offen (agents.py:287).
- CLI-Starts staffeln (Token-Bucket) — OpenCode-Session-DB: "database is locked" (agents.py:154).
- RAM-Gate vor CLI-Spawns (~310 MB RSS je Prozess) (agents.py:195).
- Concurrency-Slot VOR dem Spawn erwerben — Queue-Wartezeit zählt nicht gegen den Timeout (agents.py:76).
- Agent-Slots nach Pipeline-Stufe priorisieren (früh vor spät) — nur nötig bei Streaming; Wellen-Design umgeht es.
- .env-Datei gewinnt über geerbtes Env — --reload-Master pinnte stale Werte stundenlang (config.py:13).
- Provider-Routen pro Rolle empirisch wählen — kalt-Endpoint stallte 20 % der Judges (config.py:244).
- Timeouts = Basis + pro-Item·n, nie fix (config.py:195).
Judge-Rauschen
- Hochgewichtete LLM-Urteile: Verdacht + 2 unabhängige Bestätiger — Einzel-Judge pendelte 0↔5 Befunde (guide_qa.py:138).
- Instabile Klassifikations-Judges: Zweitpass auf die Verdachtsmenge (qa.py:516).
- Mehrheit bei Recall-kritischen Entscheidungen — Einstimmigkeit verwarf reale Einzelfunde (board_inventory.py:580).
- Einstimmigkeit bei irreversiblen Merges (board_inventory.py:1195).
- Detektor-vs-Judge-Dissens: dritter Stichentscheid (2/3), Freispruch persistieren (repair.py:82).
- Panel-Ausfall: Ersatz-Richter vor fail-open (block_calls.py:358).
- Panels: 2 = Konsens-Minimum, 3 nur wo Rauschen teuer (config.py:162).
- Quorum-Rennen mit Grace-Fenster — Sofort-Kill warf fast fertige Stimmen weg (pipeline.py:174).
- Klärungs-Loops hart deckeln, Schlussrunde muss alles entscheiden (config.py:128).
- Billige Konsensregeln (≥2 Nennungen) deterministisch im Code, nicht per LLM (board_inventory.py:546).
Fehlmerge-Schutz
- Relationen (A≤B) über beide Operanden + Richtung individuieren, Konflikte vetoen — "SAT≤Clique" vs "3-SAT≤Clique" hat hohen Cosinus (blocks.py:1150).
- Deterministische Guards nur so streng wie beweisbar; Bedeutung dem belegten Judge (blocks.py:1157).
- Casefold + NFKC vor jedem Ähnlichkeitsvergleich — "VERTEX COVER" fiel unter die Schwelle (board_inventory.py:1133).
- Acronym↔Expansion explizit als Kandidaten einspeisen — Cosinus ~0.53, nie Kandidat (blocks.py:1093).
- Auto-Merge nur über ordnungsunabhängigen Canonical-Key; leerer Key ⇒ nie (blocks.py:1106).
- Embedding-Backstop vetot strukturlose Fehl-Demotes (config.py:99).
- Negations-Guard: Antonyme messen 0.91–0.95 Cosinus — gleiche Negationsmenge als harte Merge-Vorbedingung (blocks.py:681).
- Frei generierte Titel gegen Korpus verankern — Drift zu Lehrbuch-Kanon (board_inventory.py:121).
- Quorum schützt nicht vor Ko-Halluzination — Titel ohne Korpus-Anker separat belegen (board_inventory.py:576).
- Kandidatenblöcke in Größe cappen — sonst Riesenkomponente, instabile Judge-Listen (config.py:56).
- Containment-Zuordnung nur bei genau einem signifikanten Ganzwort-Treffer (blocks.py:1250).
- Token/Stem-Match statt Substring — "bergang" ⊂ "Übergang" (qa.py:243).
- Benannte Aussagen (Reduktionen, Sätze) strukturell vor Demotion schützen (blocks.py:1322).
PDF/Text
- Nie blind einem PDF-Extraktor vertrauen — pymupdf4llm droppt Formeln still; pdftotext ist treu aber strukturarm. v1 nutzt pdftotext (Treue > Struktur); zweiter Extraktor + Verlust-Guard bei Bedarf (blocks.py:349).
- PDF-Spacing-Artefakte entzerren ("H ITTING S ET"), mit Frequenzbeleg (blocks.py:373).
- Logik-Versions-Marker für abgeleitete Artefakte — mtime-Cache überlebte Algorithmus-Änderungen (blocks.py:385).
- Optionale Abhängigkeiten (OCR) prüfen, still degradieren (blocks.py:308).
- Titel-Splits klammerbewusst (textkit.py:54).
- Unicode-Dash-Varianten tolerant normalisieren, ASCII-Hyphen schützen (textkit.py:115).
- Marker-Vergleiche gegen Escaping härten (Backslashes strippen) (guide_qa.py:36).
- Metadaten-Header vor Coverage-Detektion strippen — Phantom-Lücken (qa.py:104).
- Regex-Fänge auf Umbruch-Fortsetzung prüfen (qa.py:210).
- Große Quelltexte in ~12k-Abschnitte splitten — lost in the middle (blocks.py:437).
Token-Fresser
- Evidenz INLINE in Judge-Prompts, nie Judges selbst suchen lassen — 82 % der Lauf-Tokens waren Cache-Reads aus Judge-Tool-Loops (config.py:143). WICHTIGSTE EINZELLEKTION.
- Strukturierten Output als Antworttext, robust parsen; Tool-Writes nur Fallback — 40 von 64 Turns in einem Write/Validate-Loop (blocks.py:599).
- Tool-lose Calls über die direkte API statt CLI-Prozess (agents.py:242).
- MCP-Server nur für full-Agenten — ~3×300 MB pro Prozess (agents.py:529).
- Zusammengehörige Schritte in EINEM Call bündeln (guide_board.py:7).
- Token-Verbrauch auch bei Fehlern/Timeouts erfassen (agents.py:487).
- Rückkopplungslisten (Lücken/Fixes) über Schnittmenge filtern und hart cappen — 107 "Lücken" auf 216 Subs (blocks.py:786).
- Chunk-/Split-Größen zentral und tunebar (config.py:151).
Prompt-Design
- Faktenbasis vorgeben, VERBATIM-Zitate verlangen, jeden Claim gaten (Guide-Writer-Board.md:10).
- Maschinen-Marker als exakte Struktur-Invariante, unsichtbar, nie Überschrift (Guide-Writer-Board.md:14).
- Längenbudget als HARTE Obergrenze formulieren, nicht als Ziel (Guide-Writer-Board.md:27).
- Ausgabekanal + Format ausschließlich vorschreiben: "NUR JSON, keine Fences, keine Datei" (Guide-Outline.md:21).
- Fixierte Eingabemengen einfrieren: "Copy VERBATIM, do NOT add/remove/split/merge/rename" (Subblock-Anreichern.md:12).
- Aggregat-Titel: nur Eigenschaften, die auf ALLE Mitglieder zutreffen (Blocks-Gruppierung.md:14).
- Namen nur aus Begriffen der Quelle, nie Lehrbuch-Oberbegriff (Blocks-Naming.md:8).
- Katalognummern ("Satz 7.13") sind keine Titel (Blocks-Sanierung.md:11).
- Quellgebundene Schritte: NUR die gelieferten Auszüge, kein Web, keine PDFs (Blocks-Source-Inline.md:1).
- Bewertungs-Prompts: unbeantwortbare Fragen erkennen, Korrektheit in anderen Worten zählt (Block-Rating-Critique.md:22).
- Reservierte Parser-Zeichen dem Modell verbieten (Blocks-Gruppierung.md:16).
Übergreifende Guards
- Destruktive Entscheidungen: im Zweifel behalten (fail-open) (repair.py:8).
- Infra-Erschöpfung: fail-closed (Pause) — die Wahl pro Fehlerklasse bewusst treffen (pipeline.py:330).
- Freisprüche persistieren — sonst pendelt die Note ewig unter 10 (qa.py:437).
- Note deterministisch aus gemessenen Quoten, nie vom LLM schätzen lassen (qa.py:294).
- Qualitäts-Gate vor teuren Downstream-Phasen (config.py:132).
- QA nutzt EIGENE Detektoren/Schwellen, nie die der Pipeline — geteilte blinde Flecken (qa.py:1).
- Fix-Schwellen an Sektionsgröße koppeln; Kritisches immer fixen (config.py:170).
- Schema-Parser defensiv gegen Judge-Overreport — 65-Einträge-Vollinventar (guide_board.py:66).
- Detektor-Messlatte und Fix-Auftrag teilen dieselbe Formel — sonst unfixbare Befunde (guide_qa.py:75).
- Zwei Retry-Ebenen: Race-Restart vs. Item-Backoff/Dead-Letter, sichtbar + requeue-bar (kanban.py:135).
- Auto-Loop: Ziel erreicht / echter Stillstand / hartes Limit — transiente Verschlechterung zulassen (auto_loop.py:31).
- Guard-Strenge an Fehlerkosten ausrichten — reversible Fehl-Merges brauchen keine harten Vetos (board_inventory.py:1427).
- Nach parallelen Judges ein Reconcile-Pass gegen Duplikat-Parents (config.py:90).
- Zielgrößen sublinear (√n) statt statischer Bänder (config.py:94).
- Fakten-Checks: exakt zitierte Quellstellen einblenden, kein Keyword-Pack (blocks.py:549).
- Unicode am Import normalisieren (NFC + Kontrollzeichen→Leerzeichen), Matching diakritik-fest (NFKD, Kombinationszeichen droppen) — pdftotext liefert dekomponierte Umlaute und Steuerbytes für Sonderglyphen (ε→\x0f), LLM-Zitate präkomponierte Zeichen bzw. Müll-Echos; per-Zeichen-NFKC komponiert nie → 59/96 aak-Atome „ohne Anker" trotz wörtlicher Zitate (creator2: korpus.py:_snapshot_schreiben, textkit.py:_locker_mit_map).
- Text-Reparatur und Zitat-Anchoring nicht selbst erfinden: ftfy am Import, fuzzysearch als letzte Matching-Stufe (Hypothes.is-Muster exakt→locker→fuzzy) — Reader „verschönern" Zitate (Listing-Zeilennummern weg, verlorene Glyphen rekonstruiert); Fuzzy NUR mit Mindestlänge, harter Fehlerquote und Eindeutigkeits-Guard gegen Doppelgänger-Passagen (SubSetSum vs. Partition teilen den Satzanfang); Steuerzeichen VOR ftfy zu Leerzeichen (ftfy löscht sie und verklebt Wörter) (creator2: korpus.py:_text_reparieren, textkit.py:_fuzzy_span).
Meta
- Jede Guard/Schwelle trägt ihren gemessenen Beleg im Kommentar.
- Tunebare Parameter und QA-Messlatte strikt trennen (Messlatte nie im Suchraum).
- Deterministisch vor LLM: Konsens, Kandidaten, Guards im Code; der Judge ist Präzisions-Gate für Zweifelsfälle.
- Provider-Ausfall darf nie den Lauf reißen — Stacks unabhängig.