If you're already working with W3C PROV-DM (building provenance graphs, querying triple stores, or running ProvToolbox pipelines), this guide shows you exactly how OpenChainGraph artifacts fit into your existing workflow. No rearchitecting required: OCG artifacts are PROV entities by construction, and the @context URL makes them natively readable by any JSON-LD/PROV-aware processor.
@context field is the bridgeEvery OpenChainGraph v0.3 artifact includes a "@context" field set to "https://ainumbers.co/chaingraph/context/v0.3". This is a JSON-LD context document that maps OCG field names to their W3C PROV-DM equivalents. The implication is direct: you don't need to transform OCG artifacts before feeding them to PROV-aware tools. They are already PROV entities.
The mapping is one-to-one at the semantic level. Each OCG field corresponds to a well-defined PROV-DM term:
| OCG Field | PROV-DM Term | Meaning |
|---|---|---|
| artifact itself | prov:Entity | The artifact is a provenance entity, a thing with identity that can be derived from other things |
| tool_id | prov:wasAttributedTo | The tool that produced this artifact is the attributed agent |
| policy_parameters | prov:used | The inputs consumed during computation |
| output_payload | prov:wasGeneratedBy | The outputs produced by the computation |
| parent_hashes[] | prov:wasDerivedFrom | Each parent hash is a derivation edge: this artifact was derived from those prior artifacts |
| execution_hash | prov:hadPrimarySource | The canonical, cryptographically verifiable identifier for this entity |
Below is an annotated OCG artifact showing the PROV-DM mapping inline. The @context field is what enables a JSON-LD processor to resolve these mappings automatically.
{
"@context": "https://ainumbers.co/chaingraph/context/v0.3", // makes this a PROV entity
"tool_id": "detect_anomalies_v3", // prov:wasAttributedTo
"mandate_type": "risk_control",
"policy_parameters": { // prov:used
"threshold": 0.05,
"window": "30d"
},
"output_payload": { // prov:wasGeneratedBy
"anomaly_score": 0.82,
"flag": true
},
"execution_hash": "sha256:3f9a1b2c8d7e4f0a...", // prov:hadPrimarySource
"chain": {
"parent_hashes": ["sha256:7c2e4d8f..."], // prov:wasDerivedFrom (one per parent)
"depth": 1,
"chain_name": "fraud_detection_chain"
},
"buildType": "https://ainumbers.co/chaingraph/context/v0.2#WebCryptoSHA256"
}
A root artifact (depth 0) has an empty parent_hashes array and maps to prov:Entity with no prov:wasDerivedFrom edges: it is the provenance root. Every downstream artifact in the chain adds one or more derivation edges.
Because OCG artifacts carry a JSON-LD @context, any JSON-LD processor can expand them into full PROV-DM triples with no custom mapping code. The jsonld npm package and pyld Python library both handle this in a single function call.
Once expanded, the output can be serialized to N-Quads and loaded directly into any RDF triple store: GraphDB, Virtuoso, Apache Jena, or an in-memory store like rdflib. From there, SPARQL queries traverse the chain natively.
import jsonld from 'jsonld'; const artifact = { /* OCG artifact object from tool output */ }; // Expand: resolves @context and returns full PROV-DM URI form const expanded = await jsonld.expand(artifact); // expanded[0]['http://www.w3.org/ns/prov#wasDerivedFrom'] → parent_hashes // expanded[0]['http://www.w3.org/ns/prov#hadPrimarySource'] → execution_hash // expanded[0]['http://www.w3.org/ns/prov#wasAttributedTo'] → tool_id agent // Serialize to N-Quads for import into any RDF triple store const nquads = await jsonld.toRDF(artifact, { format: 'application/n-quads' }); // Now importable into GraphDB, Virtuoso, Apache Jena, or rdflib
from pyld import jsonld artifact = { # OCG artifact dict loaded from JSON "@context": "https://ainumbers.co/chaingraph/context/v0.3", "tool_id": "detect_anomalies_v3", # ... remaining fields } # Expand to full PROV-DM URI form expanded = jsonld.expand(artifact) # Serialize to N-Quads nquads = jsonld.to_rdf(artifact, {'format': 'application/nquads'}) # Load into rdflib for local querying import rdflib g = rdflib.ConjunctiveGraph() g.parse(data=nquads, format='nquads') # Or POST to an Apache Jena Fuseki endpoint import requests requests.post( 'http://localhost:3030/ocg/data', data=nquads, headers={'Content-Type': 'application/n-quads'} )
Once OCG artifacts are loaded into a triple store as PROV entities, SPARQL property paths can traverse the prov:wasDerivedFrom links to reconstruct the entire provenance chain from any artifact back to the root. This works because each parent_hashes entry becomes a separate prov:wasDerivedFrom triple, which SPARQL's * path operator traverses recursively.
PREFIX prov: <http://www.w3.org/ns/prov#> PREFIX ocg: <https://ainumbers.co/chaingraph/vocab/> SELECT ?artifact ?parent ?depth WHERE { ?artifact prov:wasDerivedFrom* ?parent . ?artifact ocg:execution_hash ?hash . ?artifact ocg:chain_depth ?depth . FILTER(?hash = "sha256:3f9a1b2c8d7e4f0a...") } ORDER BY ASC(?depth)
The parent_hashes array becomes multiple prov:wasDerivedFrom triples, one per parent. SPARQL traverses these naturally with property paths (*), so diamond-shaped provenance graphs (where two chains converge) are handled without special-casing.
A second useful query pattern is finding all artifacts produced by a specific tool, useful for auditing a tool's complete decision history across all chains:
PREFIX prov: <http://www.w3.org/ns/prov#> PREFIX ocg: <https://ainumbers.co/chaingraph/vocab/> SELECT ?artifact ?hash ?chain_name WHERE { ?artifact prov:wasAttributedTo ?agent . ?agent ocg:tool_id "detect_anomalies_v3" . ?artifact ocg:execution_hash ?hash . ?artifact ocg:chain_name ?chain_name . } ORDER BY DESC(?chain_name)
PROV-DM has a human-readable textual notation called PROV-N. If your team uses ProvToolbox (the W3C reference implementation in Java) for validation, visualization, or format conversion, OCG artifacts translate directly into PROV-N representation. Below is how a single artifact link in a chain would appear:
// Two entities: the artifact (depth 1) and its parent (depth 0) entity(ocg:3f9a1b2c, [prov:hadPrimarySource="sha256:3f9a1b2c8d7e4f0a..."]) entity(ocg:7c2e4d8f, []) // Attribution: produced by detect_anomalies_v3 wasAttributedTo(ocg:3f9a1b2c, agent:detect_anomalies_v3) // Derivation: child was derived from parent wasDerivedFrom(ocg:3f9a1b2c, ocg:7c2e4d8f) // Activity: the computation run that consumed the parent and generated the child used(run:r1, ocg:7c2e4d8f) wasGeneratedBy(ocg:3f9a1b2c, run:r1)
ProvToolbox's Java library (org.openprovenance.prov) supports round-tripping between PROV-N, PROV-JSON, PROV-XML, and RDF. Use it to validate your OCG artifact graphs against PROV constraints before storing them in a compliance archive.
OCG does not require prov:Activity records: the tool itself acts as both Activity and Agent in the simplified model. If your PROV schema requires explicit Activity nodes, add synthetic run:r1 activity nodes keyed on (tool_id, execution_hash); these are stable, deterministic identifiers that won't conflict across runs.
W3C PROV-CONSTRAINTS (a W3C Recommendation) defines formal validity rules for provenance graphs. OCG's directed acyclic graph (DAG) structure is always a valid PROV derivation graph by construction: the spec enforces this through the depth rule.
The key OCG invariant that maps to PROV's acyclicity requirement is:
depth(artifact) = max(depth(parent) for parent in parent_hashes) + 1 Root artifact: depth = 0, parent_hashes = [] Child artifact: depth = 1, parent_hashes = [root.execution_hash] Grandchild: depth = 2, parent_hashes = [child.execution_hash] Consequence: no artifact can reference a descendant as a parent. This is structurally equivalent to PROV's acyclicity constraint.
When validating OCG artifact graphs with a PROV-CONSTRAINTS validator (e.g., via ProvToolbox or the W3C online validator), the following constraints are automatically satisfied:
| PROV Constraint | OCG Guarantee |
|---|---|
| Acyclicity | Depth monotonicity: child depth always strictly exceeds parent depth |
| Entity identity | execution_hash is a globally unique, content-addressed identifier: no two different computations can produce the same hash |
| Attribution completeness | tool_id is always present; every entity has exactly one attributed agent |
| Generation uniqueness | Each artifact is generated by exactly one computation (its own tool execution); the hash encodes both inputs and outputs |
Any party can independently verify an OCG artifact's integrity: re-sort the policy_parameters and output_payload keys recursively, serialize with JSON.stringify, compute SHA-256 via crypto.subtle.digest, and compare to execution_hash. This is the same check ProvToolbox's validator would run against prov:hadPrimarySource. No trusted third party is required.
Five steps to integrate OpenChainGraph artifacts into an existing W3C PROV-DM toolchain. Each step can be verified independently before proceeding.
| Step | Action | Verified by |
|---|---|---|
| 1 | Confirm tool emits v0.3 artifacts with @context field set to https://ainumbers.co/chaingraph/context/v0.3 |
JSON schema validation: check @context key presence and exact URI value |
| 2 | Load artifacts into a JSON-LD processor (jsonld.expand() or pyld.expand()) |
jsonld.expand() returns objects with prov: URIs as keys; confirm wasDerivedFrom and hadPrimarySource appear |
| 3 | Import N-Quads into your triple store (GraphDB, Virtuoso, Jena, rdflib) | SPARQL SELECT COUNT(*) WHERE { ?s ?p ?o } returns expected artifact count |
| 4 | Run prov:wasDerivedFrom* property path query to traverse chain |
Chain reconstruction query (§3) returns all ancestors down to depth 0 root |
| 5 | Optional: export PROV-N via ProvToolbox for human-readable audit trail | ProvToolbox provconvert validate command exits cleanly with no constraint violations |
You do not need to build a custom OCG-to-PROV mapper, define new SPARQL ontology predicates, or restructure your existing provenance graph. OCG artifacts drop in as additional PROV entities alongside whatever your existing tools already emit. The @context handles semantic alignment automatically.