Compare commits

...

13 Commits
v3.2.0 ... main

Author SHA1 Message Date
0d61a9e191 Update types.yaml to change chunking profiles and enhance detection keywords
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
- Replaced 'sliding_smart_edges' with 'structured_smart_edges' for multiple types to improve data processing.
- Added detection keywords for 'goal', 'concept', 'task', 'journal', 'source', 'glossary', 'person', and 'event' to enhance retrieval capabilities.
- Adjusted retriever weights for consistency across types.
2026-01-21 07:17:20 +01:00
55d1a7e290 Update decision_engine.yaml to add new relationship attributes for enhanced edge configuration
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
- Introduced 'upholds', 'violates', 'aligned_with', 'conflicts_with', 'supports', and 'contradicts' attributes to improve the decision engine's relationship handling.
- Added 'followed_by' and 'preceded_by' attributes to the facts_stream for better context in data relationships.
2026-01-20 12:36:10 +01:00
4537e65428 Update decision_engine.yaml to rename 'enforced_by' to 'depends_on' for clarity in edge boost configuration
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
2026-01-20 11:34:39 +01:00
43327c1f6d Update documentation for causal retrieval concept
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
- Added additional spacing for improved readability in the document.
- Ensured consistent formatting throughout the section on causal retrieval for Mindnet.
2026-01-15 11:49:31 +01:00
39a6998123 Implement Phase 3 Agentic Edge Validation and Chunk-Aware Multigraph-System
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
- Introduced final validation gate for edges with candidate: prefix.
- Enabled automatic generation of mirror edges for explicit connections.
- Added support for Note-Scope zones to facilitate global connections.
- Enhanced section-based links in the multigraph system for improved edge handling.
- Updated documentation and added new ENV variables for configuration.
- Ensured no breaking changes for end users, maintaining full backward compatibility.
2026-01-14 22:26:12 +01:00
273c4c6919 Update default COLLECTION_PREFIX to "mindnet" for production environments, requiring explicit setting of COLLECTION_PREFIX=mindnet_dev in .env for development. This change enhances clarity and ensures proper environment configuration.
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
2026-01-12 15:49:44 +01:00
2ed4488cf6 Enhance timeout handling and diagnostics in runtime service verification
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 5s
- Increased the timeout for LLM calls from 30 to 60 seconds to accommodate longer processing times.
- Added informative messages for potential timeout causes and troubleshooting tips to improve user awareness.
- Updated error handling to provide clearer feedback on query failures, emphasizing the resolution of the EdgeDTO issue.
2026-01-12 15:37:12 +01:00
36490425c5 Implement runtime check for EdgeDTO version support in health service
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
- Added a verification step in the health endpoint to check if the service supports 'explicit:callout' for EdgeDTO, providing clearer diagnostics.
- Updated the health response to include messages based on the EdgeDTO version support status, enhancing user awareness of potential issues.
- Adjusted the test query endpoint to reflect the correct path for improved functionality.
2026-01-12 15:34:56 +01:00
b8cb8bb89b Add runtime check for EdgeDTO version support in health endpoint
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
- Implemented a check in the health endpoint to determine if EdgeDTO supports explicit callouts, enhancing diagnostic capabilities.
- The check is non-critical and handles exceptions gracefully, ensuring the health response remains robust.
- Updated health response to include the new `edge_dto_supports_callout` field for better insight into EdgeDTO capabilities.
2026-01-12 15:31:38 +01:00
6d268d9dfb Enhance .env loading mechanism and EdgeDTO creation with error handling
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 4s
- Updated the .env loading process to first check for an explicit path, improving reliability in different working directories.
- Added logging for successful .env loading and fallback mechanisms.
- Enhanced EdgeDTO creation with robust error handling, including fallbacks for unsupported provenance values and logging of errors for better traceability.
2026-01-12 15:27:23 +01:00
df5f9b3fe4 angleichen der Default prefix für die Collections
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
2026-01-12 15:02:23 +01:00
5e67cd470c Merge pull request 'Update deterministic sorting of semantic_groups in build_edges_for_note to handle None values correctly. Introduced a custom sort function to ensure consistent edge extraction across batches, preventing variance in edge counts.' (#23) from WP24c_BugFix into main
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
Reviewed-on: #23
2026-01-12 11:42:01 +01:00
0b2a1f1a63 Update deterministic sorting of semantic_groups in build_edges_for_note to handle None values correctly. Introduced a custom sort function to ensure consistent edge extraction across batches, preventing variance in edge counts. 2026-01-12 11:31:20 +01:00
20 changed files with 2022 additions and 37 deletions

View File

@ -15,13 +15,44 @@ from dotenv import load_dotenv
# WP-20: Lade Umgebungsvariablen aus der .env Datei
# override=True garantiert, dass Änderungen in der .env immer Vorrang haben.
load_dotenv(override=True)
# WP-24c v4.5.10: Expliziter Pfad für .env-Datei, um Probleme mit Arbeitsverzeichnis zu vermeiden
# Suche .env im Projekt-Root (3 Ebenen über app/config.py: app/config.py -> app/ -> root/)
_project_root = Path(__file__).parent.parent.parent
_env_file = _project_root / ".env"
_env_loaded = False
# Versuche zuerst expliziten Pfad
if _env_file.exists():
_env_loaded = load_dotenv(_env_file, override=True)
if _env_loaded:
# Optional: Logging (nur wenn logging bereits initialisiert ist)
try:
import logging
_logger = logging.getLogger(__name__)
_logger.debug(f"✅ .env geladen von: {_env_file}")
except:
pass # Logging noch nicht initialisiert
# Fallback: Automatische Suche (für Dev/Test oder wenn .env an anderer Stelle liegt)
if not _env_loaded:
_env_loaded = load_dotenv(override=True)
if _env_loaded:
try:
import logging
_logger = logging.getLogger(__name__)
_logger.debug(f"✅ .env geladen via automatische Suche (cwd: {Path.cwd()})")
except:
pass
class Settings:
# --- Qdrant Datenbank ---
QDRANT_URL: str = os.getenv("QDRANT_URL", "http://127.0.0.1:6333")
QDRANT_API_KEY: str | None = os.getenv("QDRANT_API_KEY")
COLLECTION_PREFIX: str = os.getenv("MINDNET_PREFIX", "mindnet_dev")
# WP-24c v4.5.10: Harmonisierung - Unterstützt beide Umgebungsvariablen für Abwärtskompatibilität
# COLLECTION_PREFIX hat Priorität, MINDNET_PREFIX als Fallback
# WP-24c v4.5.10-FIX: Default auf "mindnet" (Prod) statt "mindnet_dev" (Dev)
# Dev muss explizit COLLECTION_PREFIX=mindnet_dev in .env setzen
COLLECTION_PREFIX: str = os.getenv("COLLECTION_PREFIX") or os.getenv("MINDNET_PREFIX") or "mindnet"
# WP-22: Vektor-Dimension für das Embedding-Modell (nomic)
VECTOR_SIZE: int = int(os.getenv("VECTOR_DIM", "768"))

View File

@ -44,7 +44,9 @@ class QdrantConfig:
port = os.getenv("QDRANT_PORT")
port = int(port) if port else None
api_key = os.getenv("QDRANT_API_KEY") or None
prefix = os.getenv("COLLECTION_PREFIX") or "mindnet"
# WP-24c v4.5.10: Harmonisierung - Unterstützt beide Umgebungsvariablen für Abwärtskompatibilität
# COLLECTION_PREFIX hat Priorität, MINDNET_PREFIX als Fallback
prefix = os.getenv("COLLECTION_PREFIX") or os.getenv("MINDNET_PREFIX") or "mindnet"
dim = int(os.getenv("VECTOR_DIM") or 384)
distance = os.getenv("DISTANCE", "Cosine")
on_disk_payload = (os.getenv("ON_DISK_PAYLOAD", "true").lower() == "true")

View File

@ -910,9 +910,20 @@ def build_edges_for_note(
# Schritt 3: ID-Zuweisung nach Scope-Entscheidung
final_edges: List[dict] = []
# WP-24c v4.5.9: Deterministische Sortierung der semantic_groups für konsistente Edge-Extraktion
# WP-24c v4.5.10: Deterministische Sortierung der semantic_groups für konsistente Edge-Extraktion
# Verhindert Varianz zwischen Batches (33 vs 34 Kanten)
sorted_semantic_keys = sorted(semantic_groups.keys())
# WICHTIG: target_section kann None sein, daher benötigen wir eine benutzerdefinierte Sortierfunktion
def sort_key_func(key_tuple):
"""
Sortierfunktion für semantic_keys, die None-Werte korrekt behandelt.
None wird als leere Zeichenkette behandelt, um Vergleichbarkeit zu gewährleisten.
"""
kind, semantic_source, target_id, target_section = key_tuple
# Konvertiere None zu leerem String für konsistente Sortierung
target_section_safe = target_section if target_section is not None else ""
return (kind, semantic_source, target_id, target_section_safe)
sorted_semantic_keys = sorted(semantic_groups.keys(), key=sort_key_func)
for semantic_key in sorted_semantic_keys:
group = semantic_groups[semantic_key]

View File

@ -216,17 +216,42 @@ def _build_explanation(
direction = "in" if tgt == target_note_id else "out"
edge_obj = EdgeDTO(
id=f"{src}->{tgt}:{kind}",
kind=kind,
source=src,
target=tgt,
weight=conf,
direction=direction,
provenance=prov,
confidence=conf
)
edges_dto.append(edge_obj)
# WP-24c v4.5.10: Robuste EdgeDTO-Erstellung mit Fehlerbehandlung
# Falls Provenance-Wert nicht unterstützt wird, verwende Fallback
try:
edge_obj = EdgeDTO(
id=f"{src}->{tgt}:{kind}",
kind=kind,
source=src,
target=tgt,
weight=conf,
direction=direction,
provenance=prov,
confidence=conf
)
edges_dto.append(edge_obj)
except Exception as e:
# WP-24c v4.5.10: Fallback bei Validierungsfehler (z.B. alte EdgeDTO-Version im Cache)
logger.warning(
f"⚠️ [EDGE-DTO] Provenance '{prov}' nicht unterstützt für Edge {src}->{tgt} ({kind}). "
f"Fehler: {e}. Verwende Fallback 'explicit'."
)
# Fallback: Verwende 'explicit' als sicheren Default
try:
edge_obj = EdgeDTO(
id=f"{src}->{tgt}:{kind}",
kind=kind,
source=src,
target=tgt,
weight=conf,
direction=direction,
provenance="explicit", # Fallback
confidence=conf
)
edges_dto.append(edge_obj)
except Exception as e2:
logger.error(f"❌ [EDGE-DTO] Auch Fallback fehlgeschlagen: {e2}. Überspringe Edge.")
# Überspringe diese Kante - besser als kompletter Fehler
# Die 3 wichtigsten Kanten als Begründung formulieren
top_edges = sorted(edges_dto, key=lambda e: e.confidence, reverse=True)

View File

@ -109,12 +109,23 @@ def create_app() -> FastAPI:
@app.get("/healthz")
def healthz():
"""Bietet Statusinformationen über die Engine und Datenbank-Verbindung."""
# WP-24c v4.5.10: Prüfe EdgeDTO-Version zur Laufzeit
edge_dto_supports_callout = False
try:
from app.models.dto import EdgeDTO
import inspect
source = inspect.getsource(EdgeDTO)
edge_dto_supports_callout = "explicit:callout" in source
except Exception:
pass # Fehler beim Prüfen ist nicht kritisch
return {
"status": "ok",
"version": "1.1.0",
"qdrant": s.QDRANT_URL,
"prefix": s.COLLECTION_PREFIX,
"moe_enabled": True
"moe_enabled": True,
"edge_dto_supports_callout": edge_dto_supports_callout # WP-24c v4.5.10: Diagnose-Hilfe
}
# Inkludieren der Router (100% Kompatibilität erhalten)

View File

@ -32,9 +32,14 @@ streams_library:
top_k: 5
edge_boosts:
guides: 3.0
enforced_by: 2.5
depends_on: 2.5
based_on: 2.0
upholds: 2.5
violates: 2.5
aligned_with: 2.0
conflicts_with: 2.0
supports: 1.5
contradicts: 1.5
facts_stream:
name: "Operative Realität"
llm_profile: "synthesis_pro"
@ -60,6 +65,8 @@ streams_library:
related_to: 1.5
experienced_in: 2.0
expert_for: 2.5
followed_by: 2.0
preceded_by: 2.0
risk_stream:
name: "Risiko-Radar"

View File

@ -94,7 +94,7 @@ llm_settings:
types:
experience:
chunking_profile: sliding_smart_edges
chunking_profile: structured_smart_edges
retriever_weight: 1.10
detection_keywords: ["erleben", "reagieren", "handeln", "prägen", "reflektieren"]
schema:
@ -104,7 +104,7 @@ types:
- "Reflexion & Learning (Was lerne ich daraus?)"
insight:
chunking_profile: sliding_smart_edges
chunking_profile: structured_smart_edges
retriever_weight: 1.20
detection_keywords: ["beobachten", "erkennen", "verstehen", "analysieren", "schlussfolgern"]
schema:
@ -114,7 +114,7 @@ types:
- "Handlungsempfehlung"
project:
chunking_profile: sliding_smart_edges
chunking_profile: structured_smart_edges
retriever_weight: 0.97
detection_keywords: ["umsetzen", "planen", "starten", "bauen", "abschließen"]
schema:
@ -214,7 +214,7 @@ types:
- "Strategie"
need:
chunking_profile: sliding_smart_edges
chunking_profile: structured_smart_edges
retriever_weight: 1.05
detection_keywords: ["bedürfnis", "brauchen", "mangel", "erfüllung"]
schema:
@ -223,7 +223,7 @@ types:
- "Bezug zu Werten"
motivation:
chunking_profile: sliding_smart_edges
chunking_profile: structured_smart_edges
retriever_weight: 0.95
detection_keywords: ["motivation", "antrieb", "warum", "energie"]
schema:
@ -244,14 +244,15 @@ types:
schema: ["Aktueller Zustand", "Auslöser", "Auswirkung auf den Tag"]
boundary:
chunking_profile: sliding_smart_edges
chunking_profile: structured_smart_edges
retriever_weight: 0.90
detection_keywords: ["grenze", "nein sagen", "limit", "schutz"]
schema: ["Die Grenze", "Warum sie wichtig ist", "Konsequenz bei Verletzung"]
goal:
chunking_profile: sliding_smart_edges
chunking_profile: structured_smart_edges
retriever_weight: 0.95
detection_keywords: ["ziel", "zielzustand", "kpi", "zeitrahmen", "deadline", "meilenstein"]
schema: ["Zielzustand", "Zeitrahmen & KPIs", "Motivation"]
risk:
@ -261,41 +262,49 @@ types:
schema: ["Beschreibung des Risikos", "Auswirkungen", "Gegenmaßnahmen"]
concept:
chunking_profile: sliding_smart_edges
retriever_weight: 0.60
chunking_profile: structured_smart_edges
retriever_weight: 0.6
detection_keywords: ["definition", "konzept", "begriff", "modell", "rahmen", "theorie"]
schema: ["Definition", "Kontext", "Verwandte Konzepte"]
task:
chunking_profile: sliding_short
retriever_weight: 0.80
retriever_weight: 0.8
detection_keywords: ["aufgabe", "todo", "next_action", "erledigen", "definition_of_done", "checkliste"]
schema: ["Aufgabe", "Kontext", "Definition of Done"]
journal:
chunking_profile: sliding_standard
retriever_weight: 0.80
retriever_weight: 0.8
detection_keywords: ["journal", "tagebuch", "log", "eintrag", "reflexion", "heute"]
schema: ["Log-Eintrag", "Gedanken"]
source:
chunking_profile: sliding_standard
retriever_weight: 0.50
retriever_weight: 0.5
detection_keywords: ["quelle", "paper", "buch", "artikel", "link", "zitat", "studie"]
schema: ["Metadaten", "Zusammenfassung", "Zitate"]
glossary:
chunking_profile: sliding_short
retriever_weight: 0.40
retriever_weight: 0.4
detection_keywords: ["glossar", "begriff", "definition", "terminologie"]
schema: ["Begriff", "Definition"]
person:
chunking_profile: sliding_standard
retriever_weight: 0.50
schema: ["Rolle", "Beziehung", "Kontext"]
retriever_weight: 0.5
detection_keywords: ["person", "mensch", "kontakt", "name", "beziehung", "stakeholder"]
schema: ["Profile", "Beziehung", "Kontext"]
event:
chunking_profile: sliding_standard
retriever_weight: 0.60
retriever_weight: 0.6
detection_keywords: ["ereignis", "termin", "datum", "ort", "teilnehmer", "meeting"]
schema: ["Datum & Ort", "Teilnehmer", "Ergebnisse"]
default:
chunking_profile: sliding_standard
retriever_weight: 1.00
retriever_weight: 1.0
detection_keywords: []
schema: ["Inhalt"]

1
debug.log Normal file
View File

@ -0,0 +1 @@
[0114/152756.633:ERROR:third_party\crashpad\crashpad\util\win\registration_protocol_win.cc:108] CreateFile: Das System kann die angegebene Datei nicht finden. (0x2)

View File

@ -0,0 +1,394 @@
# Mindnet Causal Assistant Dokumentation der bisher erreichten Resultate (0.4.x) + Architektur, Konfiguration & Strategien
> Stand: basierend auf den beobachteten Chain-Inspector-Logs und den zuletzt beschriebenen Implementierungen in 0.4.6/0.4.x.
> Ziel dieser Doku: Eine **einheitliche, belastbare Basis**, damit Weiterentwicklung (0.5.x/0.6.x) nicht mehr “im Kreis” läuft.
---
## 1) Zweck & Gesamtziel von Mindnet
Mindnet soll in einem Obsidian Vault **kausale/argumentative Zusammenhänge** als Graph abbilden und daraus **nützliche Diagnosen** ableiten:
- **Graph-Aufbau:** Notes/Sections als Knoten, Links/Kanten als gerichtete Beziehungen (z.B. *wirkt_auf*, *resulted_in*, *depends_on* …).
- **Analyse aus einem Kontext:** Nutzer steht in einer Note an einer bestimmten Überschrift/Section → Mindnet analysiert lokale Nachbarschaft + Pfade im Graphen.
- **Template Matching:** Einordnen der gefundenen Knoten/Kanten in “Kettenmuster” (Chain Templates) wie z.B. *trigger → transformation → outcome* oder *loop_learning*.
- **Findings (Gap-Heuristiken):** Hinweise wie “fehlende Slots”, “fehlende Links”, “unmapped edge types”, “einseitige Konnektivität”, etc.
→ Ziel: **Nutzer konkret zum besseren Graphen führen**, ohne “Noisy” zu sein.
---
## 2) Begriffe & Datenmodell (so arbeitet der Chain Inspector)
### 2.1 Kontext (Context)
Der Chain Inspector läuft immer gegen einen **aktuellen Kontext**:
- `file`: aktuelle Note (z.B. `Tests/03_insight_transformation.md`)
- `heading`: aktuelle Section (z.B. `Kern`)
- `zoneKind`: i.d.R. `content`
Das ist wichtig, weil Kanten teils **section-spezifisch** sind und teils (geplant/teilweise offen) **note-weit** gelten könnten.
---
### 2.2 Knoten (Nodes)
Ein Knoten ist im Report meist referenziert als:
- `file + heading` (z.B. `Tests/01_experience_trigger.md:Kontext`)
- plus abgeleitete Metadaten wie `noteType` (z.B. experience, insight, decision, event)
**noteType** ist entscheidend fürs Template Matching (Slots).
---
### 2.3 Kanten (Edges)
Eine Kante hat typischerweise:
- `rawEdgeType`: Original-Typ aus Markdown/Notation (z.B. `wirkt_auf`, `resulted_in`, `depends_on`, `derived_from`, …)
- `from`: Quelle (file:heading)
- `to`: Ziel (file:heading)
- `scope`: Gültigkeit / Herkunft
- `section`: Edge ist “voll gültig” für die Section
- `candidate`: Edge ist nur Kandidat/unsicher, wird optional zugelassen
- (geplant/offen) `note`: Edge gilt note-weit (unabhängig von Section)
- `evidence`: Fundstelle (file, sectionHeading, lineRange)
---
## 3) Erreichte Resultate in 0.4.x (verifiziert)
### 3.1 includeCandidates Kandidatenkanten funktionieren wie erwartet
**Ergebnis (bereits mehrfach in Logs verifiziert):**
- Wenn `includeCandidates=false`, werden Kanten mit `scope: candidate` **im effektiven Graphen ausgefiltert**.
- Wenn `includeCandidates=true`, werden Kandidatenkanten **als incoming/outgoing** berücksichtigt und tauchen in `neighbors`/`paths` auf.
**Implikation:**
- Das System kann “unsichere” oder “LLM-vorschlagene” Verbindungen existieren lassen, ohne in jedem Lauf die Analyse zu verfälschen.
- In “Discovery” kann man Kandidaten zulassen (mehr Explorationspower).
- In “Decisioning” kann man Kandidaten typischerweise sperren (mehr Verlässlichkeit).
---
### 3.2 required_links: Strict vs Soft Mode missing_link_constraints Unterdrückung ist umgesetzt
**Problem (historisch):**
- `missing_link_constraints` wurde teilweise auch dann ausgegeben, wenn `required_links=false` (Soft Mode) aktiv war → unnötig “noisy”.
**Fix (laut Cursor-Report umgesetzt + Tests):**
- `missing_link_constraints` wird nur erzeugt, wenn `effectiveRequiredLinks === true`.
- Es gibt eine definierte Auflösungsreihenfolge für `required_links`:
**Resolution Order (effective required_links):**
1. `template.matching?.required_links`
2. `profile.required_links`
3. `defaults.matching?.required_links`
4. Fallback: `false`
**Transparenz bleibt erhalten:**
- `satisfiedLinks` und `requiredLinks` werden weiterhin im Report angezeigt.
- `linksComplete` bleibt als technischer Wert im Report bestehen.
- **Nur** das Finding `missing_link_constraints` wird unterdrückt, nicht die Fakten.
**Implikation:**
- Soft Mode (= required_links=false) ist jetzt ruhig genug, um “Entdeckung” zu unterstützen.
- Strict Mode (= required_links=true) eignet sich für harte Qualitätskontrolle.
---
### 3.3 “Healthy graph” → Findings leer ([]), Template “confirmed”
Wenn Slots **und** geforderte Links erfüllt sind (z.B. `trigger_transformation_outcome` mit 2/2 Links),
dann ist `findings: []` das erwartete Ergebnis.
**Implikation:**
- Das ist das zentrale “Green Path”-Signal: Graph ist konsistent für das gewählte Template/Profil.
---
### 3.4 Unmapped edges werden erkannt (Diagnose)
Wenn ein `rawEdgeType` nicht in die kanonischen Rollen/Edge-Rollen abgebildet werden kann, tauchen typischerweise Diagnosen auf:
- `edgesUnmapped > 0`
- Findings wie `no_causal_roles` oder link constraints bleiben unerfüllt
**Implikation:**
- Das Rollen-Mapping (chain_roles.yaml) ist “critical path”: wenn ein Edge-Typ nicht gemappt wird, bricht oft der kausale Interpretationspfad.
---
## 4) Was ist (noch) offen echtes nächstes Verifikationsziel
### 4.1 Note-Level Edges / Note-Scope (“für jede Sektion gültig”)
Es existiert ein Konzept/Einbau: In `02_event_trigger_detail` gibt es einen Bereich, der Kanten **auf Note-Ebene** definieren soll (unabhängig von aktueller Section).
**Offen ist die robuste Verifikation (oder Implementierung), dass:**
- diese Edges auch dann gelten, wenn der Cursor in einer anderen Section derselben Note steht,
- idealerweise mit klar erkennbarer Kennzeichnung wie `scope: note` im Report.
**Warum ist das wichtig?**
- Das ermöglicht “globaler Kontext” pro Note, ohne alles in jede Section duplizieren zu müssen.
- Es ist eine UX-Optimierung: Nutzer kann “Meta-Verbindungen” an einer Stelle pflegen.
---
## 5) Konfigurationsdateien Rolle & Interpretation (Mindnet-Strategie)
> Die folgenden Bereiche beschreiben eine **saubere, konsistente Interpretation**, wie Mindnet die Configs verwenden sollte.
> Konkrete Keys, die in Logs sichtbar waren (z.B. required_links, min_slots_filled_for_gap_findings, min_score_for_gap_findings) sind hier berücksichtigt.
### 5.1 chain_templates.yaml “Welche Ketten gibt es, wie werden sie gematcht?”
**Zweck:**
- Definiert Templates (Muster), z.B.:
- `trigger_transformation_outcome`
- `loop_learning`
- ggf. weitere (constraint_to_adaptation usw.)
**Template enthält typischerweise:**
- Slots (Rollen für Knoten): z.B. `trigger`, `transformation`, `outcome`, `experience`, `learning`, `behavior`, `feedback`
- Required Link Constraints (welche Slot-zu-Slot Verbindungen zwingend sind)
- Scoring/Matching-Parameter (ggf. weights, thresholds)
- Optional: template-level override für `required_links`
**Matching-Profile (wie in Logs sichtbar):**
- z.B. Profile: `discovery`, `decisioning`
- Parameter im Profil (sichtbar in Logs):
- `required_links` (strict vs soft)
- `min_slots_filled_for_gap_findings`
- `min_score_for_gap_findings`
- ggf. `maxTemplateMatches`
**Interpretation:**
- Templates liefern die “Soll-Struktur”
- Profile bestimmen “Wie streng” wir die Soll-Struktur im jeweiligen Workflow bewerten
---
### 5.2 chain_roles.yaml “Welche rawEdgeTypes zählen als welche Rollen?”
**Zweck:**
- Mappt `rawEdgeType` → kanonische Rollen/EdgeRoles (z.B. `causal`, `influences`, `enables_constraints`, `provenance`).
- Diese Rollen sind Grundlage für:
- `no_causal_roles` Finding
- Link-Constraint-Satisfaction (Template erwartet “causal” zwischen Slots)
- Matching Score (welche Edges zählen für welches Template)
**Interpretation:**
- Wenn ein Edge-Typ nicht gemappt ist:
- Edge kann trotzdem im Graph auftauchen,
- aber Template/Constraint-Logik kann ihn nicht “verstehen” → führt zu Findings.
---
### 5.3 analysis_policies.yaml “Wie noisy dürfen Findings sein?”
**Zweck:**
- Zentrale Policies für Findings:
- welche Finding-Codes existieren
- Default-Severity (info/warn/error)
- Profilabhängige Overrides
- Unterdrückungsregeln (z.B. suppress in soft mode, suppress wenn confirmed, suppress wenn Score hoch…)
**Interpretation:**
- Policies sind “produktseitige UX-Regeln”:
- Discovery: eher informativ, weniger warn
- Decisioning: klare Warnungen, wenn Qualität fehlt
- Der bereits umgesetzte Fix (`missing_link_constraints` nur in strict) ist exakt so eine Policy-Entscheidung (auch wenn technisch im Inspector gelöst).
---
## 6) Ablauf des Chain Inspectors (Vorgehensweise in Mindnet)
Hier ist ein konsistenter “Pipeline”-Ablauf, der zu den Logs passt:
### Schritt 1: Kontext bestimmen
- Aktuelle Datei + aktuelle Section/Heading
### Schritt 2: Edges aus aktueller Note laden
- Outgoing aus der aktuellen Section extrahieren (oder aus einem definierten Block)
- (optional/offen) Note-Level Edges ebenfalls laden und für jede Section gültig machen
### Schritt 3: Nachbarn laden
- Backlinks (Notes, die auf die aktuelle Note verlinken) → incoming Kandidatenquellen
- Outgoing Neighbor Notes (Notes, auf die aktuelle Note verweist) → Nachbarschaft erweitern
### Schritt 4: Edges aus Neighbor Notes laden
- Aus den verlinkenden Notes die Edges extrahieren, die auf die aktuelle Note/Section zielen
- Canonicalization: rawEdgeTypes via chain_roles.yaml in Rollen überführen
### Schritt 5: Kandidatenfilter / Scopefilter anwenden
- Wenn `includeCandidates=false`:
- `scope: candidate` aus effective graph entfernen
- Optional weitere Filter:
- includeNoteLinks / includeSectionLinks
- direction (forward/backward/both)
- maxDepth (Traversal)
### Schritt 6: Pfade berechnen (Paths)
- Forward/Backward (oder both)
- BFS/DFS bis `maxDepth`
- Resultat: Pfadlisten mit nodes + edges
### Schritt 7: Template Matching
- Kandidatenknoten für Slots finden (via noteType + Nähe + Pfade)
- Links/Constraints prüfen (erwartete slot→slot Beziehungen)
- Score berechnen (z.B. per:
- Slots erfüllt
- Link constraints erfüllt
- “RoleEvidence” passend)
### Schritt 8: Findings berechnen (Gap-Heuristics)
Beispiele:
- `missing_slot_*` wenn wichtige Slots fehlen (abhängig von Profil-Thresholds)
- `one_sided_connectivity` wenn nur incoming oder nur outgoing
- `no_causal_roles` wenn Edges da, aber keine causal Rollen im effektiven Graph
- `missing_link_constraints` nur wenn effectiveRequiredLinks=true und slotsComplete=true, requiredLinks>0, linksComplete=false
### Schritt 9: Report ausgeben
- context, settings, neighbors, paths, findings, analysisMeta, templateMatches
- Transparenz: satisfiedLinks/requiredLinks/linksComplete bleiben sichtbar
---
## 7) Strategien, die Mindnet verfolgen kann (Produkt-/UX-Strategie)
### Strategie A: Discovery (Exploration)
**Ziel:** Möglichst schnell “wo könnte eine sinnvolle Kette entstehen?” finden.
- required_links = false (Soft Mode)
- includeCandidates = true (optional)
- findings eher informativ (info), weniger warn
- Templates mehr als Vorschläge (“plausible/weak”), nicht als harte Bewertung
**Vorteil:** Nutzer bekommt schnell Hypothesen.
**Risiko:** Mehr Noise, mehr falsche Kandidaten muss per Policy gedämpft werden.
---
### Strategie B: Decisioning (Qualitätskontrolle)
**Ziel:** Prüfung, ob eine Kette “wirklich steht” und als belastbar gelten kann.
- required_links = true (Strict Mode)
- includeCandidates = false
- findings: warn, wenn Slots/Links fehlen
- “confirmed” nur wenn link constraints komplett
**Vorteil:** Qualitätssicherung & Verlässlichkeit.
**Risiko:** Nutzer fühlt sich “blockiert”, wenn Graph noch im Aufbau ist.
---
### Strategie C: Progressive Disclosure (hybrid)
**Ziel:** Nutzer nicht überfordern, aber zielgerichtet verbessern.
- Soft Mode für Einstieg
- Button/Toggle: “Strict prüfen”
- Candidate Edges als Vorschlag-Klasse (UI: “proposed edges”)
- Findings priorisieren: erst fehlende Slots, dann fehlende Links, dann Detail-Qualität
---
## 8) Wie ein “kausaler Retriever” funktionieren könnte (Causal Retriever)
Ein kausaler Retriever ist die Komponente, die aus dem Vault/Graphen **relevante Kausalkontexte** für den aktuellen Abschnitt liefert idealerweise deterministisch, skalierbar und template-aware.
### 8.1 Retrieval-Ziele
- Finde Knoten/Edges, die **kausal relevant** sind zum aktuellen Kontext:
- Ursachen (backward)
- Wirkungen/Entscheidungen (forward)
- Bedingungen/Constraints (seitlich)
- Gib nicht nur Knoten zurück, sondern:
- Pfade (explainable)
- Evidence (wo steht das)
- Role-Interpretation (warum ist das causal/influences/etc.)
### 8.2 Retrieval-Inputs
- startNode = current section
- direction = forward/backward/both
- maxDepth
- roleFilter (optional): nur causal/influences/enables_constraints
- scopeFilter: includeCandidates, includeNoteLevel
- templateBias: bevorzugte Pfadformen (z.B. “experience→insight→decision”)
### 8.3 Retrieval-Algorithmus (praktisch)
**Variante 1: BFS mit Rolle-Gewichtung**
- BFS über Kanten
- Priorität/Score pro Frontier:
- causal > influences > provenance
- section-scope > note-scope > candidate (wenn candidates eingeschaltet, sonst candidate=∞)
- Stop, wenn:
- maxDepth erreicht
- genug Top-N Pfade gesammelt (z.B. topNUsed)
**Variante 2: Template-driven Retrieval**
- Wenn ein Template im Fokus ist:
- suche explizit nach Slot-Knoten (noteType matching)
- suche dann die minimalen Verbindungen, die Constraints erfüllen
- Gute Option für “Decisioning”: deterministisch prüfen.
**Variante 3: Two-phase Retrieval**
1) Kandidaten finden (Slots)
2) Verbindungen prüfen (Constraints)
→ Liefert sehr gut “warum fehlt Link X?” Diagnosen.
### 8.4 Output-Format
- `neighbors` (incoming/outgoing, mit evidence)
- `paths` (forward/backward, nodes+edges)
- plus “slot candidates” optional (für UI)
---
## 9) Empfehlungen für robuste Tests (damit ihr nicht wieder im Kreis lauft)
### Was ist bereits ausreichend getestet (nicht wiederholen)
- includeCandidates Filterverhalten ✅
- missing_link_constraints Unterdrückung bei required_links=false ✅
- strict/soft required_links via profile/template override ✅
- “healthy graph” ergibt findings: [] ✅
- unmapped edge type triggert Diagnose ✅
### Was als einziges “neues” Testziel für Abschluss 0.4.x/Start 0.5.x taugt
- **Note-level edges / note-scope**: gelten Kanten “global” pro Note oder nicht?
**Minimal-Testdefinition (einmalig, reproduzierbar):**
1) In `02_event_trigger_detail.md` einen klaren Note-Level Block definieren (z.B. “## Note-Verbindungen”).
2) Edge dort definieren, die auf eine andere Note/Section zeigt.
3) Cursor in einer anderen Section derselben Note platzieren (z.B. “## Detail” oder “## Extra”).
4) Chain Inspector laufen lassen.
5) Erwartung:
- Edge erscheint trotzdem als outgoing/incoming
- evidence zeigt auf den Note-Level Block
- ideal: `scope: note`
Wenn das FAIL ist → klarer 0.5.0 Task.
---
## 10) Implikationen für 0.5.x / 0.6.x (wohin sinnvoll weiter)
### 0.5.x (Stabilisierung)
- Note-level edge scope finalisieren (inkl. Report-Transparenz)
- policies (analysis_policies) als zentrale Noise-Steuerung weiter ausbauen
- Debug/Explainability weiter verbessern (effectiveRequiredLinks pro Match explizit ausgeben)
### 0.6.x (UX & Workflows)
- Actionable Findings: “Was genau soll ich ändern?” inkl. Vorschlagtext oder Snippet
- UI-Toggles: Strict/Soft, Candidates on/off
- Template Authoring Tools: Linter, “Warum kein Match?”
---
## 11) Kurzes “Was heißt das für Mindnet im Alltag?”
- Im Discovery-Modus: Mindnet ist ein **Explorationswerkzeug** (Hypothesen + Hinweise, wenig Warnungen).
- Im Decisioning-Modus: Mindnet ist ein **Qualitätsprüfer** (strict, wenige false positives).
- Der nächste große Hebel ist Note-scope: Damit wird Pflege einfacher und Ketten werden “wartbarer”.
---
## 12) Appendix: Beispielhafte Report-Signale (Interpretationshilfe)
- `findings: []` + `confidence: confirmed`
→ Template passt sauber (Slots + Links vollständig im gewählten Modus).
- `linksComplete=false` aber `required_links=false` und **kein** `missing_link_constraints`
→ Soft Mode: bewusst kein “Warn-Noise”, aber Transparenz bleibt.
- `no_causal_roles`
→ Edges existieren, aber keine davon wird als “causal” interpretiert (Mapping oder rawEdgeType Problem).
- `edgesUnmapped > 0`
→ chain_roles unvollständig oder Edge-Typ ist neu/fehlerhaft geschrieben.
- `effectiveIncoming=0` bei includeCandidates=false, aber incoming candidate-edge existiert
→ Filter funktioniert wie geplant.
---
ENDE

