Skip to content
VERASPEC
Repository
VER 1.1 — draftdraft

§2 The VER registry, and the provenance action value space

2.1 The problem

VER 1.0 closes seventeen value spaces as JSON Schema enums — eighteen enum keywords, of which two declare dtype identically on the space descriptor and on the embedding — while 1.0 §5 uses registry language (“Registered perceptual algorithms in 1.0…”). There is no registry. Every new perceptual hash, chain action, source class, acquisition method, metric, or segment family therefore requires a full specification revision, and implementers extend by convention instead — which is how interoperability dies. The measured consequence today: provenance.chain[].action has six values and cannot express publish, export, sign, or any geometric edit, so real pipelines either lie (transcode) or omit events.

2.2 Registry policy (DRAFT)

ADR-0004 is accepted conditionally. The conditions below are conditions of ratification, not of drafting: none of them is satisfied today, and §2.3 may not ship until all of them are.

The VER Registry is established as a companion document to the specification, maintained under a Specification Required policy: a new entry requires a stable, publicly available document defining the value's exact semantics, and review by the designated expert.

The registry covers four value spaces: provenance actions, perceptual algorithms, contextual source classes, and metadata segment families. Each entry carries: the token, a one-line definition, the specification reference, the VER version in which it was registered, and its status (active | deprecated).

Registry additions are minor-version events for the registry document and do not require a schema revision for value spaces the schema has opened.

Ratification conditions (ADR-0004). All four are blocking rows on RELEASE.md's checklist:

  1. The registry must exist before §2.3 ratifies. A governed registry means: a stable published URL; immutable, individually addressable snapshots; a digest per snapshot; append-only history; a written deprecation policy; named maintainers; and an appeals path for a refused registration. A registry with none of these is a wiki, and an open value space behind a wiki is an unconstrained string.
  2. Conformance binds to a registry snapshot, never to the live registry. A Record whose chain carries a bare action token that this specification does not itself define MUST declare provenance.registry — the snapshot version and sha256 it was minted against, optionally with the snapshot's uri. A token is never reused for a different meaning, and a deprecation never invalidates history: a Record minted against snapshot N stays conformant when the token is deprecated in snapshot N+1, and a Consumer resolves the token against the snapshot the Record names.
  3. Three tiers, and what a Consumer owes each. §2.3 states them.
  4. sign is registered, and is constrained — §2.3's rules on provenance.signature and on target.

2.3 Provenance actions become an open value space (ADR-0004)

Three mechanisms were considered: (a) bump the enum every minor version, (b) an open string plus a registry, (c) namespaced x- escape values. The draft selects (b), with a closed core set, and takes one element of (c): the namespaced form is how an unregistered value is spelled. (a) makes every vendor action a standards-track event; (c) applied to every extension produces a permanent two-tier vocabulary in which the interesting values are all second class.

provenance.chain[].action is a string, not an enum. It MUST match:

text
^([a-z][a-z0-9_]{0,63}|<authority>/[a-z][a-z0-9_]{0,63})$

where <authority> is a reverse-DNS label sequence ([a-z0-9]([a-z0-9-]*[a-z0-9])? joined by ., at least two labels).

A bare token MUST either be one of the sixteen this specification defines below, or an active entry of the registry snapshot the Record names in provenance.registry. A value that is neither MUST be namespaced under an authority the Producer controls (com.example.pipeline/watermark).

Three tiers, and the Consumer's obligation to each.

TierWhich tokensWhat a Consumer MUST do
Core (must-understand)The six 1.0 values: decode, normalize, embed, transcode, redact, importUnderstand them. Reasoning about reproducibility depends on them, and they keep their exact 1.0 meanings forever
Specification-registeredThe ten added at 1.1: publish, export, compose, upscale, crop, resize, color_adjust, denoise, generate, signUnderstand them. They are defined by this document, so a 1.1 consumer resolves them without consulting anything
Registry-registered, and authority-namespacedEvery other bare token (resolved against the named snapshot), and every <authority>/<token>MAY treat as opaque. MUST preserve it, MUST NOT reject the Record on that basis, and MUST NOT infer semantics from the token's spelling

Old-consumer behaviour on a new bare token, stated because it is the failure mode this design has. A 1.1 consumer meeting a bare token outside the sixteen above is meeting a value registered after this specification shipped. It MUST treat that event as opaque custody — the same as an authority-namespaced token — and MUST NOT reject the Record. It MAY resolve the token against the snapshot named in provenance.registry; if it cannot fetch that snapshot, the event stays opaque and the Record stays conformant. A consumer that rejects on an unrecognized token has converted an extensible value space back into a closed enum, unilaterally.

