Problem
The current provenance model has a single declared_by / declared_at — a snapshot. In real programmatic, an asset moves:
creator → agency → DSP → ad server → SSP → publisher
Any of these may transcode, crop, re-encode, composite, or modify. The spec gives two unsatisfying options:
- Keep the original claim: the claim now misrepresents the current asset state.
- Replace the claim: the original attestation is lost; you cannot demonstrate who first declared what.
C2PA solved this on the cryptographic side with manifest chains. AdCP's declarative layer should mirror it.
Proposed wire shape
A provenance_history[] array recording the chain. Each entry captures a transition: who touched the asset and what they did. The current provenance object remains as the "head of chain" / most recent declaration:
Composition rules
- Append-only. A party touching the asset MUST append, MUST NOT modify earlier entries.
- Most recent entry is the head: the top-level
provenance object is by convention a copy of the last provenance_history[] entry promoted for ease of access, OR can be a fresh declaration by the current handler whose ancestry is in provenance_history[]. Spec needs to pick one — I lean the second; the head is the current party's claim, the history is everyone before.
- Transformations enum (new):
ai_generation, composite_with_human_copy, composite_with_other_ai, transcode_*, resize_*, crop, recolor, audio_dub. Open vocabulary, IPTC-aligned where possible.
- Signature interaction (depends on #TBD signed-claims): each
provenance_history[] entry carries its own signature. The integrity guarantee is "each party signed their own attestation"; no party can forge another's signature, and tampering with an earlier entry breaks its signature.
Open questions
- Bounded history? A 30-hop chain is implausible but defensively the protocol should not require unbounded growth on the wire. Maybe
provenance_history[] has a recommended cap (10? 20?) with "earliest entries may be summarized" guidance.
- Privacy at intermediaries. Some intermediaries may not want to declare their existence on the wire (e.g., to avoid revealing supply-path composition). Treat as opt-in: a party MAY append, MUST sign if they do, MUST NOT lie about what they did if they do.
- C2PA parity. When a C2PA manifest is also carried (
provenance.c2pa.manifest_url), do provenance_history[] entries need to align with C2PA's manifest chain? Probably "best-effort, not normative" — different cryptographic systems, same intent.
Out of scope
- Cryptographic enforcement of append-only beyond per-entry signatures. Tamper detection via signatures is sufficient; a true append-only log (Merkle tree etc.) is heavier than this problem warrants.
- Retroactive history reconstruction. If a party didn't append at the time, the protocol cannot fabricate history.
Refs
Priority
Post-GA. Pairs naturally with signed claims (becomes redundant without them, fully load-bearing with them). File now, schedule after signed-claims lands.
Problem
The current provenance model has a single
declared_by/declared_at— a snapshot. In real programmatic, an asset moves:creator → agency → DSP → ad server → SSP → publisher
Any of these may transcode, crop, re-encode, composite, or modify. The spec gives two unsatisfying options:
C2PA solved this on the cryptographic side with manifest chains. AdCP's declarative layer should mirror it.
Proposed wire shape
A
provenance_history[]array recording the chain. Each entry captures a transition: who touched the asset and what they did. The currentprovenanceobject remains as the "head of chain" / most recent declaration:{ "provenance": { "digital_source_type": "composite_with_trained_algorithmic_media", "declared_by": { "role": "platform", "agent_url": "https://ssp.example.com" }, "declared_at": "2026-05-12T14:30:00Z" }, "provenance_history": [ { "declared_by": { "role": "creator", "agent_url": "https://creator.example.com" }, "declared_at": "2026-05-12T10:00:00Z", "digital_source_type": "trained_algorithmic_media", "transformations": ["ai_generation"] }, { "declared_by": { "role": "agency", "agent_url": "https://agency.example.com" }, "declared_at": "2026-05-12T12:00:00Z", "digital_source_type": "composite_with_trained_algorithmic_media", "transformations": ["composite_with_human_copy"] }, { "declared_by": { "role": "platform", "agent_url": "https://dsp.example.com" }, "declared_at": "2026-05-12T14:00:00Z", "transformations": ["transcode_to_h264", "resize_300x250"] } ] }Composition rules
provenanceobject is by convention a copy of the lastprovenance_history[]entry promoted for ease of access, OR can be a fresh declaration by the current handler whose ancestry is inprovenance_history[]. Spec needs to pick one — I lean the second; the head is the current party's claim, the history is everyone before.ai_generation,composite_with_human_copy,composite_with_other_ai,transcode_*,resize_*,crop,recolor,audio_dub. Open vocabulary, IPTC-aligned where possible.provenance_history[]entry carries its own signature. The integrity guarantee is "each party signed their own attestation"; no party can forge another's signature, and tampering with an earlier entry breaks its signature.Open questions
provenance_history[]has a recommended cap (10? 20?) with "earliest entries may be summarized" guidance.provenance.c2pa.manifest_url), doprovenance_history[]entries need to align with C2PA's manifest chain? Probably "best-effort, not normative" — different cryptographic systems, same intent.Out of scope
Refs
Priority
Post-GA. Pairs naturally with signed claims (becomes redundant without them, fully load-bearing with them). File now, schedule after signed-claims lands.