docs/Handbuch.md aktualisiert
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 2s

This commit is contained in:
Lars 2025-10-06 14:22:47 +02:00
parent e99f1c2ba0
commit 66adc6a354

View File

@ -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#<n>`
- `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