PROV-O Provenance

Record agents, activities and entities.

0/3 done

Theory

PROV-O gives you three core classes:

  • prov:Entity — the data (e.g. a graph, a document)
  • prov:Activity — the process that produced it
  • prov:Agent — the human or service responsible

Plus connectors like prov:wasGeneratedBy, prov:wasAttributedTo, prov:wasDerivedFrom. Together they let you reconstruct who added what when — the audit trail your security team will eventually demand.

Analogy

PROV-O is the git log of your knowledge graph. Without it you can't tell an authoritative triple from one a junior service injected by accident.

And like git blame, the value is greatest at 3am during an incident: when a dashboard goes weird you can trace each suspicious triple back to the activity that produced it and the agent who ran it — instead of guessing.

Theory

Going deeper — provenance is a chain, not a tag

The power of PROV-O shows up when entities derive from other entities. prov:wasDerivedFrom links a new entity to the source it was built from, so you can walk backwards from a published dashboard number all the way to the raw ingest — crossing every cleaning, joining and inference step:

:report a prov:Entity ;
  prov:wasDerivedFrom :enriched_graph .
:enriched_graph prov:wasDerivedFrom :raw_import .

Why this matters for security & trust.

  • Tamper-evidence by accountability. Every triple can be traced to the activity and agent that asserted it — so an injected or wrong triple has a name attached.
  • Trust propagation. If you trust an agent, you can choose to trust the entities it generated; if an agent is compromised, the chain tells you exactly which downstream data to quarantine.
  • Provenance is itself just triples, so it lives in the same store and is queryable with SPARQL — but keep it in its own named graph so it can't be silently rewritten by the same agents whose work it records.

Visualization

Query Pattern match Bindings Result

Entity ← generated-by — Activity ← associated-with — Agent: the three-node backbone every audit query walks.

Chain several of these together with prov:wasDerivedFrom and you get a full lineage graph — the same shape a data-lineage tool draws, expressed in plain RDF you can query.

Worked example — PROV-O record

Worked example — a complete provenance record.

You imported a graph using activity :import_42, run by user :alice. Record the full audit trail like this:

@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:graph_2025_05_18 a prov:Entity ;
  prov:wasGeneratedBy :import_42 .

:import_42 a prov:Activity ;
  prov:wasAssociatedWith :alice ;
  prov:startedAtTime "2025-05-18T10:30:00Z"^^xsd:dateTime .

:alice a prov:Agent ;
  foaf:name "Alice" .

How to read it: the Entity points to the Activity that produced it (prov:wasGeneratedBy); the Activity points to the Agent responsible (prov:wasAssociatedWith). For the playground below you only need those two connector triples — declaring the classes (a prov:Entity / Activity / Agent) is recommended but the grader accepts the minimal form.

Reflect

Imagine an incident review next quarter: a wrong figure shipped to a customer. Which PROV-O triples would let you answer who, what, when in minutes instead of days?

The teams that recover fastest treat provenance as non-optional metadata written at every write, not as a nice-to-have bolted on after an outage.

  • Which single PROV-O property would you add to every write first, and why?
  • Who should be allowed to write into the provenance graph itself?

Reading in progress · 0 of 3 activities done