Every state change in the Tenor executor is accompanied by a provenance chain: a complete record of why the change happened, what facts were evaluated, which rules fired, what verdicts were produced, and who authorized the operation. Provenance is not optional logging --- it is a structural guarantee of the executor (obligation E6).
Why Provenance Matters
In a traditional system, you find out that an order was cancelled by looking at a status column in a database. If you want to know why, you search through application logs, hope the relevant context was logged, and reconstruct the story manually.
In Tenor, provenance is the story. The chain tells you:
- What facts were true at the moment of evaluation
- Which rules fired and which did not
- What verdicts were produced and at which stratum
- Which persona authorized the operation
- What precondition was satisfied
- Which entity instances transitioned and from which state to which state
- The exact timestamp and execution ID
This chain is immutable. It is recorded atomically with the state change. It cannot be retroactively modified or deleted (short of deleting the entire deployment).
Chain Structure
A provenance chain is a layered record, from outermost (flow-level) to innermost (fact-level):
FlowOutcome
└── StepRecord (one per step executed)
└── OperationProvenance
├── PersonaBinding (who authorized this)
├── PreconditionResult (which verdict was checked)
└── VerdictSet (all verdicts at time of evaluation)
└── VerdictProvenance (per verdict)
└── FactProvenance (per fact used)FlowOutcome
The top-level record for a flow execution. Contains metadata about the flow run and references to each step that was executed.
{
"provenance_chain_id": "chain_20260215_001",
"flow_id": "release_flow",
"execution_id": "exec_20260215_001",
"org": "acme",
"contract": "escrow",
"contract_hash": "sha256:9f4a2b...",
"started_at": "2026-02-15T14:30:00.000Z",
"completed_at": "2026-02-15T14:30:00.047Z",
"status": "completed",
"steps": [
{"step_id": "step_001", "ref": "prov_20260215_001"},
{"step_id": "step_002", "ref": "prov_20260215_002"}
]
}StepRecord
One record per flow step that executed. References the operation provenance for OperationSteps, or records the handoff for HandoffSteps.
{
"step_record_id": "step_001",
"step_name": "verify_approval",
"step_type": "OperationStep",
"operation": "verify_release",
"result": "success",
"operation_provenance": "prov_20260215_001",
"executed_at": "2026-02-15T14:30:00.012Z",
"duration_ms": 3
}For HandoffSteps:
{
"step_record_id": "step_003",
"step_name": "handoff_to_seller",
"step_type": "HandoffStep",
"from_persona": "escrow_agent",
"to_persona": "seller",
"executed_at": "2026-02-15T14:30:00.025Z"
}OperationProvenance
The core provenance record for a single operation execution. This is where the actual reasoning chain lives.
{
"provenance_id": "prov_20260215_001",
"operation": "verify_release",
"persona": {
"contract_persona": "escrow_agent",
"resolved_from": "tk_live_agent_key",
"resolution_method": "key_binding"
},
"precondition": {
"expression": "verdict_present(release_approval_ok)",
"result": true,
"verdict_ref": "release_approval_ok"
},
"entity_transitions": [
{
"entity": "Order",
"instance": "order_001",
"from_state": "pending",
"to_state": "approved",
"transition_declared": true
}
],
"verdict_set_ref": "vs_20260215_001",
"evaluated_at": "2026-02-15T14:30:00.008Z",
"applied_at": "2026-02-15T14:30:00.012Z",
"snapshot_id": "snap_20260215_001"
}VerdictSet
The complete set of verdicts computed during the evaluation that preceded the operation. Every verdict is recorded, not just the ones used by the operation's precondition.
{
"verdict_set_id": "vs_20260215_001",
"contract_hash": "sha256:9f4a2b...",
"evaluated_at": "2026-02-15T14:30:00.008Z",
"verdicts": [
{
"name": "payment_ok",
"value": true,
"type": "Bool",
"stratum": 0,
"rule": "check_payment",
"provenance": "vp_20260215_001"
},
{
"name": "release_approval_ok",
"value": true,
"type": "Bool",
"stratum": 1,
"rule": "check_release_approval",
"provenance": "vp_20260215_002"
},
{
"name": "eligible_for_express",
"value": false,
"type": "Bool",
"stratum": 1,
"rule": "check_express_eligibility",
"provenance": "vp_20260215_003"
}
]
}VerdictProvenance
Per-verdict record showing exactly which facts and lower-stratum verdicts contributed to this verdict.
{
"verdict_provenance_id": "vp_20260215_002",
"verdict_name": "release_approval_ok",
"rule": "check_release_approval",
"stratum": 1,
"when_expression": "verdict_present(payment_ok) AND release_approved = true",
"result": true,
"inputs": {
"verdicts_referenced": [
{
"name": "payment_ok",
"value": true,
"stratum": 0,
"provenance_ref": "vp_20260215_001"
}
],
"facts_referenced": [
{
"name": "release_approved",
"value": true,
"provenance_ref": "fp_20260215_002"
}
]
}
}FactProvenance
The leaf node of the provenance chain. Records the fact value as it was received, its declared type, and the source declaration (if any).
{
"fact_provenance_id": "fp_20260215_001",
"fact_name": "payment_received",
"declared_type": "Bool",
"value": true,
"source": "api_input",
"received_at": "2026-02-15T14:30:00.001Z"
}For facts with declared sources:
{
"fact_provenance_id": "fp_20260215_003",
"fact_name": "account_balance",
"declared_type": "Money",
"value": "15000.00",
"source": {
"name": "banking_api",
"adapter": "rest_json",
"endpoint": "https://bank.example.com/accounts/{id}/balance",
"fetched_at": "2026-02-15T14:29:59.500Z",
"cache_ttl_seconds": 30
},
"received_at": "2026-02-15T14:30:00.001Z"
}Instance Bindings
Every provenance record references specific entity instances, not just entity types. When a flow executes against Order:order_001 and Payment:pay_001, those instance IDs are recorded in the provenance chain so you can trace the complete history of a specific entity instance.
{
"entity_bindings": {
"Order": "order_001",
"Payment": "pay_001"
}
}This means you can query: "Show me every provenance chain that touched Order:order_001" and get the complete audit trail for that specific order.
Instance History Query
curl "https://api.tenor.run/acme/escrow/provenance?entity=Order&instance=order_001" \
-H "Authorization: Bearer tk_live_abc123"{
"entity": "Order",
"instance": "order_001",
"current_state": "released",
"history": [
{
"timestamp": "2026-02-15T10:00:00Z",
"operation": "create_order",
"from_state": null,
"to_state": "pending",
"persona": "buyer",
"provenance_chain_id": "chain_20260215_000"
},
{
"timestamp": "2026-02-15T14:30:00Z",
"operation": "verify_release",
"from_state": "pending",
"to_state": "approved",
"persona": "escrow_agent",
"provenance_chain_id": "chain_20260215_001"
},
{
"timestamp": "2026-02-15T14:30:00Z",
"operation": "release_funds",
"from_state": "approved",
"to_state": "released",
"persona": "escrow_agent",
"provenance_chain_id": "chain_20260215_001"
}
]
}System-Level TriggerProvenance
When a flow starts, the trigger condition is also recorded. This captures why the flow was initiated.
{
"trigger_provenance_id": "tp_20260215_001",
"flow_id": "release_flow",
"trigger_type": "verdict_present",
"trigger_expression": "verdict_present(order_ready)",
"trigger_result": true,
"trigger_verdict": {
"name": "order_ready",
"value": true,
"stratum": 2,
"provenance_ref": "vp_20260215_005"
},
"triggered_at": "2026-02-15T14:30:00.000Z",
"triggered_by": {
"api_call": "POST /acme/escrow/flows/release_flow/execute",
"request_id": "req_20260215_jkl012",
"api_key_id": "key_20260215_001",
"resolved_persona": "escrow_agent"
}
}The trigger provenance connects the API call (who initiated), the trigger condition (why the flow was eligible to run), and the verdict chain (what facts supported the trigger verdict).
Full Example: End-to-End Provenance Chain
Here is a complete provenance chain for releasing funds in an escrow contract. Read from bottom to top to follow the reasoning chain, or from top to bottom to follow the execution sequence.
The Contract
fact payment_received {
type: Bool
source: payment_gateway
}
fact release_approved {
type: Bool
}
entity Order {
states: [pending, approved, released]
initial: pending
transitions: [
(pending, approved),
(approved, released)
]
}
rule check_payment {
stratum: 0
when: payment_received = true
produce: verdict payment_ok { payload: Bool = true }
}
rule check_release {
stratum: 1
when: verdict_present(payment_ok) AND release_approved = true
produce: verdict release_ready { payload: Bool = true }
}
operation approve_release {
allowed_personas: [escrow_agent]
precondition: verdict_present(release_ready)
effects: [(Order, pending, approved)]
error_contract: {
unauthorized: "Only escrow agents can approve releases."
invalid_state: "Order is not in pending state."
precondition_not_met: "Release conditions not met."
}
}The Provenance Chain
{
"provenance_chain_id": "chain_20260215_full",
"flow_outcome": {
"flow_id": "release_flow",
"execution_id": "exec_20260215_full",
"status": "completed",
"started_at": "2026-02-15T14:30:00.000Z",
"completed_at": "2026-02-15T14:30:00.047Z"
},
"trigger": {
"type": "api_invocation",
"persona": "escrow_agent",
"api_key": "key_20260215_001",
"request_id": "req_20260215_full"
},
"steps": [
{
"step": "approve",
"operation": "approve_release",
"persona": {
"contract_persona": "escrow_agent",
"resolved_from": "tk_live_agent_key",
"method": "key_binding"
},
"precondition": {
"expression": "verdict_present(release_ready)",
"met": true
},
"transitions": [
{
"entity": "Order",
"instance": "order_001",
"from": "pending",
"to": "approved"
}
],
"verdicts_at_evaluation": {
"payment_ok": {
"value": true,
"stratum": 0,
"rule": "check_payment",
"facts_used": {
"payment_received": {
"value": true,
"type": "Bool",
"source": "payment_gateway",
"received_at": "2026-02-15T14:30:00.001Z"
}
}
},
"release_ready": {
"value": true,
"stratum": 1,
"rule": "check_release",
"verdicts_used": ["payment_ok"],
"facts_used": {
"release_approved": {
"value": true,
"type": "Bool",
"source": "api_input",
"received_at": "2026-02-15T14:30:00.001Z"
}
}
}
},
"snapshot_id": "snap_20260215_full",
"evaluated_at": "2026-02-15T14:30:00.008Z",
"applied_at": "2026-02-15T14:30:00.012Z"
}
]
}Reading this chain, you can answer every audit question:
- Who authorized the release? The
escrow_agentpersona, resolved from API keytk_live_agent_key. - Why was the release allowed? Because
release_readywas true (stratum 1). - Why was
release_readytrue? Becausepayment_okwas true (stratum 0) ANDrelease_approvedwas true (fact). - Why was
payment_oktrue? Becausepayment_receivedwas true (fact frompayment_gateway). - What changed?
Order:order_001transitioned frompendingtoapproved. - When? Evaluated at
14:30:00.008Z, applied at14:30:00.012Z. - What contract version?
sha256:9f4a2b...(deploymentdep_20260215_001).
Deterministic Reproducibility
Provenance chains are deterministically reproducible. Given the same contract hash, the same fact values, and the same entity states, the evaluator will produce the same verdicts and the same provenance chain. This is guaranteed by:
- E7 (Deterministic evaluation): The evaluator is a pure function.
- E8 (Stratum ordering): Rules evaluate in the same order every time.
- E1 (Snapshot isolation): The entity state used for evaluation is a fixed snapshot.
- E19 (Version pinning): The contract version is pinned to a content hash.
This means you can take any provenance chain, extract the inputs (contract hash, facts, entity states), feed them to a local evaluator, and get the same verdicts. This is useful for:
- Audit verification: Independently verify that a state change was correct.
- Debugging: Reproduce a production evaluation locally.
- Testing: Assert that specific fact combinations produce expected provenance chains.
- Compliance: Demonstrate to regulators that the system produces consistent, traceable decisions.
# Reproduce a provenance chain locally
tenor evaluate escrow.tenor \
--facts '{"payment_received": true, "release_approved": true}' \
--entities '{"Order": {"order_001": "pending"}}' \
--contract-hash sha256:9f4a2b...The output will match the verdicts in the recorded provenance chain exactly.