# Chain-Identifikation und Template Matching ## Übersicht Das System identifiziert und füllt Chains durch einen mehrstufigen Prozess: 1. **Graph-Indexierung**: Erfassung aller Edges (Kanten) im lokalen Subgraph 2. **Candidate-Node-Sammlung**: Identifikation potenzieller Knoten für Template-Slots 3. **Template Matching**: Backtracking-Algorithmus zur optimalen Slot-Zuordnung 4. **Link-Validierung**: Prüfung, ob Edges zwischen zugewiesenen Slots existieren 5. **Scoring & Confidence**: Bewertung der Match-Qualität --- ## 1. Graph-Indexierung ### Edge-Erfassung Der **Chain Inspector** (`src/analysis/chainInspector.ts`) erfasst alle Edges im lokalen Subgraph: - **Current Section**: Die aktuelle Section (file + heading) - **Incoming Edges**: Edges, die zur aktuellen Section zeigen - **Outgoing Edges**: Edges, die von der aktuellen Section ausgehen - **Neighbor Notes**: Verbundene Notes werden geladen, um den Subgraph zu erweitern ### Edge-Scopes Edges können drei Scopes haben: - **`section`**: Section-spezifisch (`[[Note#Heading]]`) - **`note`**: Note-weit (`[[Note]]` ohne Heading) - **`candidate`**: In "## Kandidaten" Zone ### Filterung Edges werden basierend auf `InspectorOptions` gefiltert: - `includeNoteLinks`: Ob Note-Scope Edges einbezogen werden - `includeCandidates`: Ob Candidate Edges einbezogen werden - `maxDepth`: Maximale Tiefe für Path-Traversal --- ## 2. Candidate-Node-Sammlung ### Prozess (`buildCandidateNodes`) Für jeden Edge im Subgraph werden **Candidate Nodes** erstellt: 1. **Source Nodes**: Alle Knoten, von denen Edges ausgehen 2. **Target Nodes**: Alle Knoten, zu denen Edges zeigen 3. **Note-Type-Extraktion**: Frontmatter `type:` wird aus jeder Note extrahiert 4. **Deduplizierung**: Gleiche Knoten (file + heading) werden nur einmal erfasst ### Node-Repräsentation ```typescript interface CandidateNode { nodeKey: { file: string; heading: string | null; }; noteType: string; // z.B. "insight", "decision", "experience" } ``` ### Maximale Anzahl Standardmäßig werden maximal **30 Candidate Nodes** gesammelt (konfigurierbar). --- ## 3. Template Matching ### Template-Definition (`chain_templates.yaml`) Jedes Template definiert: - **Slots**: Positionen in der Chain mit erlaubten Note-Types - **Links**: Erwartete Verbindungen zwischen Slots mit erlaubten Edge-Roles **Beispiel: `loop_learning`** ```yaml slots: - id: experience allowed_node_types: [experience, journal, event] - id: learning allowed_node_types: [insight, principle, value, belief, skill, trait] - id: behavior allowed_node_types: [habit, decision, task] - id: feedback allowed_node_types: [experience, journal, event, state] links: - from: experience to: learning allowed_edge_roles: [causal, provenance, influences] - from: learning to: behavior allowed_edge_roles: [influences, enables_constraints, causal] - from: behavior to: feedback allowed_edge_roles: [causal, influences] ``` ### Backtracking-Algorithmus (`findBestAssignment`) Der Algorithmus findet die **beste Slot-Zuordnung** durch systematisches Ausprobieren: 1. **Slot-Filterung**: Für jeden Slot werden nur Candidate Nodes gefiltert, die den `allowed_node_types` entsprechen 2. **Backtracking**: Rekursives Durchprobieren aller möglichen Zuordnungen 3. **Distinct Nodes**: Jeder Knoten kann nur einmal zugeordnet werden (wenn `distinct_nodes: true`) 4. **Scoring**: Jede vollständige Zuordnung wird bewertet 5. **Best Match**: Die Zuordnung mit dem höchsten Score wird zurückgegeben ### Slot-Zuordnung ```typescript function backtrack(assignment: Map, slotIndex: number) { // Wenn alle Slots zugeordnet sind: if (slotIndex >= slots.length) { const result = scoreAssignment(...); // Bewerte Zuordnung if (result.score > bestScore) { bestMatch = result; // Speichere besten Match } return; } // Probiere jeden passenden Candidate für diesen Slot for (const candidate of slotCandidates.get(slot.id)) { if (!alreadyAssigned(candidate)) { assignment.set(slot.id, candidate); backtrack(assignment, slotIndex + 1); // Rekursiv weiter assignment.delete(slot.id); // Backtrack } } // Auch: Slot leer lassen (für unvollständige Chains) backtrack(assignment, slotIndex + 1); } ``` --- ## 4. Link-Validierung ### Edge-Suche (`findEdgeBetween`) Für jedes Template-Link wird geprüft, ob ein Edge zwischen den zugewiesenen Slots existiert: 1. **Node-Keys**: `fromKey = "file:heading"`, `toKey = "file:heading"` 2. **Edge-Suche**: Durchsuche `allEdges` nach passendem Edge 3. **Canonicalisierung**: Edge-Typ wird auf Canonical gemappt (via `edge_vocabulary.md`) 4. **Role-Mapping**: Canonical Edge-Typ wird auf Role gemappt (via `chain_roles.yaml`) 5. **Role-Validierung**: Prüfe, ob Edge-Role in `allowed_edge_roles` enthalten ist ### Role-Evidence Wenn ein Link erfüllt ist, wird **Role Evidence** gespeichert: ```typescript roleEvidence.push({ from: "learning", // Slot-ID (nicht Dateipfad!) to: "behavior", // Slot-ID edgeRole: "causal", // Role aus chain_roles.yaml rawEdgeType: "resulted_in" // Original Edge-Typ im Vault }); ``` **Wichtig**: `roleEvidence` verwendet **Slot-IDs**, nicht Dateipfade! --- ## 5. Scoring & Confidence ### Scoring (`scoreAssignment`) **Slot-Scoring**: - Jeder zugewiesene Slot: **+2 Punkte** **Link-Scoring**: - Erfüllter Link (mit erlaubter Role): **+10 Punkte** - Fehlender Link (wenn `required_links: true`): **-5 Punkte** - Falsche Role (wenn `required_links: true`): **-5 Punkte** ### Confidence-Berechnung Die **Confidence** wird nach dem Matching berechnet: 1. **`weak`**: Wenn `slotsComplete === false` (fehlende Slots) 2. **`confirmed`**: Wenn `slotsComplete === true` UND `linksComplete === true` UND mindestens eine causal-ish Role Evidence 3. **`plausible`**: Sonst (Slots vollständig, aber Links unvollständig oder keine causal Roles) **Causal-ish Roles**: `["causal", "influences", "enables_constraints"]` (konfigurierbar in `chain_templates.yaml`) ### Completeness - **`slotsComplete`**: `missingSlots.length === 0` - **`linksComplete`**: `satisfiedLinks === requiredLinks` --- ## 6. Template-Matching-Profile ### Profile-Definition Profile steuern die Matching-Strenge: **`discovery`** (schreibfreundlich): ```yaml required_links: false # Links sind optional min_slots_filled_for_gap_findings: 2 min_score_for_gap_findings: 8 ``` **`decisioning`** (strikt): ```yaml required_links: true # Links sind Pflicht min_slots_filled_for_gap_findings: 3 min_score_for_gap_findings: 18 ``` ### Profile-Auflösung 1. **Settings**: Plugin-Einstellung `templateMatchingProfile` 2. **Template**: Template-spezifische `matching.required_links` 3. **Defaults**: `defaults.matching.required_links` --- ## 7. Beispiel: Loop Learning Match ### Input - **Current Section**: `Tests/03_insight_transformation.md#Kern` - **Edges im Subgraph**: 8 Edges (1 current, 7 neighbors) - **Candidate Nodes**: 4 Nodes (experience, learning, behavior, feedback) ### Template ```yaml name: loop_learning slots: [experience, learning, behavior, feedback] links: - experience → learning - learning → behavior - behavior → feedback ``` ### Matching-Prozess 1. **Slot-Zuordnung** (Backtracking): - `experience` → `Tests/02_event_trigger_detail.md#Detail` (noteType: `event`) - `learning` → `Tests/03_insight_transformation.md#Kern` (noteType: `insight`) - `behavior` → `Tests/04_decision_outcome.md#Entscheidung` (noteType: `decision`) - `feedback` → `Tests/01_experience_trigger.md#Kontext` (noteType: `experience`) 2. **Link-Validierung**: - `experience → learning`: ❌ Kein Edge gefunden - `learning → behavior`: ✅ Edge `resulted_in` mit Role `causal` gefunden - `behavior → feedback`: ❌ Kein Edge gefunden 3. **Scoring**: - Slots: 4 × 2 = **8 Punkte** - Links: 1 × 10 = **10 Punkte** - **Gesamt: 18 Punkte** 4. **Resultat**: ```json { "templateName": "loop_learning", "score": 18, "slotsComplete": true, "linksComplete": false, "satisfiedLinks": 1, "requiredLinks": 3, "confidence": "plausible", "roleEvidence": [ { "from": "learning", "to": "behavior", "edgeRole": "causal", "rawEdgeType": "resulted_in" } ] } ``` --- ## 8. Wichtige Konzepte ### Slot-IDs vs. Dateipfade - **Slot-IDs**: Template-interne Bezeichner (`"learning"`, `"behavior"`) - **Dateipfade**: Vault-Pfade (`"Tests/03_insight_transformation.md"`) - **roleEvidence** verwendet Slot-IDs, nicht Dateipfade! ### Canonicalisierung - **Intern**: Edge-Typen werden auf Canonical gemappt (für Analyse) - **Vault**: Original Edge-Typen (Aliase) bleiben unverändert - **Schreiben**: Plugin schreibt keine Canonicals, nur User-gewählte Typen ### Distinct Nodes Wenn `distinct_nodes: true`: - Jeder Knoten kann nur **einmal** pro Template zugeordnet werden - Verhindert zirkuläre Zuordnungen ### Edge-Target-Resolution Edges können verschiedene Pfad-Formate verwenden: - Vollständig: `Tests/03_insight_transformation.md` - Basename: `03_insight_transformation` - Wikilink: `[[03_insight_transformation]]` Das System normalisiert alle Formate für konsistente Matching. --- ## 9. Integration mit Chain Workbench Der **Chain Workbench** nutzt die Template Matches, um: 1. **Todos zu generieren**: - `missing_slot`: Fehlende Slot-Zuordnungen - `missing_link`: Fehlende Links zwischen Slots - `weak_roles`: Links mit schwachen (nicht-causalen) Roles 2. **Status zu berechnen**: - `complete`: Slots + Links vollständig - `near_complete`: 1-2 Links fehlen oder 1 Slot fehlt - `partial`: Mehrere Lücken - `weak`: Nur structural/temporal Roles, keine causal Roles 3. **Actions anzubieten**: - `insert_edge_forward`: Edge einfügen (von Slot A nach Slot B) - `link_existing`: Bestehenden Knoten verlinken - `create_note_via_interview`: Neue Note für Slot erstellen --- ## 10. Konfigurationsdateien ### `chain_templates.yaml` Definiert Template-Strukturen: - Slots mit erlaubten Note-Types - Links mit erlaubten Edge-Roles - Profile (discovery, decisioning) ### `chain_roles.yaml` Mappt Edge-Typen auf Roles: - `causal`: Direkte Kausalität - `influences`: Indirekte Einflussnahme - `enables_constraints`: Ermöglicht/Einschränkt - `structural`: Strukturelle Beziehung - `temporal`: Zeitliche Beziehung ### `edge_vocabulary.md` Definiert Canonical Edge-Typen und Aliase: - Canonical: `resulted_in` - Aliase: `führt_zu`, `resultiert_in`, etc. ### `graph_schema.md` Definiert Note-Type-Kompatibilität: - Welche Edge-Typen sind typisch für `insight → decision`? - Welche Edge-Typen sind verboten? --- ## Zusammenfassung Das System identifiziert Chains durch: 1. **Graph-Indexierung**: Erfassung aller Edges im lokalen Subgraph 2. **Candidate-Sammlung**: Identifikation potenzieller Knoten 3. **Backtracking-Matching**: Optimale Slot-Zuordnung 4. **Link-Validierung**: Prüfung vorhandener Edges 5. **Scoring**: Bewertung der Match-Qualität Das Ergebnis sind **Template Matches** mit: - Slot-Zuordnungen (welche Knoten in welchen Slots) - Link-Status (welche Links erfüllt/fehlend) - Confidence (confirmed/plausible/weak) - Role Evidence (welche Edges welche Roles haben) Diese Matches werden dann im **Chain Workbench** verwendet, um konkrete Todos und Actions zu generieren.