Repository navigation
Add is_final to the attestation object: producer-declared end of an append-only chain #1755
Description
Problem
The attestation object (record_integrity profile, 1.9) gives a consumer
everything needed to verify a chain's past — chain_uid names the stream,
prev_event links each record to its predecessor, fingerprint +
signatures bind content — but nothing to recognize its end. A consumer
watching a chain today cannot distinguish three states:
- The producer closed the chain gracefully (clean shutdown, key rotation,
log rollover). - Records stopped arriving (outage, misconfiguration).
- Records were suppressed (tampering, selective omission).
State 1 is legitimate and routine — every key rotation ends one chain and
begins another — but it is indistinguishable on the wire from states 2 and 3.
The verifier's only recourse is a timeout heuristic, which is exactly the kind
of ambient assumption tamper-evident logging is supposed to eliminate.
I hit this concretely while writing the OTel↔OCSF audit crosswalk
(AI-Identity docs/otel-ocsf-audit-crosswalk, §2.9): the OpenTelemetry audit
data model has audit.sequence.end for this; OCSF has no counterpart, so the
crosswalk has to park the signal in unmapped — a one-way door that loses the
information for any OCSF-native consumer.
Proposed change
| Attribute | Type | Description |
|---|---|---|
is_final |
boolean | When true, the producer declares this attestation's record is the last it will emit on this chain_uid. Absent means unknown — a missing is_final is not a violation and must not be treated as one. |
Rules (mirroring OTel's audit.sequence.end semantics):
is_final: trueMUST NOT appear on any record that is not the final record
of its chain.- Producers MUST NOT set it speculatively; once set, the producer MUST NOT
emit further records under thatchain_uid. - Consumers MUST treat absence as "unknown" — never as "chain continues" and
never as "chain ended".
Use cases
- Key rotation: the rotation event closes the old chain with
is_final: trueand opens the new one. A verifier can confirm the old chain
is complete rather than truncated. - Forensics / incident replay: an investigator can state "this chain is
complete through record N" instead of "no records arrived after time T". - Log rollover / retention boundaries: clean, attestable stream boundaries
without out-of-band coordination. - OTel interop: gives the OCSF side of the
audit.sequence.endmapping a
native home, closing the crosswalk's §2.9 gap.
Non-goals
Rotation handover pointers ("chain B continues chain A"), superseded-by
references, or multi-producer merge semantics. Those are separate asks; this is
only the terminal marker.
Related
- Add
attestationobject andrecord_integrityprofile #1661 —attestationobject andrecord_integrityprofile (shipped in 1.9) - issue-1698: Carry the signature bytes on
digital_signature#1709 — signature bytes ondigital_signature(open; same object family) - OpenTelemetry
audit.sequence.end— the interop precedent - Add a normalized
stop_reasonattribute for completion events #1696 —stop_reasonfor completion events (open; shows appetite for
end-state signals with forensic value)
Activity
Levaj2000 commentedon Sep 11, 2026
A convergence data point since filing: praxis-proxy/policy#84 has since added sequence numbers for stream completeness and ordering on the audit-emit side. Sequence numbers let a consumer detect gaps in what arrived; they can't answer whether the chain ended — rotation, rollover, and clean shutdown all look identical to an outage or suppression on the wire.
is_finalis the other half: the producer's explicit declaration that no more records will come under thischain_uid, which is what lets a verifier state "complete through record N" instead of "nothing arrived after time T."Absent means unknown, so this is purely additive — no existing producer or consumer changes behavior. Would appreciate review from folks on the
attestation/record_integrityside.