Provenance

Provenance: trace where a value or decision came from

Record beliefs with their evidence, revise them, and walk the revision history of any belief.

Link a decision to the episodes, beliefs, and documents it used, and record who changed each property.

Approval walkthrough → Cypher reference db.beliefLineage · db.propertyProvenance

The sources of one decision (fictional example). Two episodes support belief-99, and belief-99 supports a decision. Each edge is a DERIVED_FROM relationship written by the application, pointing from the derived node to its source. Hover a node to see when it was recorded.

Each arrow is an edge written by the application: db.recordBelief links a belief to its evidence with DERIVED_FROM edges, and db.linkDerivedFrom links any node to its sources. db.derivedFrom(“decision-2026-03-05”) follows these edges from the decision and returns each source with its depth. Its argument is the node’s string id or id(n); it does not look a node up by its id property, and an id it does not find returns no rows.

Belief revisions

Walk a belief’s revisions

db.beliefLineage takes a belief ID and walks its revision chain. It returns one row per revision with its claim, confidence, when it was created, and when a later revision superseded it. Pass a second argument hops (1–3) to include the evidence reached over DERIVED_FROM edges, up to 50 entries per row.

// Revisions of belief-99, with evidence one hop away. CALL db.beliefLineage("belief-99", 1) YIELD beliefId, claim, confidence, createdAt, supersededAt, depth, evidence RETURN claim, confidence, createdAt, depth ORDER BY createdAt;

Columns

beliefId identifies the revision. claim is what it asserted. confidence is the confidence recorded with it. createdAt is when the belief was recorded. supersededAt is when a later revision replaced it (null for the current revision). depth is how far back in the revision chain the row is from the belief you passed. evidence lists the evidence reached over DERIVED_FROM edges; it is empty unless you pass hops.

Earlier revisions and their evidence

// Earlier revisions of belief-99 and their evidence. CALL db.beliefLineage("belief-99", 1) YIELD beliefId, claim, depth, evidence WHERE depth > 0 RETURN beliefId, claim, depth, evidence ORDER BY depth DESC;
Write provenance

Record who made a change

Add a provenance object to a Cypher write request to attach attribution to each property value the statement writes. The server also records which credential made the request.

Fields

All fields are optional.

Example

Fictional data. $GRAPH is your graph name and $KEY is your API key.

curl -sS -X POST "https://invariantdb.com/graphs/$GRAPH/cypher" \ -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" \ --data '{ "query": "MATCH (p:Person {name: $name}) SET p.role = $role", "parameters": {"name": "Alice", "role": "staff engineer"}, "provenance": { "actor": "hr-sync", "source": "hris", "reason": "promotion", "requestId": "req-0001", "confidence": 1.0 } }'

Headers

The same fields can be sent as headers: X-Provenance-Actor, X-Provenance-Source, X-Provenance-Reason, X-Provenance-Request-Id, and X-Provenance-Confidence. If a field is in both the body and a header, the body value is used. Header values must be ASCII. Browser applications that call from another origin must use the body field.

Behavior

Read it back

MATCH (p:Person {name: "Alice"}) CALL db.propertyProvenance(id(p), "role") YIELD value, validFrom, validTo, txnAt, actor, source, reason, requestId, confidence, principal RETURN value, validFrom, validTo, txnAt, actor, source, reason, requestId, confidence, principal;
Property provenance

Property provenance

Three records connect a value to where it came from: DERIVED_FROM edges written by the application, the provenance fields sent with each write, and the hash-chained history log.

1 · DERIVED_FROM edges

Derivations are stored as edges.

db.recordBelief writes DERIVED_FROM edges from a belief to each piece of evidence, and db.linkDerivedFrom writes them from any node to its sources. db.reviseBelief links a revision to the belief it replaces with a REVISES edge.

(:Belief)-[:DERIVED_FROM]->(:Episode)
2 · Write attribution

A write can record who made it.

Send a provenance object or X-Provenance-* headers with a Cypher write. db.propertyProvenance returns the actor, source, reason, request ID, confidence, and credential for each version of a property. See Record who made a change.

