# Audit: Informations-Integrität (Clean-Context v4.2.0) **Datum:** 2026-01-10 **Version:** v4.2.0 **Status:** Audit abgeschlossen - **KRITISCHES PROBLEM IDENTIFIZIERT** ## Kontext Das System wurde auf den Gold-Standard v4.2.0 optimiert. Ziel ist der "Clean-Context"-Ansatz: Strukturelle Metadaten (speziell `> [!edge]` Callouts und definierte Note-Scope Zonen) werden aus den Text-Chunks entfernt, um das semantische Rauschen im Vektor-Index zu reduzieren. Diese Informationen müssen stattdessen exklusiv über den Graphen (Feld `explanation` im `QueryHit`) an das LLM geliefert werden. ## Audit-Ergebnisse ### 1. Extraktion vor Filterung (Temporal Integrity) ⚠️ **TEILWEISE** #### ✅ Note-Scope Zonen: **FUNKTIONIERT** **Status:** ✅ **KORREKT** - `build_edges_for_note()` erhält `markdown_body` (Original-Markdown) als Parameter - `extract_note_scope_zones()` analysiert den **unbearbeiteten** Markdown-Text - Extraktion erfolgt **VOR** dem Chunking-Filter - **Code-Referenz:** `app/core/graph/graph_derive_edges.py` Zeile 152-177 ```python # WP-24c v4.2.0: Note-Scope Zonen Extraktion (VOR Chunk-Verarbeitung) note_scope_edges: List[dict] = [] if markdown_body: zone_links = extract_note_scope_zones(markdown_body) # ← Original-Markdown ``` #### ❌ Callouts in Edge-Zonen: **KRITISCHES PROBLEM** **Status:** ❌ **FEHLT** **Problem:** - `build_edges_for_note()` extrahiert Callouts aus **gefilterten Chunks** (Zeile 217-265) - Chunks wurden bereits gefiltert (Edge-Zonen entfernt) in `chunking_processor.py` Zeile 38 - **Callouts in Edge-Zonen werden NICHT extrahiert!** **Code-Referenz:** ```python # app/core/graph/graph_derive_edges.py Zeile 217-265 for ch in chunks: # ← chunks sind bereits gefiltert! raw = _get(ch, "window") or _get(ch, "text") or "" # ... # C. Callouts (> [!edge]) call_pairs, rem2 = extract_callout_relations(rem) # ← rem kommt aus gefilterten chunks ``` **Konsequenz:** - Callouts in Edge-Zonen (z.B. `### Unzugeordnete Kanten` oder `## Smart Edges`) werden **nicht** in den Graph geschrieben - **Informationsverlust:** Diese Kanten existieren nicht im Graph und können nicht über `explanation` an das LLM geliefert werden **Empfehlung:** - Callouts müssen **auch** aus dem Original-Markdown (`markdown_body`) extrahiert werden - Ähnlich wie `extract_note_scope_zones()` sollte eine Funktion `extract_callouts_from_markdown()` erstellt werden - Diese sollte **vor** der Chunk-Verarbeitung aufgerufen werden ### 2. Payload-Vollständigkeit (Explanation-Mapping) ✅ **FUNKTIONIERT** **Status:** ✅ **KORREKT** (wenn Edges im Graph sind) **Code-Referenz:** `app/core/retrieval/retriever.py` Zeile 188-238 **Verifizierung:** - ✅ `_build_explanation()` sammelt alle Edges aus dem Subgraph (Zeile 189-215) - ✅ Edges werden in `EdgeDTO`-Objekte konvertiert (Zeile 205-214) - ✅ `related_edges` werden im `Explanation`-Objekt gespeichert (Zeile 236) - ✅ Top 3 Edges werden als `Reason`-Objekte formuliert (Zeile 217-228) **Einschränkung:** - Funktioniert nur, wenn Edges **im Graph sind** - Da Callouts in Edge-Zonen nicht extrahiert werden (siehe Punkt 1), fehlen sie auch in der Explanation ### 3. Prompt-Sichtbarkeit (RAG-Interface) ⚠️ **UNKLAR** **Status:** ⚠️ **TEILWEISE DOKUMENTIERT** **Code-Referenz:** `app/routers/chat.py` Zeile 178-274 **Verifizierung:** - ✅ `explain=True` wird in `QueryRequest` gesetzt (Zeile 211 in `decision_engine.py`) - ✅ `explanation` wird im `QueryHit` gespeichert (Zeile 334 in `retriever.py`) - ⚠️ **Unklar:** Wie wird `explanation.related_edges` im LLM-Prompt verwendet? **Untersuchung:** - `chat.py` verwendet `interview_template` Prompt (Zeile 212-222) - Prompt-Variablen werden aus `QueryHit` extrahiert - **Fehlend:** Explizite Verwendung von `explanation.related_edges` im Prompt **Empfehlung:** - Prüfen Sie `config/prompts.yaml` für `interview_template` - Stellen Sie sicher, dass `{related_edges}` oder ähnliche Variablen im Prompt verwendet werden - Dokumentieren Sie die Prompt-Struktur für RAG-Kontext ### 4. Edge-Case Analyse ⚠️ **KRITISCH** #### Szenario: Callout nur in Edge-Zone (kein Wikilink im Fließtext) **Status:** ❌ **INFORMATIONSVERLUST** **Beispiel:** ```markdown --- type: decision title: Meine Notiz --- # Hauptinhalt Dieser Text wird gechunkt. ## Smart Edges > [!edge] depends_on > [[Projekt Alpha]] ## Weiterer Inhalt Mehr Text... ``` **Aktuelles Verhalten:** 1. ✅ `## Smart Edges` wird als Edge-Zone erkannt 2. ✅ Zone wird vom Chunking ausgeschlossen 3. ❌ **Callout wird NICHT extrahiert** (weil aus gefilterten Chunks extrahiert wird) 4. ❌ **Kante fehlt im Graph** 5. ❌ **Kante fehlt in Explanation** 6. ❌ **LLM erhält keine Information über diese Verbindung** **Konsequenz:** - **Wissens-Vakuum:** Die Information existiert weder im Chunk-Text noch im Graph - **Semantische Verbindung verloren:** Das LLM kann diese Verbindung nicht berücksichtigen ## Zusammenfassung der Probleme ### ❌ **KRITISCH: Callout-Extraktion aus Edge-Zonen fehlt** **Problem:** - Callouts werden nur aus gefilterten Chunks extrahiert - Callouts in Edge-Zonen werden nicht erfasst - **Informationsverlust:** Diese Kanten fehlen im Graph **Lösung:** 1. Erstellen Sie `extract_callouts_from_markdown(markdown_body: str)` Funktion 2. Rufen Sie diese **vor** der Chunk-Verarbeitung auf 3. Integrieren Sie die extrahierten Callouts in `build_edges_for_note()` ### ⚠️ **WARNUNG: Prompt-Integration unklar** **Problem:** - Unklar, ob `explanation.related_edges` im LLM-Prompt verwendet werden - Keine explizite Dokumentation der Prompt-Struktur **Empfehlung:** - Prüfen Sie `config/prompts.yaml` für `interview_template` - Dokumentieren Sie die Verwendung von `related_edges` im Prompt ## Empfohlene Fixes ### Fix 1: Callout-Extraktion aus Original-Markdown **Datei:** `app/core/graph/graph_derive_edges.py` **Änderung:** ```python def extract_callouts_from_markdown(markdown_body: str, note_id: str) -> List[dict]: """ WP-24c v4.2.0: Extrahiert Callouts aus dem Original-Markdown. Wird verwendet, um Callouts in Edge-Zonen zu erfassen, die nicht in Chunks sind. """ if not markdown_body: return [] edges: List[dict] = [] # Extrahiere alle Callouts aus dem gesamten Markdown call_pairs, _ = extract_callout_relations(markdown_body) for k, raw_t in call_pairs: t, sec = parse_link_target(raw_t, note_id) if not t: continue # Bestimme scope: "note" wenn in Note-Scope Zone, sonst "chunk" # (Für jetzt: scope="note" für alle Callouts aus Markdown) payload = { "edge_id": _mk_edge_id(k, note_id, t, "note", target_section=sec), "provenance": "explicit:callout", "rule_id": "callout:edge", "confidence": PROVENANCE_PRIORITY.get("callout:edge", 1.0) } if sec: payload["target_section"] = sec edges.append(_edge( kind=k, scope="note", source_id=note_id, target_id=t, note_id=note_id, payload=payload )) return edges def build_edges_for_note( note_id: str, chunks: List[dict], note_level_references: Optional[List[str]] = None, include_note_scope_refs: bool = False, markdown_body: Optional[str] = None, ) -> List[dict]: # ... existing code ... # WP-24c v4.2.0: Callout-Extraktion aus Original-Markdown (VOR Chunk-Verarbeitung) if markdown_body: callout_edges = extract_callouts_from_markdown(markdown_body, note_id) edges.extend(callout_edges) # ... rest of function ... ``` ### Fix 2: Prompt-Dokumentation **Datei:** `config/prompts.yaml` und Dokumentation **Empfehlung:** - Prüfen Sie, ob `interview_template` `{related_edges}` verwendet - Falls nicht: Erweitern Sie den Prompt um Graph-Kontext - Dokumentieren Sie die Prompt-Struktur ## Validierung nach Fix Nach Implementierung der Fixes sollte folgendes verifiziert werden: 1. ✅ **Callouts in Edge-Zonen werden extrahiert** - Test: Erstellen Sie eine Notiz mit Callout in `## Smart Edges` - Verifizieren: Edge existiert in Qdrant `_edges` Collection 2. ✅ **Edges erscheinen in Explanation** - Test: Query mit `explain=True` - Verifizieren: `explanation.related_edges` enthält die Callout-Edge 3. ✅ **LLM erhält Graph-Kontext** - Test: Chat-Query mit Edge-Information - Verifizieren: LLM-Antwort berücksichtigt die Graph-Verbindung ## Fazit **Aktueller Status:** ⚠️ **INFORMATIONSVERLUST BEI CALLOUTS IN EDGE-ZONEN** **Hauptproblem:** - Callouts in Edge-Zonen werden nicht extrahiert - Diese Information geht vollständig verloren **Lösung:** - Implementierung von `extract_callouts_from_markdown()` erforderlich - Integration in `build_edges_for_note()` vor Chunk-Verarbeitung **Nach Fix:** - ✅ Alle Callouts werden erfasst (auch in Edge-Zonen) - ✅ Graph-Vollständigkeit gewährleistet - ✅ Explanation enthält alle relevanten Edges - ✅ LLM erhält vollständigen Kontext