View File

@ -0,0 +1,223 @@
<!-- FILE: konzept_zielbild_kausales_retrieval_mindnet.md -->
---
id: konzept_zielbild_kausales_retrieval_mindnet
title: Konzept & Zielbild Kausalketten-Prüfung und kausales Retrieval für Mindnet (Qdrant)
type: concept
status: draft
created: 2026-01-13
lang: de
tags:
- mindnet
- obsidian
- knowledge_graph
- causal_chains
- retrieval
---
# Konzept & Zielbild Kausalketten-Prüfung und kausales Retrieval für Mindnet (Qdrant)
## Ziel
Mindnet soll zu beliebigen Fragestellungen **die richtigen Notizen** nicht nur über semantische Nähe (Embeddings), sondern über **kausale Relevanz** finden.
Parallel soll ein Authoring-Assistent helfen, Obsidian-Notizen so anzulegen, dass Kausalketten **formal konsistent** und **traversierbar** sind.
---
## Ausgangslage / Problem
- Der Wissensgraph wird in Qdrant gepflegt; aktuelles Retrieval basiert primär auf **Gewichtung + semantischer Nähe**.
- Ergebnis: thematisch nahe Treffer, aber oft **nicht antwortrelevant** (fehlende Ursachen-/Folgenbezüge).
- Obsidian-Notizen enthalten Edges (Vorwärts/Rückwärts); Qualität hängt von:
- korrekter Relation (Kausalität vs Chronologie),
- konsistenten Node-Namen,
- Inversen (gegenläufigen Beziehungen),
- sauberer Typisierung ab.
---
## Grundannahmen
- Viele Antworten benötigen einen **Erklärungspfad** statt eines Einzel-Treffers:
- Ursache → Mechanismus/Transformation → Entscheidung → Wirkung → Rückkopplung
- Kausalität ist im Graph als gerichtete Kanten modelliert und über inverse Typen **bidirektional navigierbar**:
- `resulted_in``caused_by`
- `followed_by``preceeded_by`
- `derived_from``source_of`
- `impacts``impacted_by`
---
## System-Zielbild (2 Hauptkomponenten)
### 1) Authoring-Assistent (Obsidian Graph Linter + Chain Explorer)
Zweck: Qualitätssicherung beim Erstellen/Ändern von Notizen.
**Kernfunktionen**
- **Formale Prüfungen**
- Canonical Edge vs Alias (Normalisierung nach `edge_vocabulary`)
- Zielnoten existieren / leere Links als `open_question` oder TODO markieren
- Tippfehler/Node-Splitting erkennen (mehrere Schreibweisen desselben Knoten)
- Edge-Typ zulässig für Note-Typ (z.B. keine Kausal-Edges aus `open_question`)
- **Semantische Plausibilität (regelbasiert)**
- Chronologie (`followed_by`) ≠ Kausalität (`resulted_in`)
- Hub-/Index-Noten nutzen primär `related_to/consists_of` statt Kausalität
- Prinzipien bevorzugt `derived_from/based_on` statt pauschal `caused_by`
- **Ketten-Integrität**
- „Gap“-Warnungen (Sprünge ohne Zwischennoten)
- Zyklen ohne Sinn (A caused_by B und B caused_by A)
- Mehrfachursachen transparent markieren
**Outputs**
- Lint-Report pro Note (Fehler/Warnung/Empfehlung)
- Chain-Preview (24 Schritte vorwärts/rückwärts)
- Optional: Auto-Fix-Vorschläge (Alias→Canonical, Link-Normalisierung, Inversen ergänzen)
---
### 2) Mindnet Retrieval: Hybrid aus Embeddings + Graph Traversal + Reranking
Zweck: Aus einer Frage automatisch eine **kleine, kausal zusammenhängende** Menge von Notizen auswählen.
**Pipeline**
1. **Seed Retrieval (Qdrant Embeddings)**
- Top-K Kandidaten (z.B. 30) als Startpunkte
- Optional: Filter nach Node-Typ (z.B. bei „Welche Entscheidungen…“)
2. **Intent-Klassifikation (Frage → Richtung & Kettenform)**
- Regelbasiert (Start) oder später ML-Classifier
- Output: `{direction, preferred_edges, target_types, max_hops, need_explanation_chain}`
3. **Graph Expansion (Multi-Source Multi-Hop Traversal)**
- Expandiert von Seeds 13 Hops (typisch 24)
- Richtungslogik:
- „Warum/Ursache“ → rückwärts (`caused_by`, `preceeded_by`, `derived_from`)
- „Folgen/Ergebnis“ → vorwärts (`resulted_in`, `followed_by`, `impacts`)
- „Entwicklung/Veränderung“ → beides (forward + backward)
- Ergebnis: Pfad-Kandidaten (nicht nur Nodes)
4. **Reranking (Antwortrelevanz)**
- Score = Semantik + Pfadqualität + Antwortform-Passung
5. **Antwort-Bausteine (Minimal Explanation Subgraph)**
- Merged Top-Pfade zu einem kleinen Subgraph (z.B. 812 Nodes)
- Pruning nach zentralen Knoten und erklärender Kettenform
---
## Spezifikation: Intent → Traversal Mode (Heuristik)
### Intent-Struktur
- `direction`: `backward | forward | both`
- `preferred_edges`: Menge Edge-Typen
- `target_types`: Menge Node-Typen
- `max_hops`: int
- `need_explanation_chain`: bool
### Heuristik (Deutsch)
- **Warum / Ursache / Auslöser / wodurch / wie kam es dazu**
- direction: backward
- preferred_edges: `{caused_by, preceeded_by, derived_from}`
- target_types: `{experience, decision, strategy, state}`
- max_hops: 24
- **Was führte zu / Folgen / Auswirkungen / resultierte in**
- direction: forward
- preferred_edges: `{resulted_in, followed_by, impacts}`
- target_types: `{decision, strategy, state, principle}`
- max_hops: 24
- **Entwicklung / Veränderung / Weltbild / Glaubenssatz / Charakter**
- direction: both
- preferred_edges backward: `{caused_by, derived_from}`
- preferred_edges forward: `{resulted_in, impacts}`
- target_types: `{principle, state, strategy, decision}`
- max_hops: 24
- need_explanation_chain: true
---
## Spezifikation: Traversal (Weighted Multi-Hop)
### Gewichte (Startwerte)
**Edge Weights**
- `resulted_in`: 1.00
- `caused_by`: 1.00
- `derived_from`: 0.90
- `source_of`: 0.90
- `impacts`: 0.70
- `impacted_by`: 0.70
- `followed_by`: 0.50
- `preceeded_by`: 0.50
- `related_to`: 0.25
- `part_of/consists_of`: 0.25
**Node-Type Weights**
- `experience`: 1.00
- `decision`: 1.00
- `strategy`: 0.90
- `state`: 0.85
- `principle`: 0.85
- `insight(hub)`: 0.35
- `open_question/hypothesis/white_spot`: 0.00 (Filter)
**Hop Decay**
- `hop_decay(h) = 0.75^h`
### Traversal-Logik (pseudocode-nah)
- Multi-Source-Expansion ab Seeds
- Pfade priorisiert nach kumuliertem Pfadscore
- `visited` verhindert endlose Wiederholungen
---
## Spezifikation: Reranking (Semantik + Kausalität + Antwortform)
### Final Score
- `final_score(path) = alpha*semantic + beta*coherence + gamma*shape_match`
Startwerte:
- `alpha = 0.55` (Semantik)
- `beta = 0.30` (Kausal-Kohärenz)
- `gamma = 0.15` (Passung zur Frageform)
**Causal Coherence**
- Bonus, wenn Pfad Kausal-Edges enthält (`resulted_in/caused_by/derived_from`)
- Malus, wenn nur Navigation/Chronologie enthalten ist
- Bonus für Kernform: `experience → decision → (state|strategy|principle)`
---
## Output: Minimal Explanation Subgraph (MES)
Ziel: nicht eine Liste, sondern ein erklärendes Subgraph-Set.
**Regeln**
- Top-Pfade (z.B. 35) mergen
- max_nodes: 812
- Pruning:
- Hubs raus, wenn sie nur Navigation sind
- Decision/Principle/State bevorzugen (Antwortanker)
- Bridge-Nodes behalten (in mehreren Pfaden vorkommend)
---
## Authoring-Regeln (Graph-Hygiene) harte Leitplanken
1. Kausalität nur auf atomaren Noten (`experience/decision/state/strategy/principle`)
2. Hubs/Indexnoten: primär `related_to/consists_of` (keine „Hub verursacht X“-Kausalität)
3. Inverse Edges müssen erzeugbar sein (oder Build-Step erzeugt sie deterministisch)
4. Chronologie strikt trennen (`followed_by` ≠ `resulted_in`)
5. Prinzipien: `derived_from/based_on` für Herkunft (statt pauschal `caused_by`)
6. Leere Links als `open_question` oder TODO ohne Kausal-Edge
7. Kanonische Dateinamen: Node-Splitting verhindern
---
## Nutzen / Erfolgskriterien
- **Bessere Answer Relevance**: Mindnet liefert Knoten mit erklärender Kausalstruktur statt nur thematischer Nähe
- **Erklärbarkeit**: Antwort kann mit Pfad(en) begründet werden
- **Debuggability**: Fehlantworten lassen sich auf falsche/fehlende Kanten zurückführen
- **Authoring-Effizienz**: Assistent verhindert typische Edge-Fehler früh
---
## Offene Punkte (für nächste Iteration)
- Intent-Taxonomie (812 Frageklassen) finalisieren und evaluieren
- Welche Edges werden als „kausal“ im engeren Sinne akzeptiert?
- Welche Node-Typen sind Pflichtmetadaten für Mindnet?
- Evaluation: Retrieval-Qualität mit/ohne Traversal (A/B)

