33. Exact wire-level semantic kernel and cryptographic boundaries
The earlier contract identifies the right objects; this section removes the remaining implementation discretion. A conforming writer produces one exact RecordCore representation, one representation digest, and zero or more independent proofs. A store then…
The earlier contract identifies the right objects; this section removes the remaining implementation discretion. A conforming writer produces one exact RecordCore representation, one representation digest, and zero or more independent proofs. A store then produces a separate admission receipt. Importing the same RecordCore into another tenant or rebuilding another projection must not change the portable record digest.

Semantic identity, custody and presentation are related by receipts; they are not one mutable object.
v1.3 portability correction
Storage tenantId, partition, stream sequence, request idempotency, receivedAt and transport identity move out of RecordCore into AdmissionContext/IngestReceipt. A semantically meaningful organization, fleet or jurisdiction remains possible as an attributed subject/relation or administrativeScopeRef. This supersedes the illustrative tenantScope field in Section 26.2 without rewriting already accepted v1.2 records.#33.1 Conformance tuple and media types
| Tuple member | Normative value / behavior | Why it is separate |
|---|---|---|
| semanticProfile | rtracer.record-core/1.3 | Selects field meaning and required invariants |
| schemaLock | immutable schema ID + semantic version + SHA-256 digest | Selects payload structure without network lookup |
| vocabularyLock | ordered set of namespace/version/digest entries | Fixes every TermRef definition used by the record |
| canonicalProfile | rtracer.jcs-json/1 or rtracer.det-cbor/1 | Selects representation-specific canonical bytes |
| proofProfile | rtracer.cose-sign1/1 or rtracer.http-proof/1 | Selects signature framing and verification method |
| policyProfile | immutable policy bundle ID + digest | Selects admission/disclosure logic, never semantic parsing |
| API media type | application/vnd.rtracer.record+json;version=1.3 | HTTP negotiation is explicit and never inferred from a URL |
| device media type | application/vnd.rtracer.record+cbor;version=1.3 | Constrained encoders use deterministic CBOR under a separate digest |
JSON and CBOR encodings of the same conceptual record have different representation digests. A TranscodingReceipt can assert a lossless mapping between them by naming both digests, both profiles, the transformer digest and the validation corpus. Protocol Buffers may be used internally, but its serialization is not a canonical cross-language signature format.
#33.2 RecordCore 1.3 exact field contract
| Field | Type / cardinality | Validation and digest semantics |
|---|---|---|
| profile | literal string; 1 | Must equal rtracer.record-core/1.3 |
| recordId | UUIDv7 lowercase; 1 | Globally opaque; included in recordDigest; never reused |
| recordType | TermRef; 1 | Exact vocabulary lock required; no label-derived meaning |
| schemaLock | SchemaLock; 1 | ID, version, digest and canonical profile must resolve locally |
| vocabularyLocks | VocabularyLock[]; 1..32 | Sorted by namespace; duplicate namespace/version forbidden |
| subjects | SubjectRef[]; 1..64 | Set-sorted by role, entityId and qualifier digest; duplicate tuple forbidden |
| validTime | HalfOpenInterval; 1 | World/application time; end absent means open, never unknown |
| authoredAt | Instant; 1 | Producer-asserted creation time; not store transaction time |
| producer | ProducerRef; 1 | Principal, producing system, delegation and key epoch references |
| epistemic | EpistemicContext; 1 | Truth lane, knowledge state, method/confidence semantics and evidence coverage |
| administrativeScopeRef | EntityRef; 0..1 | Portable semantic scope only; never database tenant routing |
| rights | RightsContext; 1 | Immutable disclosure, purpose, retention and onward-duty references |
| body | closed schema object; 1 | No unknown members outside declared extension points |
| extensions | Extension[]; 0..32 | Namespace + schema lock + value; sorted; unknown extensions round-trip |
RecordCore 1.3 canonical JSON shape - shortened digest strings are illustrative
{
"profile": "rtracer.record-core/1.3",
"recordId": "019b5f4c-8e27-7a6d-9d12-07ce53ab7a11",
"recordType": {"id":"urn:rtracer:record:maintenance.execution","version":"1.0.0"},
"schemaLock": {"id":"urn:rtracer:schema:maintenance.execution","version":"1.0.0",
"digest":"sha256:0123456789abcdef...","canonicalProfile":"rtracer.jcs-json/1"},
"vocabularyLocks": [{"namespace":"urn:rtracer:maintenance:","version":"1.4.0",
"digest":"sha256:89abcdef01234567..."}],
"subjects": [{"entityId":"019b5f40-1d9f-76d9-a9a6-c0ad7bf10001","role":"maintainedAsset"}],
"validTime": {"start":{"seconds":"1784710800","nanos":0,"scale":"UTC"}},
"authoredAt": {"seconds":"1784714402","nanos":184000000,"scale":"UTC"},
"producer": {"principalId":"019b5f41-...","systemId":"019b5f42-...",
"delegationChainRefs":["urn:rtracer:grant:..."]},
"epistemic": {"truthLane":"observed","knowledgeState":"known",
"methodRef":"urn:rtracer:procedure:service-closeout/v2"},
"rights": {"disclosurePolicyRef":"urn:rtracer:policy:owner-team/v5",
"retentionClass":"maintenance-life-plus-10y","purposeRefs":["fleet-care"]},
"body": {"workOrderId":"019b5f43-...","result":"completed","releaseDecisionRef":"019b5f44-..."},
"extensions": []
}#33.3 Primitive lexical grammar
| Primitive | Accepted canonical grammar | Rejected examples |
|---|---|---|
| UUIDv4 root ID | xxxxxxxx-xxxx-4xxx-[89ab]xxx-xxxxxxxxxxxx lowercase hex | nil UUID, uppercase, braces, embedded VIN/MAC/tenant meaning |
| UUIDv7 event ID | xxxxxxxx-xxxx-7xxx-[89ab]xxx-xxxxxxxxxxxx lowercase hex | nil UUID, uppercase, braces, non-v7 for newly minted records/proofs/receipts/events |
| Digest | sha256: followed by exactly 64 lowercase hex characters | base64 ambiguity, uppercase hex, algorithm omitted |
| IntegerString | 0 or -?[1-9][0-9]*; schema bounds digits and sign | +1, 01, -0, exponent form |
| DecimalString | 0, -?[1-9][0-9]*, or either plus .[0-9]+; no trailing zero unless scale requires it | .5, 1., 1e3, NaN, Infinity, -0 |
| Instant | seconds=IntegerString, nanos integer 0..999999999, scale UTC or TAI | local offset, implicit scale, nanos outside range |
| TermRef.id | absolute URI/URN in NFC Unicode; max 512 UTF-8 bytes | relative path, embedded credential, display label as identifier |
| LanguageString | text NFC + valid BCP-47 tag + direction ltr/rtl/auto | language inferred from user locale |
| Money | ISO currency term + integer minor units + exponent table version | binary float, locale-formatted number, currency inferred |
Resource limits are semantic security
Before allocating the full body, reject a record over 8 MiB, nesting depth over 64, object members over 4,096, arrays over 100,000 entries, strings over the field-specific maximum, subjects over 64, extensions over 32 or vocabulary locks over 32. Bulk media and telemetry bytes belong in digest-addressed artifacts, not RecordCore.#33.4 Domain-separated digests
Digest construction and domain separation
canonicalBytes = canonicalize(recordCore, canonicalProfile)
recordDigest = SHA256(
UTF8("RTRACER\0RECORDCORE\0v1.3\0") || canonicalBytes
)
bodyDigest = SHA256(
UTF8("RTRACER\0BODY\0") || canonicalize({recordType, schemaLock, body})
)
ProofTargetV1_4 {
profile, proofId, targetKind, targetId,
targetProfile, targetDigest, auxiliaryDigests[], proofPurpose,
signerPrincipalId, verificationMethodId, keyEpoch, suite,
createdAt, validUntil?, audience?, challenge?
}
proofTargetDigest = SHA256(
UTF8("RTRACER\0PROOF-TARGET\0v1.4\0") || JCS(ProofTargetV1_4)
)
Every ProofTarget field is signed. COSE protected suite, key/epoch,
content type and profile MUST repeat and match the target exactly.
canonicalBytes = canonicalize(recordCore, canonicalProfile)
recordDigest = SHA256(
UTF8("RTRACER\0RECORDCORE\0v1.3\0") || canonicalBytes
)
bodyDigest = SHA256(
UTF8("RTRACER\0BODY\0") || canonicalize({recordType, schemaLock, body})
)
proofTargetDigest = SHA256(
UTF8("RTRACER\0PROOF-TARGET\0v1\0") ||
canonicalize({recordId, recordDigest, proofPurpose, audience?, validUntil?})
)
The byte NUL separators and ASCII domain labels are literal. Hash algorithms,
canonical profiles and target object fields are fixed by profile version.- recordDigest identifies one portable RecordCore representation, including recordId; equal bodyDigest alone never merges records or physical entities.
- Artifact digests use a separate RTRACER\0ARTIFACT domain and include byte length and media type in the manifest, while the digest remains over exact bytes.
- A new canonicalization profile creates a new representation digest. It never replaces or re-labels the prior digest.
- Hash agility is additive: a HashUpgradeAttestation binds an old digest and new digest to the same retained bytes; it does not mutate historical references.
#33.5 Deterministic canonicalization procedure
- Read bytes with a media-type-specific strict parser. Reject duplicate map keys before materializing an object and reject ill-formed UTF-8 or Unicode surrogate values.
- Resolve schemaLock, vocabularyLocks and canonicalProfile from a local content-addressed registry. No validation-time network fetch or mutable latest alias is permitted.
- Validate structure, cardinality, lexical forms and extension placement before applying any normalization.
- Validate every internal canonical string against the schema's exact NFC and lexical form; reject non-canonical input rather than silently normalizing signed semantic bytes. Never case-fold an opaque identifier, signature, free text, external serial or source value.
- External/source identifiers are preserved verbatim in IdentifierAssertion.sourceValue. Any normalized search key is an attributed, versioned derivation and never replaces the source value or enters RecordCore as if supplied by the issuer.
- A separate pre-admission adapter may convert convenience timestamps and quantities into canonical structured forms, but its output is newly authored input and its TransformationReceipt preserves the source bytes, transformer digest and validation result.
- Sort object members per the selected profile. Sort only arrays declared set-valued using the schema's total canonical key; preserve every other array order.
- Serialize exact canonical bytes, reparse them under the same profile, and require byte-for-byte idempotence before digesting.
#33.6 ProofRecord and verification result
| Field | Requirement |
|---|---|
| proofId | UUIDv7; immutable and distinct from target record |
| target | recordId, recordDigest, canonicalProfile and optional bodyDigest |
| purpose | authorship, observation-attestation, registry-assertion, custody, approval, release or transport; never generic signed |
| signer | principal/key ID, issuer/trust domain, key epoch and credential chain references |
| suite | Ed25519 baseline where permitted; P-256 alternative for regulated/FIPS deployments; algorithm confusion forbidden |
| createdAt / validUntil | Instant values; verification evaluates key and proof validity at createdAt and current status separately |
| signature | COSE_Sign1 or exact profile framing over proofTargetDigest |
| verification | append-only result naming verifier, trust bundle, revocation snapshot, algorithm implementation and limitations |
Proof verification returns VALID, INVALID, INDETERMINATE or UNSUPPORTED plus reason codes. VALID means the cryptographic operation and selected trust checks succeeded; it never upgrades the underlying claim from asserted or derived to observed truth.
#33.7 AdmissionContext and IngestReceipt
Store-local admission objects - deliberately excluded from RecordCore
AdmissionContext {
tenantId, streamId, expectedStreamSequence, writerEpoch,
authenticatedPrincipalId, workloadIdentity, requestId,
idempotencyKey, receivedAt, sourceAddressClass,
requestedPurpose, admissionPolicyLock
}
IngestReceipt {
receiptId, tenantId, streamId, streamSequence, shardId, shardPosition,
recordId, recordDigest, admissionDecision, findingCodes[],
receivedAt, committedAt, writerEpoch, previousReceiptDigest,
validatorSetDigest, schemaRegistrySnapshotDigest, policyDecisionRef,
outboxEventId, storeWorkloadIdentity, receiptDigest, storeProofRef
}The store retains rejected and quarantined input through a FailureReceipt whose disclosure is tightly controlled. A rejection never consumes a stream sequence. An accepted retry with the same idempotency binding returns the original receipt; a different request digest under the same key is EQUIVOCATION and cannot be resolved by last-write-wins.