From 6047e9496409f87b99b60ad3db2740a6b271a3ba Mon Sep 17 00:00:00 2001 From: Lars Date: Mon, 12 Jan 2026 08:04:28 +0100 Subject: [PATCH] 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. --- app/core/graph/graph_derive_edges.py | 7 ++++++- app/core/ingestion/ingestion_processor.py | 16 +++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/core/graph/graph_derive_edges.py b/app/core/graph/graph_derive_edges.py index a42e8fa..195926f 100644 --- a/app/core/graph/graph_derive_edges.py +++ b/app/core/graph/graph_derive_edges.py @@ -910,7 +910,12 @@ def build_edges_for_note( # Schritt 3: ID-Zuweisung nach Scope-Entscheidung 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 # Prüfe, ob diese Gruppe Callout-Kanten enthält has_callouts = any(e.get("provenance") == "explicit:callout" for e in group) diff --git a/app/core/ingestion/ingestion_processor.py b/app/core/ingestion/ingestion_processor.py index 9cd2d78..69c9045 100644 --- a/app/core/ingestion/ingestion_processor.py +++ b/app/core/ingestion/ingestion_processor.py @@ -268,7 +268,6 @@ class IngestionService: # WP-24c v4.5.9: Strikte Change Detection (Hash-basierte Inhaltsprüfung) # 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) - c_miss, e_miss = artifacts_missing(self.client, self.prefix, note_id) content_changed = True hash_match = False @@ -290,11 +289,18 @@ class IngestionService: # 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)}") - # WP-24c v4.5.9: Strikte Logik - überspringe komplett wenn Hash identisch UND keine Artefakte fehlen - # Dies verhindert redundante Embedding-Generierung und Chunk-Verarbeitung - if not force_replace and hash_match and old_payload and not c_miss and not e_miss: - logger.info(f"⏭️ [SKIP] '{note_id}' unverändert (Hash identisch, alle Artefakte vorhanden)") + # WP-24c v4.5.9: Strikte Logik - überspringe komplett wenn Hash identisch + # WICHTIG: Artifact-Check NACH Hash-Check, da purge_before die Artefakte löschen kann + # Wenn Hash identisch ist, sind die Artefakte entweder vorhanden oder werden gerade neu geschrieben + 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"} + + # 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: return {**result, "status": "dry-run", "changed": True, "note_id": note_id}