26. Canonical record ledger, claims, evidence, and identity resolution
The canonical ledger is not a mutable vehicle row. It is an ordered set of immutable typed records whose relationships allow a policy-bound view to be reconstructed for valid time and knowledge time. Record acceptance is a transaction: either the canonical…
The canonical ledger is not a mutable vehicle row. It is an ordered set of immutable typed records whose relationships allow a policy-bound view to be reconstructed for valid time and knowledge time. Record acceptance is a transaction: either the canonical record, subject links, digest, idempotency binding and outbox entry commit together, or none do.

The append is authoritative; every downstream view is versioned and rebuildable.
#26.1 Four records that must not collapse
| Object | Authority | Mutation rule |
|---|---|---|
| RecordCore | Producer-authored semantic content, subjects, valid time and source context | Immutable; digest excludes proofs, transport and store metadata |
| ProofRecord | Signature/attestation over one exact RecordCore digest | Additional proofs may append without changing the core |
| IngestReceipt | Store acceptance decision, transaction time, validator/policy lock and log position | One or more custodians may issue receipts; producer cannot self-assert store time |
| ProjectionReceipt | Projector code/policy/registry versions, input watermarks and output digest | Rebuildable; never authoritative history |
Integrity is not truth or authority
A valid proof establishes that a key signed particular bytes under a profile. It does not establish that the signer was authorized, the claim was accurate, the vehicle was owned, the configuration was safe or the event occurred.#26.2 RecordCore v1
Canonical producer-authored RecordCore - illustrative JSON
{
"recordId": "018f4d6e-7db2-7e40-9a13-7d7f12f00101",
"recordType": "rtracer.claim.assertion/v1",
"schemaRef": {"id": "schema:rtracer.claim.assertion/v1", "digest": "sha256:..."},
"subjects": [{"entityId": "018f...aa", "role": "subject"}],
"validTime": {"start": "2026-07-22T09:00:00Z", "end": null},
"authoredAt": "2026-07-22T09:00:02.700Z",
"producer": {"principalId": "018f...10", "systemId": "018f...11"},
"tenantScope": "018f...01",
"truthLane": "asserted",
"visibilityPolicyRef": "policy:owner-team/v3",
"body": {"predicate": "vehicle:paintColor", "object": {"term": "color:blue"}},
"extensions": []
}| Field group | Requirement |
|---|---|
| identity | recordId is opaque and immutable; recordType and schemaRef select exact semantics |
| subjects | one or more typed subject links; roles are schema-governed and order-independent unless declared |
| time | valid interval is application time; authoredAt is an issuer claim, not system transaction time |
| producer | human/device/service principal, producing system, tenant and delegation chain where relevant |
| epistemic | truth lane, knowledge state, confidence semantics, evidence coverage and verification state |
| policy | visibility policy, purpose restrictions, retention class and sensitive-field map |
| body | closed payload governed by recordType; extensions are explicit namespaced containers |
| integrity | canonical core digest is computed outside the core; proofs and store receipts reference ID plus digest |
| correction | supersedes/corrects/retracts/disputes/derivesFrom relations remain separate typed records |
Store-authored IngestReceipt v1.4 - illustrative JSON
{
"receiptProfile": "rtracer.ingest-receipt/1.4",
"target": {"recordId": "018f...0101", "recordDigest": "sha256:..."},
"decision": "accepted",
"acceptedAt": "2026-07-22T09:00:03.184Z",
"storeId": "018f...store",
"ledgerId": "018f...ledger",
"logicalShardId": "ledger-03",
"chainEpoch": "1",
"commitSequence": "982173",
"streamId": "018f...stream",
"streamSequence": "185",
"validatorSetDigest": "sha256:...",
"registrySnapshotDigest": "sha256:...",
"authorizationDecisionRef": "record:policy-decision",
"previousReceiptDigest": "sha256:...",
"canonicalAdmissionEventId": "019b...event"
}
{
"target": {"recordId": "018f...0101", "coreDigest": "sha256:..."},
"decision": "accepted",
"acceptedAt": "2026-07-22T09:00:03.184Z",
"storeId": "018f...store",
"partition": "tenant-01/ledger-03",
"ledgerSequence": "982173",
"validatorSetDigest": "sha256:...",
"registrySnapshotDigest": "sha256:...",
"authorizationDecisionRef": "record:policy-decision",
"previousReceiptDigest": "sha256:..."
}#26.3 Minimal logical ledger tables
| Table | Primary key / indexes | Purpose |
|---|---|---|
| entity_root | entity_id; tenant_id, created_seq | Durable opaque identity and coarse kind only |
| record_ledger | record_id; unique tenant+ledger_seq; record_type+recorded_at | Canonical bytes/digest, schema lock, valid time, producer and policy |
| record_subject | record_id+ordinal; index entity_id+valid_start | Typed subject/object participation without parsing payload |
| record_relation | source_record+relation+target_record | Correction, derivation, dispute, corroboration and custody graph |
| idempotency_binding | tenant+principal+key | Request digest, result record, status and expiry policy |
| evidence_artifact | artifact_id; digest+byte_length | Immutable object metadata, encryption, rights and storage locator |
| identifier_assertion | record_id; namespace+normalized_value | Attributed external identifier claim and conflict lookup |
| outbox_event | logical_shard+chain_epoch+commit_sequence+event_kind | Atomic publication state, attempts, next retry and dead-letter reason |
| projection_checkpoint | projection_id+tenant+logical_shard+chain_epoch | Last applied sequence, code/schema version, digest and rebuild state |
| quarantine_item | quarantine_id; received_at | Original bytes, failure stage, reason, reviewer and disposition |
The logical model does not require one relational product. It does require the uniqueness, atomicity and replay semantics shown above. Database-generated cascade updates and deletes are prohibited on canonical records.
#26.4 Claim and evidence separation
| Object | Carries | Does not prove |
|---|---|---|
| Observation | procedure, phenomenon, result, sensor/operator, time, configuration and quality | Cause, identity or fitness beyond its measured scope |
| Assertion | issuer, subject, predicate, object, scope, effective interval and authority context | Truth merely because signed or repeated |
| DerivedClaim | input record IDs, formula/model digest, parameters, output, uncertainty and execution receipt | Stronger authority than its method and inputs support |
| EvidenceArtifact | bytes/digest, capture, custody, rights, privacy, edit lineage and availability | That the depicted or encoded proposition occurred |
| Verification | checker, method, target claim/evidence, result, time, limitations and challenge path | Global truth outside the verification procedure |
| Decision | authorized decider, candidate claims, policy, rationale, effective scope and appeal | Erasure of competing historical evidence |
#26.5 Identity resolution is a reviewable decision
- Normalize each external identifier only within its issuer namespace and normalizer version; never globally.
- Generate candidates from exact identifiers, known relationships, configuration evidence, provenance, geometry, media or temporal proximity.
- Compute feature-level evidence contributions with direction, quality, independence and contradiction; do not expose one unexplained score as truth.
- Apply hard exclusions such as overlapping exclusive custody, incompatible manufacturing provenance, impossible time/location or explicit split decisions.
- Return candidate, conflict, insufficient-evidence or no-match. Automatic merge is forbidden for high-impact identity roots.
- Require a signed continuity/merge/split decision with reviewer, policy version, evidence set, uncertainty, consequences and appeal/reversal path.
- Represent an erroneous merge through superseding identity-resolution records; never rewrite the source entities or claims.
#26.6 Bitemporal query contract
Deterministic bitemporal projection - pseudocode
resolve(entityId, validAt, knownAt, projectionPolicy, schemaLock):
records = ledger.records_for(entityId)
.where(valid_time contains validAt)
.where(recorded_at <= knownAt)
.where(schema is interpretable under schemaLock)
records = apply_corrections_as_known_at(records, knownAt)
claimSets = group_by_proposition_and_scope(records)
decisions = evaluate_trust_policy(claimSets, projectionPolicy)
return Projection(value_or_conflict=decisions,
input_record_ids=all_inputs,
policy_digest=projectionPolicy.digest,
as_of={validAt, knownAt},
explanation=decision_receipts)- validAt answers what applied in the world; knownAt answers what the system had accepted by then.
- A correction recorded today may change today's view of last year without altering what yesterday's users could have known.
- Projection responses include input record IDs, policy/schema versions, conflict disposition and checkpoint sequence.
- Pagination is bound to a stable ledger snapshot; page two cannot silently observe a newer state than page one.