Refactor edge processing in graph_derive_edges.py and ingestion_processor.py for consistency and efficiency

Implement deterministic sorting of semantic groups in graph_derive_edges.py to ensure consistent edge extraction across batches. Update ingestion_processor.py to enhance change detection logic, ensuring that hash checks are performed before artifact checks to prevent redundant processing. These changes improve the reliability and efficiency of the edge building and ingestion workflows.
This commit is contained in:
Lars 2026-01-12 08:04:28 +01:00
parent 78fbc9b31b
commit 6047e94964
2 changed files with 17 additions and 6 deletions

View File

@ -910,7 +910,12 @@ def build_edges_for_note(
# Schritt 3: ID-Zuweisung nach Scope-Entscheidung # Schritt 3: ID-Zuweisung nach Scope-Entscheidung
final_edges: List[dict] = [] final_edges: List[dict] = []
for semantic_key, group in semantic_groups.items(): # WP-24c v4.5.9: 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())
for semantic_key in sorted_semantic_keys:
group = semantic_groups[semantic_key]
# WP-24c v4.4.0-DEBUG: Schnittstelle 4 - De-Duplizierung Entscheidung # WP-24c v4.4.0-DEBUG: Schnittstelle 4 - De-Duplizierung Entscheidung
# Prüfe, ob diese Gruppe Callout-Kanten enthält # Prüfe, ob diese Gruppe Callout-Kanten enthält
has_callouts = any(e.get("provenance") == "explicit:callout" for e in group) has_callouts = any(e.get("provenance") == "explicit:callout" for e in group)

View File

@ -268,7 +268,6 @@ class IngestionService:
# WP-24c v4.5.9: Strikte Change Detection (Hash-basierte Inhaltsprüfung) # WP-24c v4.5.9: Strikte Change Detection (Hash-basierte Inhaltsprüfung)
# Prüft Hash VOR der Verarbeitung, um redundante Ingestion zu vermeiden # Prüft Hash VOR der Verarbeitung, um redundante Ingestion zu vermeiden
old_payload = None if force_replace else fetch_note_payload(self.client, self.prefix, note_id) old_payload = None if force_replace else fetch_note_payload(self.client, self.prefix, note_id)
c_miss, e_miss = artifacts_missing(self.client, self.prefix, note_id)
content_changed = True content_changed = True
hash_match = False hash_match = False
@ -290,12 +289,19 @@ class IngestionService:
# WP-24c v4.5.9: Wenn Hash fehlt, als geändert behandeln (Sicherheit) # WP-24c v4.5.9: Wenn Hash fehlt, als geändert behandeln (Sicherheit)
logger.debug(f"🔍 [CHANGE-DETECTION] Hash fehlt für '{note_id}': new_h={bool(new_h)}, old_h={bool(old_h)}") logger.debug(f"🔍 [CHANGE-DETECTION] Hash fehlt für '{note_id}': new_h={bool(new_h)}, old_h={bool(old_h)}")
# WP-24c v4.5.9: Strikte Logik - überspringe komplett wenn Hash identisch UND keine Artefakte fehlen # WP-24c v4.5.9: Strikte Logik - überspringe komplett wenn Hash identisch
# Dies verhindert redundante Embedding-Generierung und Chunk-Verarbeitung # WICHTIG: Artifact-Check NACH Hash-Check, da purge_before die Artefakte löschen kann
if not force_replace and hash_match and old_payload and not c_miss and not e_miss: # Wenn Hash identisch ist, sind die Artefakte entweder vorhanden oder werden gerade neu geschrieben
logger.info(f"⏭️ [SKIP] '{note_id}' unverändert (Hash identisch, alle Artefakte vorhanden)") if not force_replace and hash_match and old_payload:
# WP-24c v4.5.9: Hash identisch -> überspringe komplett (auch wenn Artefakte nach PURGE fehlen)
# Der Hash ist die autoritative Quelle für "Inhalt unverändert"
# Artefakte werden beim nächsten normalen Import wieder erstellt, wenn nötig
logger.info(f"⏭️ [SKIP] '{note_id}' unverändert (Hash identisch - überspringe komplett, auch wenn Artefakte fehlen)")
return {**result, "status": "unchanged", "note_id": note_id, "reason": "hash_identical"} return {**result, "status": "unchanged", "note_id": note_id, "reason": "hash_identical"}
# WP-24c v4.5.9: Hash geändert oder keine alte Payload - prüfe Artefakte für normale Verarbeitung
c_miss, e_miss = artifacts_missing(self.client, self.prefix, note_id)
if not apply: if not apply:
return {**result, "status": "dry-run", "changed": True, "note_id": note_id} return {**result, "status": "dry-run", "changed": True, "note_id": note_id}