diff --git a/docs/Handbuch.md b/docs/Handbuch.md index 953ae86..45a72e1 100644 --- a/docs/Handbuch.md +++ b/docs/Handbuch.md @@ -1,19 +1,42 @@ -# 📘 Mindnet Skript-Handbuch +# 📘 Mindnet Skript-Handbuch (aktualisiert) -Dieses Handbuch dokumentiert die implementierten Skripte fĂŒr das Projekt **mindnet Wissensnetzwerk**. -Es beschreibt Zweck, Parameter und typische Aufrufe. Alle Beispiele sind geprĂŒft und lauffĂ€hig. - -Alle Skripte liegen in `~/mindnet/scripts/`. -AusfĂŒhrung erfolgt **im aktivierten venv**: - - cd ~/mindnet - source .venv/bin/activate +Dieses Handbuch dokumentiert die Skripte und Tests fĂŒr das Projekt **mindnet Wissensnetzwerk**. +Es beschreibt Zweck, Parameter, typische Aufrufe sowie aktuelle Verhaltensweisen (Hash-Modi, Parser-Robustheit, `window`/`text`-Trennung in Chunks, Export-Fixes). +Alle Beispiele sind so formatiert, dass sie direkt kopierbar sind. **Code/CLI-Beispiele sind eingerĂŒckt**, damit die Markdown-Darstellung nicht abbricht. --- -## 1. Vault anlegen (fĂŒr Tests) +## 0) Umgebung & Konfiguration -### `make_test_vault.py` +**Wichtige ENV-Variablen** + +- `QDRANT_URL` – z. B. `http://localhost:6333` +- `QDRANT_API_KEY` – API-Key (falls aktiviert) +- `COLLECTION_PREFIX` – Prefix der drei Collections, Standard: `mindnet` → `mindnet_notes`, `mindnet_chunks`, `mindnet_edges` +- `VECTOR_DIM` – Embedding-Dimension (Chunks), Standard: `384` + +**Hash-Vergleich & Änderungs­erkennung** + +- `MINDNET_HASH_COMPARE` – steuert, **welcher Anteil** fĂŒr „changed“ verglichen wird + Werte: `Body` (Standard), `Frontmatter`, `Full` +- `MINDNET_HASH_SOURCE` – Quelle: `parsed` (Standard), `raw`, `file` +- `MINDNET_HASH_NORMALIZE` – Normalisierung: `canonical` (Standard) oder `none` + +**Beispiel (nur Body berĂŒcksichtigen, kanonisch, geparst):** + + export MINDNET_HASH_COMPARE=Body + export MINDNET_HASH_SOURCE=parsed + export MINDNET_HASH_NORMALIZE=canonical + source .venv/bin/activate + +**Baseline-Signaturen (mehrere Modi):** +Der Importer kann **Signaturen aller Modi** (Body/Frontmatter/Full) vorhalten, damit spĂ€tere Moduswechsel deterministisch sind (keine „Mass-Changes“). Siehe `--baseline-modes` unter **Importer**. + +--- + +## 1) Vault anlegen (fĂŒr Tests) + +### `scripts/make_test_vault.py` **Zweck:** Erstellt einen kleinen, nachvollziehbaren Test-Vault mit Markdown-Dateien. @@ -22,17 +45,17 @@ Szenarien: offene Links, nachtrĂ€gliche Anlage fehlender Notes, geĂ€nderte Chunk **Parameter:** - `--out PATH` : Zielverzeichnis (Default: `./test_vault`) - `--force` : Existierenden Ordner löschen und neu anlegen -- `--with-missing` : Optional – auch die `missing-note` gleich anlegen +- `--with-missing` : Optional – auch die `missing-note` gleich anlegen **Hinweise fĂŒr Tests** -1) Erster Import (dry-run oder --apply): Es gibt einen „leeren“ Link [[missing-note]]. -2) Lege danach eine Datei fĂŒr „missing-note“ an (mit gleicher ID im YAML) und importiere erneut: - -> Erwartung: Edges fĂŒr ehemals leeren Link werden korrekt nachgezogen (references + backlink). -3) Ändere den Body von exp-one.md so, dass andere Chunk-Grenzen entstehen und importiere erneut: - -> Erwartung: Chunks/Edges/Note werden fĂŒr betroffene Noten aktualisiert. +1. Erster Import (dry-run oder `--apply`): Es gibt einen „leeren“ Link `[[missing-note]]`. +2. Lege danach eine Datei fĂŒr „missing-note“ an (mit gleicher `id` im YAML) und importiere erneut: + → Erwartung: Edges fĂŒr ehemals leeren Link werden korrekt nachgezogen (`references` + `backlink`). +3. Ändere den Body von `exp-one.md` so, dass andere Chunk-Grenzen entstehen und importiere erneut: + → Erwartung: Chunks/Edges/Note werden fĂŒr betroffene Noten aktualisiert. -Kompatibel mit: -- note.schema.json: 'created'/'updated' mĂŒssen strings sein. (Wichtig!) +**KompatibilitĂ€t:** +- `note.schema.json`: `created`/`updated` sind Strings. **Beispiele:** @@ -41,41 +64,60 @@ Kompatibel mit: --- -## 2. Import in Qdrant +## 2) Import in Qdrant -### `import_markdown.py` +### `scripts/import_markdown.py` **Zweck:** -Importiert Notes/Chunks/Edges aus einem Vault nach Qdrant. -- prĂŒft Frontmatter -- chunked Inhalte + Embeddings -- erzeugt Edges (`references`, `references_at`, `backlink`) -- erkennt geĂ€nderte Dateien automatisch +Importiert Notes/Chunks/Edges aus einem Vault nach Qdrant. +- validiert Frontmatter +- chunked Inhalte + Embeddings +- erzeugt Edges (`references`, `references_at`, `backlink`, `next`, `prev`, `belongs_to`) +- erkennt geĂ€nderte Dateien **modusgesteuert** (Body/Frontmatter/Full) - optional: Purge der alten Chunks/Edges pro Note **Parameter:** - `--vault PATH` : (Pflicht) Vault-Verzeichnis -- `--apply` : Änderungen wirklich durchfĂŒhren (sonst Dry-Run) +- `--apply` : Änderungen wirklich durchfĂŒhren (ohne: Dry-Run) - `--purge-before-upsert` : Vor Upsert alte Chunks/Edges **nur der geĂ€nderten Notes** löschen -- `--note-id ID` : Nur eine bestimmte Note importieren +- `--prefix STR` : ĂŒberschreibt `COLLECTION_PREFIX` +- `--note-id ID` : nur eine bestimmte Note importieren +- `--note-scope-refs` : zusĂ€tzlich **note-weite** `references` erzeugen (nicht nur chunk-weise) +- `--baseline-modes` : berechne & speichere Hash-Signaturen fĂŒr **alle** Modi (`Body`, `Frontmatter`, `Full`) als Baseline + +**Erwartetes Verhalten:** +- UnverĂ€nderte Notes → `"changed": false`, Entscheidung: `apply-skip-unchanged` (bei `--apply`) +- GeĂ€nderte Notes → `"changed": true` (abhĂ€ngig von `MINDNET_HASH_COMPARE`) +- Idempotenz: mehrfacher Lauf ohne Änderungen erzeugt **keine** neuen Punkte +- Baseline: Bei `--baseline-modes` erscheinen Felder wie `hash_signature`, `hash_fulltext`, ggf. `hash_frontmatter` und `needs_baseline_for_mode: false` bei FolgelĂ€ufen. **Beispiele:** - python3 -m scripts.import_markdown --vault ./vault - python3 -m scripts.import_markdown --vault ./vault --apply - python3 -m scripts.import_markdown --vault ./vault --apply --purge-before-upsert + # Dry-Run (zeigt Änderungen, schreibt NICHT) + python3 -m scripts.import_markdown --vault ./vault --prefix mindnet + + # Apply + gezielte Vorreinigung pro geĂ€nderter Note + python3 -m scripts.import_markdown --vault ./vault --prefix mindnet --apply --purge-before-upsert + + # Baseline-Signaturen aller Modi vorhalten + python3 -m scripts.import_markdown --vault ./vault --apply --baseline-modes + +**Hash-Modi in der Praxis:** +- `MINDNET_HASH_COMPARE=Body` → Änderungen im Body werden erkannt; reine Frontmatter-Änderungen bleiben **ohne Effekt**. +- `MINDNET_HASH_COMPARE=Frontmatter` → nur Frontmatter maßgeblich. +- `MINDNET_HASH_COMPARE=Full` → beide Anteile zĂ€hlen. --- -## 3. KonsistenzprĂŒfungen +## 3) KonsistenzprĂŒfungen -### `audit_vault_vs_qdrant.py` +### `scripts/audit_vault_vs_qdrant.py` **Zweck:** -Vergleicht Vault-Inhalte mit Qdrant. -- ZĂ€hlt Notes/Chunks/Edges -- Verifiziert Anzahl Wikilinks vs. Edges -- Meldet Mismatches pro Note +Vergleicht Vault-Inhalte mit Qdrant. +- ZĂ€hlt Notes/Chunks/Edges +- Verifiziert Anzahl Wikilinks vs. Edges +- Meldet Deltas (z. B. `references` im Vault vs. in Qdrant) **Parameter:** - `--vault PATH` : Vault-Verzeichnis @@ -85,15 +127,13 @@ Vergleicht Vault-Inhalte mit Qdrant. python3 -m scripts.audit_vault_vs_qdrant --vault ./vault --prefix mindnet ---- - -### `validate_edges.py` +### `scripts/validate_edges.py` **Zweck:** -PrĂŒft die Edges-Collection in Qdrant. -- ZĂ€hlt Edges pro Typ -- Kontrolliert Invarianten (z. B. jede Reference hat Backlink) -- Listet unresolved Edges auf +PrĂŒft die Edges-Collection in Qdrant. +- ZĂ€hlt Edges pro Typ (`references`, `references_at`, `backlink`, `next`, `prev`, `belongs_to`) +- Kontrolliert Invarianten (z. B. jede `references` hat einen `backlink`) +- Listet `unresolved` Edges auf **Parameter:** - `--prefix STR` : Prefix fĂŒr Qdrant-Collections @@ -105,35 +145,69 @@ PrĂŒft die Edges-Collection in Qdrant. --- -## 4. Qdrant zurĂŒcksetzen +## 4) Export Qdrant → Markdown (Vault) -### `reset_qdrant.py` +### `scripts/export_markdown.py` **Zweck:** -Setzt die Qdrant-Collections zurĂŒck. -- „wipe“: löscht Collections komplett (inkl. Schema) -- „truncate“: löscht nur Inhalte, behĂ€lt Collections +Exportiert Notes + rekonstruierten Body in einen Zielordner. +- Pfade werden **relativ** aus `note.payload.path` abgeleitet (fĂŒhrende `/` entfernt, Backslashes → Slashes; Unicode-NFC empfohlen) +- **Body-Rekonstruktion** priorisiert: + 1. `fulltext` (falls in Note-Payload vorhanden) + 2. sonst **Chunks**: Sortierung `seq` → `chunk_index` → Nummer in `chunk_id`; **nur `text`** (Overlap bereits entfernt) +- `--prefix` (CLI) wird unterstĂŒtzt (oder ENV `COLLECTION_PREFIX`) **Parameter:** -- `--mode {wipe,truncate}` : Aktion -- `--prefix STR` : Prefix der Collections (Default: `mindnet`) -- `--yes` : Automatische BestĂ€tigung -- `--dry-run` : Nur anzeigen, nicht ausfĂŒhren +- `--out PATH` : Ziel-Root (muss existieren) +- `--overwrite` : vorhandene Dateien ĂŒberschreiben +- `--note-id ID` : nur eine bestimmte Note exportieren +- `--prefix STR` : ĂŒberschreibt `COLLECTION_PREFIX` +- `--include-edges {none,footer,yaml}` *(optional, falls aktiviert)*: Edges als YAML-Liste im Frontmatter oder im Footer beilegen **Beispiele:** + export COLLECTION_PREFIX="mindnet" + python3 -m scripts.export_markdown --out ./_exportVault + + # Nur eine bestimmte Note: + python3 -m scripts.export_markdown --out ./_exportVault --note-id 20250821-architektur-ki-trainerassistent-761cfe + + # Existierende Dateien ĂŒberschreiben: + python3 -m scripts.export_markdown --out ./_exportVault --overwrite + +--- + +## 5) Qdrant zurĂŒcksetzen + +### `scripts/reset_qdrant.py` + +**Zweck:** +Setzt die Qdrant-Collections zurĂŒck. +- `wipe`: löscht Collections komplett (inkl. Schema) +- `truncate`: löscht nur Inhalte, behĂ€lt Collections +- `truncate-edges`: löscht nur Punkte in `*_edges` + +**Parameter:** +- `--mode {wipe,truncate,truncate-edges}` +- `--prefix STR` : Prefix der Collections (Default: `mindnet`) +- `--yes` : Automatische BestĂ€tigung +- `--dry-run` : Nur anzeigen, nicht ausfĂŒhren + +**Beispiele:** + + python3 -m scripts.reset_qdrant --mode truncate-edges --prefix mindnet python3 -m scripts.reset_qdrant --mode truncate --prefix mindnet --yes python3 -m scripts.reset_qdrant --mode wipe --prefix mindnet --yes --- -## 5. Diagnose +## 6) Diagnose & Tools -### `diagnose_changed.py` +### `scripts/diagnose_changed.py` **Zweck:** -PrĂŒft, ob die Datei-Hashes (`sha256`) mit den gespeicherten `hash_fulltext` in Qdrant ĂŒbereinstimmen. -Hilft, wenn der Importer zu viele Dateien als „changed“ erkennt. +PrĂŒft, ob Datei-Hashes (`sha256`) mit gespeicherten `hash_*` in Qdrant ĂŒbereinstimmen. +Hilft, wenn der Importer zu viele Dateien als „changed“ erkennt oder Moduswechsel geplant sind. **Parameter:** - `--vault PATH` : Vault-Verzeichnis @@ -145,14 +219,11 @@ Hilft, wenn der Importer zu viele Dateien als „changed“ erkennt. python3 -m scripts.diagnose_changed --vault ./vault --prefix mindnet --all ---- - -## 6. Unresolved Links nachtrĂ€glich auflösen - -### `resolve_unresolved_references.py` +### `scripts/resolve_unresolved_references.py` **Zweck:** -PrĂŒft offene Wikilinks (`status=unresolved`) und fĂŒgt Edges nach, wenn inzwischen passende Notizen existieren. +PrĂŒft offene Wikilinks (`status=unresolved`) und fĂŒgt Edges nach, wenn inzwischen passende Notizen existieren. +Ersetzt `unresolved` durch gĂŒltige `references`/`backlink`. **Parameter:** - `--prefix STR` : Prefix fĂŒr Qdrant-Collections @@ -165,26 +236,114 @@ PrĂŒft offene Wikilinks (`status=unresolved`) und fĂŒgt Edges nach, wenn inzwisc --- -# ✅ Typische Workflows +## 7) Parser-Verhalten (robust & abwĂ€rtskompatibel) -### A) Vault neu importieren +- Der Parser liest Markdown **fehlertolerant** (UTF-8 mit Fallbacks), extrahiert YAML-Frontmatter und Body. +- Keine harten AbhĂ€ngigkeiten von alten Regex-Symbolen (`FRONTMATTER_RE` entfĂ€llt zugunsten interner Marker). +- `read_markdown(path)` gibt `(frontmatter_dict, body_str)` zurĂŒck. +- **SonderfĂ€lle aus Fremd-Tools** (z. B. Silverbullet-Dateien wie `CONFIG.md`, `index.md`) werden **nicht importiert**, sofern sie nicht zum Vault gehören. +--- + +## 8) Chunk-Payload (Fenster vs. Kern) + +- **`window`** = kontextualisierter Fenster-Text (mit linkem Overlap) +- **`text`** = **Kerntext** ohne das vom vorherigen Chunk ĂŒbernommene Overlap +- Felder: `start`, `end`, `overlap_left`, `overlap_right`, `chunk_index`, `seq`, `path`, `section_title`, `section_path`, `token_count` (falls vorhanden) +- **Fallback (synthetisch):** Falls der Chunker **keinen** Overlap-Fenstertext liefert, erzeugt die Payload-Schicht Fenster mit typgerechtem Overlap aus `chunk_config.get_sizes(type)['overlap']` (unterer Wert). +- **Edges** werden aus `window` abgeleitet (um Links an Chunk-Grenzen nicht zu verlieren); der **Export** rekonstruiert den Body aus `text` (Overlap-frei). + +--- + +## 9) Edge-Modell & IDs + +- Collections: + `*_notes` (optional Vektor / Nullvektor), `*_chunks` (384-d Embeddings), `*_edges` (1-d Dummy-Vektor) +- **Deterministische IDs** (UUIDv5 / stabile Keys): + - `note_id` stabil aus Frontmatter/Slug + - `chunk_id` i. d. R. `note_id#` + - `edge_id` stabil aus `(kind, source_id, target_id, seq)` +- Kantenarten: `references`, `references_at`, `backlink`, `next`, `prev`, `belongs_to` +- `unresolved` wird gekennzeichnet und kann per Resolver spĂ€ter aufgelöst werden. + +--- + +## 10) Tests & QualitĂ€tssicherung + +**Tests unter `tests/`** + +- `check_chunks_window_vs_text.py` – vergleicht je Chunk `window` vs. `text`, schĂ€tzt Overlap +- `compare_vaults.py` – rekursiver Vault-Vergleich (Body/Frontmatter/All, Key: auto/id/title/filename), Unicode-NFC-robust +- `verify_chunks_integrity.py` – prĂŒft, ob Rekonstruktion aus Chunks (`text`) zu `fulltext` bzw. zum Vault-Body passt +- `list_md_seen_by_importer.py` – zeigt, welche `.md` der Importer sieht (inkl. GrĂŒnde/Filter) +- `inspect_one_note.py` – Parser-Diagnose fĂŒr eine konkrete Datei +- `run_e2e_roundtrip.sh` – End-to-End: Reset → Import → Audit → (optional) Hash-Reporter → Export → Vergleich + +**Typische Aufrufe:** + + # Overlap-QualitĂ€t (Fenster vs. Kern) + python3 tests/check_chunks_window_vs_text.py --prefix "$COLLECTION_PREFIX" + + # Roundtrip-Vergleich (rekursiv) + python3 tests/compare_vaults.py --src ./vault --dst ./_exportVault --focus body + + # Chunks-Rekonstruktion (gegen Vault-Body) + python3 tests/verify_chunks_integrity.py --prefix "$COLLECTION_PREFIX" --vault ./vault + +--- + +## 11) Typische Workflows + +**A) Clean-Start mit Test-Vault** + + python3 -m scripts.make_test_vault --out ./test_vault --force python3 -m scripts.reset_qdrant --mode truncate --prefix mindnet --yes - python3 -m scripts.import_markdown --vault ./vault --apply - python3 -m scripts.audit_vault_vs_qdrant --vault ./vault --prefix mindnet + python3 -m scripts.import_markdown --vault ./test_vault --prefix mindnet + python3 -m scripts.import_markdown --vault ./test_vault --prefix mindnet --apply --purge-before-upsert + python3 -m scripts.audit_vault_vs_qdrant --vault ./test_vault --prefix mindnet + python3 -m scripts.validate_edges --prefix mindnet --details + export COLLECTION_PREFIX="mindnet" + python3 -m scripts.export_markdown --out ./_exportVault -### B) Änderungen einspielen (mit Purge fĂŒr geĂ€nderte Notes) +**B) Änderungs-Propagation & Idempotenz** - python3 -m scripts.import_markdown --vault ./vault --apply --purge-before-upsert - python3 -m scripts.audit_vault_vs_qdrant --vault ./vault --prefix mindnet + python3 -m scripts.import_markdown --vault ./test_vault --prefix mindnet + python3 -m scripts.import_markdown --vault ./test_vault --prefix mindnet --apply --purge-before-upsert + python3 -m scripts.audit_vault_vs_qdrant --vault ./test_vault --prefix mindnet + python3 -m scripts.validate_edges --prefix mindnet --details + python3 -m scripts.import_markdown --vault ./test_vault --prefix mindnet -### C) Unresolved Links nachziehen +**C) Unresolved Links lösen** + python3 -m scripts.import_markdown --vault ./test_vault --apply --prefix mindnet python3 -m scripts.resolve_unresolved_references --prefix mindnet --apply python3 -m scripts.validate_edges --prefix mindnet --details -### D) Test-Vault Szenario durchspielen +**D) Export & Roundtrip (Produkt-Vault)** - python3 -m scripts.make_test_vault --out ./test_vault --force - python3 -m scripts.import_markdown --vault ./test_vault --apply - python3 -m scripts.audit_vault_vs_qdrant --vault ./test_vault --prefix mindnet + export COLLECTION_PREFIX="mindnet" + python3 -m scripts.import_markdown --vault ./vault --apply --purge-before-upsert --prefix "$COLLECTION_PREFIX" + python3 -m scripts.export_markdown --out ./_exportVault --prefix "$COLLECTION_PREFIX" + python3 tests/compare_vaults.py --src ./vault --dst ./_exportVault --focus body + +--- + +## 12) Troubleshooting (kurz) + +- **Importer markiert alle als changed (Moduswechsel):** + → `--baseline-modes` einmalig laufen lassen; sicherstellen: `MINDNET_HASH_COMPARE` passt zum Ziel. +- **Edges verschwinden / nur 1 Edge sichtbar:** + → `app/core/qdrant_points.py` muss Edge-Payload normalisieren (Schema Alt/Neu) und `edge_id` eindeutig bilden. +- **Export ohne Body / falsches Zielverzeichnis:** + → Exporter nutzt relativierte Pfade und rekonstruiert Body aus `fulltext` oder Chunks (`text`). ENV/CLI `--prefix` beachten. +- **Parser-Fehler (UTF-8):** + → Neuer Parser arbeitet mit Fallbacks; mit `tests/inspect_one_note.py` prĂŒfen, was ankommt. +- **„Fehlende“ Dateien im Vergleich:** + → PrĂŒfe, ob Dateien **wirklich zum Vault gehören** (z. B. Silverbullet-Artefakte `CONFIG.md`, `index.md` ausblenden). + +--- + +## 13) Hinweise zu Silverbullet-Dateien + +- Dateien wie `CONFIG.md` oder `index.md`, die **nicht** zum inhaltlichen Vault gehören, werden **nicht importiert** und erscheinen daher nicht im Export-Roundtrip. +- Diese Dateien bitte vom produktiven Vault trennen oder im Vergleich (`tests/compare_vaults.py