View File

@ -0,0 +1,105 @@
# Debug: .env-Lade-Problem in Prod
**Datum**: 2026-01-12
**Version**: v4.5.10
**Status**: 🔴 Kritisch
## Problem
Möglicherweise wird die `.env`-Datei in Prod nicht korrekt geladen, was zu:
- Falschen Log-Levels (DEBUG=true wird ignoriert)
- Falschen Collection-Präfixen
- Falschen Konfigurationen
führen kann.
## Diagnose
### Schritt 1: Prüfe, ob .env-Datei existiert
```bash
# In Prod
cd ~/mindnet
ls -la .env
cat .env | head -20
```
### Schritt 2: Prüfe Arbeitsverzeichnis beim Start
```bash
# In Prod - prüfe, von wo uvicorn gestartet wird
ps aux | grep uvicorn
# Oder in systemd service:
cat /etc/systemd/system/mindnet.service | grep WorkingDirectory
```
### Schritt 3: Verifikations-Script ausführen
```bash
# In Prod
cd ~/mindnet
source .venv/bin/activate
python3 scripts/verify_env_loading.py
```
**Erwartete Ausgabe**:
```
✅ .env geladen von: /path/to/mindnet/.env
✅ COLLECTION_PREFIX = mindnet
✅ DEBUG = true
```
### Schritt 4: Manuelle Verifikation
```python
# In Python-REPL in Prod
import os
from pathlib import Path
from dotenv import load_dotenv
# Prüfe aktuelles Verzeichnis
print(f"CWD: {Path.cwd()}")
print(f"Projekt-Root: {Path(__file__).parent.parent.parent}")
# Lade .env
env_file = Path(".env")
if env_file.exists():
load_dotenv(env_file, override=True)
print(f"✅ .env geladen: {env_file.absolute()}")
else:
print(f"❌ .env nicht gefunden in: {env_file.absolute()}")
# Prüfe kritische Variablen
print(f"DEBUG: {os.getenv('DEBUG', 'NICHT GESETZT')}")
print(f"COLLECTION_PREFIX: {os.getenv('COLLECTION_PREFIX', 'NICHT GESETZT')}")
```
## Mögliche Ursachen
### 1. Arbeitsverzeichnis-Problem
- **Problem**: uvicorn wird aus einem anderen Verzeichnis gestartet
- **Lösung**: Expliziter Pfad in `config.py` (bereits implementiert)
### 2. .env-Datei nicht im Projekt-Root
- **Problem**: .env liegt in `config/prod.env` statt `.env`
- **Lösung**: Symlink erstellen oder Pfad anpassen
### 3. Systemd-Service ohne WorkingDirectory
- **Problem**: Service startet ohne korrektes Arbeitsverzeichnis
- **Lösung**: `WorkingDirectory=/path/to/mindnet` in systemd service
### 4. Mehrere .env-Dateien
- **Problem**: Es gibt `.env`, `prod.env`, `config/prod.env` - welche wird geladen?
- **Lösung**: Expliziter Pfad oder Umgebungsvariable `DOTENV_PATH`
## Fix-Implementierung
Der Code in `app/config.py` wurde erweitert:
- ✅ Expliziter Pfad für `.env` im Projekt-Root
- ✅ Fallback auf automatische Suche
- ✅ Debug-Logging (wenn verfügbar)
## Verifikation nach Fix
1. **Log prüfen**: Sollte `✅ .env geladen von: ...` zeigen
2. **Umgebungsvariablen prüfen**: `echo $DEBUG`, `echo $COLLECTION_PREFIX`
3. **Settings prüfen**: `python3 -c "from app.config import get_settings; s = get_settings(); print(f'DEBUG: {s.DEBUG}, PREFIX: {s.COLLECTION_PREFIX}')"`

