WP24c - Agentic Edge Validation & Chunk-Aware Multigraph-System (v4.5.8) #22
|
|
@ -2,7 +2,7 @@
|
||||||
FILE: app/core/database/qdrant_points.py
|
FILE: app/core/database/qdrant_points.py
|
||||||
DESCRIPTION: Object-Mapper für Qdrant. Konvertiert JSON-Payloads (Notes, Chunks, Edges)
|
DESCRIPTION: Object-Mapper für Qdrant. Konvertiert JSON-Payloads (Notes, Chunks, Edges)
|
||||||
in PointStructs und generiert deterministische UUIDs.
|
in PointStructs und generiert deterministische UUIDs.
|
||||||
VERSION: 1.5.3 (WP-Fix: Centralized Identity Enforcement)
|
VERSION: 4.0.0 (WP-24c: Gold-Standard Identity - 4-Parameter-ID)
|
||||||
STATUS: Active
|
STATUS: Active
|
||||||
DEPENDENCIES: qdrant_client, uuid, os, app.core.graph.graph_utils
|
DEPENDENCIES: qdrant_client, uuid, os, app.core.graph.graph_utils
|
||||||
LAST_ANALYSIS: 2026-01-10
|
LAST_ANALYSIS: 2026-01-10
|
||||||
|
|
@ -95,8 +95,11 @@ def _normalize_edge_payload(pl: dict) -> dict:
|
||||||
def points_for_edges(prefix: str, edge_payloads: List[dict]) -> Tuple[str, List[rest.PointStruct]]:
|
def points_for_edges(prefix: str, edge_payloads: List[dict]) -> Tuple[str, List[rest.PointStruct]]:
|
||||||
"""
|
"""
|
||||||
Konvertiert Kanten-Payloads in PointStructs.
|
Konvertiert Kanten-Payloads in PointStructs.
|
||||||
WP-24c Audit v1.5.3: Nutzt die zentrale _mk_edge_id Funktion aus graph_utils.
|
WP-24c v4.0.0: Nutzt die zentrale _mk_edge_id Funktion aus graph_utils.
|
||||||
Dies eliminiert den ID-Drift zwischen manuellen und virtuellen Kanten.
|
Dies eliminiert den ID-Drift zwischen manuellen und virtuellen Kanten.
|
||||||
|
|
||||||
|
GOLD-STANDARD v4.0.0: Die ID-Generierung verwendet STRICT nur die 4 Parameter
|
||||||
|
(kind, source_id, target_id, scope). rule_id und variant werden ignoriert.
|
||||||
"""
|
"""
|
||||||
_, _, edges_col = _names(prefix)
|
_, _, edges_col = _names(prefix)
|
||||||
points: List[rest.PointStruct] = []
|
points: List[rest.PointStruct] = []
|
||||||
|
|
@ -104,25 +107,23 @@ def points_for_edges(prefix: str, edge_payloads: List[dict]) -> Tuple[str, List[
|
||||||
for raw in edge_payloads:
|
for raw in edge_payloads:
|
||||||
pl = _normalize_edge_payload(raw)
|
pl = _normalize_edge_payload(raw)
|
||||||
|
|
||||||
# Extraktion der Identitäts-Parameter
|
# Extraktion der Identitäts-Parameter (GOLD-STANDARD v4.0.0: nur 4 Parameter)
|
||||||
kind = pl.get("kind", "edge")
|
kind = pl.get("kind", "edge")
|
||||||
s = pl.get("source_id", "unknown-src")
|
s = pl.get("source_id", "unknown-src")
|
||||||
t = pl.get("target_id", "unknown-tgt")
|
t = pl.get("target_id", "unknown-tgt")
|
||||||
scope = pl.get("scope", "note")
|
scope = pl.get("scope", "note")
|
||||||
|
|
||||||
# Optionale Differenzierung (falls von graph_derive_edges gesetzt)
|
# Hinweis: rule_id und variant werden im Payload gespeichert,
|
||||||
rule_id = pl.get("rule_id")
|
# fließen aber NICHT in die ID-Generierung ein (v4.0.0 Standard)
|
||||||
variant = pl.get("variant")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Aufruf der Single-Source-of-Truth für IDs
|
# Aufruf der Single-Source-of-Truth für IDs
|
||||||
|
# GOLD-STANDARD v4.0.0: Nur 4 Parameter werden verwendet
|
||||||
point_id = _mk_edge_id(
|
point_id = _mk_edge_id(
|
||||||
kind=kind,
|
kind=kind,
|
||||||
s=s,
|
s=s,
|
||||||
t=t,
|
t=t,
|
||||||
scope=scope,
|
scope=scope
|
||||||
rule_id=rule_id,
|
|
||||||
variant=variant
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Synchronisierung des Payloads mit der berechneten ID
|
# Synchronisierung des Payloads mit der berechneten ID
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,10 @@ def build_edges_for_note(
|
||||||
if not cid: continue
|
if not cid: continue
|
||||||
|
|
||||||
# Verbindung Chunk -> Note
|
# Verbindung Chunk -> Note
|
||||||
|
# WP-24c v4.0.0: rule_id wird nur im Payload gespeichert, fließt nicht in die ID ein
|
||||||
edges.append(_edge("belongs_to", "chunk", cid, note_id, note_id, {
|
edges.append(_edge("belongs_to", "chunk", cid, note_id, note_id, {
|
||||||
"chunk_id": cid,
|
"chunk_id": cid,
|
||||||
"edge_id": _mk_edge_id("belongs_to", cid, note_id, "chunk", "structure:belongs_to"),
|
"edge_id": _mk_edge_id("belongs_to", cid, note_id, "chunk"),
|
||||||
"provenance": "structure",
|
"provenance": "structure",
|
||||||
"rule_id": "structure:belongs_to",
|
"rule_id": "structure:belongs_to",
|
||||||
"confidence": PROVENANCE_PRIORITY["structure:belongs_to"]
|
"confidence": PROVENANCE_PRIORITY["structure:belongs_to"]
|
||||||
|
|
@ -48,14 +49,15 @@ def build_edges_for_note(
|
||||||
if idx < len(chunks) - 1:
|
if idx < len(chunks) - 1:
|
||||||
next_id = _get(chunks[idx+1], "chunk_id", "id")
|
next_id = _get(chunks[idx+1], "chunk_id", "id")
|
||||||
if next_id:
|
if next_id:
|
||||||
|
# WP-24c v4.0.0: rule_id wird nur im Payload gespeichert, fließt nicht in die ID ein
|
||||||
edges.append(_edge("next", "chunk", cid, next_id, note_id, {
|
edges.append(_edge("next", "chunk", cid, next_id, note_id, {
|
||||||
"chunk_id": cid,
|
"chunk_id": cid,
|
||||||
"edge_id": _mk_edge_id("next", cid, next_id, "chunk", "structure:order"),
|
"edge_id": _mk_edge_id("next", cid, next_id, "chunk"),
|
||||||
"provenance": "structure", "rule_id": "structure:order", "confidence": PROVENANCE_PRIORITY["structure:order"]
|
"provenance": "structure", "rule_id": "structure:order", "confidence": PROVENANCE_PRIORITY["structure:order"]
|
||||||
}))
|
}))
|
||||||
edges.append(_edge("prev", "chunk", next_id, cid, note_id, {
|
edges.append(_edge("prev", "chunk", next_id, cid, note_id, {
|
||||||
"chunk_id": next_id,
|
"chunk_id": next_id,
|
||||||
"edge_id": _mk_edge_id("prev", next_id, cid, "chunk", "structure:order"),
|
"edge_id": _mk_edge_id("prev", next_id, cid, "chunk"),
|
||||||
"provenance": "structure", "rule_id": "structure:order", "confidence": PROVENANCE_PRIORITY["structure:order"]
|
"provenance": "structure", "rule_id": "structure:order", "confidence": PROVENANCE_PRIORITY["structure:order"]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -77,8 +79,8 @@ def build_edges_for_note(
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"chunk_id": cid,
|
"chunk_id": cid,
|
||||||
# WP-Fix: Variant=sec sorgt für eindeutige ID pro Sektion
|
# WP-24c v4.0.0: variant wird nur im Payload gespeichert (target_section), fließt nicht in die ID ein
|
||||||
"edge_id": _mk_edge_id(k, cid, t, "chunk", "inline:rel", variant=sec),
|
"edge_id": _mk_edge_id(k, cid, t, "chunk"),
|
||||||
"provenance": "explicit", "rule_id": "inline:rel", "confidence": PROVENANCE_PRIORITY["inline:rel"]
|
"provenance": "explicit", "rule_id": "inline:rel", "confidence": PROVENANCE_PRIORITY["inline:rel"]
|
||||||
}
|
}
|
||||||
if sec: payload["target_section"] = sec
|
if sec: payload["target_section"] = sec
|
||||||
|
|
@ -90,9 +92,10 @@ def build_edges_for_note(
|
||||||
raw_t, k, p = cand.get("to"), cand.get("kind", "related_to"), cand.get("provenance", "semantic_ai")
|
raw_t, k, p = cand.get("to"), cand.get("kind", "related_to"), cand.get("provenance", "semantic_ai")
|
||||||
t, sec = parse_link_target(raw_t, note_id)
|
t, sec = parse_link_target(raw_t, note_id)
|
||||||
if t:
|
if t:
|
||||||
|
# WP-24c v4.0.0: rule_id und variant werden nur im Payload gespeichert, fließen nicht in die ID ein
|
||||||
payload = {
|
payload = {
|
||||||
"chunk_id": cid,
|
"chunk_id": cid,
|
||||||
"edge_id": _mk_edge_id(k, cid, t, "chunk", f"candidate:{p}", variant=sec),
|
"edge_id": _mk_edge_id(k, cid, t, "chunk"),
|
||||||
"provenance": p, "rule_id": f"candidate:{p}", "confidence": PROVENANCE_PRIORITY.get(p, 0.90)
|
"provenance": p, "rule_id": f"candidate:{p}", "confidence": PROVENANCE_PRIORITY.get(p, 0.90)
|
||||||
}
|
}
|
||||||
if sec: payload["target_section"] = sec
|
if sec: payload["target_section"] = sec
|
||||||
|
|
@ -104,9 +107,10 @@ def build_edges_for_note(
|
||||||
t, sec = parse_link_target(raw_t, note_id)
|
t, sec = parse_link_target(raw_t, note_id)
|
||||||
if not t: continue
|
if not t: continue
|
||||||
|
|
||||||
|
# WP-24c v4.0.0: rule_id und variant werden nur im Payload gespeichert, fließen nicht in die ID ein
|
||||||
payload = {
|
payload = {
|
||||||
"chunk_id": cid,
|
"chunk_id": cid,
|
||||||
"edge_id": _mk_edge_id(k, cid, t, "chunk", "callout:edge", variant=sec),
|
"edge_id": _mk_edge_id(k, cid, t, "chunk"),
|
||||||
"provenance": "explicit", "rule_id": "callout:edge", "confidence": PROVENANCE_PRIORITY["callout:edge"]
|
"provenance": "explicit", "rule_id": "callout:edge", "confidence": PROVENANCE_PRIORITY["callout:edge"]
|
||||||
}
|
}
|
||||||
if sec: payload["target_section"] = sec
|
if sec: payload["target_section"] = sec
|
||||||
|
|
@ -118,9 +122,10 @@ def build_edges_for_note(
|
||||||
r, sec = parse_link_target(raw_r, note_id)
|
r, sec = parse_link_target(raw_r, note_id)
|
||||||
if not r: continue
|
if not r: continue
|
||||||
|
|
||||||
|
# WP-24c v4.0.0: rule_id und variant werden nur im Payload gespeichert, fließen nicht in die ID ein
|
||||||
payload = {
|
payload = {
|
||||||
"chunk_id": cid, "ref_text": raw_r,
|
"chunk_id": cid, "ref_text": raw_r,
|
||||||
"edge_id": _mk_edge_id("references", cid, r, "chunk", "explicit:wikilink", variant=sec),
|
"edge_id": _mk_edge_id("references", cid, r, "chunk"),
|
||||||
"provenance": "explicit", "rule_id": "explicit:wikilink", "confidence": PROVENANCE_PRIORITY["explicit:wikilink"]
|
"provenance": "explicit", "rule_id": "explicit:wikilink", "confidence": PROVENANCE_PRIORITY["explicit:wikilink"]
|
||||||
}
|
}
|
||||||
if sec: payload["target_section"] = sec
|
if sec: payload["target_section"] = sec
|
||||||
|
|
@ -129,9 +134,10 @@ def build_edges_for_note(
|
||||||
# Automatische Kanten-Vererbung aus types.yaml
|
# Automatische Kanten-Vererbung aus types.yaml
|
||||||
for rel in defaults:
|
for rel in defaults:
|
||||||
if rel != "references":
|
if rel != "references":
|
||||||
|
# WP-24c v4.0.0: rule_id und variant werden nur im Payload gespeichert, fließen nicht in die ID ein
|
||||||
def_payload = {
|
def_payload = {
|
||||||
"chunk_id": cid,
|
"chunk_id": cid,
|
||||||
"edge_id": _mk_edge_id(rel, cid, r, "chunk", f"edge_defaults:{rel}", variant=sec),
|
"edge_id": _mk_edge_id(rel, cid, r, "chunk"),
|
||||||
"provenance": "rule", "rule_id": f"edge_defaults:{rel}", "confidence": PROVENANCE_PRIORITY["edge_defaults"]
|
"provenance": "rule", "rule_id": f"edge_defaults:{rel}", "confidence": PROVENANCE_PRIORITY["edge_defaults"]
|
||||||
}
|
}
|
||||||
if sec: def_payload["target_section"] = sec
|
if sec: def_payload["target_section"] = sec
|
||||||
|
|
@ -146,19 +152,21 @@ def build_edges_for_note(
|
||||||
|
|
||||||
for r in refs_note:
|
for r in refs_note:
|
||||||
if not r: continue
|
if not r: continue
|
||||||
|
# WP-24c v4.0.0: rule_id wird nur im Payload gespeichert, fließt nicht in die ID ein
|
||||||
edges.append(_edge("references", "note", note_id, r, note_id, {
|
edges.append(_edge("references", "note", note_id, r, note_id, {
|
||||||
"edge_id": _mk_edge_id("references", note_id, r, "note", "explicit:note_scope"),
|
"edge_id": _mk_edge_id("references", note_id, r, "note"),
|
||||||
"provenance": "explicit", "confidence": PROVENANCE_PRIORITY["explicit:note_scope"]
|
"provenance": "explicit", "rule_id": "explicit:note_scope", "confidence": PROVENANCE_PRIORITY["explicit:note_scope"]
|
||||||
}))
|
}))
|
||||||
# Backlinks zur Stärkung der Bidirektionalität
|
# Backlinks zur Stärkung der Bidirektionalität
|
||||||
edges.append(_edge("backlink", "note", r, note_id, note_id, {
|
edges.append(_edge("backlink", "note", r, note_id, note_id, {
|
||||||
"edge_id": _mk_edge_id("backlink", r, note_id, "note", "derived:backlink"),
|
"edge_id": _mk_edge_id("backlink", r, note_id, "note"),
|
||||||
"provenance": "rule", "confidence": PROVENANCE_PRIORITY["derived:backlink"]
|
"provenance": "rule", "rule_id": "derived:backlink", "confidence": PROVENANCE_PRIORITY["derived:backlink"]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
# 4) De-Duplizierung (In-Place)
|
# 4) De-Duplizierung (In-Place)
|
||||||
# Da die EDGE-ID nun die Sektion (variant) enthält, bleiben Links auf
|
# WP-24c v4.0.0: Da die EDGE-ID nur auf 4 Parametern basiert (kind, source, target, scope),
|
||||||
# unterschiedliche Abschnitte derselben Note erhalten.
|
# werden Links auf unterschiedliche Abschnitte derselben Note durch die De-Duplizierung
|
||||||
|
# konsolidiert. Die Sektion-Information bleibt im Payload (target_section) erhalten.
|
||||||
unique_map: Dict[str, dict] = {}
|
unique_map: Dict[str, dict] = {}
|
||||||
for e in edges:
|
for e in edges:
|
||||||
eid = e["edge_id"]
|
eid = e["edge_id"]
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
"""
|
"""
|
||||||
FILE: app/core/graph/graph_utils.py
|
FILE: app/core/graph/graph_utils.py
|
||||||
DESCRIPTION: Basale Werkzeuge, ID-Generierung und Provenance-Konfiguration für den Graphen.
|
DESCRIPTION: Basale Werkzeuge, ID-Generierung und Provenance-Konfiguration für den Graphen.
|
||||||
AUDIT v1.6.2:
|
AUDIT v4.0.0:
|
||||||
- Festlegung des globalen Standards für Kanten-IDs (WP-24c).
|
- GOLD-STANDARD v4.0.0: Strikte 4-Parameter-ID für Kanten (kind, source, target, scope).
|
||||||
- Fix für ImportError (_edge Funktion wiederhergestellt).
|
- Eliminiert ID-Inkonsistenz zwischen Phase 1 (Autorität) und Phase 2 (Symmetrie).
|
||||||
- Integration der .env Pfad-Auflösung für Schema und Vokabular.
|
- rule_id und variant werden ignoriert in der ID-Generierung (nur im Payload gespeichert).
|
||||||
VERSION: 1.6.2 (WP-24c: Global Identity Standard)
|
- Fix für das "Steinzeitaxt"-Problem durch konsistente ID-Generierung.
|
||||||
|
VERSION: 4.0.0 (WP-24c: Gold-Standard Identity)
|
||||||
STATUS: Active
|
STATUS: Active
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
@ -87,30 +88,32 @@ def parse_link_target(raw: str, current_note_id: Optional[str] = None) -> Tuple[
|
||||||
|
|
||||||
def _mk_edge_id(kind: str, s: str, t: str, scope: str, rule_id: Optional[str] = None, variant: Optional[str] = None) -> str:
|
def _mk_edge_id(kind: str, s: str, t: str, scope: str, rule_id: Optional[str] = None, variant: Optional[str] = None) -> str:
|
||||||
"""
|
"""
|
||||||
WP-24c: DER GLOBALE STANDARD für Kanten-IDs.
|
WP-24c v4.0.0: DER GLOBALE STANDARD für Kanten-IDs.
|
||||||
Erzeugt eine deterministische UUIDv5. Dies stellt sicher, dass manuelle Links
|
Erzeugt eine deterministische UUIDv5. Dies stellt sicher, dass manuelle Links
|
||||||
und systemgenerierte Symmetrien dieselbe Point-ID in Qdrant erhalten.
|
und systemgenerierte Symmetrien dieselbe Point-ID in Qdrant erhalten.
|
||||||
|
|
||||||
|
GOLD-STANDARD v4.0.0: Die ID basiert STRICT auf vier Parametern:
|
||||||
|
f"edge:{kind}:{source}:{target}:{scope}"
|
||||||
|
|
||||||
|
Die Parameter rule_id und variant werden IGNORIERT und fließen NICHT in die ID ein.
|
||||||
|
Sie können weiterhin im Payload gespeichert werden, haben aber keinen Einfluss auf die Identität.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
kind: Typ der Relation (z.B. 'mastered_by')
|
kind: Typ der Relation (z.B. 'mastered_by')
|
||||||
s: Kanonische ID der Quell-Note
|
s: Kanonische ID der Quell-Note
|
||||||
t: Kanonische ID der Ziel-Note
|
t: Kanonische ID der Ziel-Note
|
||||||
scope: Granularität (Standard: 'note')
|
scope: Granularität (Standard: 'note')
|
||||||
rule_id: Optionale ID der Regel (aus graph_derive_edges)
|
rule_id: Optionale ID der Regel (aus graph_derive_edges) - IGNORIERT in ID-Generierung
|
||||||
variant: Optionale Variante für multiple Links zum selben Ziel
|
variant: Optionale Variante für multiple Links zum selben Ziel - IGNORIERT in ID-Generierung
|
||||||
"""
|
"""
|
||||||
if not all([kind, s, t]):
|
if not all([kind, s, t]):
|
||||||
raise ValueError(f"Incomplete data for edge ID: kind={kind}, src={s}, tgt={t}")
|
raise ValueError(f"Incomplete data for edge ID: kind={kind}, src={s}, tgt={t}")
|
||||||
|
|
||||||
# STRENGER STANDARD: Nutzt Doppelpunkte als Trenner.
|
# GOLD-STANDARD v4.0.0: STRICT 4-Parameter-ID
|
||||||
|
# Keine Suffixe für rule_id oder variant im Hash-String!
|
||||||
# Jede manuelle Änderung an diesem String-Format führt zu doppelten Kanten in der DB!
|
# Jede manuelle Änderung an diesem String-Format führt zu doppelten Kanten in der DB!
|
||||||
base = f"edge:{kind}:{s}:{t}:{scope}"
|
base = f"edge:{kind}:{s}:{t}:{scope}"
|
||||||
|
|
||||||
if rule_id:
|
|
||||||
base += f":{rule_id}"
|
|
||||||
if variant:
|
|
||||||
base += f":{variant}"
|
|
||||||
|
|
||||||
# Nutzt den URL-Namespace für deterministische Reproduzierbarkeit
|
# Nutzt den URL-Namespace für deterministische Reproduzierbarkeit
|
||||||
return str(uuid.uuid5(uuid.NAMESPACE_URL, base))
|
return str(uuid.uuid5(uuid.NAMESPACE_URL, base))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ DESCRIPTION: Der zentrale IngestionService (Orchestrator).
|
||||||
WP-25a: Integration der Mixture of Experts (MoE) Architektur.
|
WP-25a: Integration der Mixture of Experts (MoE) Architektur.
|
||||||
WP-15b: Two-Pass Workflow mit globalem Kontext-Cache.
|
WP-15b: Two-Pass Workflow mit globalem Kontext-Cache.
|
||||||
WP-20/22: Cloud-Resilienz und Content-Lifecycle integriert.
|
WP-20/22: Cloud-Resilienz und Content-Lifecycle integriert.
|
||||||
AUDIT v3.4.3:
|
AUDIT v4.0.0:
|
||||||
- Entfernung des inkompatiblen edge_registry.initialize Aufrufs.
|
- GOLD-STANDARD v4.0.0: Phase 2 verwendet exakt dieselbe 4-Parameter-ID wie Phase 1.
|
||||||
|
- Authority-Check in Phase 2 prüft mit konsistenter ID-Generierung.
|
||||||
|
- Eliminiert Duplikate durch inkonsistente ID-Generierung (Steinzeitaxt-Problem).
|
||||||
- Beibehaltung der strikten 2-Phasen-Strategie (Authority-First).
|
- Beibehaltung der strikten 2-Phasen-Strategie (Authority-First).
|
||||||
- Fix für das Steinzeitaxt-Problem via zentralisierter ID-Logik.
|
VERSION: 4.0.0 (WP-24c: Gold-Standard Identity)
|
||||||
VERSION: 3.4.3 (WP-24c: Compatibility Fix)
|
|
||||||
STATUS: Active
|
STATUS: Active
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
|
@ -148,13 +149,15 @@ class IngestionService:
|
||||||
src, tgt, kind = v_edge.get("note_id"), v_edge.get("target_id"), v_edge.get("kind")
|
src, tgt, kind = v_edge.get("note_id"), v_edge.get("target_id"), v_edge.get("kind")
|
||||||
if not src or not tgt: continue
|
if not src or not tgt: continue
|
||||||
|
|
||||||
# WP-Fix: Nutzung der zentralisierten ID-Logik aus graph_utils
|
# WP-24c v4.0.0: Nutzung der zentralisierten ID-Logik aus graph_utils
|
||||||
|
# GOLD-STANDARD: Exakt 4 Parameter (kind, source, target, scope)
|
||||||
try:
|
try:
|
||||||
v_id = _mk_edge_id(kind, src, tgt, "note")
|
v_id = _mk_edge_id(kind, src, tgt, "note")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# AUTHORITY-CHECK: Nur schreiben, wenn keine manuelle Kante existiert
|
# AUTHORITY-CHECK: Nur schreiben, wenn keine manuelle Kante existiert
|
||||||
|
# Prüft mit exakt derselben 4-Parameter-ID, die in Phase 1 verwendet wurde
|
||||||
if not is_explicit_edge_present(self.client, self.prefix, v_id):
|
if not is_explicit_edge_present(self.client, self.prefix, v_id):
|
||||||
final_virtuals.append(v_edge)
|
final_virtuals.append(v_edge)
|
||||||
logger.info(f" 🔄 [SYMMETRY] Add inverse: {src} --({kind})--> {tgt}")
|
logger.info(f" 🔄 [SYMMETRY] Add inverse: {src} --({kind})--> {tgt}")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user