The value space is therefore syntactically open and administratively governed: the schema admits both forms, and registry membership is a rule of the standard enforced by the profile, not by the schema. A Producer that invents watermark as a bare token with no registry snapshot behind it is non-conformant; the same Producer emitting com.example.pipeline/watermark is conformant, today, with no standards action required.

Core and specification-registered actions (sixteen entries). The six VER 1.0 values are registered unchanged; ten are added:

TokenRegisteredDefinition
decode1.0The Asset was decoded to a pixel buffer.
normalize1.0CPNP-1 was executed, producing the Canonical Buffer.
embed1.0One or more vectors were computed.
transcode1.0The Asset was re-encoded into another container or codec without geometric or tonal change.
redact1.0Metadata was removed or replaced under 1.0 §7.5.
import1.0The Asset entered the Producer's custody.
publish1.1The Record, or a projection of it, was made available to parties outside the Producer.
export1.1A rendition of the Asset was written out for consumption elsewhere.
compose1.1Two or more Assets were combined into this one. Requires a lineage block (§3).
upscale1.1Resolution was increased, by interpolation or by a model.
crop1.1A sub-rectangle was selected.
resize1.1Dimensions were changed without cropping.
color_adjust1.1Tonal or colour values were altered (grade, curve, white balance).
denoise1.1A noise-reduction operator was applied.
generate1.1Pixel content was produced by a model rather than captured or edited.
sign1.1A detached signature was computed over the Record and recorded in provenance.signature (E17). The event's at is the signing time and its actor is the signer.

2.3.1 Asset events and Record events (target)

An acquisition chain that mixes “what happened to the pixels” with “what happened to the document describing the pixels” is ambiguous exactly where provenance matters. 1.1 separates them:

provenance.chain[].target is an optional value, asset | record. Absent means asset — which is what every 1.0 chain event was, so no 1.0 event changes meaning.

  • sign acts on the Record. Where a sign event states target, it MUST be record (schema-encoded).
  • publish acts on whichever of the two the Producer made available, and SHOULD state which.
  • Every other registered action in §2.3's table acts on the Asset.

provenance.acquisition.acquired_at, which the chronology rules below lean on, is defined here because 1.0 used it without defining it: it is the instant the Asset entered the Producer's custody, as an RFC 3339 timestamp with an explicit offset. Chain events MUST NOT precede it (VER1202) — a comparison that is only meaningful now that the quantity has a definition.

2.3.2 uri on a chain event

provenance.chain[].uri is an optional absolute URI naming where the event's output was placed: the publication URI for a publish, the rendition's location for an export.

  • A publish event SHOULD carry uri, or carry an identifier from which the publication URI is derivable. The 1.0 gap this closes is measured: the reference federation pipeline had no legal home for its at:// publication URI and put it in a search-index payload instead (REC-11, WIRE-30).
  • uri is deliberately not digest-coupled (§15.3). It names a location, not a content-addressed artifact whose integrity this Record binds. A Consumer MUST NOT treat a chain uri as evidence of anything but the Producer's claim that it published there.

2.3.3 sign requires the signature it describes

A Record whose chain carries a sign event MUST carry provenance.signature (schema-encoded). A sign event without a signature asserts a signing that left no artifact, which is indistinguishable from a false claim.

The converse is not required: a signed Record need not carry a sign event, because signing may happen after assembly. The event is inside the signed payload — E17 removes only provenance.signature before canonicalization, not the chain — so a Producer that wants the signing time inside the signature writes the event first and signs afterwards.

sign is registered because signing is a first-class operation with a first-class home in the Record — provenance.signature — and, until now, no way to say that it happened. It is the one registered action that acts on the Record rather than on the Asset.

transcode MUST NOT be used for upscale, crop, resize, color_adjust, denoise, or generate. Recording a geometric or tonal edit as a transcode is non-conformant in 1.1; it was merely undetectable in 1.0.

Every action that changes pixels — compose, upscale, crop, resize, color_adjust, denoise, generate — produces a new Asset with a new content_hash and a new pixel_hash. Where the Producer holds the input, the resulting Record SHOULD carry a lineage block naming it.

2.4 The remaining three value spaces

identity.perceptual[].alg, embeddings[].source.class, and metadata.raw[].segment are registered but not yet opened in this draft: the schema keeps their enums closed. Opening them is gated on the registry document existing, because an open value space without a populated registry is just an unconstrained string. The intent is to open alg and segment in the same revision that publishes the registry; source.class additionally requires a grade assignment for each new class (E19) and MUST NOT be opened before the grade table is registry-backed.

The mechanism of §2.3 is designed to generalise to all three, and to the other value spaces §2.1 counts. It has not been applied to them here. Until it is, SCH-22's observation — that VER uses registry language with no registry behind it — is answered for one value space out of seventeen and open for the rest.