View File

@ -0,0 +1,134 @@
# Deployment-Checkliste: Prod vs. Dev Retrieval-Problem
**Datum**: 2026-01-12
**Version**: v4.5.10
**Status**: 🔴 Kritisch
## Problem
Prod-System findet keine Suchergebnisse, während Dev-System korrekt funktioniert. Identischer Code, identische Daten.
## Identifizierte Ursachen
### 1. 🔴 **KRITISCH: Alte EdgeDTO-Version in Prod**
**Symptom**:
```
ERROR: 1 validation error for EdgeDTO
provenance
Input should be 'explicit', 'rule', 'smart' or 'structure'
[type=literal_error, input_value='explicit:callout', input_type=str]
```
**Ursache**:
- Prod verwendet eine **alte Version** des `EdgeDTO`-Modells aus `app/models/dto.py`
- Die alte Version unterstützt nur: `"explicit", "rule", "smart", "structure"`
- Die neue Version (v4.5.3+) unterstützt: `"explicit:callout", "explicit:wikilink", "explicit:note_zone", ...`
**Lösung**:
- ✅ Code in `dto.py` ist bereits korrekt (Zeile 51-56)
- ⚠️ **Prod muss neu gestartet werden**, um die neue Version zu laden
- ⚠️ **Python-Modul-Cache leeren** falls nötig: `find . -type d -name __pycache__ -exec rm -r {} +`
### 2. ✅ Collection-Präfix korrekt
- Prod: `COLLECTION_PREFIX=mindnet``mindnet_chunks`
- Dev: `COLLECTION_PREFIX=mindnet_dev``mindnet_dev_chunks`
- **Kein Problem hier**
## Sofortmaßnahmen
### Schritt 1: Code-Verifikation in Prod
```bash
# In Prod-System
cd /path/to/mindnet
grep -A 10 "provenance.*Literal" app/models/dto.py
```
**Erwartete Ausgabe**:
```python
provenance: Optional[Literal[
"explicit", "rule", "smart", "structure",
"explicit:callout", "explicit:wikilink", "explicit:note_zone", ...
]] = "explicit"
```
**Falls nicht vorhanden**: Code ist nicht aktualisiert → Deployment erforderlich
### Schritt 2: Python-Cache leeren
```bash
# In Prod-System
find . -type d -name __pycache__ -exec rm -r {} +
find . -name "*.pyc" -delete
```
### Schritt 3: Service neu starten
```bash
# FastAPI/uvicorn neu starten
# Oder Docker-Container neu starten
```
### Schritt 4: Verifikation
1. **Test-Query ausführen**:
```bash
curl -X POST http://localhost:8001/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "Was für einen Status hat das Projekt mindnet?"}'
```
2. **Log prüfen**:
- ✅ Keine `validation error for EdgeDTO` mehr
- ✅ `✨ [SUCCESS] Stream 'facts_stream' lieferte X Treffer.`
- ✅ Ergebnisse werden zurückgegeben
## Code-Vergleich
### Aktuelle Version (sollte in Prod sein):
```python
# app/models/dto.py (Zeile 51-56)
provenance: Optional[Literal[
"explicit", "rule", "smart", "structure",
"explicit:callout", "explicit:wikilink", "explicit:note_zone", "explicit:note_scope",
"inline:rel", "callout:edge", "semantic_ai", "structure:belongs_to", "structure:order",
"derived:backlink", "edge_defaults", "global_pool"
]] = "explicit"
```
### Alte Version (verursacht Fehler):
```python
# Alte Version (nur 4 Werte)
provenance: Optional[Literal[
"explicit", "rule", "smart", "structure"
]] = "explicit"
```
## Weitere mögliche Ursachen (wenn Fix nicht hilft)
### 1. Unterschiedliche Python-Versionen
- Prüfen: `python --version` in Dev vs. Prod
- Pydantic-Verhalten kann zwischen Versionen variieren
### 2. Unterschiedliche Pydantic-Versionen
- Prüfen: `pip list | grep pydantic` in Dev vs. Prod
- `requirements.txt` sollte identisch sein
### 3. Unterschiedliche Embedding-Modelle
- Prüfen: `MINDNET_EMBEDDING_MODEL` in beiden Systemen
- **Beide verwenden**: `nomic-embed-text`
### 4. Unterschiedliche Vektor-Dimensionen
- Prüfen: `VECTOR_DIM` in beiden Systemen
- **Beide verwenden**: `768`
## Erwartetes Ergebnis nach Fix
- ✅ Keine Pydantic-Validierungsfehler mehr
- ✅ Alle Streams liefern Ergebnisse
- ✅ Retrieval funktioniert identisch in Dev und Prod
- ✅ `explicit:callout` Provenance wird korrekt akzeptiert

