Skip to content

RFC #3305 amendment: allow both format_ids and format on products; decouple wire shape from AdCP-Version #3765

@bokelley

Description

@bokelley

Type: spec amendment to #3305
Target: 3.1 (lands with v2 creatives)
Severity: load-bearing — without this, the "publish both during transition" story isn't actually legal

Problem

The current #3305 / #3307 design specifies oneOf(format_ids, format) on product.json, requiring a product to be either v1 or v2 shape but not both. Combined with informal version negotiation in adopter docs, this conflates two independent version axes:

  1. Protocol version (AdCP-Version: 3.0 / 3.1 / 3.2) — envelope shape, task lifecycle, error codes
  2. Format authoring choice (v1 named vs v2 inline) — what the seller has done with their format catalog

A 3.2 seller can legitimately still author v1 formats — the spec keeps v1 alive through 4.0 specifically so protocol upgrades don't force format-catalog migrations. Conversely, a 3.1+ buyer that supports v2 may receive products from a 3.0 seller that only emits v1. Protocol version doesn't tell you what format shape to expect, and shouldn't.

Tying wire shape to AdCP-Version forces sellers to either downgrade protocol or migrate everything at once. That's the wrong coupling.

Proposed change

  1. Relax product.json from oneOf(format_ids, format) to "both allowed; at least one required." Validators accept three states:

    • format_ids only — v1 product (seller hasn't migrated)
    • format only — v2 product (post-cutover seller, post-5.0)
    • both populated — typical 3.1-era seller during transition (SDK-derived dual emission)
  2. Add normative buyer rule: "If both format_ids and format are present on a product, prefer format. format_ids is treated as fallback / metadata for v1-only buyers."

  3. Add normative seller rule: "Sellers MAY emit both shapes per product. When they do, the two MUST refer to the same underlying format declaration (same canonical narrowing). SDK adapters are RECOMMENDED to derive one from the other mechanically to guarantee consistency."

Why this matters

Without this change, sellers facing mixed buyer fleets have three bad options:

  • Publish duplicate product records (one v1, one v2) — doubles their product catalog and creates inconsistency risk
  • Implement per-buyer wire-shape selection (version-sniffing on every request) — adds complexity without real value
  • Fragment their buyer audience by capability — combinatorial mess

With this change:

  • Seller authors v2 once, SDK emits both fields on the wire, every buyer reads what it knows
  • Forward-compat works naturally — unknown-field tolerance is already the standard cross-version compat mechanism
  • Protocol upgrade and creative-format migration become independent decisions, which is what they should always have been

Implementation note

Small schema change, but load-bearing. Without it, the "publish both during transition" path described in #3305's migration table isn't actually legal under the schema as drafted, and we end up with forced version gating that the migration timeline (3.1 preview → 5.0 removal) can't accommodate.

The oneOf was likely there to enforce "pick one" cleanly, but the SDK-side dual-emission pattern makes "both, derived from one source" a strictly cleaner option.

Companion work

The dual-emission requires a v1↔v2 mapping algorithm. That's a separate spec issue (forthcoming) covering: a canonical mapping registry for well-known v1 formats published by AAO, a canonical field on v1 format definitions for custom seller mappings, and SDK-side projection rules using the asset_group_id bridge that #3307 already added to v1 format slot declarations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.creativerfcProtocol change — auto-adds to roadmap boardschemaJSON Schema source-of-truth: definitions, codegen artifacts, validation, hygiene

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions