diff --git a/docs/00_Dokumentations_Index.md b/docs/00_Dokumentations_Index.md index 28adf43..6fe2141 100644 --- a/docs/00_Dokumentations_Index.md +++ b/docs/00_Dokumentations_Index.md @@ -1,187 +1,110 @@ -# Mindnet Causal Assistant - Dokumentations-Index +# Mindnet Causal Assistant – Dokumentations-Index > **Version:** 1.0.0 -> **Stand:** 2025-01-XX -> **Vollständige Übersicht:** Alle Dokumentations-Dateien und deren Inhalte +> **Stand:** Januar 2026 +> **Plugin:** Mindnet Causal Assistant (Obsidian) --- -## Dokumentations-Struktur +## Übersicht -### Hauptdokumentation (nach Zielgruppe) +Die Dokumentation ist in **zwei Perspektiven** organisiert: -1. **[01_Benutzerhandbuch.md](./01_Benutzerhandbuch.md)** - Endnutzer -2. **[02_Administratorhandbuch.md](./02_Administratorhandbuch.md)** - Administratoren -3. **[03_Entwicklerhandbuch.md](./03_Entwicklerhandbuch.md)** - Entwickler -4. **[04_Architektur.md](./04_Architektur.md)** - Architekten -5. **[05_Installation_Deployment.md](./05_Installation_Deployment.md)** - Installation - -### Spezialisierte Referenzen - -6. **[06_Konfigurationsdateien_Referenz.md](./06_Konfigurationsdateien_Referenz.md)** - Config-Dateien Format & Aufbau -7. **[Interview_Config_Guide.md](./Interview_Config_Guide.md)** - Vollständige Anleitung für `interview_config.yaml` (inkl. WP-26 Features, GenAI-freundlich) -8. **[07_Event_Handler_Commands.md](./07_Event_Handler_Commands.md)** - Event Handler & Commands - -### WP-26 Integration (Section Types & Intra-Note-Edges) - -9. **[06_LH_WP26_Plugin_Integration.md](./06_LH_WP26_Plugin_Integration.md)** - Lastenheft für WP-26 Plugin-Integration (vollständige Anforderungen) -10. **[WP26_Plugin_Interface_Specification.md](./WP26_Plugin_Interface_Specification.md)** - Vollständige Schnittstellenspezifikation für Plugin-Entwicklung -11. **[WP26_Implementation_Checklist.md](./WP26_Implementation_Checklist.md)** - Implementierungs-Checkliste mit Tasks und Phasen - -### Chain Inspector Reports - -- [CHAIN_INSPECTOR_V0_REPORT.md](./CHAIN_INSPECTOR_V0_REPORT.md) - v0.0 Implementierung -- [CHAIN_INSPECTOR_V02_REPORT.md](./CHAIN_INSPECTOR_V02_REPORT.md) - v0.2 Features -- [CHAIN_INSPECTOR_V03_REPORT.md](./CHAIN_INSPECTOR_V03_REPORT.md) - v0.3 Features -- [CHAIN_INSPECTOR_V04_REPORT.md](./CHAIN_INSPECTOR_V04_REPORT.md) - v0.4 Template Matching -- [CHAIN_INSPECTOR_V042_REPORT.md](./CHAIN_INSPECTOR_V042_REPORT.md) - v0.4.2 Updates - -### Konzepte & Details - -- [02_causal_chain_retrieving.md](./02_causal_chain_retrieving.md) - Kausale Ketten-Retrieval -- [DANGLING_TARGET_CASES.md](./DANGLING_TARGET_CASES.md) - Dangling Target Findings - -### Legacy-Dokumentation - -- [readme.md](./readme.md) - MVP 1.0 Quickstart -- [Handbuch.md](./Handbuch.md) - MVP 1.0 Handbuch -- [TESTING_WITH_REAL_VAULT.md](./TESTING_WITH_REAL_VAULT.md) - Testing mit echtem Vault +1. **Nach Modul** – technische Inhalte nach Komponenten (Analysis, Interview, Mapping, usw.) +2. **Nach Rolle** – gezielte Einstiege für Nutzer, Administratoren, Entwickler, Architekten, Projektleitung --- -## Vollständigkeits-Checkliste +## Einstieg nach Rolle -### ✅ Module & Komponenten - -- [x] **Analysis** (`src/analysis/`) - Chain Inspector, Template Matching, Graph Index, Section Context, Severity Policy -- [x] **Commands** (`src/commands/`) - Inspect Chains, Fix Findings -- [x] **Dictionary** (`src/dictionary/`) - Chain Roles Loader, Chain Templates Loader, Config Path Manager, Dictionary Loader, Parsers, Types -- [x] **Entity Picker** (`src/entityPicker/`) - Note Index, Folder Tree, Filters, Wikilink -- [x] **Export** (`src/export/`) - Graph Export -- [x] **Graph** (`src/graph/`) - Graph Builder, Graph Index, Render Chain Report, Resolve Target, Traverse -- [x] **Interview** (`src/interview/`) - Config Loader, Parser, Wizard State, Loop State, Renderer, Write Frontmatter, Section Key Resolver, Extract Target, Slugify -- [x] **Lint** (`src/lint/`) - Lint Engine, Rules (Hub Has Causality, Missing Target, Unknown Edge) -- [x] **Mapping** (`src/mapping/`) - Semantic Mapping Builder, Mapping Extractor, Mapping Builder, Edge Type Selector, Update Mapping Blocks, Section Parser, Worklist Builder, Graph Schema, Schema Helper, Folder Helpers -- [x] **Parser** (`src/parser/`) - Parse Edges From Callouts, Parse Frontmatter, Parse Rel Links -- [x] **Schema** (`src/schema/`) - Graph Schema Loader -- [x] **UI** (`src/ui/`) - Alle Modals (Interview Wizard, Profile Selection, Edge Type Chooser, Entity Picker, Adopt Note, Folder Tree, Link Prompt, Inline Edge Type, Confirm Overwrite), Settings Tab, Markdown Toolbar, Mindnet View -- [x] **Unresolved Link** (`src/unresolvedLink/`) - Handler, Link Helpers, Adopt Helpers -- [x] **Vocabulary** (`src/vocab/`) - Vocabulary, Vocabulary Loader, Parse Edge Vocabulary - -### ✅ Funktionen & Features - -- [x] **Note-Erstellung** - Mit Profilen, Frontmatter-Generierung -- [x] **Interview-Wizard** - Steps, Loops, Nested Loops, Section-basierte Ausgabe -- [x] **Semantic Mapping** - Builder, Extractor, Edge Type Assignment -- [x] **Chain Inspector** - Template Matching, Findings Generation -- [x] **Fix Findings** - Automatische Behebung von Findings -- [x] **Unresolved Link Handling** - Reading View, Editor, Note Adoption -- [x] **Edge-Type-Änderung** - Kontext-Erkennung, Edge Type Selector -- [x] **Graph Export** - JSON-Export -- [x] **Linting** - Lint Engine mit Regeln -- [x] **Live-Reload** - Automatisches Neuladen von Config-Dateien - -### ✅ Commands - -- [x] `mindnet-reload-edge-vocabulary` - Edge Vocabulary neu laden -- [x] `mindnet-validate-current-note` - Note validieren (Lint) -- [x] `mindnet-export-graph` - Graph exportieren -- [x] `mindnet-show-chains-from-current-note` - Ketten von aktueller Note zeigen -- [x] `mindnet-create-note-from-profile` - Note mit Profil erstellen -- [x] `mindnet-change-edge-type` - Edge-Type ändern -- [x] `mindnet-debug-chain-roles` - Chain Roles Debug-Info -- [x] `mindnet-debug-chain-templates` - Chain Templates Debug-Info -- [x] `mindnet-fix-findings` - Findings beheben -- [x] `mindnet-inspect-chains` - Chains analysieren -- [x] `mindnet-build-semantic-mappings` - Semantic Mapping Blöcke bauen - -### ✅ Event Handler - -- [x] **Vault Modify Event** - Live-Reload von Config-Dateien -- [x] **Vault Create Event** - Note Adoption -- [x] **Markdown Post Processor** - Unresolved Link Handling (Reading View) -- [x] **DOM Click Event** - Unresolved Link Handling (Editor) - -### ✅ Settings - -- [x] **Pfad-Settings** (6) - Alle Config-Datei-Pfade -- [x] **Graph & Chain Settings** (4) - maxHops, strictMode, showCanonicalHints, chainDirection -- [x] **Interview Settings** (1) - autoStartInterviewOnCreate -- [x] **Unresolved Link Settings** (6) - interceptUnresolvedLinkClicks, autoStartOnUnresolvedClick, bypassModifier, editorFollowModifier, waitForFirstModifyAfterCreate, waitForModifyTimeoutMs, debugLogging -- [x] **Note Adoption Settings** (4) - adoptNewNotesInEditor, adoptMaxChars, adoptConfirmMode, highConfidenceWindowMs -- [x] **Semantic Mapping Settings** (6) - mappingWrapperCalloutType, mappingWrapperTitle, mappingWrapperFolded, defaultEdgeType, unassignedHandling, allowOverwriteExistingMappings, defaultNotesFolder -- [x] **Inline Micro Edge Suggester Settings** (3) - inlineMicroEnabled, inlineMaxAlternatives, inlineCancelBehavior -- [x] **Export Settings** (1) - exportPath -- [x] **Chain Inspector Settings** (3) - chainInspectorIncludeCandidates, chainInspectorMaxTemplateMatches, templateMatchingProfile -- [x] **Fix Actions Settings** (5) - createMissingNote (mode, defaultTypeStrategy, includeZones), createMissingHeading (level), promoteCandidate (keepOriginal) - -### ✅ Konfigurationsdateien - -- [x] **edge_vocabulary.md** - Format, Parsing-Regeln, Beispiel -- [x] **graph_schema.md** - Format, Parsing-Regeln, Beispiel -- [x] **interview_config.yaml** - Format, Felder, Beispiel (Profile, Steps, Loops) - **Siehe auch:** [Interview_Config_Guide.md](./Interview_Config_Guide.md) für vollständige Anleitung -- [x] **chain_roles.yaml** - Format, Felder, Beispiel (Roles, Edge Types) -- [x] **chain_templates.yaml** - Format, Felder, Beispiel (Templates, Slots, Links, Defaults, Profiles) -- [x] **analysis_policies.yaml** - Geplante Struktur (noch nicht vollständig implementiert) - -### ✅ Wirkungsweise - -- [x] **Live-Reload** - Debounced (200ms), Last-Known-Good Fallback -- [x] **Config-Loading** - YAML/Markdown Parsing, Error Handling -- [x] **Template Matching** - Slot-basiertes Matching, Link Constraints -- [x] **Findings Generation** - Gap-Heuristiken, Severity-Policy -- [x] **Note Adoption** - Confidence-Evaluation, Adoption-Flow -- [x] **Unresolved Link Handling** - Reading View vs Editor, Modifier-Keys -- [x] **Semantic Mapping** - Section-Parsing, Link-Extraktion, Edge-Type-Assignment +| Rolle | Primäre Dokumente | Kurzbeschreibung | +|-------|-------------------|------------------| +| **Nutzer** | [13_Erfassung_Causal_Ketten](13_Erfassung_Causal_Ketten.md), [01_Benutzerhandbuch](01_Benutzerhandbuch.md), [07_Event_Handler_Commands](07_Event_Handler_Commands.md) | Erfassung & Ketten, Installation, Commands, Troubleshooting | +| **Administrator** | [02_Administratorhandbuch](02_Administratorhandbuch.md), [06_Konfigurationsdateien_Referenz](06_Konfigurationsdateien_Referenz.md), [Interview_Config_Guide](Interview_Config_Guide.md) | Konfiguration, Pfade, Live-Reload, Wartung | +| **Entwickler** | [03_Entwicklerhandbuch](03_Entwicklerhandbuch.md), [04_Architektur](04_Architektur.md), [Module](modules/README.md) | Code-Struktur, Testing, Build, Erweiterungen | +| **Architekt** | [04_Architektur](04_Architektur.md), [02_concepts/03_chain_identification_and_matching](02_concepts/03_chain_identification_and_matching.md) | System-Design, Datenfluss, Konzepte | +| **Projektleitung** | [04_Architektur](04_Architektur.md), [README](../README.md), [STATUS_DOD](../STATUS_DOD.md) | Überblick, Scope, Definition of Done | +| **Systemadmin** | [05_Installation_Deployment](05_Installation_Deployment.md), [02_Administratorhandbuch](02_Administratorhandbuch.md) | Installation, Deployment, Umgebung | --- -## Dokumentations-Abdeckung +## Einstieg nach Modul -### Vollständig dokumentiert - -✅ **Alle Module** - Alle 14 Hauptmodule sind dokumentiert -✅ **Alle Commands** - Alle 11 Commands sind dokumentiert -✅ **Alle Event Handler** - Alle 4 Event Handler sind dokumentiert -✅ **Alle Settings** - Alle 40+ Settings sind dokumentiert -✅ **Alle Config-Dateien** - Alle 6 Config-Dateien sind dokumentiert -✅ **Wirkungsweise** - Alle Hauptfunktionen sind beschrieben -✅ **Konfiguration** - Format und Aufbau aller Config-Dateien sind dokumentiert - -### Teilweise dokumentiert - -⚠️ **Analysis Policies** - Erwähnt, aber noch nicht vollständig implementiert -⚠️ **Einige UI-Komponenten** - Basis-Funktionalität dokumentiert, Details könnten erweitert werden - -### Nicht dokumentiert (nicht vorhanden oder nicht relevant) - -- **Tests** - Test-Dateien sind nicht Teil der Benutzer-Dokumentation -- **Mocks** - Mock-Dateien sind nicht Teil der Benutzer-Dokumentation -- **Build-Scripts** - Build-Scripts sind in Entwicklerhandbuch dokumentiert +| Modul | Pfad | Beschreibung | +|-------|------|--------------| +| **Analysis** | [modules/analysis](modules/analysis.md) | Chain Inspector, Template Matching, Scoring, Findings | +| **Dictionary** | [modules/dictionary](modules/dictionary.md) | Config-Loader, Chain Roles, Chain Templates, Dictionary | +| **Interview** | [modules/interview](modules/interview.md) | Wizard, Loop State, Renderer, Section Key Resolver | +| **Mapping** | [modules/mapping](modules/mapping.md) | Semantic Mapping, Edge Type Selector, Update Mapping Blocks | +| **Parser** | [modules/parser](modules/parser.md) | Edges aus Callouts, Frontmatter, Links | +| **Graph** | [modules/graph](modules/graph.md) | Graph Builder, Traversal, Resolution, Export | +| **Vocabulary** | [modules/vocabulary](modules/vocabulary.md) | Edge Vocabulary, Normalisierung, Aliases | +| **Unresolved Link** | [modules/unresolvedLink](modules/unresolvedLink.md) | Link-Handler, Adoption, Heading-Normalisierung | +| **Workbench** | [modules/workbench](modules/workbench.md) | Chain Workbench, Todo-Generator, Status, Actions | +| **Lint** | [modules/lint](modules/lint.md) | Lint Engine, Rules, Findings | +| **UI** | [modules/ui](modules/ui.md) | Modals, Settings Tab, Entity Picker | --- -## Schnellzugriff nach Thema +## Kern-Dokumente -### Installation & Setup -→ [05_Installation_Deployment.md](./05_Installation_Deployment.md) +### Nutzung & Konfiguration -### Konfiguration -→ [02_Administratorhandbuch.md](./02_Administratorhandbuch.md) -→ [06_Konfigurationsdateien_Referenz.md](./06_Konfigurationsdateien_Referenz.md) -→ [Interview_Config_Guide.md](./Interview_Config_Guide.md) - Interview-Profile erstellen (GenAI-freundlich) +- [13_Erfassung_Causal_Ketten](13_Erfassung_Causal_Ketten.md) – **Praxis-Handbuch:** Elemente erfassen und Causal-Ketten schließen +- [01_Benutzerhandbuch](01_Benutzerhandbuch.md) – Endnutzer-Workflows, Commands, Einstellungen +- [07_Event_Handler_Commands](07_Event_Handler_Commands.md) – alle Commands und Event-Handler +- [02_Administratorhandbuch](02_Administratorhandbuch.md) – Plugin-Konfiguration, Pfade, Wartung +- [06_Konfigurationsdateien_Referenz](06_Konfigurationsdateien_Referenz.md) – Format aller Config-Dateien, Gewichtung, Analysis Policies +- [Interview_Config_Guide](Interview_Config_Guide.md) – interview_config.yaml (Profile, Steps, Loops, WP-26) -### Nutzung -→ [01_Benutzerhandbuch.md](./01_Benutzerhandbuch.md) -→ [07_Event_Handler_Commands.md](./07_Event_Handler_Commands.md) +### Technik & Konzepte -### Entwicklung -→ [03_Entwicklerhandbuch.md](./03_Entwicklerhandbuch.md) -→ [04_Architektur.md](./04_Architektur.md) +- [04_Architektur](04_Architektur.md) – System-Design, Komponenten, Datenfluss +- [03_Entwicklerhandbuch](03_Entwicklerhandbuch.md) – Projekt-Struktur, Build, Testing +- [02_concepts/03_chain_identification_and_matching](02_concepts/03_chain_identification_and_matching.md) – Template Matching, Scoring, Confidence +- [02_causal_chain_retrieving](02_causal_chain_retrieving.md) – Kausale Ketten-Retrieval -### WP-26 Integration -→ [WP26_Plugin_Interface_Specification.md](./WP26_Plugin_Interface_Specification.md) -→ [WP26_Implementation_Checklist.md](./WP26_Implementation_Checklist.md) +### Operation & Deployment + +- [05_Installation_Deployment](05_Installation_Deployment.md) – Installation, Deployment + +--- + +## Spezialthemen + +- [12_Heading_Block_Link_Recommendation](12_Heading_Block_Link_Recommendation.md) – Überschrift vs. Block-Link, Normalisierung, Obsidian-Verhalten +- [09_Workbench_Analysis_Basis](09_Workbench_Analysis_Basis.md) – Workbench-Analyse +- [10_Workbench_Findings_Integration](10_Workbench_Findings_Integration.md) – Findings-Integration +- [DANGLING_TARGET_CASES](DANGLING_TARGET_CASES.md) – Dangling-Target-Fälle + +--- + +## WP-26 Integration + +- [06_LH_WP26_Plugin_Integration](06_LH_WP26_Plugin_Integration.md) – Lastenheft für WP-26 Plugin-Integration +- [WP26_Plugin_Interface_Specification](WP26_Plugin_Interface_Specification.md) – Schnittstellenspezifikation +- [WP26_Implementation_Checklist](WP26_Implementation_Checklist.md) – Implementierungs-Checkliste + +--- + +## Reports & Archive + +- [CHAIN_INSPECTOR_V042_REPORT](CHAIN_INSPECTOR_V042_REPORT.md) – aktuellster Chain Inspector Report +- Weitere Reports: [CHAIN_INSPECTOR_V0_REPORT](CHAIN_INSPECTOR_V0_REPORT.md) … [CHAIN_INSPECTOR_V04_REPORT](CHAIN_INSPECTOR_V04_REPORT.md) +- Legacy: [readme](readme.md), [Handbuch](Handbuch.md), [TESTING_WITH_REAL_VAULT](TESTING_WITH_REAL_VAULT.md) + +--- + +## Vollständigkeits-Checkliste (Stand) + +| Bereich | Status | +|---------|--------| +| Module | 14 Module dokumentiert | +| Commands | 11+ Commands | +| Settings | 40+ Settings | +| Config-Dateien | 6 Dateien (edge_vocabulary, graph_schema, interview_config, chain_roles, chain_templates, analysis_policies) | +| Scoring & Gewichtung | Template Matching + Profile + Analysis Policies | +| Heading-Normalisierung | normalizeHeadingForMatch (^Block-ID entfernen, Idempotenz ohne ^) | --- diff --git a/docs/02_concepts/03_chain_identification_and_matching.md b/docs/02_concepts/03_chain_identification_and_matching.md index 960da2e..c62b7f6 100644 --- a/docs/02_concepts/03_chain_identification_and_matching.md +++ b/docs/02_concepts/03_chain_identification_and_matching.md @@ -1,5 +1,10 @@ # Chain-Identifikation und Template Matching +> **Stand:** Januar 2026 +> **Siehe auch:** [modules/analysis](../modules/analysis.md), [06_Konfigurationsdateien_Referenz](../06_Konfigurationsdateien_Referenz.md) + +--- + ## Übersicht Das System identifiziert und füllt Chains durch einen mehrstufigen Prozess: @@ -176,13 +181,17 @@ roleEvidence.push({ ### Scoring (`scoreAssignment`) -**Slot-Scoring**: -- Jeder zugewiesene Slot: **+2 Punkte** +**Implementierung:** `src/analysis/templateMatching.ts` -**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** +| Komponente | Punkte | +|------------|--------| +| Jeder zugewiesene Slot | +2 | +| Intra-Note-Bonus (alle Slots in derselben Note) | +5 | +| Erfüllter Link (mit erlaubter Edge-Role) | +10 | +| Fehlender Link (wenn `required_links: true`) | -5 | +| Falsche Role (wenn `required_links: true`) | -5 | + +**Heading-Matching:** Vergleiche via `headingsMatch` (normalisiert `^BlockID`; siehe [12_Heading_Block_Link_Recommendation](../../12_Heading_Block_Link_Recommendation.md)). ### Confidence-Berechnung @@ -221,6 +230,8 @@ min_slots_filled_for_gap_findings: 3 min_score_for_gap_findings: 18 ``` +**Profil-Auswahl:** Plugin-Setting `templateMatchingProfile` (`discovery` | `decisioning`). Profil-Definitionen in `chain_templates.yaml` unter `defaults.profiles`. + ### Profile-Auflösung 1. **Settings**: Plugin-Einstellung `templateMatchingProfile` @@ -372,6 +383,23 @@ Definiert Note-Type-Kompatibilität: - Welche Edge-Typen sind typisch für `insight → decision`? - Welche Edge-Typen sind verboten? +### `analysis_policies.yaml` + +Definiert Severity-Policies pro Profil (discovery, decisioning) für Findings: +- `missing_link_constraints`, `weak_chain_roles`, `unmapped_edge_types`, `missing_slot_*` + +--- + +## 11. Matching-Parameter (defaults.matching) + +| Parameter | Standard | Beschreibung | +|-----------|----------|--------------| +| `distinct_nodes` | true | Jeder Knoten nur einmal pro Template | +| `required_links` | true | Links erforderlich (profil-überschreibbar) | +| `max_candidate_nodes` | 30 | Max. Candidate Nodes pro Template | +| `max_matches_per_template` | 2 | Max. unterschiedliche Zuordnungen (z. B. intra-note + cross-note) | +| `max_assignments_collected` | 1000 | Schleifenschutz beim Backtracking | + --- ## Zusammenfassung diff --git a/docs/06_Konfigurationsdateien_Referenz.md b/docs/06_Konfigurationsdateien_Referenz.md index ae9a709..9dfc7ab 100644 --- a/docs/06_Konfigurationsdateien_Referenz.md +++ b/docs/06_Konfigurationsdateien_Referenz.md @@ -531,58 +531,75 @@ templates: ### Zweck -Definiert Policies für Findings (Severity, Unterdrückung, etc.). +Definiert Severity-Policies für Findings pro Profil (discovery, decisioning). ### Format -**YAML-Datei** (geplant, noch nicht vollständig implementiert). +**YAML-Datei** mit `profiles` und `severities` je Finding-Typ. -### Geplante Struktur +### Aktuelle Struktur ```yaml -version: "1.0" - -findings: - missing_slot_*: - default_severity: warn - profiles: - discovery: - severity: info - suppress_if: - - slots_filled < 2 - decisioning: - severity: warn - suppress_if: [] - dangling_target: - default_severity: error - suppress_if: [] - missing_link_constraints: - default_severity: warn - suppress_if: - - required_links == false - no_causal_roles: - default_severity: info - suppress_if: [] +version: 1 +profiles: + discovery: + severities: + missing_link_constraints: info + weak_chain_roles: info + unmapped_edge_types: info + missing_slot_*: info + decisioning: + severities: + missing_link_constraints: warn + weak_chain_roles: info + unmapped_edge_types: warn + missing_slot_*: warn ``` -### Felder (geplant) +### Felder -#### Root-Level +- **`version`** (number, optional): Config-Version +- **`profiles`** (object, required): Profil-Name → Severity-Overrides + - **`severities`** (object): Finding-Code → Severity (`info`, `warn`, `error`) -- **`version`** (string, optional): Config-Version -- **`findings`** (object, required): Mapping von Finding-Codes zu Policies +### Verwendung -#### Finding Policy +- **Severity Policy:** `severityPolicy.ts` nutzt diese Datei für Profil-spezifische Severities +- **Profil-Auswahl:** Plugin-Setting `templateMatchingProfile` (`discovery` | `decisioning`) -- **`default_severity`** (string, required): Standard-Severity (`error`, `warn`, `info`) -- **`profiles`** (object, optional): Profil-spezifische Overrides - - **`discovery`** (object, optional): Discovery-Profil-Parameter - - **`decisioning`** (object, optional): Decisioning-Profil-Parameter -- **`suppress_if`** (array, optional): Bedingungen für Unterdrückung +--- -### Status +## Template-Matching-Gewichtung (chain_templates.yaml) -**Noch nicht vollständig implementiert.** Aktuell wird Severity-Policy teilweise in `severityPolicy.ts` gehandhabt. +### Scoring-Logik (Implementierung) + +Die Scoring-Logik ist in `src/analysis/templateMatching.ts` implementiert: + +| Komponente | Punkte | +|------------|--------| +| Jeder zugewiesene Slot | +2 | +| Intra-Note-Bonus (alle Slots in derselben Note) | +5 | +| Erfüllter Link (mit erlaubter Edge-Role) | +10 | +| Fehlender Link (wenn `required_links: true`) | -5 | +| Falsche Role (wenn `required_links: true`) | -5 | + +### Profil-Parameter (defaults.profiles) + +| Parameter | discovery | decisioning | Beschreibung | +|-----------|-----------|-------------|--------------| +| `required_links` | false | true | Links sind Pflicht | +| `min_slots_filled_for_gap_findings` | 2 | 3 | Min. Slots für Gap-Findings | +| `min_score_for_gap_findings` | 8 | 18 | Min. Score für Gap-Findings | + +### Matching-Parameter (defaults.matching) + +| Parameter | Standard | Beschreibung | +|-----------|----------|--------------| +| `distinct_nodes` | true | Jeder Knoten nur einmal pro Template | +| `required_links` | true | Links erforderlich (profil-überschreibbar) | +| `max_candidate_nodes` | 30 | Max. Candidate Nodes pro Template | +| `max_matches_per_template` | 2 | Max. unterschiedliche Zuordnungen pro Template | +| `max_assignments_collected` | 1000 | Schleifenschutz beim Backtracking | --- diff --git a/docs/12_Heading_Block_Link_Recommendation.md b/docs/12_Heading_Block_Link_Recommendation.md index 778fd55..b467d27 100644 --- a/docs/12_Heading_Block_Link_Recommendation.md +++ b/docs/12_Heading_Block_Link_Recommendation.md @@ -42,16 +42,13 @@ Bei einer Zeile `## Überschrift ^Block` in der Zieldatei: **Fazit:** Der Interview-Assistent erzeugt `[[Note#Überschrift]]`. In Obsidian springt dieser Link **in die Note, aber nicht auf die Überschrift** (siehe Abschnitt 1). Obsidian-typisches Springen auf die Überschrift (inkl. Highlight des Abschnitts) liefert nur `[[Titel#Überschrift Block]]` (UI-erzeugt, ohne `^`). -### 2.3 Inspect Chains & Chain Workbench +### 2.3 Inspect Chains & Chain Workbench (Stand: Jan 2026) -- **chainInspector** vergleicht überall **strikt:** - `edge.target.heading === context.heading` und - `edge.source.sectionHeading === context.heading`. -- **dangling_target_heading:** Prüfung gegen `metadataCache.getFileCache(...).headings` mit - `h.heading === targetHeading` (ebenfalls exakt). -- **Chain Workbench** nutzt dieselben Konzepte (context/assignment mit `heading`); keine Normalisierung. - -**Folge:** Sobald eine Seite `"Überschrift ^block"` und ein Link `[[Titel#Überschrift]]` vorkommt (oder umgekehrt), stimmen die Strings nicht überein → kein Match, ggf. falscher `dangling_target_heading`. +- **headingsMatch / normalizeHeadingForMatch** (`src/unresolvedLink/linkHelpers.ts`): + - **Mit ^Block-ID:** `"Überschrift ^Block"` → `"Überschrift"` (Block-Suffix entfernt) + - **Ohne ^:** Rückgabe unverändert (Idempotenz für bereits normalisierte Formen) +- **Matchen:** `"Überschrift ^Block"` und `"Überschrift"` gelten als dieselbe Sektion. +- **Nicht unterstützt:** `"Überschrift Block"` (Obsidian-UI, ohne ^) wird **nicht** zu `"Überschrift"` normalisiert – für zuverlässiges Matching Links mit `^` verwenden. --- @@ -75,30 +72,24 @@ Um nicht zu viele Änderungen gleichzeitig zu öffnen: - **Nur eine Baustelle:** **Normalisierung in Inspect Chains & Chain Workbench** (zentrale Normalisierungsfunktion + alle Heading-Vergleiche und `dangling_target_heading` auf normalisierte Form umstellen). - **Interview-Assistent vorerst unverändert:** Weiter `[[Note#Überschrift]]` ausgeben. Eine spätere, **optionale** Anpassung (z. B. Ausgabe `[[Note#Überschrift Block]]` im Obsidian-Stil, damit der Klick auf die Überschrift springt) kann separat erfolgen. -### 4.2 Normalisierungsregel (für Vergleiche) +### 4.2 Umsetzte Normalisierungsregel (Stand: Jan 2026) -Drei Schreibweisen sollen als **dieselbe Sektion** gelten: +**Implementiert in `normalizeHeadingForMatch` (linkHelpers.ts):** -- `Überschrift` (Interview, reiner Text) -- `Überschrift ^Block` (Quelldokument / sectionParser) -- `Überschrift Block` (Obsidian-UI-Link, ohne `^`) +1. **Mit ^Block-ID:** Block-Suffix entfernen: `\s*\^[a-zA-Z0-9_-]+\s*$` → z. B. `"Überschrift ^Block"` → `"Überschrift"`, `"Lars ist gut ^PersLars"` → `"Lars ist gut"`. +2. **Ohne ^:** Rückgabe unverändert (Idempotenz). Multi-Wort-Überschriften wie `"Lars ist gut"` werden nicht gekürzt. -**Kanonische Form für Vergleiche:** +**Matchen:** `"Überschrift ^Block"` und `"Überschrift"` gelten als dieselbe Sektion. `"Lars ist gut ^PersLars"` und `"Lars ist gut"` matchen. -1. Am Ende **Block-Suffix mit Caret** entfernen: `\s+\^[a-zA-Z0-9_-]+$` → z. B. `"Überschrift ^Block"` → `"Überschrift"`. -2. Danach **ein einzelnes Wort am Ende** (nur Buchstaben, Zahlen, Bindestrich, Unterstrich) optional entfernen: `\s+[a-zA-Z0-9_-]+$` → z. B. `"Überschrift Block"` → `"Überschrift"`. +**Nicht unterstützt:** `"Überschrift Block"` (Obsidian-UI, ohne ^) wird **nicht** automatisch zu `"Überschrift"` normalisiert – zur Vermeidung von Fehlmatches bei kanonischen Multi-Wort-Überschriften. **Empfehlung:** Für zuverlässiges Matching Links mit `^` verwenden: `[[Note#Überschrift ^Block]]`. -So werden alle drei Varianten auf `"Überschrift"` abgebildet. **Randfall:** Eine Überschrift, die wirklich „X Y“ heißt (ohne Block-ID), würde ebenfalls zu „X“ normalisiert und könnte mit „X“ matchen; in der Praxis selten. Die Funktion **nur** für Vergleiche/Prüfungen nutzen, nicht für Anzeige oder gespeicherte Links. +### 4.3 Umsetzte Maßnahmen -### 4.3 Konkrete Maßnahmen (nur diese eine Baustelle) +1. **Zentrale Normalisierung:** `normalizeHeadingForMatch` und `headingsMatch` in `src/unresolvedLink/linkHelpers.ts` – nur ^Block-Suffix entfernen, sonst Idempotenz. -1. **Eine zentrale Normalisierungsfunktion** (z. B. in `linkHelpers` oder eigenem Modul): Eingabe = Überschrift-String, Ausgabe = kanonische Form wie oben. +2. **Inspect Chains & Chain Workbench:** Nutzen `headingsMatch` für alle Heading-Vergleiche. -2. **Inspect Chains (chainInspector):** Alle Vergleiche mit `heading` / `sectionHeading` auf die **normalisierte** Form umstellen; bei **dangling_target_heading** `targetHeading` und Cache-Headings vor dem Vergleich normalisieren. - -3. **Chain Workbench:** Dieselbe Normalisierung überall, wo Headings verglichen werden. - -4. **graphIndex / Interview:** Keine Änderung in dieser Baustelle. +3. **Interview-Assistent:** Unverändert – erzeugt weiterhin `[[Note#Überschrift]]`. ### 4.4 Optional später (separate Baustelle) @@ -106,8 +97,8 @@ So werden alle drei Varianten auf `"Überschrift"` abgebildet. **Randfall:** Ein --- -## 5. Kurzfassung +## 5. Kurzfassung (Stand: Jan 2026) -- **Obsidian (beobachtet):** Manueller Link auf Überschrift mit Block-ID → `[[Titel#Überschrift Block]]` (ohne `^`). Klick springt auf Überschrift und highlighted den Abschnitt. `[[Titel#Überschrift]]` springt nur in die Note, nicht auf die Überschrift. `[[Titel#^Block]]` highlighted nur die Überschrift. -- **Eine Baustelle:** Nur **Normalisierung in Inspect Chains & Chain Workbench** umsetzen (zentrale Funktion: Block-Suffix mit `^` und ggf. ein trailinges Wort entfernen; alle Heading-Vergleiche und `dangling_target_heading` auf diese Form umstellen). Interview-Assistent und graphIndex in dieser Runde **nicht** anfassen. -- **Optional später:** Interview-Assistent so anpassen, dass er z. B. `[[Note#Überschrift Block]]` erzeugt (Obsidian-Stil), damit der Klick auf den Link auf die Überschrift springt. +- **Plugin-Normalisierung:** `normalizeHeadingForMatch` entfernt nur `^BlockID`; bei Überschriften ohne `^` wird unverändert zurückgegeben (Idempotenz). Dadurch matchen `"Lars ist gut ^PersLars"` und `"Lars ist gut"` korrekt. +- **Empfehlung:** Für zuverlässiges Matching Links mit `^` verwenden: `[[Note#Überschrift ^Block]]`. Obsidian-Form `[[Titel#Überschrift Block]]` (ohne `^`) wird nicht automatisch normalisiert. +- **Obsidian (beobachtet):** Manueller Link → `[[Titel#Überschrift Block]]` (ohne `^`). Klick springt auf Überschrift. `[[Titel#^Block]]` highlighted nur die Überschrift. diff --git a/docs/13_Erfassung_Causal_Ketten.md b/docs/13_Erfassung_Causal_Ketten.md new file mode 100644 index 0000000..ff36144 --- /dev/null +++ b/docs/13_Erfassung_Causal_Ketten.md @@ -0,0 +1,309 @@ +# Handbuch: Erfassung & Causal-Ketten in Obsidian + +> **Zielgruppe:** Du beim täglichen Erfassen (auch unterwegs) +> **Plugin:** Mindnet Causal Assistant +> **Stand:** August 2026 +> **Zweck:** Elemente so anlegen und vernetzen, dass kausale Ketten erkennbar, prüfbar und schließbar sind. + +--- + +## 1. Was du erzeugst + +Mindnet speichert Wissen als **Markdown im Vault**. Das Plugin hilft, daraus einen **kausalen Graphen** zu machen. + +| Baustein | Bedeutung | Beispiel | +|----------|-----------|----------| +| **Note** | Eine Entität (Datei) mit Typ und `id` | Experience „Geburt der Kinder“ | +| **Section** | Abschnitt unter einer Überschrift; optional mit Typ | `## Learning ^learning` + `[!section] insight` | +| **Block-ID** | Anker hinter der Überschrift (`^…`) | `^learning`, `^next` | +| **Edge** | Gerichtete Beziehung mit Typ | `caused_by`, `guides`, `resulted_in` | +| **Kette** | Mehrere Notes/Sections + Edges in einem Muster | Experience → Insight → Decision | + +**Merksatz:** Text allein reicht nicht. Ketten entstehen, wenn du **Rollen** (Typen) und **Kanten** (Edges) setzt. + +### Urlaub / Weiterarbeit ohne Massen-Relink + +Neue Notes so anlegen, dass sie später **nicht** umgeschrieben werden müssen. Alte Notes nicht anfassen, nur neue sauber schreiben. + +| Immer so | Nie so (später teuer) | +|----------|------------------------| +| Überschrift mit Block-ID: `## Learning ^learning` | Überschrift ohne `^…` | +| Section-Typ: `> [!section] insight` | Nur Fließtext ohne Typ | +| Intra-Note: `[[#^learning]]` | `[[#Learning]]` ohne `^` | +| Cross-Note: `[[Note#Überschrift ^block]]` | `[[Note#Überschrift]]` ohne Block-ID | +| Kanten als `[!edge]` mit kanonischem Typ (`guides`, `caused_by`, `derived_from`) | Nur lose Wikilinks oder Alias-Typen wie `derives` | + +**Create note from profile** und **Chain Workbench** schreiben diese Form jetzt selbst. Manuelle Obsidian-UI-Links (`[[Note#Überschrift Block]]` ohne `^`) vermeiden. + +```mermaid +flowchart LR + E[Experience / Situation] -->|causal / influences| I[Insight / Learning] + I -->|guides / foundation_for| D[Decision / nächster Schritt] + D -->|causal| E2[neue Experience / Feedback] +``` + +--- + +## 2. Die wichtigsten Commands + +Command Palette: `Ctrl+P` (macOS: `Cmd+P`). + +| Wann | Command | +|------|---------| +| Neu anfangen | **Mindnet: Create note from profile** | +| Links zu Edges machen | **Mindnet: Build semantic mapping blocks (by section)** | +| Edge-Typ wählen/ändern | **Mindnet: Edge-Type ändern** | +| Note prüfen | **Mindnet: Validate current note** | +| Ketten verstehen | **Mindnet: Inspect Chains (Current Section)** | +| Lücken schließen | **Mindnet: Chain Workbench (Current Section)** | +| Vault-weit Lücken finden | **Mindnet: Scan Vault for Chain Gaps** | +| Findings beheben | **Mindnet: Fix Findings (Current Section)** | + +Einstellungen: **Mindnet: Einstellungen öffnen** (oder Plugin-Name in der linken Settings-Leiste). + +--- + +## 3. Alltags-Workflow: von der Idee zur Kette + +### Schritt A — Element anlegen + +1. **Mindnet: Create note from profile** +2. Profil wählen, z. B.: + - **Experience – Basis** → Erlebnis / Situation + - **Insight – Basis** → Erkenntnis / Learning + - weitere Profile je nach Vault-Config +3. Titel und Ordner setzen → Note öffnet sich +4. Interview-Wizard ausfüllen → **Review → Apply & Finish** + +Ergebnis typischerweise: + +- Frontmatter mit `id`, `title`, `type`, … +- Sections mit Überschriften +- oft schon `[!section] …` und `^block-id` (WP-26) + +> **Tipp:** **Mindnet: Create note from profile** startet den Wizard immer. Für eine schon offene Note: **Mindnet: Interview für aktuelle Note starten**. + +### Schritt B — Verbindungen setzen (während oder nach dem Schreiben) + +**Variante 1 – im Text verlinken, dann mappen** + +1. Im Fließtext oder am Section-Ende Wikilinks setzen, z. B. `[[Meine Einsicht]]` +2. Cursor in die Section +3. **Mindnet: Edge-Type ändern** → passenden Typ wählen + oder zuerst Links setzen und danach **Build semantic mapping blocks** +4. Mapping-Block prüfen: + +```markdown +> [!abstract] 🕸️ Semantic Mapping +> +> > [!edge] caused_by +> > [[Früheres Erlebnis]] +> +> > [!edge] guides +> > [[Nächster Schritt ^next]] +``` + +**Variante 2 – fehlende Note aus einem Link erzeugen** + +1. `[[Noch nicht existierende Note]]` schreiben +2. Link anklicken (Reading View: Klick; Editor oft `Ctrl`+Klick) +3. Profil wählen → Note (+ optional Wizard) + +**Variante 3 – Intra-Note (innerhalb einer Datei)** + +Sections derselben Note verbinden, bevorzugt mit Block-ID: + +```markdown +## Situation ^sit +> [!section] experience + +… + +## Learning ^learning +> [!section] insight + +> [!edge] derived_from +> [[#^sit]] + +## Nächster Schritt ^next +> [!section] decision + +> [!edge] guides +> [[#^learning]] +``` + +**Link-Empfehlung für zuverlässiges Matching:** + +| Form | Nutzen | +|------|--------| +| `[[Note#Überschrift ^block]]` oder `[[#^block]]` | zuverlässig für Chain Inspector / Workbench | +| `[[Note#Überschrift]]` | oft vom Interview erzeugt; springt in Obsidian nicht immer zur Überschrift | +| Obsidian-UI ohne `^` (`…#Überschrift Block`) | gut zum Navigieren, Matching kann schwächer sein | + +### Schritt C — Kette prüfen + +1. Cursor in die relevante Section stellen +2. **Mindnet: Chain Workbench (Current Section)** öffnen +3. Matches und Status lesen (siehe Abschnitt 5) +4. Todos abarbeiten: fehlende Edges, fehlende Notes, falsche Typen +5. Optional: **Inspect Chains** für den textuellen Report (Console / Report) + +### Schritt D — Qualität sichern + +1. **Validate current note** → keine Errors +2. Bei Bedarf **Fix Findings** +3. Speichern — Obsidian Sync übernimmt den Vault + +--- + +## 4. Welche Kette willst du erzählen? + +Das Plugin matcht gegen **Chain Templates** (Datei `chain_templates.yaml`). Du musst sie nicht auswendig kennen — aber die Kernmuster helfen beim Erfassen: + +### 4.1 Trigger → Transformation → Outcome + +**Frage:** Was hat mich verändert, und was folgte daraus? + +| Slot | Typische Typen | Deine Rolle beim Erfassen | +|------|----------------|---------------------------| +| trigger | experience, event, obstacle, risk, state | Auslöser / Situation | +| transformation | insight, belief, value, principle, … | innere Veränderung | +| outcome | decision, project, habit, goal | Folge / Handlung | + +Edges zwischen den Slots: eher **causal**, **influences**, **provenance** (`foundation_for` u. ä.). + +### 4.2 Learning Loop + +**Frage:** Erlebnis → Lernen → Verhalten → neues Erlebnis? + +| Slot | Typische Typen | +|------|----------------| +| experience | experience, event, situation | +| learning | insight, principle, value, … | +| behavior | habit, decision, task | +| feedback | experience, journal, event, state | + +Viele Experience-Interviews legen genau diese Abschnitte nahe (Situation → Learning → Nächster Schritt). + +### 4.3 Decision Logic + +**Frage:** Was treibt die Entscheidung, was begrenzt sie, was entsteht? + +driver + constraint → decision → outcome + +### 4.4 Weitere Muster (kurz) + +- **constraint_to_adaptation** — Problem → Anpassung → Stabilisierung +- **person_influence** — Person → inneres Modell → Entscheidung/Outcome +- **state_trigger_response** — Zustand → Auslöser → Reaktion → neuer Zustand + +**Praxisregel:** Beim Schreiben eine dieser Geschichten im Kopf behalten und die fehlenden Glieder als Notes/Sections + Edges nachziehen — nicht „irgendwelche Links“. + +--- + +## 5. Workbench lesen: Status & Todos + +| Status | Bedeutung | Typische Aktion | +|--------|-----------|-----------------| +| **complete** | Slots und geforderte Links passen | fertig / nur noch Feinschliff | +| **near_complete** | fast vollständig | 1–2 Todos (Edge oder Slot) | +| **partial** | mehrere Lücken | gezielt fehlende Glieder anlegen | +| **weak** | schwache/unsichere Zuordnung | Typen und Edges prüfen, Template evtl. falsch | + +Häufige Todos: + +- **missing_slot** — fehlendes Glied der Kette (Note oder Section anlegen) +- **missing_link** — Verbindung zwischen vorhandenen Gliedern fehlt → Edge einfügen +- **dangling_target** — Link zeigt ins Leere → Note/Heading erzeugen oder Link retargeten + +**Arbeitsweise:** Immer zuerst **near_complete** schließen — dort ist der Erkenntnisgewinn pro Klick am höchsten. Vault-weit: **Scan Vault for Chain Gaps**. + +--- + +## 6. Section Types & Effective Type + +Innerhalb einer Note können Abschnitte **eigene Typen** haben: + +```markdown +--- +type: experience +--- + +## Learning ^learning +> [!section] insight + +Was ich daraus lerne … +``` + +- Ohne `[!section]` gilt der **Note-Type** (`experience`). +- Mit `[!section] insight` zählt die Section als **insight** fürs Template-Matching (**effective type**). +- So kann eine Experience-Note intern schon die Learning-Loop abbilden, ohne sofort drei Dateien anzulegen. + +**Wann eigene Datei, wann Section?** + +| Situation | Empfehlung | +|-----------|------------| +| Ein Erlebnis mit Situation / Reaktion / Learning / nächstem Schritt | eine Note, Sections + Intra-Note-Edges | +| Learning soll später vielen Experiences gehören | eigene Insight-Note + Cross-Note-Edge | +| Entscheidung betrifft mehrere Projekte | eigene Decision-Note | + +--- + +## 7. Mini-Checkliste pro Erfassungs-Session + +Vor dem Schließen der Note: + +- [ ] Frontmatter hat `id` und sinnvollen `type` +- [ ] Wichtige Abschnitte haben Überschrift (+ idealerweise `^block-id`) +- [ ] Wo nötig: `[!section] …` gesetzt +- [ ] Beziehungen liegen als `[!edge]` (Mapping-Block) vor — nicht nur lose Wikilinks +- [ ] Mindestens eine erkennbare Ketten-Idee (z. B. Learning Loop oder Trigger→Outcome) +- [ ] **Validate** ohne Errors +- [ ] Bei Ambition: Workbench zeigt **near_complete** oder **complete** für das Haupt-Template + +--- + +## 8. Typischer Tagesablauf (Urlaub / unterwegs) + +1. **Erfassen** — 1–3 Experiences oder Insights über Profile + Interview +2. **Verknüpfen** — Edges zu bestehenden Notes/Sections (Mapping / Edge-Type) +3. **Ketten schließen** — Workbench auf der wichtigsten Section, 5–15 Minuten Todos +4. **Optional Scan** — einmal am Tag/Woche Vault Gap Scan, nahe Lücken priorisieren + +Obsidian Sync speichert den Vault zentral. Plugin-Updates (`main.js`) synct nur, wenn Community-Plugins in Sync aktiviert sind — sonst nach Build manuell in `.obsidian/plugins/mindnet-causal-assistant/` legen. + +--- + +## 9. Häufige Stolpersteine + +| Problem | Was tun | +|---------|---------| +| Keine Profile beim Create | Config-Pfad `_system/dictionary/interview_config.yaml` / Sync prüfen | +| Workbench „Chain Roles/Templates nicht geladen“ | Pfade in Plugin-Settings prüfen | +| Kette wird nicht erkannt | Edge-Typ zu generisch/falsch; Section-Type fehlt; Link ohne treffendes Heading/`^block` | +| Link springt nicht zur Section | Form mit Block-ID nutzen (`[[#^id]]` oder Heading+`^block`) | +| Mapping an falscher Stelle | Cursor in die richtige Section; Mapping erneut bauen | + +--- + +## 10. Kurz-Rezept: „Ich will eine Learning-Loop sauber machen“ + +1. Experience-Note aus Profil **Experience – Basis** +2. Interview: Situation, Reaktion, Learning, Nächster Schritt ausfüllen +3. Prüfen: Sections haben Block-IDs; Learning = `[!section] insight` (falls vorgesehen) +4. Edges setzen, z. B. Learning ← Situation, Nächster Schritt ← Learning (`guides` / passende Rolle) +5. Cursor auf Learning-Section → **Chain Workbench** → Template `loop_learning` / verwandte Matches +6. Todos bis **near_complete** oder **complete** +7. Validate → speichern + +--- + +## Siehe auch + +- [01_Benutzerhandbuch](01_Benutzerhandbuch.md) — Commands & Settings im Detail +- [07_Event_Handler_Commands](07_Event_Handler_Commands.md) — vollständige Command-Referenz +- [12_Heading_Block_Link_Recommendation](12_Heading_Block_Link_Recommendation.md) — Link-Formen & Matching +- [Interview_Config_Guide](Interview_Config_Guide.md) — Profile anpassen (Admin) +- [02_concepts/03_chain_identification_and_matching](02_concepts/03_chain_identification_and_matching.md) — Matching-Technik + +**Tipp:** Diese Datei nach `_system/docs/` (oder ähnlich) im Vault kopieren, dann liegt sie über Obsidian Sync auf allen Geräten. diff --git a/docs/by_role/README.md b/docs/by_role/README.md new file mode 100644 index 0000000..b7b2c80 --- /dev/null +++ b/docs/by_role/README.md @@ -0,0 +1,81 @@ +# Dokumentation nach Rolle + +> **Zielgruppe:** Alle +> **Einstieg:** Wählen Sie Ihre Rolle und folgen Sie den verlinkten Dokumenten + +--- + +## Nutzer + +**Primäre Dokumente:** + +- [13_Erfassung_Causal_Ketten](../13_Erfassung_Causal_Ketten.md) – **Alltag:** Erfassen, verlinken, Causal-Ketten prüfen/schließen +- [01_Benutzerhandbuch](../01_Benutzerhandbuch.md) – Installation, Commands, Workflows, Troubleshooting +- [07_Event_Handler_Commands](../07_Event_Handler_Commands.md) – alle Commands und Event-Handler + +**Zusätzlich:** + +- [05_Installation_Deployment](../05_Installation_Deployment.md) – Installation +- [12_Heading_Block_Link_Recommendation](../12_Heading_Block_Link_Recommendation.md) – Überschriften-Links (Obsidian) + +--- + +## Administrator + +**Primäre Dokumente:** + +- [02_Administratorhandbuch](../02_Administratorhandbuch.md) – Plugin-Konfiguration, Pfade, Wartung +- [06_Konfigurationsdateien_Referenz](../06_Konfigurationsdateien_Referenz.md) – alle Config-Dateien, Gewichtung, Analysis Policies +- [Interview_Config_Guide](../Interview_Config_Guide.md) – interview_config.yaml + +**Zusätzlich:** + +- [05_Installation_Deployment](../05_Installation_Deployment.md) – Deployment + +--- + +## Entwickler + +**Primäre Dokumente:** + +- [03_Entwicklerhandbuch](../03_Entwicklerhandbuch.md) – Projekt-Struktur, Build, Testing +- [04_Architektur](../04_Architektur.md) – System-Design +- [modules/README](../modules/README.md) – Modul-Übersicht + +**Zusätzlich:** + +- [02_concepts/03_chain_identification_and_matching](../02_concepts/03_chain_identification_and_matching.md) – Template Matching, Scoring +- [06_Konfigurationsdateien_Referenz](../06_Konfigurationsdateien_Referenz.md) – Config-Formate + +--- + +## Architekt + +**Primäre Dokumente:** + +- [04_Architektur](../04_Architektur.md) – Komponenten, Datenfluss +- [02_concepts/03_chain_identification_and_matching](../02_concepts/03_chain_identification_and_matching.md) – Chain-Identifikation, Scoring +- [02_causal_chain_retrieving](../02_causal_chain_retrieving.md) – Kausale Ketten + +**Zusätzlich:** + +- [modules/](../modules/) – Modul-Details + +--- + +## Projektleitung + +**Primäre Dokumente:** + +- [04_Architektur](../04_Architektur.md) – Überblick +- [README](../../README.md) – Projekt-README +- [STATUS_DOD](../../STATUS_DOD.md) – Definition of Done + +--- + +## Systemadmin + +**Primäre Dokumente:** + +- [05_Installation_Deployment](../05_Installation_Deployment.md) – Installation, Deployment +- [02_Administratorhandbuch](../02_Administratorhandbuch.md) – Konfiguration diff --git a/docs/modules/README.md b/docs/modules/README.md new file mode 100644 index 0000000..ace8883 --- /dev/null +++ b/docs/modules/README.md @@ -0,0 +1,58 @@ +# Module – technische Dokumentation + +> **Zielgruppe:** Entwickler, Architekten +> **Übersicht:** Modul-basierte Dokumentation des Mindnet Causal Assistant Plugins + +--- + +## Modul-Übersicht + +| Modul | Pfad in `src/` | Kurzbeschreibung | +|-------|----------------|------------------| +| [Analysis](analysis.md) | `analysis/` | Chain Inspector, Template Matching, Scoring, Findings | +| [Dictionary](dictionary.md) | `dictionary/` | Config-Loader, Chain Roles, Chain Templates | +| [Interview](interview.md) | `interview/` | Wizard, Loop State, Renderer, Section Key Resolver | +| [Mapping](mapping.md) | `mapping/` | Semantic Mapping, Edge Type Selector | +| [Parser](parser.md) | `parser/` | Edges aus Callouts, Frontmatter, Links | +| [Graph](graph.md) | `graph/` | Graph Builder, Traversal, Resolution | +| [Vocabulary](vocabulary.md) | `vocab/` | Edge Vocabulary, Normalisierung | +| [Unresolved Link](unresolvedLink.md) | `unresolvedLink/` | Link-Handler, Adoption, Heading-Normalisierung | +| [Workbench](workbench.md) | `workbench/` | Chain Workbench, Todo-Generator, Status | +| [Lint](lint.md) | `lint/` | Lint Engine, Rules | +| [UI](ui.md) | `ui/` | Modals, Settings Tab, Entity Picker | + +--- + +## Abhängigkeiten (vereinfacht) + +``` +main.ts + ├── analysis ← dictionary, graph, parser + ├── commands ← analysis, graph, mapping, ui, ... + ├── dictionary ← vault + ├── graph ← parser + ├── interview ← dictionary, parser + ├── mapping ← parser, schema + ├── parser + ├── vocab ← vault + ├── lint ← vocab, parser + ├── unresolvedLink ← interview, entityPicker + ├── workbench ← analysis, interview, mapping + └── ui +``` + +--- + +## Weitere Module + +- **schema/** – Graph Schema Loader +- **entityPicker/** – Note Index, Folder Tree, Filters +- **export/** – Graph Export +- **utils/** – Logger + +--- + +## Siehe auch + +- [04_Architektur](../04_Architektur.md) – System-Design +- [02_concepts/03_chain_identification_and_matching](../02_concepts/03_chain_identification_and_matching.md) – Template Matching, Scoring diff --git a/docs/modules/analysis.md b/docs/modules/analysis.md new file mode 100644 index 0000000..7e7e272 --- /dev/null +++ b/docs/modules/analysis.md @@ -0,0 +1,112 @@ +# Modul: Analysis + +> **Pfad:** `src/analysis/` +> **Zielgruppe:** Entwickler, Architekten + +--- + +## Übersicht + +Das Analysis-Modul enthält die Chain Inspector-Logik, Template Matching, Scoring und Findings-Erzeugung. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `chainInspector.ts` | Haupt-Analyse-Engine | +| `templateMatching.ts` | Template Matching, Scoring, Backtracking | +| `graphIndex.ts` | Graph-Indexierung, Edge-Erfassung | +| `sectionContext.ts` | Section-Context-Handling | +| `severityPolicy.ts` | Severity-Policy für Findings | + +--- + +## Scoring-Logik (Template Matching) + +### scoreAssignment + +Die Funktion `scoreAssignment` bewertet jede Slot-Zuordnung: + +| Komponente | Punkte | +|------------|--------| +| Jeder zugewiesene Slot | +2 | +| Intra-Note-Bonus (alle Slots in derselben Note) | +5 | +| Erfüllter Link (mit erlaubter Edge-Role) | +10 | +| Fehlender Link (wenn `required_links: true`) | -5 | +| Falsche Role (wenn `required_links: true`) | -5 | + +### Link-Validierung + +- **findEdgeBetween:** Sucht Edge zwischen zwei Nodes (file:heading) +- **headingsMatch:** Vergleicht Überschriften (normalisiert über `normalizeHeadingForMatch`) +- **Role-Mapping:** Edge-Typ → Role via `chain_roles.yaml` + +### Profile-Auflösung + +1. **Settings:** `templateMatchingProfile` (`discovery` | `decisioning`) +2. **Template:** `template.matching.required_links` +3. **Defaults:** `defaults.matching.required_links` + +--- + +## Template-Matching-Profile + +| Profil | required_links | min_slots_filled_for_gap_findings | min_score_for_gap_findings | +|--------|----------------|-----------------------------------|----------------------------| +| `discovery` | false | 2 | 8 | +| `decisioning` | true | 3 | 18 | + +Profile werden in `chain_templates.yaml` unter `defaults.profiles` definiert. + +--- + +## Confidence-Berechnung + +| Confidence | Bedingung | +|------------|-----------| +| `confirmed` | slotsComplete AND linksComplete AND mind. eine causal-ish Role | +| `plausible` | slotsComplete, aber (nicht linksComplete ODER keine causal-ish Role) | +| `weak` | nicht slotsComplete | + +**causal-ish Roles:** `["causal", "influences", "enables_constraints"]` (konfigurierbar in `chain_templates.yaml`) + +--- + +## Analysis Policies + +Datei: `analysis_policies.yaml` (Pfad via Settings `analysisPoliciesPath`) + +```yaml +version: 1 +profiles: + discovery: + severities: + missing_link_constraints: info + weak_chain_roles: info + unmapped_edge_types: info + missing_slot_*: info + decisioning: + severities: + missing_link_constraints: warn + weak_chain_roles: info + unmapped_edge_types: warn + missing_slot_*: warn +``` + +--- + +## Abhängigkeiten + +- **Dictionary:** Chain Roles, Chain Templates +- **Graph:** Graph Index, Traversal +- **Parser:** Edge-Extraktion +- **Unresolved Link:** `headingsMatch`, `normalizeHeadingForMatch` + +--- + +## Siehe auch + +- [02_concepts/03_chain_identification_and_matching](../02_concepts/03_chain_identification_and_matching.md) +- [06_Konfigurationsdateien_Referenz](../06_Konfigurationsdateien_Referenz.md) – chain_templates, chain_roles, analysis_policies diff --git a/docs/modules/dictionary.md b/docs/modules/dictionary.md new file mode 100644 index 0000000..1090759 --- /dev/null +++ b/docs/modules/dictionary.md @@ -0,0 +1,67 @@ +# Modul: Dictionary + +> **Pfad:** `src/dictionary/` +> **Zielgruppe:** Entwickler, Administratoren + +--- + +## Übersicht + +Das Dictionary-Modul lädt und parst alle Konfigurationsdateien (YAML, Markdown) und stellt sie den anderen Modulen zur Verfügung. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `DictionaryLoader.ts` | Generischer Loader mit Last-Known-Good | +| `ChainRolesLoader.ts` | Lädt chain_roles.yaml | +| `ChainTemplatesLoader.ts` | Lädt chain_templates.yaml | +| `ConfigPathManager.ts` | Pfad-Auflösung für Config-Dateien | +| `parseChainRoles.ts` | Parser für chain_roles | +| `parseChainTemplates.ts` | Parser für chain_templates | +| `types.ts` | TypeScript-Typen | + +--- + +## Geladene Config-Dateien + +| Datei | Pfad-Setting | Inhalt | +|-------|-------------|--------| +| edge_vocabulary | edgeVocabularyPath | Kanonische Edge-Typen, Aliases | +| graph_schema | graphSchemaPath | Empfehlungen für Edge-Typen | +| interview_config | interviewConfigPath | Profile, Steps, Loops | +| chain_roles | chainRolesPath | Edge-Typ → Role Mapping | +| chain_templates | chainTemplatesPath | Templates, Slots, Links, Profile | +| analysis_policies | analysisPoliciesPath | Severity-Policies pro Profil | + +--- + +## Live-Reload + +- **Debounced:** 200ms bei Dateiänderung +- **Last-Known-Good:** Bei Parse-Fehlern wird letzte gültige Config verwendet +- **Vault Modify Event:** Automatisches Neuladen bei Änderung im Vault + +--- + +## Chain Templates – Struktur + +- **defaults.matching:** required_links, distinct_nodes, max_candidate_nodes, max_matches_per_template, max_assignments_collected +- **defaults.profiles:** discovery, decisioning (min_slots_filled_for_gap_findings, min_score_for_gap_findings) +- **templates:** name, slots, links, matching (optional) + +--- + +## Chain Roles – Struktur + +- **roles:** Mapping Role-Name → edge_types[] +- **Standard-Rollen:** causal, influences, enables_constraints, provenance, epistemic, normative, structural, temporal + +--- + +## Siehe auch + +- [06_Konfigurationsdateien_Referenz](../06_Konfigurationsdateien_Referenz.md) +- [02_Administratorhandbuch](../02_Administratorhandbuch.md) diff --git a/docs/modules/graph.md b/docs/modules/graph.md new file mode 100644 index 0000000..1997680 --- /dev/null +++ b/docs/modules/graph.md @@ -0,0 +1,28 @@ +# Modul: Graph + +> **Pfad:** `src/graph/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Graph Building, Traversal, Target Resolution, Report Rendering. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `GraphBuilder.ts` | Baut Graph aus Vault | +| `GraphIndex.ts` | Indexierung für Traversal | +| `traverse.ts` | BFS/DFS Traversal | +| `resolveTarget.ts` | Link → File Auflösung | +| `renderChainReport.ts` | Report-Rendering | + +--- + +## Siehe auch + +- [analysis/graphIndex](../analysis.md) – Graph Index für Chain Inspector diff --git a/docs/modules/interview.md b/docs/modules/interview.md new file mode 100644 index 0000000..951e5ae --- /dev/null +++ b/docs/modules/interview.md @@ -0,0 +1,47 @@ +# Modul: Interview + +> **Pfad:** `src/interview/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Interview-Wizard zur strukturierten Erfassung von Inhalten, Section-basierte Ausgabe, Frontmatter-Generierung. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `InterviewConfigLoader.ts` | Lädt interview_config.yaml | +| `parseInterviewConfig.ts` | YAML → InterviewConfig Parser | +| `wizardState.ts` | Wizard State (Steps, Loops) | +| `loopState.ts` | Nested Loops | +| `renderer.ts` | Output-Rendering (Section-basiert) | +| `writeFrontmatter.ts` | Frontmatter-Generierung | +| `sectionKeyResolver.ts` | Section-Key-Auflösung | +| `extractTargetFromAnchor.ts` | Target-Extraktion aus Anchors | +| `targetTypeResolver.ts` | Note-Type- und Section-Type-Auflösung | +| `slugify.ts` | Slug-Generierung für Dateinamen | + +--- + +## Step-Typen + +- `capture_frontmatter`, `capture_text`, `capture_text_line` +- `loop`, `review`, `instruction` +- `llm_dialog`, `entity_picker` (experimentell) + +--- + +## WP-26 Features + +- `section_type`, `block_id`, `generate_block_id`, `references` + +--- + +## Siehe auch + +- [Interview_Config_Guide](../Interview_Config_Guide.md) diff --git a/docs/modules/lint.md b/docs/modules/lint.md new file mode 100644 index 0000000..2bed832 --- /dev/null +++ b/docs/modules/lint.md @@ -0,0 +1,28 @@ +# Modul: Lint + +> **Pfad:** `src/lint/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Linting Engine für Note-Validierung, regelbasierte Prüfungen, Findings. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `LintEngine.ts` | Haupt-Engine | +| `rules/` | Einzelne Regeln | +| `rule_hub_has_causality.ts` | Kausale Edges prüfen | +| `rule_missing_target.ts` | Fehlende Targets | +| `rule_unknown_edge.ts` | Unbekannte Edge-Types | + +--- + +## Command + +`mindnet-validate-current-note` – validiert aktuelle Note diff --git a/docs/modules/mapping.md b/docs/modules/mapping.md new file mode 100644 index 0000000..87b7f0d --- /dev/null +++ b/docs/modules/mapping.md @@ -0,0 +1,32 @@ +# Modul: Mapping + +> **Pfad:** `src/mapping/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Semantic Mapping – Section-basierte Gruppierung von Links nach Edge-Typen, Edge-Type-Assignment. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `semanticMappingBuilder.ts` | Baut Mapping-Blöcke | +| `mappingExtractor.ts` | Extrahiert existierende Mappings | +| `mappingBuilder.ts` | Erstellt Mapping-Struktur | +| `edgeTypeSelector.ts` | Edge-Type-Auswahl (empfohlen via graph_schema) | +| `updateMappingBlocks.ts` | Aktualisiert Note | +| `sectionParser.ts` | Section-Parsing | +| `graphSchema.ts` | Schema-Lookup für Empfehlungen | +| `folderHelpers.ts` | Ordner-Hilfsfunktionen | +| `worklistBuilder.ts` | Worklist für Pending Assignments | + +--- + +## Siehe auch + +- [06_Konfigurationsdateien_Referenz](../06_Konfigurationsdateien_Referenz.md) – graph_schema diff --git a/docs/modules/parser.md b/docs/modules/parser.md new file mode 100644 index 0000000..9278ee2 --- /dev/null +++ b/docs/modules/parser.md @@ -0,0 +1,37 @@ +# Modul: Parser + +> **Pfad:** `src/parser/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Markdown-Parsing: Edges aus Callouts, Frontmatter, Links. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `parseEdgesFromCallouts.ts` | Parst `>> [!edge] type` Callouts, Targets | +| `parseFrontmatter.ts` | Frontmatter-Referenz | +| `parseRelLinks.ts` | Relative Links in Sections | +| `types.ts` | Parser-Typen | + +--- + +## Edge-Callout-Format + +```markdown +>> [!edge] resulted_in +>> [[#^impact]] +>> [[#^learning]] +``` + +--- + +## Siehe auch + +- [mapping/sectionParser](../mapping.md) – Section-Parsing diff --git a/docs/modules/ui.md b/docs/modules/ui.md new file mode 100644 index 0000000..321ab5e --- /dev/null +++ b/docs/modules/ui.md @@ -0,0 +1,38 @@ +# Modul: UI + +> **Pfad:** `src/ui/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +UI-Komponenten: Modals, Settings Tab, Entity Picker, Markdown Toolbar. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `MindnetSettingTab.ts` | Plugin-Einstellungen | +| `InterviewWizardModal.ts` | Interview-Wizard | +| `ProfileSelectionModal.ts` | Profil-Auswahl | +| `EntityPickerModal.ts` | Note/Ordner-Auswahl | +| `ChainWorkbenchModal.ts` | Chain Workbench | +| `VaultTriageScanModal.ts` | Vault-Triage-Scan | +| `EdgeTypeChooserModal.ts` | Edge-Type-Auswahl | +| `AdoptNoteModal.ts` | Note-Adoption | +| `LinkPromptModal.ts` | Link-Prompt | +| `LinkTargetPickerModal.ts` | Link-Ziel-Auswahl | +| `ConfirmOverwriteModal.ts` | Überschreibbestätigung | +| `InlineEdgeTypeModal.ts` | Inline Edge-Type-Suggester | +| `FolderTreeModal.ts` | Ordnerbaum | +| `markdownToolbar.ts` | Markdown-Toolbar | +| `MindnetView.ts` | Mindnet-View | + +--- + +## Siehe auch + +- [01_Benutzerhandbuch](../01_Benutzerhandbuch.md) diff --git a/docs/modules/unresolvedLink.md b/docs/modules/unresolvedLink.md new file mode 100644 index 0000000..32a45d3 --- /dev/null +++ b/docs/modules/unresolvedLink.md @@ -0,0 +1,62 @@ +# Modul: Unresolved Link + +> **Pfad:** `src/unresolvedLink/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Das Unresolved-Link-Modul behandelt das Abfangen von Klicks auf unaufgelöste Links, Note-Adoption und die Normalisierung von Überschriften für Matching. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `unresolvedLinkHandler.ts` | Haupt-Handler für Link-Clicks | +| `linkHelpers.ts` | Link-Parsing, Heading-Normalisierung, Matching | +| `adoptHelpers.ts` | Note-Adoption-Logik | + +--- + +## Heading-Normalisierung (normalizeHeadingForMatch) + +**Zweck:** Überschriften für Vergleich (Inspect Chains, Chain Workbench) auf kanonische Form bringen. + +### Regeln + +1. **Mit ^Block-ID:** `"Überschrift ^Block"` → `"Überschrift"` (Block-Suffix entfernen) +2. **Ohne ^:** Rückgabe unverändert (Idempotenz für bereits normalisierte Formen) + +### Wichtige Eigenschaft: Idempotenz + +`norm(norm(x)) === norm(x)` – mehrfache Normalisierung ändert nichts. + +### Beispiele + +| Input | Output | +|-------|--------| +| `"Lars ist gut ^PersLars"` | `"Lars ist gut"` | +| `"Lars ist gut"` | `"Lars ist gut"` | +| `"Nächster Schritt ^next"` | `"Nächster Schritt"` | +| `"Überschrift ^Block"` | `"Überschrift"` | + +### headingsMatch + +Vergleicht zwei Überschriften über `normalizeHeadingForMatch` – beide müssen nach Normalisierung identisch sein. + +--- + +## Obsidian-Verhalten + +- **Manuell verlinkt:** Obsidian erzeugt `[[Titel#Überschrift Block]]` (ohne `^`) +- **Empfehlung:** Für zuverlässiges Matching Links mit `^` verwenden: `[[Note#Überschrift ^Block]]` + +--- + +## Siehe auch + +- [12_Heading_Block_Link_Recommendation](../12_Heading_Block_Link_Recommendation.md) +- [Analysis-Modul](analysis.md) – Nutzung von headingsMatch diff --git a/docs/modules/vocabulary.md b/docs/modules/vocabulary.md new file mode 100644 index 0000000..9c67eb0 --- /dev/null +++ b/docs/modules/vocabulary.md @@ -0,0 +1,32 @@ +# Modul: Vocabulary + +> **Pfad:** `src/vocab/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Edge Vocabulary Loading, Normalisierung (Alias → Canonical), Inverse Edge Resolution. + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `Vocabulary.ts` | Lookup-Methoden | +| `VocabularyLoader.ts` | Lädt edge_vocabulary.md | +| `parseEdgeVocabulary.ts` | Parst Markdown zu EdgeVocabulary | + +--- + +## Format + +Markdown mit Tabellen oder Callouts. Kanonische Typen, Inverse, Aliases. + +--- + +## Siehe auch + +- [06_Konfigurationsdateien_Referenz](../06_Konfigurationsdateien_Referenz.md) – edge_vocabulary diff --git a/docs/modules/workbench.md b/docs/modules/workbench.md new file mode 100644 index 0000000..64d952e --- /dev/null +++ b/docs/modules/workbench.md @@ -0,0 +1,61 @@ +# Modul: Workbench + +> **Pfad:** `src/workbench/` +> **Zielgruppe:** Entwickler + +--- + +## Übersicht + +Das Workbench-Modul implementiert die **Chain Workbench** – eine UI zur Analyse von Ketten und zur Bearbeitung von Lücken (Todos, Actions). + +--- + +## Komponenten + +| Datei | Beschreibung | +|-------|--------------| +| `ChainWorkbenchModal.ts` | Haupt-Modal (in ui/) | +| `workbenchBuilder.ts` | Baut Workbench-Daten aus Template Matches | +| `todoGenerator.ts` | Erzeugt Todos (missing_slot, missing_link, weak_roles) | +| `statusCalculator.ts` | Berechnet Status (complete, near_complete, partial, weak) | +| `zoneDetector.ts` | Erkennt Zonen (note_links, candidates_only) | +| `createSectionAction.ts` | Aktion: Sektion erstellen | +| `linkExistingAction.ts` | Aktion: Bestehenden Knoten verlinken | +| `insertEdgeIntoSectionContent.ts` | Edge in Section-Content einfügen | +| `interviewOrchestration.ts` | Orchestriert Interview bei Create-Actions | + +--- + +## Vault Triage Scan + +- **Command:** `mindnet-vault-triage-scan` +- **Modal:** VaultTriageScanModal +- **Sortierung:** near_complete zuerst, dann nach Score absteigend + +--- + +## Status-Werte + +| Status | Bedingung | +|--------|-----------| +| `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 | + +--- + +## Fix Actions + +- **createMissingNote:** Skeleton, Create+Open, Create+Wizard +- **createMissingHeading:** Neues Heading mit konfigurierbarem Level +- **promoteCandidate:** Candidate als echten Slot übernehmen + +--- + +## Siehe auch + +- [09_Workbench_Analysis_Basis](../09_Workbench_Analysis_Basis.md) +- [10_Workbench_Findings_Integration](../10_Workbench_Findings_Integration.md) +- [Analysis-Modul](analysis.md) – Template Matching, Scoring diff --git a/src/interview/targetTypeResolver.ts b/src/interview/targetTypeResolver.ts index 58df17e..5be6f9e 100644 --- a/src/interview/targetTypeResolver.ts +++ b/src/interview/targetTypeResolver.ts @@ -102,6 +102,8 @@ export interface HeadingWithType { heading: string; sectionType: string | null; level: number; + /** Block-ID from `## Title ^id`; null if the heading has none. */ + blockId: string | null; } export async function getHeadingsWithSectionTypes( @@ -115,10 +117,11 @@ export async function getHeadingsWithSectionTypes( for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line === undefined) continue; - const match = line.match(/^(#{1,6})\s+(.+?)(?:\s*\^[\w-]+)?\s*$/); + const match = line.match(/^(#{1,6})\s+(.+?)(?:\s*\^([a-zA-Z0-9_-]+))?\s*$/); if (match && match[1] && match[2]) { const level = match[1].length; const heading = match[2].trim(); + const blockId = match[3] ?? null; let sectionType: string | null = null; for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) { const nextLine = lines[j]; @@ -129,7 +132,7 @@ export async function getHeadingsWithSectionTypes( break; } } - result.push({ heading, sectionType, level }); + result.push({ heading, sectionType, level, blockId }); } } return result; diff --git a/src/main.ts b/src/main.ts index 6c74470..ff9572a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -383,6 +383,14 @@ export default class MindnetCausalAssistantPlugin extends Plugin { }, }); + this.addCommand({ + id: "mindnet-start-interview-current-note", + name: "Mindnet: Interview für aktuelle Note starten", + callback: async () => { + await this.startInterviewForActiveFile(); + }, + }); + this.addCommand({ id: "mindnet-create-note-from-profile", name: "Mindnet: Create note from profile", @@ -852,7 +860,9 @@ export default class MindnetCausalAssistantPlugin extends Plugin { async (wizardResult: WizardResult) => { new Notice("Interview saved and changes applied"); }, - this // Pass plugin instance for graph schema loading + this, // Pass plugin instance for graph schema loading + undefined, + !isUnresolvedClick ); } catch (e) { const msg = e instanceof Error ? e.message : String(e); @@ -869,6 +879,66 @@ export default class MindnetCausalAssistantPlugin extends Plugin { return this.createNoteFromProfileAndOpen(result, result.title); } + /** Start interview wizard on the open note (profile from frontmatter or picker). */ + private async startInterviewForActiveFile(): Promise { + const file = this.app.workspace.getActiveFile(); + if (!file || file.extension !== "md") { + new Notice("Bitte eine Markdown-Notiz öffnen"); + return; + } + + const config = await this.ensureInterviewConfigLoaded(); + if (!config) { + return; + } + + const content = await this.app.vault.read(file); + const profileKeyMatch = content.match(/^interview_profile\s*:\s*(.+)$/m); + let profileKey = profileKeyMatch?.[1]?.trim() ?? ""; + if ( + (profileKey.startsWith('"') && profileKey.endsWith('"')) || + (profileKey.startsWith("'") && profileKey.endsWith("'")) + ) { + profileKey = profileKey.slice(1, -1); + } + + const profile = profileKey + ? config.profiles.find((p) => p.key === profileKey) + : undefined; + + const openWizard = (chosen: import("./interview/types").InterviewProfile) => { + new InterviewWizardModal( + this.app, + chosen, + file, + content, + async () => { + new Notice("Interview completed and changes applied"); + }, + async () => { + new Notice("Interview saved and changes applied"); + }, + this.settings, + this + ).open(); + }; + + if (profile) { + openWizard(profile); + return; + } + + new ProfileSelectionModal( + this.app, + config, + async (result) => { + openWizard(result.profile); + }, + file.basename, + file.parent?.path ?? "" + ).open(); + } + /** * Register unresolved link handlers for Reading View and Live Preview. */ diff --git a/src/tests/unresolvedLink/linkHelpers.test.ts b/src/tests/unresolvedLink/linkHelpers.test.ts index e96b4ed..36a87c0 100644 --- a/src/tests/unresolvedLink/linkHelpers.test.ts +++ b/src/tests/unresolvedLink/linkHelpers.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -import { normalizeLinkTarget, normalizeHeadingForMatch, headingsMatch, isUnresolvedLink, waitForFileModify, parseWikilinkAtPosition } from "../../unresolvedLink/linkHelpers"; +import { normalizeLinkTarget, normalizeHeadingForMatch, headingsMatch, isUnresolvedLink, waitForFileModify, parseWikilinkAtPosition, parseHeadingWithBlockId, formatStableWikilinkTarget, formatStableWikilink } from "../../unresolvedLink/linkHelpers"; import { App, TFile } from "obsidian"; describe("normalizeLinkTarget", () => { @@ -59,6 +59,64 @@ describe("normalizeHeadingForMatch", () => { }); }); +describe("parseHeadingWithBlockId", () => { + it("splits heading and block-id", () => { + expect(parseHeadingWithBlockId("Nächster Schritt ^next")).toEqual({ + heading: "Nächster Schritt", + blockId: "next", + }); + }); + + it("returns heading only when no block-id", () => { + expect(parseHeadingWithBlockId("Nächster Schritt")).toEqual({ + heading: "Nächster Schritt", + blockId: null, + }); + }); +}); + +describe("formatStableWikilinkTarget", () => { + it("writes intra-note block ref", () => { + expect(formatStableWikilinkTarget({ blockId: "sit" })).toBe("#^sit"); + }); + + it("writes cross-note heading + block (vacation-stable form)", () => { + expect( + formatStableWikilinkTarget({ + basename: "Geburt", + heading: "Nächster Schritt", + blockId: "next", + }) + ).toBe("Geburt#Nächster Schritt ^next"); + }); + + it("parses block-id out of heading if passed combined", () => { + expect( + formatStableWikilinkTarget({ + basename: "Geburt", + heading: "Nächster Schritt ^next", + }) + ).toBe("Geburt#Nächster Schritt ^next"); + }); + + it("falls back to heading-only when no block-id", () => { + expect( + formatStableWikilinkTarget({ + basename: "Geburt", + heading: "Nächster Schritt", + }) + ).toBe("Geburt#Nächster Schritt"); + }); + + it("writes note-only link", () => { + expect(formatStableWikilinkTarget({ basename: "Geburt" })).toBe("Geburt"); + }); + + it("wraps in brackets", () => { + expect(formatStableWikilink({ basename: "Geburt", blockId: "sit" })).toBe("[[Geburt#^sit]]"); + }); +}); + describe("headingsMatch", () => { it("matches same heading", () => { expect(headingsMatch("Überschrift", "Überschrift")).toBe(true); diff --git a/src/ui/LinkTargetPickerModal.ts b/src/ui/LinkTargetPickerModal.ts index 7a6aceb..cb818c9 100644 --- a/src/ui/LinkTargetPickerModal.ts +++ b/src/ui/LinkTargetPickerModal.ts @@ -1,7 +1,7 @@ /** * Modal zur Auswahl des Link-Ziels: Ganze Note oder ein Abschnitt (Überschrift inkl. Sektionstyp). * Wird in der Interview-Toolbar nach der Note-Auswahl angezeigt. - * Speichert Link als [[Note]] oder [[Note#Abschnitt]]. + * Speichert Link als [[Note]], [[Note#Abschnitt ^block]] oder [[Note#Abschnitt]]. */ import { App, Modal, TFile } from "obsidian"; @@ -10,9 +10,10 @@ import { resolveTargetTypeForNoteLink, type HeadingWithType, } from "../interview/targetTypeResolver"; +import { formatStableWikilinkTarget } from "../unresolvedLink/linkHelpers"; export interface LinkTargetPick { - linkTarget: string; // "Note" oder "Note#Abschnitt" + linkTarget: string; // "Note", "Note#Abschnitt ^block" oder "Note#Abschnitt" targetType: string | null; } @@ -102,7 +103,11 @@ export class LinkTargetPickerModal extends Modal { .createEl("span", { text: ` (Sektion: ${h.sectionType})`, cls: "target-type" }) .style.color = "var(--text-muted)"; } - const linkTarget = `${this.basename}#${h.heading}`; + const linkTarget = formatStableWikilinkTarget({ + basename: this.basename, + heading: h.heading, + blockId: h.blockId, + }); headingBtn.onclick = () => { if (this.resolve) { this.resolve({ linkTarget, targetType: h.sectionType }); diff --git a/src/ui/MindnetSettingTab.ts b/src/ui/MindnetSettingTab.ts index 982f66d..81cab70 100644 --- a/src/ui/MindnetSettingTab.ts +++ b/src/ui/MindnetSettingTab.ts @@ -465,7 +465,7 @@ export class MindnetSettingTab extends PluginSettingTab { new Setting(containerEl) .setName("Auto-start interview on create") .setDesc( - "Startet automatisch den Interview-Wizard, wenn eine neue Notiz über ein Profil erstellt wird." + "Zusätzlich zum Command „Create note from profile“ (der den Wizard immer startet): Wizard auch bei anderen Create-Wegen automatisch öffnen." ) .addToggle((toggle) => toggle diff --git a/src/unresolvedLink/linkHelpers.ts b/src/unresolvedLink/linkHelpers.ts index f3a7993..3c425f2 100644 --- a/src/unresolvedLink/linkHelpers.ts +++ b/src/unresolvedLink/linkHelpers.ts @@ -31,6 +31,71 @@ export function normalizeHeadingForMatch(heading: string | null): string | null return s || null; } +/** + * Split heading text into title and optional trailing block-id. + * "Nächster Schritt ^next" → { heading: "Nächster Schritt", blockId: "next" } + * "Nächster Schritt" → { heading: "Nächster Schritt", blockId: null } + * "^sit" / "#^sit" are not headings; use formatStableWikilinkTarget for those. + */ +export function parseHeadingWithBlockId(raw: string | null | undefined): { + heading: string | null; + blockId: string | null; +} { + if (raw == null) return { heading: null, blockId: null }; + const s = raw.trim(); + if (!s) return { heading: null, blockId: null }; + const match = s.match(/^(.*?)(?:\s*\^([a-zA-Z0-9_-]+))\s*$/); + if (match && match[2]) { + const heading = (match[1] ?? "").trim(); + return { heading: heading || null, blockId: match[2] }; + } + return { heading: s, blockId: null }; +} + +export interface StableLinkParts { + /** Note basename. Empty/null = intra-note link. */ + basename?: string | null; + heading?: string | null; + blockId?: string | null; +} + +/** + * Stable wikilink *target* (without [[ ]]). Prefer this for every write path. + * Intra-note + blockId → #^block + * Cross-note + heading + blockId → Note#Heading ^block + * Cross-note + blockId only → Note#^block + * Cross-note + heading only → Note#Heading + * Note only → Note + */ +export function formatStableWikilinkTarget(parts: StableLinkParts): string { + const basename = (parts.basename ?? "").trim(); + let heading = parts.heading?.trim() || null; + let blockId = parts.blockId?.trim() || null; + if (heading && !blockId) { + const parsed = parseHeadingWithBlockId(heading); + heading = parsed.heading; + blockId = parsed.blockId; + } else if (heading && blockId) { + heading = parseHeadingWithBlockId(heading).heading ?? heading.replace(/\s*\^[a-zA-Z0-9_-]+\s*$/, "").trim(); + } + + if (!basename) { + if (blockId) return `#^${blockId}`; + if (heading) return `#${heading}`; + return ""; + } + if (heading && blockId) return `${basename}#${heading} ^${blockId}`; + if (blockId) return `${basename}#^${blockId}`; + if (heading) return `${basename}#${heading}`; + return basename; +} + +/** Same as formatStableWikilinkTarget, wrapped in [[ ]]. */ +export function formatStableWikilink(parts: StableLinkParts): string { + const target = formatStableWikilinkTarget(parts); + return target ? `[[${target}]]` : ""; +} + /** * Compare two headings for equality using normalized form (block-id suffix and trailing word stripped). * Use for Inspect Chains / Chain Workbench matching only. diff --git a/src/unresolvedLink/unresolvedLinkHandler.ts b/src/unresolvedLink/unresolvedLinkHandler.ts index aa28cf9..c59101b 100644 --- a/src/unresolvedLink/unresolvedLinkHandler.ts +++ b/src/unresolvedLink/unresolvedLinkHandler.ts @@ -49,12 +49,13 @@ export async function startWizardAfterCreate( onWizardComplete: (result: any) => void, onWizardSave: (result: any) => void, pluginInstance?: { ensureGraphSchemaLoaded?: () => Promise }, - initialPendingEdgeAssignments?: import("../interview/wizardState").PendingEdgeAssignment[] + initialPendingEdgeAssignments?: import("../interview/wizardState").PendingEdgeAssignment[], + forceStart = false ): Promise { // Determine if wizard should start - const shouldStartInterview = isUnresolvedClick + const shouldStartInterview = forceStart || (isUnresolvedClick ? (settings.autoStartOnUnresolvedClick || settings.autoStartInterviewOnCreate) - : settings.autoStartInterviewOnCreate; + : settings.autoStartInterviewOnCreate); if (!shouldStartInterview) { if (settings.debugLogging) { diff --git a/src/workbench/createSectionAction.ts b/src/workbench/createSectionAction.ts index dafac3a..fb6d63f 100644 --- a/src/workbench/createSectionAction.ts +++ b/src/workbench/createSectionAction.ts @@ -14,6 +14,8 @@ import { EntityPickerModal } from "../ui/EntityPickerModal"; import { NoteIndex } from "../entityPicker/noteIndex"; import { detectZoneFromContent } from "./zoneDetector"; import { removeBlanksAndInsert } from "./edgeInsertHelper"; +import { formatStableWikilinkTarget } from "../unresolvedLink/linkHelpers"; +import { slugify } from "../interview/slugify"; /** Common section/node types for dropdown when slot has no allowed_node_types. */ const FALLBACK_SECTION_TYPES = [ @@ -130,9 +132,10 @@ export async function createSectionInNote( sectionContent += `> [!${wrapperType}]${foldMarker}${wrapperTitle ? ` ${wrapperTitle}` : ""}\n`; for (const edge of result.initialEdges) { - const targetLink = edge.targetHeading - ? `${edge.targetNote}#${edge.targetHeading}` - : edge.targetNote; + const targetLink = formatStableWikilinkTarget({ + basename: edge.targetNote, + heading: edge.targetHeading, + }); sectionContent += `>> [!edge] ${edge.edgeType}\n>> [[${targetLink}]]\n`; } @@ -159,13 +162,11 @@ export async function createSectionInNote( // Gegenkanten in den anderen Notes einfügen (Vorwärts- bzw. Rückwärtskante) const sourcePath = result.targetFilePath.replace(/\.md$/, ""); - const sourceFragment = - result.blockId && result.heading - ? `${result.heading} ^${result.blockId}` - : result.blockId - ? `^${result.blockId}` - : result.heading ?? ""; - const sourceLink = sourceFragment ? `${sourcePath}#${sourceFragment}` : sourcePath; + const sourceLink = formatStableWikilinkTarget({ + basename: sourcePath, + heading: result.heading, + blockId: result.blockId, + }); for (const edge of result.initialEdges) { const otherPathRaw = edge.targetNote.replace(/\.md$/, ""); @@ -553,10 +554,10 @@ async function showCreateSectionModal( }); }); - // Block ID (optional) + // Block ID — auto from heading if left empty (stable links for later ingest) new Setting(contentEl) - .setName("Block-ID (optional)") - .setDesc("z. B. learning, insight-1") + .setName("Block-ID") + .setDesc("Pflicht für stabile Links. Leer = aus der Überschrift erzeugt.") .addText((text) => { text.setValue("").onChange((value) => { this.blockId = value.trim(); @@ -616,6 +617,12 @@ async function showCreateSectionModal( new Notice("Bitte eine Ziel-Note wählen"); return; } + const heading = this.heading.trim(); + const blockId = this.blockId || slugify(heading); + if (!blockId) { + new Notice("Block-ID fehlt und konnte nicht aus der Überschrift erzeugt werden"); + return; + } this.initialEdges = requiredEdges.map((e, i) => ({ edgeType: this.chosenEdgeTypes[i] ?? e.suggestedAlias ?? e.edgeType, targetNote: e.targetNote, @@ -625,8 +632,8 @@ async function showCreateSectionModal( })); this.result = { targetFilePath: this.targetFilePath, - heading: this.heading.trim(), - blockId: this.blockId || null, + heading, + blockId, sectionType: this.sectionType || null, sectionBody: this.sectionBody, initialEdges: this.initialEdges, diff --git a/src/workbench/interviewOrchestration.ts b/src/workbench/interviewOrchestration.ts index 7cd3aa3..fe19491 100644 --- a/src/workbench/interviewOrchestration.ts +++ b/src/workbench/interviewOrchestration.ts @@ -184,7 +184,8 @@ export async function createNoteViaInterview( new Notice("Wizard saved"); }, pluginInstance, - pendingEdgeAssignments // Pass initial edge assignments to wizard + pendingEdgeAssignments, + true ); } diff --git a/src/workbench/linkExistingAction.ts b/src/workbench/linkExistingAction.ts index 9b4da25..b60a9c1 100644 --- a/src/workbench/linkExistingAction.ts +++ b/src/workbench/linkExistingAction.ts @@ -2,12 +2,14 @@ * Link existing action for missing_slot todos. */ -import { Notice } from "obsidian"; -import type { App, Editor, TFile } from "obsidian"; +import { Notice, TFile } from "obsidian"; +import type { App, Editor } from "obsidian"; import type { MissingSlotTodo } from "./types"; import { EntityPickerModal } from "../ui/EntityPickerModal"; +import { LinkTargetPickerModal } from "../ui/LinkTargetPickerModal"; import { NoteIndex } from "../entityPicker/noteIndex"; import { findSection } from "./zoneDetector"; +import { formatStableWikilink } from "../unresolvedLink/linkHelpers"; /** * Link existing note/section to fill missing slot. @@ -56,7 +58,15 @@ export async function linkExisting( // This is a placeholder - the real implementation would need to update the match const targetNote = selectedNote.basename.replace(/\.md$/, ""); - const linkText = `[[${targetNote}]]`; + let linkText = formatStableWikilink({ basename: targetNote }); + const pickedFile = app.vault.getAbstractFileByPath(selectedNote.path); + if (pickedFile instanceof TFile) { + const picker = new LinkTargetPickerModal(app, pickedFile, targetNote, file.path); + const pick = await picker.show(); + if (pick?.linkTarget) { + linkText = `[[${pick.linkTarget}]]`; + } + } // Insert link at cursor position const cursor = editor.getCursor(); diff --git a/src/workbench/writerActions.ts b/src/workbench/writerActions.ts index 3c6d186..2703c38 100644 --- a/src/workbench/writerActions.ts +++ b/src/workbench/writerActions.ts @@ -14,7 +14,7 @@ import type { Vocabulary } from "../vocab/Vocabulary"; import type { EdgeVocabulary } from "../vocab/types"; import type { MindnetSettings } from "../settings"; import { computeSectionContentAfterInsertEdge } from "./insertEdgeIntoSectionContent"; -import { headingsMatch } from "../unresolvedLink/linkHelpers"; +import { formatStableWikilinkTarget, headingsMatch } from "../unresolvedLink/linkHelpers"; /** * Insert edge forward (from source to target). @@ -68,9 +68,10 @@ export async function insertEdgeForward( // Build target link (extract basename from file path) const targetBasename = todo.toNodeRef.file.replace(/\.md$/, "").split("/").pop() || todo.toNodeRef.file; - const targetLink = todo.toNodeRef.heading - ? `${targetBasename}#${todo.toNodeRef.heading}` - : targetBasename; + const targetLink = formatStableWikilinkTarget({ + basename: targetBasename, + heading: todo.toNodeRef.heading, + }); if (debugLogging) { console.log("[insertEdgeForward] Target link:", targetLink); @@ -486,9 +487,10 @@ async function createInverseEdge( // Build source link (for inverse edge, source is the original target) const sourceBasename = todo.fromNodeRef.file.replace(/\.md$/, "").split("/").pop() || todo.fromNodeRef.file; - const sourceLink = todo.fromNodeRef.heading - ? `${sourceBasename}#${todo.fromNodeRef.heading}` - : sourceBasename; + const sourceLink = formatStableWikilinkTarget({ + basename: sourceBasename, + heading: todo.fromNodeRef.heading, + }); // Always ask user to select target section (or whole note) // Open target file in editor first @@ -973,9 +975,10 @@ export async function promoteCandidate( // Find candidate edge in zone const candidateEdge = todo.candidateEdge; const edgeType = candidateEdge.rawEdgeType; - const targetLink = candidateEdge.to.heading - ? `[[${candidateEdge.to.file}#${candidateEdge.to.heading}]]` - : `[[${candidateEdge.to.file}]]`; + const targetLink = formatStableWikilinkTarget({ + basename: candidateEdge.to.file, + heading: candidateEdge.to.heading, + }); // Determine source section (from evidence or current context) const sourceSectionHeading = candidateEdge.evidence.sectionHeading;