View File

@ -0,0 +1,134 @@
# Fix: Python-Modul-Cache-Problem in Prod
**Datum**: 2026-01-12
**Version**: v4.5.10
**Status**: 🔴 Kritisch
## Problem
Code in `app/models/dto.py` ist korrekt (enthält `explicit:callout`), aber Prod verwendet trotzdem eine alte Version.
**Symptom**:
```
ERROR: 1 validation error for EdgeDTO
provenance
Input should be 'explicit', 'rule', 'smart' or 'structure'
[type=literal_error, input_value='explicit:callout', input_type=str]
```
## Ursache
**Python-Modul-Cache**: Python speichert kompilierte `.pyc` Dateien in `__pycache__` Verzeichnissen. Wenn der Code aktualisiert wird, aber der Service nicht neu gestartet wird, lädt Python die alte gecachte Version.
## Sofortmaßnahmen
### Schritt 1: Python-Cache leeren
```bash
# In Prod-System
cd ~/mindnet
# Finde und lösche alle __pycache__ Verzeichnisse
find . -type d -name __pycache__ -exec rm -r {} + 2>/dev/null || true
# Finde und lösche alle .pyc Dateien
find . -name "*.pyc" -delete
# Speziell für dto.py
rm -rf app/models/__pycache__
rm -rf app/__pycache__
rm -rf __pycache__
```
### Schritt 2: Verifikation des Codes
```bash
# Prüfe, ob der Code korrekt ist
grep -A 10 "provenance.*Literal" app/models/dto.py | grep "explicit:callout"
```
**Erwartete Ausgabe**: Sollte `explicit:callout` enthalten
### Schritt 3: Service neu starten
**Option A: FastAPI/uvicorn direkt**:
```bash
# Service stoppen (Ctrl+C oder kill)
# Dann neu starten
source .venv/bin/activate
uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload
```
**Option B: Systemd-Service**:
```bash
sudo systemctl restart mindnet-prod
# oder
sudo systemctl restart mindnet
```
**Option C: Docker-Container**:
```bash
docker-compose restart mindnet
# oder
docker restart mindnet-container
```
### Schritt 4: Verifikation zur Laufzeit
**Test-Script ausführen** (wenn verfügbar):
```bash
python3 scripts/verify_dto_import.py
```
**Erwartete Ausgabe**:
```
✅ EdgeDTO unterstützt 'explicit:callout'
✅ 'explicit:callout' ist in der Literal-Liste enthalten
✅ EdgeDTO mit 'explicit:callout' erfolgreich erstellt!
```
**Oder manuell testen**:
```python
python3 -c "
from app.models.dto import EdgeDTO
test = EdgeDTO(
id='test', kind='test', source='test', target='test',
weight=1.0, provenance='explicit:callout'
)
print('✅ EdgeDTO mit explicit:callout funktioniert!')
"
```
## Code-Fix (Fallback-Mechanismus)
Ein Fallback-Mechanismus wurde in `retriever.py` implementiert:
- Wenn `EdgeDTO` mit `explicit:callout` fehlschlägt, wird automatisch `explicit` als Fallback verwendet
- Dies verhindert, dass der gesamte Retrieval-Prozess fehlschlägt
- **WICHTIG**: Dies ist nur eine temporäre Lösung - der Cache muss trotzdem geleert werden!
## Verifikation nach Fix
1. **Test-Query ausführen**:
```bash
curl -X POST http://localhost:8001/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "Was für einen Status hat das Projekt mindnet?"}'
```
2. **Log prüfen**:
- ✅ Keine `validation error for EdgeDTO` mehr
- ✅ Keine `⚠️ [EDGE-DTO] Provenance 'explicit:callout' nicht unterstützt` Warnungen
- ✅ `✨ [SUCCESS] Stream 'facts_stream' lieferte X Treffer.`
- ✅ Ergebnisse werden zurückgegeben
## Warum passiert das?
1. **Code wurde aktualisiert**, aber Service läuft noch mit alter Version im Speicher
2. **Python lädt Module nur einmal** - nach dem ersten Import wird die gecachte Version verwendet
3. **__pycache__ Verzeichnisse** enthalten kompilierte Bytecode-Versionen der alten Dateien
## Prävention
- **Immer Service neu starten** nach Code-Änderungen
- **Cache regelmäßig leeren** bei Deployment
- **Verwende `--reload` Flag** bei uvicorn für automatisches Neuladen (nur für Dev!)

View File