db.propertyProvenance(id, prop)
3 · Hash-chained history log

Write history is hash-chained.

Each record in the graph’s history log stores the hash of the previous record, so changing any past record breaks verification from that point on. Check the chain with GET /graphs/{name}/audit/verify, which reports the first record where verification failed. The log is not signed or anchored outside the server, so the check does not detect a rewrite of the whole log, or removal of the most recent records, by someone with write access to the server.

prevHash ← hash ← nextHash
Anatomy of an approval

Tracing an approval to its inputs

March 5. Susan approved a $4.2M commercial property policy. Six months later a regulator asks why. The steps below show the data the application recorded along the way.

Fictional example. Each step shows data the application recorded with db.recordEpisode, db.recordBelief, and db.linkDerivedFrom.

CASE FILE · pol-2026-03-9847
Susan approved a $4.2M commercial property policy.
BIND · recorded 14:32:18Z
1
14:14:33Z · viewed
Loss-run history opened.
7-year history. Two small water claims, both closed. No fire, no liability, no fraud flags. The application recorded the document view as an episode.
// The loss history as recorded at 14:14:33Z. MATCH (r:Risk {id: "CP-2026-9847"})-[:HAS_HISTORY]->(c:Claim) AT RECORDED "2026-03-05T14:14:33Z" RETURN c.date, c.amount, c.peril, c.status;
loss-run-2019-2026.pdf episode-482
2
14:18:51Z · rules
Sprinkler credit rule fired.
Engineer report attached the week before — NFPA-13 wet system, monitored 24/7. Rule SPRINKLER-CREDIT-12pct matched. 12% off the filed rate.
engineer-report-2026-02-27.pdf rule SPRINKLER-CREDIT-12pct belief-114
3
14:22:09Z · docs
CAT score pulled.
Wildfire score 24/100 from the catastrophe-model vendor. Flood zone X. Earthquake zone 3. Within the appetite band for the territory. The application recorded the API call as an episode with the response body as its payload, so the response can be retrieved later.
CAT model API response rule CAT-WITHIN-APPETITE episode-501
4
14:26:42Z · known
Reinsurance treaty checked, ceded to the property quota.
$4.2M is under the $5M single-risk cession threshold. Goes entirely through the per-risk treaty. No facultative negotiation needed. The treaty version at that clock is fetchable via AT RECORDED.
treaty-2026-property-quota.json rule TREATY-AUTOCEDE-LE-5M
5
14:32:18Z · decided
Bound and quote sent.
Premium $48,720 / yr at filed rates with the 12% sprinkler credit. Effective 2026-04-01. The application linked the Decision node to each belief, rule, document, and episode with db.linkDerivedFrom.
// The inputs linked to the decision, one hop out. MATCH (d:Decision {id: "decision-2026-03-05"})-[:DERIVED_FROM]->(src) RETURN labels(src) AS kind, src.id, src.createdAt ORDER BY src.createdAt;

Each step reads data the application recorded. Steps 1 and 5 show the Cypher queries for two of them.

History chain

Verify the history chain

GET /graphs/{name}/audit/verify re-hashes the graph’s history log and returns {"status":"clean","records":N,"last_seq":N} or {"status":"broken","offset":…,"record_index":…,"reason":"…"}. CALL db.verifyAclChain() YIELD status, entries, brokenAtEventId, reason checks the separate log of field-access-control events; its status is clean or broken.

curl -sS -H "Authorization: Bearer $KEY" \ "https://invariantdb.com/graphs/$GRAPH/audit/verify"
// Check the field-access-control event log. CALL db.verifyAclChain() YIELD status, entries, brokenAtEventId, reason RETURN status, entries, reason;
clean Example output (fictional): status: clean · entries: 48712 · reason: null
If an entry was altered. status is broken, brokenAtEventId is the first event whose hash does not reproduce, and reason describes the failure.

Approval walkthrough

An interactive version of the fictional underwriting approval above: the documents viewed, the rules applied, and the decision.