Lineage representation
Status
Accepted — model adopted, shape revised — 23 August 2026 (owner review).
The model — minimal parentage in the Record, rich recipes outside it bound by digest — is accepted. The shape of a parent reference is revised, because the shape originally drafted let a parent be named by identifiers that resolve to nothing (a bare record_id, which annex E16 scopes to its producer) or to a group rather than an asset (a pixel_hash, which annex E27 says is never an identity). The revised shape, the recipe envelope, and the fixture requirements are stated below and are in standards/ver/1.1-draft/VER-1.1-draft.md §3 and the draft schema.
Nothing in VER 1.0.x depends on the outcome.
Context
VER 1.0 describes exactly one asset per Record and says nothing about where that asset came from. §9's acquisition chain covers the Record's own custody — decode, normalize, embed — and acquisition.source_uri names a fetch location. Neither answers the question a derived asset raises: which other asset is this one derived from, and how?
The gap has three concrete shapes, all of them ordinary:
- Derivation. A crop, a resize, an upscale, a colour adjustment. The output is a new Asset with a new
content_hashand a newpixel_hash, related to its input by a transform that the Record cannot express.source_urimight point at the parent file, or at a CDN, or at nothing. - Composition. A collage, a panorama, a composite. Multiple parents, which no single-valued field can carry.
- Export. The same visual asset re-encoded for a platform. The
content_hashchanges,pixel_hashsurvives if nothing was resampled, and the relationship is currently expressible only by inference from a matchingpixel_hash— which annex E27 explicitly warns against treating as an identity claim.
C2PA covers some of this, in its own model, for signed assets. VER 1.0 binds to a C2PA manifest through content_hash (§9) but does not restate its lineage, and most assets in an AI retrieval pipeline carry no manifest at all. §13 lists "reserved extension points" and lineage is not among them, so this is an omission rather than a deferral.
The generative-media case makes it urgent: a Record describing an image produced from other images has no way to say which ones, and that is exactly the question a provenance-aware retrieval system is asked.
Options
(a) An in-record lineage object. Self-contained: one document answers "what is this and where did it come from", and a consumer needs no second fetch. Records grow without bound for deep derivation chains, the full recipe of a complex composite is large and often proprietary, and a Record — which is supposed to be an immutable statement about one asset — starts carrying a graph.
(b) Separate lineage and recipe records. Keeps the Record about one asset and lets the graph be a graph. Every lineage question becomes a second fetch against infrastructure that may not exist, and in a federated deployment (VER-F) the lineage record may be on a server the consumer cannot reach. Absence of a lineage record becomes indistinguishable from absence of lineage.
(c) Both, split by size and stability. Minimal parent references in the Record; rich recipes external, bound by digest. Two mechanisms to specify, and a judgement call about where the line sits.
Decision
Option (c), with the parent reference reshaped.
In the Record: a minimal, bounded parents[].
relationis required:derived|composed|exported. Three values chosen to be distinguishable without knowing the transform —derivedchanges the Canonical Buffer,composedhas multiple parents,exportedre-encodes without changing the Canonical Buffer, so parent and child share apixel_hashand differ only incontent_hash. 1.1 §3.3 states that definition normatively, and draws the consequence the wording implies: a platform export that resamples, or that drops a consumed ICC profile or Orientation tag (annex E1), changes the Canonical Buffer and is thereforederived, notexported.- **At least one globally resolvable identifier is REQUIRED:
record_uri, or the pair{producer_id, record_id}.** This is a rule about resolvability — being able to obtain a statement about the parent — not about identity strength, and it is encoded in the draft schema as ananyOfover those two forms. - A bare
record_idno longer satisfies that rule. Annex E16 scopesrecord_idto its producer, so alone it names nothing outside that producer's namespace; the original draft treated it as one of three interchangeable identifiers, which was wrong. It MAY accompany aproducer_id— which is exactly what makes the pair resolvable — or arecord_uri. - **
content_hashSHOULD be present whenever the Producer holds the parent bytes.** It is the strongest identity claim available (it binds to exact bytes and to any C2PA manifest) and the only one stable across producers, but it does not satisfy the resolvability rule on its own: a digest says what the parent is and not where a statement about it can be found. A parent reference with nocontent_hashdraws a conformance warning, and is an error in a named high-trust profile — a profile that is itself a ratification deliverable. - **
pixel_hashbecomes an object,{value, cpnp_version}, and never satisfies the resolvability rule.** The object form exists because a rendered-identity digest without its universe is a digest a consumer will compare across universes (1.0 §13, annex E10); the structured hash carriage the Record uses elsewhere is the same idea. A parent identified down to apixel_hashresolves to a candidate, and 1.1 §3.3 carries the mitigation as normative text: a Consumer MUST treat every match as a candidate, MUST NOT treat a match as proof, and MUST NOT use it as a join key. - Multi-parent is native. A composite lists every input, which is the whole reason a single-valued field will not do.
lineageis optional, and its absence means "not stated", never "no parents". Stated explicitly, as a normative bullet in 1.1 §3.3 and not only here, because the opposite reading is the natural one and it is wrong: most Records will omitlineagebecause their Producer does not track parentage, not because the Asset is original.
Outside the Record: a recipe envelope, bound by recipe_sha256. The full transform recipe — parameters, layer graph, model calls, seeds — lives in an external document identified by its SHA-256. The Record carries the digest only. Two revisions to the original:
recipe_uripresent ⇒recipe_sha256REQUIRED (schema-encoded). A URI a Consumer is told to fetch and verify, with nothing to verify against, is a fetch instruction dressed as an integrity mechanism.- The envelope is specified, minimally, at 1.1 §3.4: media type
application/json; top level `{recipe_version, canonicalization: "rfc8785-jcs", steps: [...]}; extensible only throughx-<authority>` keys, which a Consumer MUST ignore when unrecognised. VER does not define step vocabulary —opbelongs to the producing tool — but "verify it before use" is unactionable when two producers cannot agree on what document they are hashing.
This keeps the Record bounded and keeps proprietary recipes disclosable at the owner's discretion while still being committed to: a producer cannot alter the recipe after publication without the digest changing.
Semantic fixtures before ratification. Lineage is where a schema check is least useful, because every interesting failure is a statement about a graph. Eight fixtures MUST exist and be exercised, and they are on the 1.1 checklist: exported, composed, duplicate parent, contradictory (an exported relation whose parent and child pixel_hash differ), self-parent, cycle (across two Records, on each edge type), missing digest (recipe_uri without recipe_sha256), and dangling (an unresolvable record_uri — which MUST be accepted, because making network reachability part of conformance is the mistake VER1303 exists to avoid). 1.1 §3.5 carries the table.
Not in scope: a lineage query protocol, transitive-closure semantics, and any obligation to resolve recipe_sha256. Those need deployment experience VER does not have.
Consequences
Good.
- The common case — one parent, one transform — is one small object, no second fetch, and works offline and federated.
- Composites are representable at all, which they are not today.
- Record size stays bounded. A deep chain is a chain of Records, each linking to its parents, rather than one Record carrying a graph.
recipe_sha256gives an integrity commitment without a disclosure requirement — the same shape as §7.5's redaction-with-proof, and for the same reason.- Composes with ADR-0004:
compose,crop,upscale, andgeneratebecome legal chain actions, so the event and the relationship can both be recorded.
- The resolvability rule makes the common failure — a parent nobody can look up — a validation error instead of a discovery six months later.
Bad.
- Two mechanisms, and the line between them is a judgement call. Some producers will inline what should be external; nothing prevents it.
- **The resolvability rule excludes a real case: a producer that holds the parent bytes but has no Record for them.** Such a producer knows the parent's
content_hashand can say nothing else about it, and under this rule it cannot state the parentage at all. That is the deliberate trade — a parent reference nobody can resolve is a claim nobody can check — but it is a cost, and a producer in that position must either mint a Record for the parent or omit the lineage.content_hash-only references are the obvious candidate for relaxation if deployment shows the rule is too strict. - Parent references can still dangle. A
record_urimay name a Record on a server that no longer exists. This is inherent to distributed lineage; fixture 8 pins that a dangling reference is accepted, so at least the behaviour is decided rather than discovered. - A parent identified down to a
pixel_hashinvites exactly the misuse annex E27 warns about. 1.1 §3.3 carries the mitigation as a normative bullet, and the resolvability rule means such a reference cannot stand alone. A mitigation that lives only in an ADR is not a mitigation, which is why it is in the draft's normative text and cited here rather than the other way round. - Lineage is unsigned unless the whole Record is signed (annex E17). An unsigned
parents[]is an assertion, not evidence — the same trust tier as bare EXIF, and it must be read that way. - The recipe envelope is a second schema to publish and maintain, and it defines almost nothing: three members and an extension rule. A minimal envelope that exists beats a rich one that does not, but it will read as thin.
Neutral.
- No wire carriage today: no provenance federates at all (
WIRE-30). Wire carriage for lineage is 1.1 §14 material and can land later than the Record fields. - If ratification reverses to option (b),
parents[]leaves the 1.1 schema andrecipe_sha256stays. Only the draft changes.