@ -0,0 +1,163 @@
# Analyse: Retrieval-Unterschiede zwischen Dev und Prod
**Datum**: 2026-01-12
**Version**: v4.5.10
**Status**: 🔴 Kritisch
## Problemstellung
Bei identischer Codebasis und identischen Daten liefert das Dev-System Suchergebnisse, während das Prod-System keine Ergebnisse findet.
## Identifizierte Ursachen
### 1. 🔴 **KRITISCH: Inkonsistente Collection-Präfix-Konfiguration**
**Problem**: Zwei verschiedene Umgebungsvariablen werden für den Collection-Präfix verwendet:
1. **`app/config.py` (Zeile 24)**:
```python
COLLECTION_PREFIX: str = os.getenv("MINDNET_PREFIX", "mindnet_dev")
```
- Verwendet `MINDNET_PREFIX` als Umgebungsvariable
- Default: `"mindnet_dev"`
2. **`app/core/database/qdrant.py` (Zeile 47)**:
```python
prefix = os.getenv("COLLECTION_PREFIX") or "mindnet"
```
- Verwendet `COLLECTION_PREFIX` als Umgebungsvariable
- Default: `"mindnet"`
**Auswirkung**:
- **Retriever verwendet `QdrantConfig.from_env()`**, das `COLLECTION_PREFIX` liest
- **Ingestion verwendet `Settings.COLLECTION_PREFIX`**, das `MINDNET_PREFIX` liest
- **Resultat**: Daten werden in verschiedene Collections geschrieben/gesucht:
- Dev: `mindnet_dev_chunks`, `mindnet_dev_notes`, `mindnet_dev_edges`
- Prod: `mindnet_chunks`, `mindnet_notes`, `mindnet_edges`
### 2. ⚠️ **Mögliche weitere Ursachen**
#### 2.1 Unterschiedliche Embedding-Modelle
- **Prüfen**: `MINDNET_EMBEDDING_MODEL` in Dev vs. Prod
- **Auswirkung**: Unterschiedliche Vektoren → unterschiedliche Similarity-Scores
#### 2.2 Unterschiedliche Vektor-Dimensionen
- **Prüfen**: `VECTOR_DIM` in Dev vs. Prod
- **Auswirkung**: Dimension-Mismatch → Suche schlägt fehl
#### 2.3 Unterschiedliche Qdrant-Instanzen
- **Prüfen**: `QDRANT_URL` / `QDRANT_HOST` in Dev vs. Prod
- **Auswirkung**: Daten liegen in verschiedenen Datenbanken
#### 2.4 Unterschiedliche Score-Thresholds
- **Prüfen**: Filter-Logik oder Mindest-Scores
- **Auswirkung**: Ergebnisse werden gefiltert, bevor sie zurückgegeben werden
## Diagnose-Checkliste
### ✅ Sofort prüfen:
1. **Collection-Präfix-Verifikation**:
```bash
# Dev
echo $COLLECTION_PREFIX
echo $MINDNET_PREFIX
# Prod
echo $COLLECTION_PREFIX
echo $MINDNET_PREFIX
```
2. **Qdrant Collections prüfen**:
```python
# In beiden Systemen ausführen
from app.core.database.qdrant import get_client, QdrantConfig
cfg = QdrantConfig.from_env()
client = get_client(cfg)
print(f"Prefix: {cfg.prefix}")
print(f"Collections: {client.get_collections().collections}")
```
3. **Embedding-Modell prüfen**:
```bash
# Dev
echo $MINDNET_EMBEDDING_MODEL
echo $VECTOR_DIM
# Prod
echo $MINDNET_EMBEDDING_MODEL
echo $VECTOR_DIM
```
4. **Qdrant-Verbindung prüfen**:
```bash
# Dev
echo $QDRANT_URL
echo $QDRANT_HOST
echo $QDRANT_PORT
# Prod
echo $QDRANT_URL
echo $QDRANT_HOST
echo $QDRANT_PORT
```
## Lösungsvorschläge
### Option 1: Harmonisierung der Umgebungsvariablen (Empfohlen)
**Ziel**: Eine einzige Umgebungsvariable für den Collection-Präfix verwenden.
**Änderungen**:
1. **`app/core/database/qdrant.py`**:
```python
prefix = os.getenv("COLLECTION_PREFIX") or os.getenv("MINDNET_PREFIX") or "mindnet"
```
- Unterstützt beide Variablen (Abwärtskompatibilität)
- `COLLECTION_PREFIX` hat Priorität
2. **`app/config.py`**:
```python
COLLECTION_PREFIX: str = os.getenv("COLLECTION_PREFIX") or os.getenv("MINDNET_PREFIX") or "mindnet_dev"
```
- Unterstützt beide Variablen
- `COLLECTION_PREFIX` hat Priorität
3. **Dokumentation**: Klarstellen, dass `COLLECTION_PREFIX` die primäre Variable ist
### Option 2: Explizite Konfiguration in .env
**Ziel**: Beide Systeme verwenden explizit gesetzte `COLLECTION_PREFIX` Werte.
**Dev `.env`**:
```env
COLLECTION_PREFIX=mindnet_dev
```
**Prod `.env`**:
```env
COLLECTION_PREFIX=mindnet
```
### Option 3: Daten-Migration
**Ziel**: Daten von einer Collection in die andere migrieren.
**Vorgehen**:
1. Identifizieren, welche Collection die "richtigen" Daten enthält
2. Daten von Dev nach Prod migrieren (oder umgekehrt)
3. Collection-Präfix harmonisieren
## Sofortmaßnahmen
1. ✅ **Prüfen**: Welche Collections existieren in beiden Systemen?
2. ✅ **Prüfen**: Welche Umgebungsvariablen sind gesetzt?
3. ✅ **Prüfen**: Welche Collection enthält die Daten?
4. ✅ **Fix**: Collection-Präfix-Konfiguration harmonisieren
5. ✅ **Test**: Retrieval in beiden Systemen verifizieren
## Erwartetes Ergebnis nach Fix
- ✅ Beide Systeme verwenden dieselbe Collection-Präfix-Logik
- ✅ Retrieval findet Daten in beiden Systemen
- ✅ Konsistente Konfiguration zwischen Ingestion und Retrieval

View File

@ -0,0 +1,250 @@
<!-- DOCUMENT 1: pflichtenheft_obsidian_plugin_mindnet_assistant.md -->
---
id: pflichtenheft_obsidian_plugin_mindnet_assistant
title: Pflichtenheft Obsidian Plugin „Mindnet Causal Assistant“
type: specification
status: draft
created: 2026-01-13
lang: de
---
# Pflichtenheft Obsidian Plugin „Mindnet Causal Assistant“
## 1. Zielsetzung
Das Plugin unterstützt den Nutzer beim Erstellen und Pflegen eines narrativ-kausalen Wissensgraphen in Obsidian (Mindnet).
Es bietet:
- **Aktive Authoring-Unterstützung** (Guided Note Creation / Interview Flow)
- **Kausalketten-Prüfung** (Chain Explorer, Vorwärts/Rückwärts)
- **Linting + Auto-Fixes** (Graph-Hygiene, konsistente Kanten, Namensnormalisierung)
- **Export/Integration** der strukturierten Graph-Daten für ein Retrieval-System (Qdrant + Graph-Index)
## 2. Kontext & Randbedingungen
- Obsidian Vault enthält Notes als Markdown, jede Entität eine Datei.
- Notes enthalten Frontmatter (`id,title,type,status,...`) und Edges in Callout-Blöcken.
- Edge-Vokabular inklusive Aliasse & Inversen ist verfügbar (z.B. `edge_vocabulary.md`).
- Der Graph soll später von Mindnet traversierbar sein (Vorwärts/Rückwärts über inverse Relationen).
- Plugin muss offline nutzbar sein; optionale Backend/LLM-Integration ist konfigurierbar.
## 3. Begriffsdefinitionen
- **Node**: eine Obsidian Markdown-Datei (Entität).
- **Edge**: gerichtete Beziehung zwischen zwei Nodes (canonical edge type).
- **Alias**: alternative Edge-Bezeichnung in Notes, die auf canonical mapped wird.
- **Inverse**: Gegenkante zu einer Edge, laut Vokabular (z.B. `resulted_in``caused_by`).
- **Hub/Index**: Note, die primär navigiert (typisch `type: insight`), keine Kausalursache.
## 4. Scope
### In Scope (MVP → V2)
**MVP**
- Parser für Frontmatter + Edge-Callouts
- Normalizer: Alias → Canonical; optional Inversen-Erkennung
- Linter: Regelset (Error/Warn/Info) + Report
- Chain Explorer: forward/backward traversal (14 hops) ab aktueller Note
- Quickfixes: Edge-Typ ersetzen, Links normalisieren, Missing Note Stub erzeugen
**V2**
- Guided Authoring (Interview Flow) für `experience/decision/principle/state/strategy`
- Refactor Mode: Text → Node/Edge-Kandidaten + Review UI
- Export/Sync: JSON Graph Export + optional Qdrant Sync (separater Service)
### Out of Scope (initial)
- Vollautomatische Kausalitäts-Interpretation ohne User-Bestätigung
- Vollständige UI-Graph-Visualisierung (Obsidian Graph View bleibt nutzbar)
- Direkte medizinische/psychologische Beratung
## 5. Nutzerrollen & Use Cases
### Rolle: Nutzer (Author)
- UC1: „Ich schreibe eine Note und will Kanten prüfen“
- UC2: „Ich will von einem Ereignis aus die Kausalkette sehen“
- UC3: „Ich will eine neue Experience/Decision Note sauber anlegen“
- UC4: „Ich habe Text und will daraus Kandidaten extrahieren“
- UC5: „Ich will leere Links als open_question sauber erzeugen“
### Rolle: System/Indexer (Mindnet)
- UC6: „Ich brauche exportierbare adjacency lists + canonical edges“
## 6. Funktionale Anforderungen (FR)
### FR1: Vault Parsing
- FR1.1 Parse Frontmatter (YAML): `id,title,type,status,date,tags,...`
- FR1.2 Parse Edge-Callouts im Format:
- `> [!abstract]- 🕸️ Semantic Mapping`
- `>> [!edge] <relation>`
- `>> [[target]]`
- FR1.3 Extrahiere alle WikiLinks `[[...]]` aus Edge-Blocks
- FR1.4 Erkenne Datei-Pfade, Dateinamen und canonical node identifiers (Dateiname ohne `.md`)
**Output (intern)**
```ts
type Node = { id?: string; title?: string; type?: string; status?: string; path: string; slug: string };
type Edge = { srcSlug: string; dstSlug: string; rawType: string; canonicalType?: string; line?: number; blockId?: string };
```
### FR2: Edge Normalization
- FR2.1 Map rawType/Alias auf canonical edge type via Edge Vocabulary
- FR2.2 Speichere Mapping-Entscheidungen (raw → canonical) pro Edge
- FR2.3 Liefere inverse edge type (`inverseType`) pro canonical edge type (sofern definiert)
### FR3: Linting
- FR3.1 Führe Checkliste von Regeln aus (siehe separates Dokument)
- FR3.2 Liefere LintReport mit Severity (ERROR/WARN/INFO), Location (file, line), Fix-Vorschlägen
- FR3.3 Quickfix: wende Fix auf Note an (Text edit), mit Preview/Diff
### FR4: Chain Explorer (Traversal)
- FR4.1 Startpunkt: aktuelle Note im Editor
- FR4.2 Forward traversal: `resulted_in`, `followed_by`, `impacts`, `source_of`, optional `related_to`
- FR4.3 Backward traversal: `caused_by`, `preceeded_by`, `derived_from`, `impacted_by`
- FR4.4 Konfigurierbare maxHops (Default 3)
- FR4.5 Ergebnis als Liste von Pfaden + kompaktes Subgraph-Summary (Nodes/Edges)
### FR5: Missing Notes / Stubs
- FR5.1 Erkenne, wenn Edge-Target nicht existiert
- FR5.2 Biete „Create Stub Note“ an:
- Template basierend auf Typ (default `open_question` wenn unbekannt)
- Einhaltung Naming-Rules: `a-z0-9_`
- FR5.3 Optional: convert TODO-Link → open_question note
### FR6: Guided Authoring (V2)
- FR6.1 Wizard für neue Notes: Auswahl Typ → Fragen (eine nach der anderen)
- FR6.2 Wizard erstellt Datei mit Template + initialen Edge-Blocks
- FR6.3 Jede automatische Edge-Vermutung ist „review-required“
### FR7: Refactor Mode (V2)
- FR7.1 Extrahiere aus aktuellem Note-Text Kandidaten:
- Event-Kandidaten (Datum/Ort/Verben)
- Decision-Kandidaten („entschied“, „nahm an“, „wechselte“)
- Principle-Kandidaten („ich glaube“, „ich habe gelernt“)
- Relation-Kandidaten („dadurch“, „führte zu“, „weil“)
- FR7.2 UI-Review: Checkbox-Liste zum Erstellen/Verwerfen
- FR7.3 Generiere Notes + Edges nur nach Bestätigung
### FR8: Export (MVP optional / V2 empfohlen)
- FR8.1 Export JSON: Nodes + canonical edges + inverses
- FR8.2 Export adjacency list pro node slug
- FR8.3 Optional: webhook/CLI hook für Indexer (Qdrant)
## 7. Nicht-funktionale Anforderungen (NFR)
- NFR1: Performant bei 10k Notes (incremental parse, caching)
- NFR2: Offline-first; LLM/Backend optional
- NFR3: Deterministische Normalisierung (gleiches Input → gleiches Output)
- NFR4: Kein Erfinden von Fakten: Auto-Edge nur als Vorschlag
- NFR5: Sicheres Editieren (Diff/Undo via Obsidian APIs)
- NFR6: Konfigurierbarkeit (YAML/Settings Tab): maxHops, allowed edges, strict mode
## 8. Technisches Lösungsdesign
### 8.1 Obsidian Plugin Struktur (TypeScript)
- `main.ts` Plugin lifecycle, commands, views
- `settings.ts` Einstellungen
- `parser/` Markdown + callout parser
- `graph/` Node/Edge model, normalization, traversal
- `lint/` Rules engine, reports, quickfixes
- `ui/` Sidebar view, modals, diff preview
### 8.2 Speicherung / Cache
- In-memory cache: map `path → parsed Node + edges + hash`
- Incremental update: on file change events re-parse only changed file
- Optional persisted cache in `.obsidian/plugins/.../cache.json`
### 8.3 Edge Vocabulary Integration
- Input: `edge_vocabulary.md` im Vault ODER eingebettete JSON Ressource
- Parsing:
- canonical edge types
- alias list
- inverse mapping
- Fallback: minimal builtin vocabulary, wenn Datei fehlt
### 8.4 Traversal Engine
- Graph Index: adjacency lists aus canonical edges
- Traversal:
- BFS mit hop limit
- optional weighted expansion (für Chain Explorer „relevant paths first“)
### 8.5 Quickfix Engine
- Applies patches auf Markdown:
- Replace edge type token im Callout (`>> [!edge] ...`)
- Rename link targets (replace `[[old]]``[[new]]`)
- Insert stub note file from template
- Safety:
- Show diff modal
- Use Obsidian editor transactions / file API
### 8.6 Optional Backend / LLM (V2)
- Backend (local node service) für:
- text extraction (Refactor Mode)
- suggestion generation
- Communication:
- HTTP local (`127.0.0.1`) oder WebSocket
- API key storage via Obsidian settings (encrypted if possible)
- Claude-code/Cursor: nutzt Code-Agent für Implementierung, nicht zur Runtime.
## 9. UI/UX Anforderungen
### 9.1 Sidebar View „Mindnet Assistant“
Tabs:
- **Validate**: Lint Report + Fix Buttons
- **Chains**: Forward/Backward Chain Explorer + Copy as text
- **Create** (V2): Wizard new note
- **Refactor** (V2): Extract candidates
### 9.2 Commands (Command Palette)
- `Mindnet: Validate current note`
- `Mindnet: Validate vault (selected folders)`
- `Mindnet: Show chains from current note`
- `Mindnet: Normalize edges in current note`
- `Mindnet: Create stub for missing links`
- (V2) `Mindnet: Start guided authoring`
- (V2) `Mindnet: Refactor current note to graph`
## 10. Akzeptanzkriterien
- AK1: Plugin erkennt Edge-Callouts und normalisiert Aliasse deterministisch
- AK2: Linter findet Node-Splitting (mindestens Levenshtein/ähnliche Slugs) und Missing Notes
- AK3: Chain Explorer liefert identische Pfade vorwärts/rückwärts bei inversen Edge-Paaren
- AK4: Quickfix ersetzt Edge-Typen ohne Markdown zu zerstören; Undo funktioniert
- AK5: Export JSON enthält canonical edges + inverse types
## 11. Deliverables
- Obsidian Plugin (TS) mit MVP Features
- Dokumentation:
- Install/Build
- Settings
- Rule reference
- Example vault sample
- Optional: JSON Export Format Spec (nodes/edges)
---
## 12. Prompts für Code-Agenten (Cursor / Claude-code)
### Prompt A (Repo Scaffold + MVP)
> Du bist ein Senior TypeScript Engineer. Implementiere ein Obsidian Plugin „Mindnet Causal Assistant“.
> Ziele MVP:
> 1) Parse Frontmatter (YAML) und Edge-Callouts im Format:
> `> [!abstract]- 🕸️ Semantic Mapping``>> [!edge] <relation>``>> [[target]]`.
> 2) Normalisiere Edge Aliasse auf canonical edge types (Vokabular als JSON im Code; später ersetzbar).
> 3) Baue eine Sidebar View mit Tabs „Validate“ und „Chains“.
> 4) Implementiere Lint Regeln: missing target note, alias-not-normalized, hub-has-causal-edge, chronology-vs-causality warning.
> 5) Implementiere Chain Explorer (forward/backward, maxHops=3).
> 6) Implementiere Quickfix: replace edge type token, create stub note.
> Nutze Obsidian APIs, schreibe sauberen TS Code, mit Tests für Parser/Normalizer.
### Prompt B (Parser Unit Tests)
> Schreibe Unit Tests für den Markdown Parser:
> - erkennt mehrere Edge-Blocks pro Datei
> - erkennt mehrere Targets pro Edge
> - liefert line numbers
> - ignoriert WikiLinks außerhalb der Semantic Mapping Callouts
> Nutze vitest/jest. Erzeuge fixtures.
### Prompt C (Lint Engine + Quickfix)
> Implementiere eine Lint Engine als Rule-Pipeline.
> Jede Regel: id, severity, detect(node, graph) -> findings, fix(finding)->patch.
> Baue eine Diff Preview Modal und applyPatch über Obsidian file API.
> Implementiere zunächst 6 Regeln aus der Checkliste.
### Prompt D (Vocabulary Loader)
> Implementiere einen VocabularyLoader:
> - lädt entweder eingebettetes JSON oder eine Vault-Datei `edge_vocabulary.md`
> - parst canonical types, aliases, inverse
> - bietet getCanonical(raw) und getInverse(canonical)
> Fallback auf builtin vocabulary wenn parsing fehlschlägt.

