All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 2s
350 lines
14 KiB
Markdown
350 lines
14 KiB
Markdown
# 📘 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 & Änderungserkennung**
|
||
|
||
- `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#<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 ./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
|