fluid-core/docs/adr/0005-revision-identity.md
tegwick 76912adef8
Some checks failed
ci / build (push) Failing after 1m6s
Generate contract types, pin fixtures to spec, add build and ADRs
Completes FLUID-WP-0002. The record types in internal/contract are
generated from schemas/ by a dependency-free generator; fixtures
transcribed from the spec's worked examples validate against those
schemas and round-trip through the generated types with
DisallowUnknownFields, so a spec change that misses the schemas fails
CI rather than drifting silently.

Adds identifier prefix helpers, Makefile, GitHub Actions, and five ADRs
recording the Go choice, out-of-process attachment, the wire contract as
boundary, the evidence store, and revision identity.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014KmVxhJ35tCo7rE7UnLwWu

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1116572@bnt-lap001
Assistant-Session: 8ba9bb93-a72a-4883-b189-2499cce5c400
2026-09-04 02:03:12 +02:00

47 lines
1.9 KiB
Markdown

# ADR-0005 — Revision identity
**Status:** accepted · **Date:** 2026-09-04
## Context
Blueprint §54 lists this as deliberately open: "Should revision numbering be
global, per interface, semantic, or content-addressed?" It asks for the answer
to come from implementation experience rather than premature standardization.
An answer is nonetheless needed before anything can be published, so this ADR
picks the smallest one that does not foreclose the others.
## Decision
Two identifiers, with different jobs.
**A human-facing revision id, sequential per interface.** `R-000221` with a
`revision_number` of 22, both scoped to one interface. This is what appears in
audit trails, CLI output and conversation.
**A content address for every artifact the revision names.** The contract and
the implementation each carry a `sha256:` digest. A revision is reproducibly
associated with its artifacts through those digests, per Blueprint §25.
Identity is therefore human-sequential; equality is content-addressed.
## Rationale
Global numbering was rejected: it couples unrelated interfaces and makes the
number meaningless as a lineage signal.
Purely content-addressed identity was rejected as the primary handle. Digests
are correct but unreadable, and Blueprint §16 of the schema spec is explicit
that human-readable prefixes are recommended for operational tooling. A framework
whose central concept cannot be said out loud will not get used carefully.
Semantic versioning was rejected because compatibility is already declared
separately, in `compatibility.class`. Encoding it a second time in the
identifier invites the two to disagree.
## What stays open
Whether `revision_number` should be dense (no gaps) is unresolved. Failed
candidates currently consume a number. That is defensible — the attempt is part
of the history — but it may prove noisy. Revisit after the first real interface
has produced enough failed candidates to tell.