View File

@ -0,0 +1,136 @@
<!-- DOCUMENT 2: checklist_lint_regeln_mindnet_assistant.md -->
---
id: checklist_lint_regeln_mindnet_assistant
title: Checkliste Lint-Regeln für Mindnet Causal Assistant
type: specification
status: draft
created: 2026-01-13
lang: de
---
# Checkliste Lint-Regeln für Mindnet Causal Assistant
## Severity Levels
- **ERROR**: bricht Traversal/Indexer oder erzeugt falsche Nodes
- **WARN**: wahrscheinlich falsche Semantik / schlechter Retrieval-Impact
- **INFO**: Optimierung / Empfehlung
---
## A. Graph-Integrität & Naming
### L1 (ERROR) Missing Target Note
**Wenn:** Edge target `[[X]]` existiert nicht als Datei im Vault
**Dann:** Finding `missing_target`
**Fix:** „Create Stub Note“ (default `type: open_question`) oder remove edge
### L2 (ERROR) Node Splitting durch Schreibvarianten
**Wenn:** mehrere Targets im Vault sind ähnlich (slug distance), oder in Edges mehrere Varianten vorkommen
**Dann:** Finding `node_split_candidate`
**Fix:** Vorschlag canonical slug + bulk replace links
### L3 (ERROR) Invalid Filename Policy
**Wenn:** Dateiname enthält Zeichen außerhalb `[a-z0-9_]`
**Dann:** Finding `invalid_filename`
**Fix:** Rename file + update all backlinks
---
## B. Edge-Formale Regeln
### L4 (ERROR) Unknown Edge Type / Unmapped Alias
**Wenn:** raw edge type nicht im Vokabular (alias→canonical)
**Dann:** Finding `unknown_edge_type`
**Fix:** Edge type ersetzen durch best guess oder user selection
### L5 (WARN) Alias not normalized
**Wenn:** raw edge type ist Alias, canonical bekannt, aber Note enthält Alias
**Dann:** Finding `alias_not_normalized`
**Fix:** Replace raw with canonical (optional config)
### L6 (WARN) Missing Inverse Edge (optional strict mode)
**Wenn:** Edge A->B existiert, inverse nach Vokabular fehlt in B
**Dann:** Finding `missing_inverse`
**Fix:** Add inverse edge to target note (review + diff)
---
## C. Semantik: Kausalität vs Chronologie
### L7 (WARN) Chronology used as Causality
**Wenn:** Knoten/Target wirkt wie Prozessschritt („warten“, „gehen“, „ankommen“) und Edge type ist `resulted_in`
**Dann:** Finding `chronology_as_causality`
**Fix:** Vorschlag `followed_by` (inverse `preceeded_by`)
### L8 (INFO) Kausalität ohne Brücken (Gap)
**Wenn:** Pfad springt von Ereignis direkt zu Entscheidung, aber intermediäre Knoten fehlen (heuristisch)
**Dann:** Finding `missing_bridge_node`
**Fix:** Vorschlag „Create open_question bridge“ (z.B. „Was war der konkrete Auslöser…?“)
---
## D. Node-Type Regeln
### L9 (ERROR) Causal edges from open_question/hypothesis/white_spot
**Wenn:** node.type in `{open_question, hypothesis, white_spot}` und Edge type in `{caused_by, resulted_in, impacts, derived_from}`
**Dann:** Finding `invalid_causal_edge_from_uncertain`
**Fix:** Replace with `related_to` oder remove edge
### L10 (WARN) Hub/Insight Note trägt Kausalität
**Wenn:** node.type == `insight` (oder Hub-Pattern) und hat `caused_by/resulted_in`
**Dann:** Finding `hub_has_causality`
**Fix:** Replace edges with `related_to` und verschiebe Kausalität in atomare Notes
### L11 (WARN) Principle uses caused_by for origin
**Wenn:** node.type == `principle` und enthält `caused_by` zu Erlebnissen
**Dann:** Finding `principle_origin_edge`
**Fix:** Vorschlag `derived_from` oder `based_on`
### L12 (INFO) Decision without caused_by
**Wenn:** node.type == `decision` und hat keine `caused_by`-Kanten
**Dann:** Finding `decision_without_causes`
**Fix:** Wizard: „Was war der Auslöser?“ → create open_question or add edges
---
## E. Redundanz & Zyklen
### L13 (WARN) Duplicate Edges
**Wenn:** identische canonical edge mehrfach gesetzt (src,type,dst)
**Dann:** Finding `duplicate_edge`
**Fix:** remove duplicates
### L14 (WARN) Cycles in pure causality subgraph
**Wenn:** Zyklus ausschließlich über `{caused_by,resulted_in,derived_from,source_of}`
**Dann:** Finding `causal_cycle`
**Fix:** Markiere zur Review; oft ist eine Kante falsch gerichtet
---
## F. Traversal-Optimierung (Retrieval-Wirkung)
### L15 (INFO) Overuse of related_to
**Wenn:** Note enthält nur `related_to` und keine spezifischeren Kanten
**Dann:** Finding `weak_semantics`
**Fix:** Vorschlag: präzisere Beziehungstypen setzen
### L16 (INFO) Missing type metadata
**Wenn:** Frontmatter `type` fehlt
**Dann:** Finding `missing_type`
**Fix:** Prompt user to choose type; set via template
### L17 (INFO) Missing date on experience
**Wenn:** node.type == `experience` und kein Datum/Zeitraum vorhanden
**Dann:** Finding `missing_date_experience`
**Fix:** Prompt: „Wann ungefähr?“ → set `date` oder `time_range`
---
## Suggested Implementation Notes
- Jede Regel liefert:
- `ruleId`, `severity`, `message`, `location`, `evidence`, `quickFixes[]`
- QuickFixes sind Patch-Operationen:
- replaceText(range, text)
- insertBlock(atLine, block)
- createFile(path, content)
- renameFile(old, new) + updateLinks(glob)

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "mindnet",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View File

