# 📘 Mindnet Skript-Handbuch (aktualisiert) 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. --- ## 0) Umgebung & Konfiguration **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. Szenarien: offene Links, nachträgliche Anlage fehlender Notes, geänderte Chunk-Grenzen. **Parameter:** - `--out PATH` : Zielverzeichnis (Default: `./test_vault`) - `--force` : Existierenden Ordner löschen und neu 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. **Kompatibilität:** - `note.schema.json`: `created`/`updated` sind Strings. **Beispiele:** python3 -m scripts.make_test_vault --out ./test_vault --force python3 -m scripts.make_test_vault --out ./test_vault --force --with-missing --- ## 2) Import in Qdrant ### `scripts/import_markdown.py` **Zweck:** 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 (ohne: Dry-Run) - `--purge-before-upsert` : Vor Upsert alte Chunks/Edges **nur der geänderten Notes** löschen - `--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:** # 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 ### `scripts/audit_vault_vs_qdrant.py` **Zweck:** 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 - `--prefix STR` : Prefix für Qdrant-Collections (Default: `mindnet`) **Beispiel:** python3 -m scripts.audit_vault_vs_qdrant --vault ./vault --prefix mindnet ### `scripts/validate_edges.py` **Zweck:** 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 - `--details` : Detailausgabe mit Beispielen **Beispiel:** python3 -m scripts.validate_edges --prefix mindnet --details --- ## 4) Export Qdrant → Markdown (Vault) ### `scripts/export_markdown.py` **Zweck:** 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:** - `--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 --- ## 6) Diagnose & Tools ### `scripts/diagnose_changed.py` **Zweck:** 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 - `--prefix STR` : Prefix (Default: `mindnet`) - `--note-id ID` : Nur bestimmte Note prüfen - `--all` : Alle Notes prüfen **Beispiel:** python3 -m scripts.diagnose_changed --vault ./vault --prefix mindnet --all ### `scripts/resolve_unresolved_references.py` **Zweck:** 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 - `--apply` : Änderungen wirklich ausführen (sonst nur Vorschau) **Beispiele:** python3 -m scripts.resolve_unresolved_references --prefix mindnet python3 -m scripts.resolve_unresolved_references --prefix mindnet --apply --- ## 7) Parser-Verhalten (robust & abwärtskompatibel) - 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 ./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) Änderungs-Propagation & Idempotenz** 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 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) Export & Roundtrip (Produkt-Vault)** 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