Reference
Graph comparison and quality diagnostics
Behavior
Input condition |
Diagnostic |
Interpretation left to caller |
|---|---|---|
Edge references absent node |
Dangling edge |
Reject, repair, or allow external identity |
Node has degree zero |
Orphan |
Valid isolated fact or missing relation |
Several nodes share a fingerprint |
Duplicate group |
Alias, duplicate, or intentional version |
Revision changes edges |
Structural diff |
Expected update or unexpected drift |
How it works
graph_diff compares caller-provided node IDs and hashable edge keys.
inspect_graph_quality calculates structural observations. The caller sets
thresholds and acceptance policy.
from mari_components.graph import graph_diff, inspect_graph_quality
change = graph_diff(
before_nodes=previous.node_ids,
before_edges=previous.edge_keys,
after_nodes=current.node_ids,
after_edges=current.edge_keys,
)
quality = inspect_graph_quality(
nodes=current.node_ids,
edges=current.endpoints,
fingerprint=lambda node: normalized_identity[node],
)
The diff uses exact identity and set semantics. Callers can run entity resolution before comparison when that is appropriate.
Preserve relation type and edge identity in edge keys when parallel relations carry different meaning. An endpoints-only key collapses those distinctions. Use stable scoped object identity to compare the same object across revisions, then compare its fingerprint to detect content changes.
diff_records detects changes that preserve node identity, such as a modified
function body or an updated entity attribute. Identity and fingerprints remain
caller projections.
from mari_components.graph import diff_records
records = diff_records(
previous.symbols,
current.symbols,
identity=lambda symbol: symbol.qualified_name,
fingerprint=lambda symbol: (symbol.signature, symbol.body_hash),
)
for change in records.modified:
schedule_impact_analysis(change.record_id)
When a fingerprint says that a record changed, diff_record_fields can name
the caller-projected fields responsible for the change.
from mari_components.graph import diff_record_fields
changes = diff_record_fields(
previous.clauses,
current.clauses,
identity=lambda clause: clause.clause_id,
fields={
"text": lambda clause: clause.text,
"scope": lambda clause: clause.scope,
"effective": lambda clause: clause.valid_time,
},
)
Measures
For derived outputs, pass changed current stamps and collection membership to the dependency planner. Structural differences identify changed topology. Receipts determine whether completed computations remain reusable after that change.
Measure |
Calculation |
|---|---|
Node/edge change rate |
Symmetric difference divided by union |
Dangling-edge rate |
Edges with missing endpoints divided by edges |
Orphan rate |
Zero-degree nodes divided by nodes |
Duplicate rate |
Nodes in repeated fingerprint groups divided by nodes |
Construction fidelity |
Entity completeness, relation preservation, multiplicity, negation |
Papers and implementations
KGCQualKGCQual implementationStructural quality metricsKnowledge graph quality survey
KGCQual is Apache-2.0. Mari’s built-in report is structural and model-free. Semantic fidelity evaluators remain injectable.