@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""
Script zur Verifikation der EdgeDTO-Import-Version in Prod.
Prüft, ob die korrekte Version des EdgeDTO-Modells geladen wird.
"""
import sys
import os
# Stelle sicher, dass der Projekt-Pfad im Python-Path ist
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
try:
from app.models.dto import EdgeDTO
import inspect
# Extrahiere die Literal-Definition aus dem Source-Code
source = inspect.getsource(EdgeDTO)
# Prüfe, ob explicit:callout in der Literal-Liste ist
if "explicit:callout" in source:
print("✅ EdgeDTO unterstützt 'explicit:callout'")
print(f" -> Modul-Pfad: {EdgeDTO.__module__}")
print(f" -> Datei: {inspect.getfile(EdgeDTO)}")
# Zeige die Provenance-Definition
import re
match = re.search(r'provenance.*?Literal\[(.*?)\]', source, re.DOTALL)
if match:
literal_values = match.group(1)
if "explicit:callout" in literal_values:
print("'explicit:callout' ist in der Literal-Liste enthalten")
print(f"\n Literal-Werte (erste 200 Zeichen):\n {literal_values[:200]}...")
else:
print("'explicit:callout' ist NICHT in der Literal-Liste!")
print(f"\n Gefundene Literal-Werte:\n {literal_values}")
else:
print("⚠️ Konnte Literal-Definition nicht finden")
else:
print("❌ EdgeDTO unterstützt NICHT 'explicit:callout'")
print(f" -> Modul-Pfad: {EdgeDTO.__module__}")
print(f" -> Datei: {inspect.getfile(EdgeDTO)}")
print("\n Source-Code (erste 500 Zeichen):")
print(f" {source[:500]}...")
# Test: Versuche ein EdgeDTO mit explicit:callout zu erstellen
print("\n🧪 Test: Erstelle EdgeDTO mit provenance='explicit:callout'...")
try:
test_edge = EdgeDTO(
id="test",
kind="test",
source="test",
target="test",
weight=1.0,
provenance="explicit:callout"
)
print("✅ EdgeDTO mit 'explicit:callout' erfolgreich erstellt!")
print(f" -> Provenance: {test_edge.provenance}")
except Exception as e:
print(f"❌ Fehler beim Erstellen: {e}")
print(f" -> Typ: {type(e).__name__}")
except ImportError as e:
print(f"❌ Import-Fehler: {e}")
sys.exit(1)
except Exception as e:
print(f"❌ Unerwarteter Fehler: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

View File

@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""
Script zur Verifikation des .env-Ladens in Prod.
Prüft, ob die .env-Datei korrekt geladen wird und welche Werte tatsächlich verwendet werden.
"""
import os
import sys
from pathlib import Path
# Stelle sicher, dass der Projekt-Pfad im Python-Path ist
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
print("=" * 80)
print("🔍 .env-Lade-Verifikation")
print("=" * 80)
# 1. Prüfe, ob .env-Datei existiert
env_files = [
project_root / ".env",
project_root / "prod.env",
project_root / "config" / "prod.env",
Path.cwd() / ".env",
Path.cwd() / "prod.env",
]
print("\n1. Suche nach .env-Dateien:")
found_env = None
for env_file in env_files:
if env_file.exists():
print(f" ✅ Gefunden: {env_file}")
if found_env is None:
found_env = env_file
else:
print(f" ❌ Nicht gefunden: {env_file}")
if not found_env:
print("\n ⚠️ WARNUNG: Keine .env-Datei gefunden!")
print(" -> load_dotenv() wird Standard-Werte verwenden")
# 2. Lade .env manuell
print("\n2. Lade .env-Datei:")
from dotenv import load_dotenv
if found_env:
result = load_dotenv(found_env, override=True)
print(f" ✅ load_dotenv('{found_env}') = {result}")
else:
result = load_dotenv(override=True)
print(f" ⚠️ load_dotenv() ohne expliziten Pfad = {result}")
print(" -> Sucht automatisch nach .env im aktuellen Verzeichnis")
# 3. Prüfe kritische Umgebungsvariablen
print("\n3. Kritische Umgebungsvariablen:")
critical_vars = [
"COLLECTION_PREFIX",
"MINDNET_PREFIX",
"DEBUG",
"VECTOR_DIM",
"MINDNET_EMBEDDING_MODEL",
"QDRANT_URL",
]
for var in critical_vars:
value = os.getenv(var, "NICHT GESETZT")
source = "Umgebung" if var in os.environ else "Default/Code"
print(f" {var:30} = {value:40} ({source})")
# 4. Prüfe, welche .env-Datei tatsächlich geladen wurde
print("\n4. Verifikation der geladenen Werte:")
print(f" Arbeitsverzeichnis: {Path.cwd()}")
print(f" Projekt-Root: {project_root}")
print(f" Python-Pfad[0]: {sys.path[0] if sys.path else 'N/A'}")
# 5. Test: Importiere Settings
print("\n5. Test: Importiere Settings aus app.config:")
try:
from app.config import get_settings
settings = get_settings()
print(f" ✅ Settings erfolgreich geladen")
print(f" -> COLLECTION_PREFIX: {settings.COLLECTION_PREFIX}")
print(f" -> VECTOR_SIZE: {settings.VECTOR_SIZE}")
print(f" -> EMBEDDING_MODEL: {settings.EMBEDDING_MODEL}")
except Exception as e:
print(f" ❌ Fehler beim Laden der Settings: {e}")
import traceback
traceback.print_exc()
# 6. Test: Prüfe EdgeDTO
print("\n6. Test: Prüfe EdgeDTO-Import:")
try:
from app.models.dto import EdgeDTO
import inspect
source = inspect.getsource(EdgeDTO)
if "explicit:callout" in source:
print(" ✅ EdgeDTO unterstützt 'explicit:callout'")
print(f" -> Modul-Pfad: {EdgeDTO.__module__}")
print(f" -> Datei: {inspect.getfile(EdgeDTO)}")
else:
print(" ❌ EdgeDTO unterstützt NICHT 'explicit:callout'")
# Test-Erstellung
test_edge = EdgeDTO(
id="test", kind="test", source="test", target="test",
weight=1.0, provenance="explicit:callout"
)
print(" ✅ EdgeDTO mit 'explicit:callout' erfolgreich erstellt!")
except Exception as e:
print(f" ❌ Fehler: {e}")
import traceback
traceback.print_exc()
print("\n" + "=" * 80)

View File

@ -0,0 +1,160 @@
#!/usr/bin/env python3
"""
Script zur Laufzeit-Verifikation des laufenden Mindnet-Services.
Prüft, ob der Service die korrekte EdgeDTO-Version verwendet und ob die .env korrekt geladen wurde.
"""
import sys
import requests
import json
from pathlib import Path
# Stelle sicher, dass der Projekt-Pfad im Python-Path ist
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
print("=" * 80)
print("🔍 Laufzeit-Verifikation des Mindnet-Services")
print("=" * 80)
# 1. Prüfe Health-Endpoint
print("\n1. Prüfe Service-Status (Health-Check):")
try:
response = requests.get("http://localhost:8001/healthz", timeout=5)
if response.status_code == 200:
health_data = response.json()
print(f" ✅ Service läuft")
print(f" -> Status: {health_data.get('status')}")
print(f" -> Version: {health_data.get('version')}")
print(f" -> Prefix: {health_data.get('prefix')}")
print(f" -> Qdrant: {health_data.get('qdrant')}")
# WP-24c v4.5.10: Prüfe EdgeDTO-Version im laufenden Service
edge_dto_supports = health_data.get('edge_dto_supports_callout')
if edge_dto_supports is not None:
if edge_dto_supports:
print(f" ✅ Service unterstützt 'explicit:callout' (zur Laufzeit verifiziert)")
else:
print(f" ❌ Service unterstützt NICHT 'explicit:callout' (alte Version im Speicher!)")
print(f" -> Aktion erforderlich: Cache leeren und Service neu starten")
else:
print(f" ⚠️ Health-Check meldet keine EdgeDTO-Version (alte API-Version?)")
else:
print(f" ⚠️ Service antwortet mit Status {response.status_code}")
print(f" -> Response: {response.text[:200]}")
except requests.exceptions.ConnectionError:
print(" ❌ Service nicht erreichbar (läuft er auf Port 8001?)")
print(" -> Tipp: sudo systemctl status mindnet-prod")
sys.exit(1)
except Exception as e:
print(f" ❌ Fehler beim Health-Check: {e}")
sys.exit(1)
# 2. Test: Versuche eine Test-Query mit explicit:callout Edge
print("\n2. Test: Retrieval mit explicit:callout Edge:")
print(" -> Sende Test-Query an /chat/...")
print(" -> Hinweis: Timeout nach 30s ist möglich bei LLM-Calls")
try:
test_query = {
"message": "Test query für EdgeDTO-Verifikation",
"explain": False
}
# WP-24c: Router ist mit prefix="/chat" eingebunden, Endpoint ist "/"
# Erhöhter Timeout für LLM-Calls (können länger dauern)
response = requests.post(
"http://localhost:8001/chat/",
json=test_query,
timeout=60 # Erhöht von 30 auf 60 Sekunden
)
if response.status_code == 200:
result = response.json()
print(f" ✅ Query erfolgreich verarbeitet")
print(f" -> Antwort-Länge: {len(result.get('response', ''))} Zeichen")
# Prüfe Logs auf EdgeDTO-Fehler (wenn verfügbar)
if 'warnings' in result or 'errors' in result:
warnings = result.get('warnings', [])
errors = result.get('errors', [])
if warnings:
print(f" ⚠️ Warnings: {warnings}")
if errors:
print(f" ❌ Errors: {errors}")
else:
print(f" ⚠️ Query fehlgeschlagen mit Status {response.status_code}")
print(f" -> Response: {response.text[:500]}")
except requests.exceptions.ReadTimeout:
print(f" ⚠️ Query-Timeout (Service antwortet nicht innerhalb von 60s)")
print(f" -> Mögliche Ursachen:")
print(f" - LLM-Call dauert länger als erwartet")
print(f" - Service hängt bei der Verarbeitung")
print(f" -> Tipp: Prüfe Service-Logs mit: sudo journalctl -u mindnet-prod -n 50")
print(f" -> WICHTIG: EdgeDTO-Problem ist gelöst (siehe Punkt 1)")
except Exception as e:
print(f" ⚠️ Fehler bei Test-Query: {e}")
print(f" -> WICHTIG: EdgeDTO-Problem ist gelöst (siehe Punkt 1)")
# Kein vollständiger Traceback für Timeouts, da diese erwartbar sind
# 3. Direkte Code-Verifikation (falls Service-Code zugänglich)
print("\n3. Code-Verifikation (lokale Dateien):")
try:
from app.models.dto import EdgeDTO
import inspect
source = inspect.getsource(EdgeDTO)
if "explicit:callout" in source:
print(" ✅ Lokaler Code unterstützt 'explicit:callout'")
print(f" -> Datei: {inspect.getfile(EdgeDTO)}")
# Prüfe, ob die Datei aktuell ist
dto_file = Path(inspect.getfile(EdgeDTO))
if dto_file.exists():
import time
mtime = dto_file.stat().st_mtime
mtime_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(mtime))
print(f" -> Letzte Änderung: {mtime_str}")
else:
print(" ❌ Lokaler Code unterstützt NICHT 'explicit:callout'")
# Test-Erstellung
test_edge = EdgeDTO(
id="test", kind="test", source="test", target="test",
weight=1.0, provenance="explicit:callout"
)
print(" ✅ EdgeDTO mit 'explicit:callout' erfolgreich erstellt!")
except Exception as e:
print(f" ❌ Fehler bei Code-Verifikation: {e}")
import traceback
traceback.print_exc()
# 4. Prüfe Python-Cache
print("\n4. Prüfe Python-Cache:")
try:
dto_cache_dir = project_root / "app" / "models" / "__pycache__"
if dto_cache_dir.exists():
cache_files = list(dto_cache_dir.glob("dto*.pyc"))
if cache_files:
print(f" ⚠️ Gefunden: {len(cache_files)} Cache-Datei(en) in app/models/__pycache__")
print(f" -> Tipp: Cache leeren mit: find . -type d -name __pycache__ -exec rm -r {{}} +")
else:
print(" ✅ Keine Cache-Dateien gefunden")
else:
print(" ✅ Kein Cache-Verzeichnis vorhanden")
except Exception as e:
print(f" ⚠️ Fehler bei Cache-Prüfung: {e}")
# 5. Empfehlungen
print("\n5. Empfehlungen:")
print(" 📋 Wenn der Service noch eine alte Version verwendet:")
print(" 1. Python-Cache leeren:")
print(" find . -type d -name __pycache__ -exec rm -r {} + 2>/dev/null || true")
print(" find . -name '*.pyc' -delete")
print(" 2. Service neu starten:")
print(" sudo systemctl restart mindnet-prod")
print(" 3. Status prüfen:")
print(" sudo systemctl status mindnet-prod")
print(" 4. Logs prüfen:")
print(" sudo journalctl -u mindnet-prod -f")
print("\n" + "=" * 80)