Vertiefung · Script-Architektur

14 Scripts, eine Kernbibliothek

cm_core.py als Fundament. Wie ID-Generierung, Duplikaterkennung und temporale Metadaten funktionieren.

01
cm_core.py — Das Fundament

Alle 13 anderen Scripts importieren cm_core. Es enthält: Workspace-Management, ID-Generierung, Index-I/O, History-Logging, Tag-Normalisierung, Duplikaterkennung und die temporale Metadaten-Factory.

# Kern-Funktionen in cm_core.py
get_workspace(project, base) → Path # Safe name generation
generate_id(type, ws, index) → str # arch-001, dec-002...
load/save_index(ws) → dict # Flacher JSON-Index
find_similar_nodes(ws, title, content) → list # Duplikat-Check
make_temporal(source_date, valid_from...) → dict
normalize_tags("api, REST, Express") → ["api","express","rest"]
content_hash(content) → str # MD5[:12] für Duplikate
02
ID-Generierung — Der Batch-Bug

generate_id() liest normalerweise den Index von Disk. Problem: Bei cm_ingest mit --split erzeugt eine Schleife 10 Nodes. Der Index auf Disk wird erst am Ende geschrieben → alle IDs wären identisch. Lösung: optionaler in-memory Index-Parameter.

# VORHER (Bug): Alle IDs = api-001
for nd in nodes_to_create:
  node_id = generate_id(type, ws) # liest Disk → immer gleich!

# NACHHER (Fix): api-001, api-002, api-003...
for nd in nodes_to_create:
  node_id = generate_id(type, ws, index) # in-memory!
  index["nodes"][node_id] = {...} # Index wächst in-memory mit
03
Duplikaterkennung — Wort-Overlap statt Embeddings

find_similar_nodes vergleicht Titel-Wörter und Tags. Threshold 0.6 = 60% Wort-Überlappung. Kein ML, kein API-Call — nur Set-Operationen. Schnell, transparent, deterministisch.

# Titel-Ähnlichkeit
title_words = {"postgresql", "als", "datenbank"}
existing_words = {"postgresql", "statt", "mongodb"}
overlap = len({"postgresql"}) / max(3, 3) = 0.33 → unter 0.6 → kein Duplikat

# Tag-Overlap (≥3 gemeinsame Tags → ähnlich)
new_tags = {"database", "postgresql", "sql", "migration"}
existing_tags = {"database", "postgresql", "sql"}
overlap = 3 → ≥ 3 → ⚠️ Duplikat-Warnung
04
Temporale Metadaten — make_temporal()

Jeder Node kann source_date, valid_from, valid_until und temporal_confidence tragen. Die Factory-Funktion erzeugt das Dict, cm_add.py setzt es im Index.

# In cm_core.py
def make_temporal(source_date="", valid_from="",
    valid_until="", temporal_confidence="unknown"):
  return {
    "source_date": source_date,
    "valid_from": valid_from,
    "valid_until": valid_until,
    "temporal_confidence": temporal_confidence
  }

# In cm_add.py — neues Feld neben relevance
index["nodes"][node_id] = {
  ...
  "confidence": args.confidence, # NEU: high/medium/low/unknown
  "temporal": temporal, # NEU: Zeitdaten
}