Status: Accepted (2026-07-12)
Date: 2026-07-12
Supersedes: ADR-026
Decision: release history is a per-component authenticated chain, not a
producer-selected FROM..TO query. Every release resolves refs once to immutable
commit object IDs and uses exactly one of three interval modes:
TO, including every reachable root. The Git
operation is git rev-list TO; there is no FROM commit.B covers B and every
in-range descendant reachable from TO, while excluding the history
reachable from every parent of B. As a set this is
Reach(TO) − union(Reach(parent(B))); the Git operation is
git rev-list TO --not B^@. B MUST be reachable from TO. The boundary is
chain-genesis state pinned by the out-of-band bootstrap descriptor (ADR-028),
not a mutable choice made by the candidate policy. A legacy
[policy] adoption_boundary value may mirror it but MUST match it.Reach(TO) − Reach(P), where P
is the TO bound by the accepted predecessor attestation; the Git operation
is git rev-list P..TO. The predecessor MUST be the verifier-selected current
chain head for the same repository and component, its signature and complete
chain MUST verify, P MUST be an ancestor of TO, and any tag naming P
MUST still resolve to P. A caller-supplied alternate FROM, a missing or
ambiguous chain head, a moved ref, or a non-ancestor aborts verification.The commit set above is normative; implementations MAY choose an ordering for
processing so long as every member appears exactly once in the provenance
vector. Newly merged unrelated history is included whenever it becomes
reachable from TO and was not reachable from the predecessor.
A release attestation MUST bind its interval mode, resolved TO, resolved
boundary when applicable, and the cryptographic identity of its predecessor
attestation for a recurring release. Promotion, demotion, or another
superseding re-evaluation at the same TO preserves the prior decision’s source
interval, source-predecessor link, original active authority, and candidate
state; it does not create an empty new source interval or let candidate-only
keys re-evaluate their enrollment. The next source release references the
accepted terminal attestation available for the current source head when
continuity advances. A later supersession of an older source release does not
rewrite an existing successor link. A history rewrite, skipped link, or
conflicting accepted source head is a verification failure.
Predicate v0.1 remains a historical format and cannot express these complete
continuity claims. A v0.4 release-conformance claim requires the successor
predicate selected by the predicate-versioning work; v0.1 bytes are not changed
by this decision. Migration from a v0.1 release therefore establishes a new
authenticated v0.4 chain genesis (ADR-028): it MAY pin the last trusted v0.1
TO as an adoption boundary, which is re-included and re-verified. The v0.1
attestation is historical evidence, not a continuity-capable predecessor.
Rationale: Git two-dot notation excludes its left endpoint. The former
root..TO wording therefore excluded the root it claimed to include, while the
implementation’s empty-start special case did something different. More
importantly, allowing the producer to select any ancestor as FROM permits
policy or provenance history to be skipped. Explicit set definitions remove the
notation ambiguity; predecessor attestations make continuity an authenticated
property rather than a command-line convention. Including the adoption boundary
matches the promise that only history before it is exempt. Treating the
boundary as immutable chain genesis also prevents a candidate policy from moving
its own verification start.
Rejected: literal root..TO or boundary..TO (excludes the named commit);
arbitrary caller-selected FROM (permits history skipping); tag-only
predecessors without an accepted attestation (tags can move and do not prove
chain continuity); excluding the boundary (silently exempts one more commit than
the prose claims); requiring a single repository root (unnecessary — all newly
reachable roots can be included safely); allowing the active/candidate policy to
move the boundary after bootstrap (self-authorizing re-baselining); treating
promotion as a new empty interval (confuses evolving evidence with new source).
Revisit trigger: an accepted current-state/transparency profile that changes
how the canonical predecessor head is discovered; or a non-Git source system
whose reachability model cannot represent the three interval sets faithfully.