#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ make_test_vault.py — Erzeugt einen kleinen, reproduzierbaren Test-Vault für den Markdown-Importer. Version: 1.0.0 (2025-09-05) Änderungen: - Initiale Version mit 4 Szenarien (base, add-targets, change-chunking, cleanup) - Frontmatter entspricht Parser-Anforderungen: title, id, type, status, created (+ optionale Felder) (vgl. parser.validate_required_frontmatter) - Inhalte decken Wikilinks, zunächst fehlende Ziele (unresolved), spätere Zielanlage und Re-Chunking ab. Beschreibung: Erstellt unter ./test_vault/ eine kleine Ordnerstruktur mit Markdown-Dateien: - base: Legt 4 Notizen an. Zwei haben Wikilinks, wovon einige zunächst ins Leere zeigen (Ziel-Notizen existieren noch nicht). - add-targets: Legt die vorher fehlenden Ziel-Notizen an, so dass der Importer Kanten (references/backlink und references_at) auflösen kann. - change-chunking: Ändert eine bestehende Notiz so, dass sich die Chunk-Grenzen deutlich verschieben (Überschriften + Textblöcke). Dient zum Test, ob der Importer Notes/Chunks/Edges sauber nachzieht. - cleanup: Löscht den gesamten test_vault wieder. Aufruf: python3 -m scripts.make_test_vault --scenario base python3 -m scripts.make_test_vault --scenario add-targets python3 -m scripts.make_test_vault --scenario change-chunking python3 -m scripts.make_test_vault --scenario cleanup Hinweise: - Dieses Skript erzeugt KEINE Qdrant-Daten; es schreibt nur Markdown-Dateien. - Zum Testen: 1) base erzeugen → Importer (dry-run) → Audit vergleichen. 2) add-targets erzeugen → Importer erneut laufen lassen → prüfen, ob vormals „unresolved“ jetzt aufgelöst wurden (edges & edges_at). 3) change-chunking ausführen → Importer mit --apply → prüfen, ob Chunks/Edges umgezogen/aktualisiert wurden. - Verwende beim Importer denselben Vault-Pfad: --vault ./test_vault - Virtuelle Umgebung: Für dieses Skript selbst nicht nötig; für den Importer natürlich weiterhin in deinem venv laufen. """ from __future__ import annotations import argparse import os import shutil from pathlib import Path from datetime import datetime ROOT = Path(__file__).resolve().parents[1] # Projektwurzel (.. /mindnet) VAULT = ROOT / "test_vault" # ---------- Hilfsfunktionen ---------- def write_file(path: Path, content: str): path.parent.mkdir(parents=True, exist_ok=True) with open(path, "w", encoding="utf-8") as f: f.write(content) def iso_now(): return datetime.now().isoformat(timespec="seconds") # ---------- Inhalte (Szenario-Varianten) ---------- def file_index_base() -> str: # Enthält Links auf bestehende und noch NICHT bestehende Ziele return f"""--- title: "Index – Mini-Testvault" id: "test-index" type: "concept" status: "draft" created: {iso_now()} tags: ["area/test","type/concept"] --- ## Überblick Dies ist der kleine Test-Vault. ## Verweise - [[test-alpha]] (existiert) - [[test-beta]] (existiert) - [[test-gamma]] (existiert) - [[test-delta]] (FEHLT zunächst — wird erst in add-targets angelegt) """ def file_alpha_base() -> str: # Hat Wikilinks auf beta (existiert) und epsilon (fehlt zunächst) return f"""--- title: "Alpha" id: "test-alpha" type: "concept" status: "draft" created: {iso_now()} tags: ["area/test","type/concept"] --- ## Abschnitt A Alpha verweist auf [[test-beta]] und auf [[test-epsilon]] (FEHLT zunächst). ## Abschnitt B Noch etwas Text, damit beim Re-Chunking später Grenzen sichtbar werden. """ def file_beta_base() -> str: # Kurze Notiz ohne Links return f"""--- title: "Beta" id: "test-beta" type: "concept" status: "draft" created: {iso_now()} tags: ["area/test","type/concept"] --- Beta hat zunächst keine Links. """ def file_gamma_base() -> str: # Viele Abschnitte → erzeugt mehrere Chunks return f"""--- title: "Gamma" id: "test-gamma" type: "concept" status: "draft" created: {iso_now()} tags: ["area/test","type/concept"] --- ## Einleitung Dieser Abschnitt enthält einen Link zu [[test-index]]. ## Details Gamma liefert Details. Hier noch ein Link zu [[test-beta]]. ## Weitere Hinweise Hier steht Text, damit die Chunker-Logik genug Material hat. """ def file_delta_added() -> str: # Wird erst im Szenario add-targets erstellt (auflösen von vormals unresolved [[test-delta]]) return f"""--- title: "Delta (neu angelegt)" id: "test-delta" type: "concept" status: "draft" created: {iso_now()} tags: ["area/test","type/concept"] --- Delta wurde nachträglich angelegt, um ehemals leere Links aufzulösen. """ def file_epsilon_added() -> str: # Wird erst im Szenario add-targets erstellt (auflösen von [[test-epsilon]] aus Alpha) return f"""--- title: "Epsilon (neu angelegt)" id: "test-epsilon" type: "concept" status: "draft" created: {iso_now()} tags: ["area/test","type/concept"] --- Epsilon existiert nun und kann referenziert werden. """ def file_gamma_changed_chunking() -> str: # Ersetzt die ursprüngliche Gamma-Datei mit deutlich mehr (und anders geschnittenen) Abschnitten, # so dass sich die Chunk-Grenzen ändern. return f"""--- title: "Gamma (rechunked)" id: "test-gamma" type: "concept" status: "draft" created: {iso_now()} tags: ["area/test","type/concept"] --- # Einleitung (H1 statt H2) Kurzer Teaser. Verweis auf [[test-index]] bleibt bestehen. ## Teil 1 – Kontext Mehr Text. Dieser Abschnitt ist länger und soll den ursprünglichen „Details“-Block ersetzen. Außerdem Verweis auf [[test-beta]]. ## Teil 2 – Beispiele - Beispiel 1: Ein etwas längerer Listenpunkt mit Beschreibung. - Beispiel 2: Noch ein Punkt. - Beispiel 3: Und noch einer. ## Teil 3 – Fazit Zusammenfassung und ggf. ein weiterer Verweis auf [[test-alpha]]. """ # ---------- Szenarien ausführen ---------- def scenario_base(): # Frisch anlegen / überschreiben (VAULT / "notes").mkdir(parents=True, exist_ok=True) write_file(VAULT / "notes" / "index.md", file_index_base()) write_file(VAULT / "notes" / "alpha.md", file_alpha_base()) write_file(VAULT / "notes" / "beta.md", file_beta_base()) write_file(VAULT / "notes" / "gamma.md", file_gamma_base()) print(f"[base] Angelegt: {VAULT}") def scenario_add_targets(): # Nur neue Ziele hinzufügen (delta, epsilon) if not VAULT.exists(): print("test_vault fehlt – bitte erst --scenario base ausführen.") return write_file(VAULT / "notes" / "delta.md", file_delta_added()) write_file(VAULT / "notes" / "epsilon.md", file_epsilon_added()) print("[add-targets] Neue Zielnotizen delta/epsilon angelegt.") def scenario_change_chunking(): # Gamma ersetzen, um Chunk-Grenzen zu verschieben if not VAULT.exists(): print("test_vault fehlt – bitte erst --scenario base ausführen.") return write_file(VAULT / "notes" / "gamma.md", file_gamma_changed_chunking()) print("[change-chunking] gamma.md geändert (deutlich andere Abschnittsstruktur).") def scenario_cleanup(): if VAULT.exists(): shutil.rmtree(VAULT) print("[cleanup] test_vault gelöscht.") else: print("[cleanup] nichts zu tun – test_vault existiert nicht.") # ---------- CLI ---------- def main(): ap = argparse.ArgumentParser() ap.add_argument( "--scenario", required=True, choices=["base", "add-targets", "change-chunking", "cleanup"], help="Welches Setup erzeugt werden soll." ) args = ap.parse_args() if args.scenario == "base": scenario_base() elif args.scenario == "add-targets": scenario_add_targets() elif args.scenario == "change-chunking": scenario_change_chunking() elif args.scenario == "cleanup": scenario_cleanup() if __name__ == "__main__": main()