Skip to content

RDFC-1.0 canonical graph digest — pgrdf.graph_digest(graph): graph identity that survives reload #117

Description

@styk-tv

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: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.
  • Optionally expose the canonical serialization itself (pairs with pgrdf.export_graph / import_graph — native portable dump+restore (proven at 120M) #36 export_graph).
  • 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2deferred / contingentenhancementImprovement to existing behaviour

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions