Skip to content

provenance_history[]: chain of custody for assets that move through intermediaries #4443

@bokelley

Description

@bokelley

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:

{
  "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

  • 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

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    creativeenhancementNew feature or requestschemaJSON Schema source-of-truth: definitions, codegen artifacts, validation, hygienespec / protocol

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions