You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A sha256 over exported N-Triples is a digest of one stored copy, not of the graph. Blank
nodes are existential variables — their labels are minted per parse — so loading the same file
twice produces different bytes for identical structure, forever. SHACL makes this the common
case, not an edge case: every sh:property constraint hangs off a blank node.
Measured on a 948-triple SHACL ontology: 531 of 948 triples involve a blank node (130
distinct). Two independently-loaded copies of the same file differed by 6 bytes — entirely
blank-node label-length variance — while being structurally identical. Any downstream scheme
that pins graph identity to a byte digest reports false divergence on every reload.
Client-side approximations exist (first-degree blank-node neighbourhood signatures). Their
verdict is asymmetric by construction: unequal digests prove difference, equal digests are
only evidence of isomorphism — symmetric blank-node structures can collide. Only canonical
relabelling closes that gap, and the engine is the right seat for it.
What
pgrdf.graph_digest(graph_id bigint) -> text — the sha256 of the graph's asserted triples
after RDF Dataset Canonicalization (RDFC-1.0 / URDNA2015) canonical blank-node relabelling,
serialized as sorted canonical N-Triples.
Asserted-only by default; an include_inferred variant may follow.
Document the complexity honestly: RDFC-1.0 is worst-case exponential on adversarial
blank-node automorphism structures; real ontologies are far from that. A guard (node-count /
recursion budget) that raises rather than degrades keeps the fail-closed direction.
Acceptance
Reload test: load the same source file into two fresh graphs → graph_digest equal, byte
digests of the two exports unequal.
Negative control: two genuinely different graphs → unequal digests.
Regression: digest stable across dump/restore round-trip.
Non-goals
Does not replace byte digests — those remain correct for copy verification (expect_sha256
import guards). This adds the identity plane a byte digest cannot express.
Related: #36 (native export), and the companion issue on load-time source-byte digests.
Why
A sha256 over exported N-Triples is a digest of one stored copy, not of the graph. Blank
nodes are existential variables — their labels are minted per parse — so loading the same file
twice produces different bytes for identical structure, forever. SHACL makes this the common
case, not an edge case: every
sh:propertyconstraint hangs off a blank node.Measured on a 948-triple SHACL ontology: 531 of 948 triples involve a blank node (130
distinct). Two independently-loaded copies of the same file differed by 6 bytes — entirely
blank-node label-length variance — while being structurally identical. Any downstream scheme
that pins graph identity to a byte digest reports false divergence on every reload.
Client-side approximations exist (first-degree blank-node neighbourhood signatures). Their
verdict is asymmetric by construction: unequal digests prove difference, equal digests are
only evidence of isomorphism — symmetric blank-node structures can collide. Only canonical
relabelling closes that gap, and the engine is the right seat for it.
What
pgrdf.graph_digest(graph_id bigint) -> text— the sha256 of the graph's asserted triplesafter RDF Dataset Canonicalization (RDFC-1.0 / URDNA2015) canonical blank-node relabelling,
serialized as sorted canonical N-Triples.
include_inferredvariant may follow.blank-node automorphism structures; real ontologies are far from that. A guard (node-count /
recursion budget) that raises rather than degrades keeps the fail-closed direction.
Acceptance
graph_digestequal, bytedigests of the two exports unequal.
Non-goals
Does not replace byte digests — those remain correct for copy verification (
expect_sha256import guards). This adds the identity plane a byte digest cannot express.
Related: #36 (native export), and the companion issue on load-time source-byte digests.