Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
7b8c004
feat(creative): v2 Phase 1 — asset_group vocabulary, scenes, delivery…
bokelley Apr 26, 2026
8d090c0
fix(creative): address Phase 1 review catches — audio.mdx VAST bug + …
bokelley Apr 26, 2026
8fdc407
fix(docs): vast_version must be a single string, not an array
bokelley Apr 26, 2026
6324fba
chore(changeset): correct phase 1 bump from patch to minor
bokelley Apr 27, 2026
4df03c2
refactor(creative): replace delivery_type addition with zip asset type
bokelley Apr 27, 2026
77398b3
feat(creative): v2 Phase 2 — canonical format catalog, ProductFormatD…
bokelley Apr 27, 2026
4b0231a
docs(creative): add v2 overview with worked examples (Meta Reels, IAB…
bokelley Apr 27, 2026
170fa41
refactor(creative): collapse build_capability into format inputs; add…
bokelley Apr 27, 2026
8db52b9
docs(creative): drop "generative formats" framing in v2 overview; add…
bokelley Apr 28, 2026
5b74e25
refactor(creative): rename canonical formats — asset_pool_composed → …
bokelley Apr 28, 2026
202ce2e
feat(creative): v2 migration guide + 5 reference fixtures + product.j…
bokelley Apr 28, 2026
77d69b0
fix(creative): address review feedback — doc/schema mismatches, missi…
bokelley Apr 28, 2026
6dcf8dd
feat(creative): manifest inputs field; bundled extensions schema + fi…
bokelley Apr 28, 2026
53f8dbe
refactor(creative): drop inputs concept, add format_kind discriminato…
bokelley Apr 28, 2026
a7734e3
docs(creative): tighten style_reference description with brand.json r…
bokelley Apr 28, 2026
550b042
fix(creative): doc/schema cleanup; full canonical fixture coverage; n…
bokelley Apr 29, 2026
c5de39c
docs(creative): server-side implementation considerations for v2 sale…
bokelley Apr 29, 2026
32b4a7f
Merge remote-tracking branch 'origin/main' into bokelley/v2-phase1-vo…
bokelley Apr 30, 2026
19e6a30
feat(creative): v2 review-feedback round — format_options array, cano…
bokelley Apr 30, 2026
23c8bea
fix(creative): drop invented creative_agents field from v2 third-part…
bokelley Apr 30, 2026
6882b0c
feat(creative): add production-source axis (image_source / video_sour…
bokelley Apr 30, 2026
e074941
feat(creative): v2 red-team schema fixes — manifest v2 path, carousel…
bokelley Apr 30, 2026
55edddf
docs(creative): v2 red-team docs round — glossary, vocabulary table, …
bokelley Apr 30, 2026
601bd95
docs(creative): expand v2 creative-agent migration walkthrough
bokelley Apr 30, 2026
76f7990
Merge remote-tracking branch 'origin/main' into bokelley/v2-phase1-vo…
bokelley Apr 30, 2026
b3c29bc
feat(creative): runtime_status on ProductFormatDeclaration; align ite…
bokelley Apr 30, 2026
1cc7e20
feat(creative): custom format_kind + format_shape registry + format_s…
bokelley Apr 30, 2026
f0650d7
Merge remote-tracking branch 'origin/main' into bokelley/v2-phase1-vo…
bokelley May 1, 2026
a8228b6
feat(creative): A1 dual-emission of format_ids+format_options legal; …
bokelley May 1, 2026
fbb207b
fix(creative): R1-R7 review-line fixes — card-asset, validate_input r…
bokelley May 1, 2026
d7faae4
feat(schema): add optional display_name to ProductFormatDeclaration
claude May 3, 2026
4bbce58
docs(creative): drop per-canonical status differentiation pre-GA — ev…
bokelley May 3, 2026
90ea4bc
refactor(creative): rename v2 → canonical-formats throughout (path + …
bokelley May 16, 2026
5eba428
Merge remote-tracking branch 'origin/main' into bokelley/v2-phase1-vo…
bokelley May 16, 2026
de7a6f0
feat(canonical-formats): address SDK implementor review on PR #3307 —…
bokelley May 16, 2026
501df3f
refactor(canonical-formats): rename v2_only → canonical_formats_only …
bokelley May 16, 2026
d46f83c
feat(canonical-formats): second expert-review pass on PR #3307 — wire…
bokelley May 16, 2026
f29effd
docs(canonical-formats): v2-native seller v1-emission options (closes…
bokelley May 16, 2026
47a9995
fix(ci): correct changeset package name + add error-code drift dispos…
bokelley May 16, 2026
de074fd
refactor(creative): move brand_kit_override from CreativeManifest ont…
bokelley May 16, 2026
3bb819e
feat(canonical-formats): four inline tightenings from python-implemen…
bokelley May 16, 2026
ffbef21
feat(canonical-formats): v1_format_ref on ProductFormatDeclaration; d…
bokelley May 16, 2026
ef7693f
refactor(canonical-formats): collapse status/runtime_status to experi…
bokelley May 16, 2026
972a157
feat(canonical-formats): F+H — slot-constraint mutex + card-asset des…
bokelley May 16, 2026
c97e4bb
fix(canonical-formats): expert-review fixes — rename stragglers, semv…
bokelley May 16, 2026
9dff810
fix(canonical-formats): SDK-side fixes from 4th implementor review — …
bokelley May 17, 2026
762ba1f
fix(canonical-formats): tighten cross-boundary visibility prose on FO…
bokelley May 17, 2026
4c9f19b
feat(canonical-formats): format_shape promotion migration contract; v…
bokelley May 17, 2026
0786e35
fix(canonical-formats): registry globs use underscore namespace to ma…
bokelley May 17, 2026
f34bf5b
feat(canonical-formats): mandate errors[] augmentation as single surf…
bokelley May 17, 2026
7357e58
feat(canonical-formats): 5 upstream asks from adcp-client #1815 proto…
bokelley May 17, 2026
360d084
feat(canonical-formats): converge v1 wire namespace via AAO-hosted v1…
bokelley May 17, 2026
8e5b514
fix(canonical-formats): reconcile registry + fixtures + AAO catalog n…
bokelley May 17, 2026
50da682
fix(canonical-formats): replace fictional .adcp placeholder domains w…
bokelley May 17, 2026
44bd9d2
feat(canonical-formats): annotate 9 more catalog entries; document em…
bokelley May 17, 2026
9f56844
fix(canonical-formats): drop 17 per-size/per-duration registry litera…
bokelley May 17, 2026
f88522c
refactor(canonical-formats): drop meta_reels literal — registry is pu…
bokelley May 17, 2026
e2fae6b
feat(canonical-formats): publisher-scoped format catalog via adagents…
bokelley May 17, 2026
6b3438b
fix(canonical-formats): audit-driven hygiene + slot-param consistency…
bokelley May 17, 2026
6de5b95
feat(canonical-formats): size flexibility on display canonicals (size…
bokelley May 17, 2026
28c9acf
feat(canonical-formats): expert-review round 3 — v1_format_ref array …
bokelley May 17, 2026
56e8805
fix(canonical-formats): de-annotate 8 generative display catalog entr…
bokelley May 17, 2026
1c19b3d
feat(canonical-formats): v1 catalog canonical: annotation is always a…
bokelley May 18, 2026
84a43fa
feat(canonical-formats): de-annotate 8 generative display catalog ent…
bokelley May 18, 2026
d2a24a6
fix(canonical-formats): final cleanup pass — load ui-element-formats,…
bokelley May 18, 2026
ca8ce30
docs(canonical-formats): 5 adopter-feedback additions before lock — f…
bokelley May 18, 2026
0acb56a
chore: revert dist/ to main state — build artifacts don't belong in t…
bokelley May 18, 2026
83a6e91
Merge origin/main into bokelley/v2-phase1-vocab-scenes-delivery
bokelley May 18, 2026
dd9ad8b
chore: re-sync dist/ to origin/main — earlier revert was against stal…
bokelley May 18, 2026
a936b3f
feat(canonical-formats): native_tracker asset type — native parity to…
bokelley May 18, 2026
70974f7
refactor(canonical-formats): native_tracker → pixel_tracker; apply ac…
bokelley May 18, 2026
e3f37ae
docs+tests(canonical-formats): pixel_tracker docs section, 9 negative…
bokelley May 18, 2026
018da46
feat(pixel_tracker): add audible_video_complete (IAB Native event 500…
bokelley May 18, 2026
5067fbc
feat(pixel_tracker): bidirectional v1↔v2 cross-version contract for S…
bokelley May 18, 2026
cc89ac5
feat(canonical-formats): round-2 adopter feedback — native_in_feed ca…
bokelley May 19, 2026
e646b58
fix(canonical-formats): protocol-expert fixes — count drift + IAB Nat…
bokelley May 19, 2026
2542b00
fix(canonical-formats): code-reviewer follow-ups — final count drift …
bokelley May 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/canonical-formats-adopter-feedback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"adcontextprotocol": minor
---

canonical-formats: five adopter-flagged additions before lock. Each surfaces guidance that was implicit in the spec but not findable; one resolves a normative silence.

**1. "What `format_kind` is NOT for" decision rule** (canonical-formats.mdx). Adopters seeing the broadcast / DOOH / generative annotations were tempted to propose `format_kind: dooh_image` or `format_kind: broadcast_video` in 3.2. New section enumerates the six axes (creative type / production model / slot shape / channel / measurement / targeting) and the rule of thumb: new `format_kind` ONLY when the creative ASSET is structurally different. All 50 ad formats in the catalog ship via this rule; zero new canonicals added for broadcast / DOOH / native / generative.

**2. `slots_override` authoring decision rule** (canonical-formats.mdx). When to use it vs leave it off was implicit across the four annotation patterns. New section + table makes it explicit: would a buyer composing the manifest list **different assets** vs the canonical's defaults? Yes → `slots_override`. No → omit. Worked cases: IAB MREC (default), native standard (override), DOOH (default), broadcast (default), generative (override), host-read podcast (override).

**3. End-to-end `adagents.json` fetch flow worked example** (canonical-formats.mdx). The pieces were documented separately (publisher catalog, property scoping, capability_id resolution, community-mirror fallback, supersession). New section walks the full buyer journey in order: `Product` with `publisher_properties` → fetch `<domain>/.well-known/adagents.json` → fall back to AAO mirror on 404 → check `superseded_by` → scope `formats[]` by `applies_to_property_ids` → resolve `capability_id` against same-file `formats[]`. Concrete payload sequence included.

**4. Multi-size fan-out normative decision** (canonical-formats.mdx + error code prose). The spec was silent on whether SDKs MAY fan out a multi-size v2 declaration to N v1 format_ids via catalog lookup. Resolved as MAY-do non-normative: SDKs without catalog access emit only seller-asserted refs (the conservative wire shape, default normative behavior); SDKs with catalog access MAY synthesize the missing per-size refs. Either way, `FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE` MUST fire as a transparency advisory; `error.details.synthesized_refs` lists catalog-resolved entries when fan-out is in play. Two SDKs processing the same input may produce different `format_ids[]` lengths, but the advisory keeps consumers in sync.

**5. `format_schema` fetch-contract test fixtures** (static/examples/format-schemas/). 14 paired positive + negative test vectors covering all 7 failure-mode categories per the normative contract: digest verification, transport (https-only / redirect / oversize), SSRF (RFC 1918 / metadata endpoint), `$ref` sandboxing (cross-origin / depth-exceeded), schema-compile budget (catastrophic regex), schema validity (body is JSON but not a valid schema), graceful degradation (404 with/without cache). Each fixture documents the `setup` to simulate, the `expected_outcome`, the `expected_error_code`, and the rationale linking back to the contract clause. README at `static/examples/format-schemas/README.md` documents shape and usage. Cross-SDK conformance harness tracked as follow-up #4699.

Validation: schema build clean, 14 canonical fixtures + 28 negative fixtures (was 19) + 50-entry catalog convention lint all green.
47 changes: 47 additions & 0 deletions .changeset/canonical-formats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
"adcontextprotocol": minor
---

**Canonical formats (AdCP 3.1).** v2 introduces a structured creative-format vocabulary that buyers and sellers can validate against without per-seller integration code. 13 canonical `format_kind` values (image, html5, display_tag, image_carousel, video_hosted, video_vast, audio_hosted, audio_daast, sponsored_placement, native_in_feed, responsive_creative, agent_placement, custom) with a two-axis model: `format_kind` names the creative TYPE; `asset_source` names the production model (buyer_uploaded / publisher_host_recorded / seller_pre_rendered_from_brief / seller_human_designed / agent_synthesized). Products carry `format_options[]` declarations narrowing a canonical with `params`, `slots`, `applies_to_channels`, optional `capability_id` for multi-format routing, and optional `experimental` flag. The full reference is at `docs/creative/canonical-formats.mdx`.

**Wire-shape details adopters care about:**

- `v1_format_ref` is ALWAYS an array of `{agent_url, id}` entries — single-ref is `[{...}]`. Multi-size declarations carry one ref per size in `params.sizes[]`. The `FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE` error code surfaces when ref count < sizes[] count.
- v1 catalog's `canonical:` annotation is ALWAYS an object — minimal `{ "kind": "image" }`, rich `{ "kind", "asset_source", "slots_override" }`. The object form is what lets the 8 generative catalog entries (`display_*_generative`) project losslessly to v2: buyer ships a text prompt, not image bytes.
- Display canonicals (`image`, `html5`, `display_tag`) support three size modes (mutex-enforced at schema layer): fixed `width+height`, multi-size `sizes: [{w,h}]` (mirrors OpenRTB `banner.format[]`), responsive `min_width/max_width/min_height/max_height`. The same product can carry N format_options across the three modes.
- `ProductFormatDeclaration.canonical_formats_only: true` is the v2-only marker (mutex with `v1_format_ref`).
- `format_kind: "custom"` requires `format_shape` (vocabulary entry) + `format_schema` (URI+digest) and either `canonical_formats_only: true` OR `v1_format_ref`.

**Publisher catalog (`adagents.json formats[]`).** Publishers declare their format support once via top-level `formats[]` (with optional `applies_to_property_ids` / `applies_to_property_tags` scoping). Placements reference declarations by `capability_id`. For platforms that haven't adopted AdCP (Meta, TikTok, etc.), AAO publishes community-maintained adagents.json at `creative.adcontextprotocol.org/translated/<platform>/adagents.json`; `superseded_by` field signals platform-adoption cutover. New media-buy filters `list_creative_formats(publisher_domain, property_id)` answer "what formats does this publisher accept?" with a normative resolution chain (publisher hosted → AAO mirror → agent-derived from products) and a response `source` field labeling which tier produced the list.

**Where each piece of metadata lives (the "no new canonical" pattern).** Before reaching for a new canonical, the spec checks: production model → `asset_source`; slot shape → `slots_override`; channel → `applies_to_channels`; tracking / measurement → `sync_event_sources` / `event_log`. New canonical only when the CREATIVE ASSET is structurally different. Applied: generative, broadcast TV, DOOH, native all stay on existing canonicals via sibling refinement. Conversion pixels (Meta Pixel, GA4) explicitly belong on event_log, NOT on `platform_extensions` of a creative format.

**Coverage at GA.** 50/50 ad formats in the AAO catalog annotated with the projection-ref object form. 7 UI scaffolding entries (`product_card_*`, `format_card_*`, `proposal_card_*`, `native_product_card`) split into `ui-element-formats.json` — they're agent-interface widgets, not ad formats; `list_creative_formats` returns them so consumers can resolve by `format_id`, but they never project to ad canonicals.

**Error codes added** (all surfaced via response `errors[]` augmentation; non-fatal advisories): `FORMAT_PROJECTION_FAILED`, `FORMAT_DECLARATION_DIVERGENT`, `FORMAT_DECLARATION_V1_AMBIGUOUS`, `FORMAT_CAPABILITY_UNRESOLVED`, `FORMAT_DECLARATION_V1_LOSSY_MULTI_SIZE`, `PIXEL_TRACKER_LOSSY_DOWNGRADE`, `PIXEL_TRACKER_UPGRADE_INFERRED`.

**Cross-version pixel_tracker contract (normative for SDK auto-negotiation)**: when a 3.1 buyer SDK talks to a 3.0.x seller that doesn't know `pixel_tracker`, the SDK MUST downgrade to v1 `{asset_type: url, url_type: tracker_pixel}` shape and emit `PIXEL_TRACKER_LOSSY_DOWNGRADE` with per-field details. Conversely a 3.1 SDK reading v1 trackers MUST upgrade by inferring event/method from `asset_id` conventions and emit `PIXEL_TRACKER_UPGRADE_INFERRED`. Both directions are lossy-with-advisory — no REFUSE branch, even for `method: js` (v1 sellers fire the URL as a GET; counter-based measurement increments, but JS-execution-dependent measurement like OMID-style verification won't run). Buyer-side decision per asset: accept the loss or route to a 3.1-capable seller. Full bidirectional mapping table documented in `pixel-tracker-asset.json` description.

**Renderer-fired pixel tracker asset type (#4706)**: new `pixel_tracker` asset type at `static/schemas/source/core/assets/pixel-tracker-asset.json` — the generic web-pixel tracker primitive, applies to any web-rendered canonical (image, html5, image_carousel, responsive_creative, sponsored_placement, native_*, plus non-VAST/DAAST events on video_hosted/audio_hosted). Discriminated union with `event` (impression, viewable_mrc_50, viewable_mrc_100, viewable_video_50, click, custom), `method` (img, js), `url` (uri-template with universal-macros support), and `custom_event_name` (required when event is `custom`). Discriminator shape and event/method enums formalized in IAB OpenRTB Native 1.2 (`imptrackers[]` / `jstracker` / `eventtrackers[]` / `link.clicktrackers[]`). Scope is RENDERER-FIRED trackers — conversion pixels (Meta Pixel, GA4, server-side postbacks) stay on `sync_event_sources` / `event_log` per the format-vs-event_log boundary documented in canonical-formats.mdx. Formats with format-specific tracker structures keep their own primitives: `vast_tracker` (VAST `<TrackingEvents>`), `daast_tracker` (DAAST parity).

**Catalog tracker upgrade**: 45 ad-format payload entries in `server/src/creative-agent/reference-formats.json` previously carrying `impression_tracker` as `asset_type: "url"` upgraded to `asset_type: "pixel_tracker"` with `event: "impression"` + `method: "img"` — display / native / dooh / video_hosted / audio_hosted families all benefit. Plus 4 `slots_override` declarations on `native_standard` / `native_content` reshaped to use `pixel_tracker` for impression and click trackers. To match real measurement plans (impression + viewability + click trackers are commonly attached together), 90 additional optional slots added across the 45 web-rendered entries: each now carries `viewability_tracker` (`event: viewable_mrc_50`) and `click_tracker` (`event: click`) as optional `pixel_tracker` slots. Buyer populates only the trackers their measurement plan declares; absent slots are skipped. New vocabulary entries: `impression_tracker`, `click_tracker`, `viewability_tracker` in asset-group-vocabulary, all mapping to `asset_type: pixel_tracker`.

**`pixel_tracker.event` enum mirrors IAB Native event-type registry**: 5 standardized event values plus `click` and `custom`. Maps 1:1 to IAB OpenRTB Native 1.2: `impression` (1), `viewable_mrc_50` (2), `viewable_mrc_100` (3), `viewable_video_50` (4), `audible_video_complete` (500). `audible_video_complete` is distinct from `viewable_video_50` — the former is 100% completion with audio on; the latter is 50% pixels for ≥2 seconds with audio on. Meaningful on non-VAST video (Meta Reels, YouTube Shorts, TikTok Spark) where audible-complete is measured but VAST `<TrackingEvents>` isn't the wire format.

**Negative-fixture coverage**: 10 new test vectors for `pixel_tracker` in `tests/canonical-negative-fixtures.test.cjs` covering valid shapes (impression img / impression js / viewable_mrc_50 / click / audible_video_complete / custom-with-name) and the rejection paths (custom without `custom_event_name`, non-custom with `custom_event_name`, invalid event enum, invalid method enum). Total negative-fixture count goes from 28 → 38.

**Other adopter-facing additions:**

- `ProductFormatDeclaration.seller_preference: "preferred" | "accepted" | "discouraged"` — soft routing hint on multi-format products.
- `placement-definition.json format_options[]` (capability_id reference OR inline) with same-file resolution scope.
- Convention lint at `tests/canonical-format-conventions.test.cjs` enforces: object-form `canonical:`, array-form `v1_format_ref[]`, size-mode mutex, AAO-mirror URL convention, slot/param consistency.

**Round-2 adopter feedback (Pia Malovrh / Nastassia Fulconis, 2026-05-18 Slack):**

- **`native_in_feed` canonical added.** 13th `format_kind` covering IAB OpenRTB Native 1.2 in-feed native ads, content-recommendation widgets (Taboola, Outbrain, Yahoo Native, AdMob Native), and publisher in-feed sponsored placements without catalog dependency. Slots map 1:1 to IAB Native asset types (`title`, `body_text`, `main_image`, `icon`, `cta`, `advertiser_name`, `sponsored_label`, `landing_page_url`, plus renderer-fired `pixel_tracker` trackers). Routing answer: buyer agents reading `native_in_feed` know to assemble title+image+body+CTA; reading `sponsored_placement` know to attach a catalog feed. Defaults to non-experimental (IAB Native 1.2 contract is well-established).
- **`sponsored_placement` narrowed.** Canonical is now normatively catalog-keyed retail-media ONLY: REQUIRES `source_catalog` slot. Schema description explicitly excludes IAB in-feed native, content-recommendation, PMax-style algorithmic surfaces, and single-image/video creative — those route elsewhere. Earlier broader framing failed buyer-agent routing (buyer reading `sponsored_placement` couldn't disambiguate Amazon SP from Taboola).
- **`scenes` → `video_brief` rename.** Renamed `static/schemas/source/creative/scenes.json` → `creative/video-brief.json` (`$id: /schemas/creative/video-brief.json`), wrapper field `scenes[]` → `segments[]`, per-segment `description` → `prompt`. The shape was always a structured generation brief (no camera direction, shot type, mood, or reference attachments) — the rename calls it that. asset_group_id `scenes` → `video_brief` (with `scenes`, `storyboard`, `shot_brief` as aliases). Distinct from `creative_brief` (free-form text); `video_brief` is the structured timed-prompt form. Buyers wanting visual-direction surface still attach `reference-asset.json` with `purpose: storyboard`.
- **`seller_preference` semantics clarified.** Schema description and `ProductFormatDeclaration` description now state normatively that `format_options[]` is the closed set of accepted formats for a product — sellers MUST reject `create_media_buy` requests targeting any `format_kind` outside that set. `seller_preference` is a soft ranking hint WITHIN the accepted set, NOT an enforcement axis. There is intentionally no `required` enum value; the closed-set rule already handles "this is the only format that works" (list one entry → that's the set). Pia's "won't work vs please don't" distinction is resolved structurally rather than via enum proliferation.
- **Registry two-tier boundary documented; platform-specific IDs removed.** Dropped `youtube_video_id` and `pin_id` from `asset-group-vocabulary.json`. Added normative paragraph: the canonical vocabulary is the IAB-aligned portable tier; platform-specific asset identifiers (TikTok video IDs, Snap attachment IDs, Meta Advantage+ creative IDs, etc.) belong on the canonical's `platform_extensions[]` (URI+digest reference to the platform's extension schema). Earlier draft set precedent for every platform's identifier vocabulary leaking into the canonical registry — explicitly reversed before GA.

**Resolves** #4148 (canonical-formats vocabulary), #4620 (publisher-scoped catalogs), #4652 (.adcp placeholder cleanup), #4689 (catalog generative deannotation). Coordinated with adcp-client #1815 (SDK v1↔v2 projection) and adcp-go (catalog consumer).
30 changes: 30 additions & 0 deletions .changeset/v2-phase1-vocab-scenes-zip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
"adcontextprotocol": minor
---

feat(creative): v2 Phase 1 — asset_group_id vocabulary registry, `scenes` schema, `zip` asset type, video/audio mdx asset_type fixes

First PR implementing the v2 creative formats RFC (#3305). Backwards-compatible additions only — no v1 producers are affected. Minor bump because this introduces new schemas (`asset-group-vocabulary.json`, `scenes.json`, `zip-asset.json`), which are additive features rather than bug fixes.

**New schemas:**

- `static/schemas/source/core/asset-group-vocabulary.json` — canonical registry of `asset_group_id` values (the seven existing catalog vocab entries plus 12 audit-driven additions: `video_vertical`, `video_horizontal`, `audio`, `companion_image`, `companion_banner`, `brand_name`, `body_text`, `cards`, `landing_page_url`, `privacy_policy_url`, `youtube_video_id`, `pin_id`). Includes the `landing_page_url` aliases canonicalizing six different field names today (`click_url`, `link`, `final_url`, `link_url`, `click_through_url`, `landing_url`). Non-canonical IDs remain valid for platform-specific extensions; validators MAY soft-warn on non-canonical usage.

- `static/schemas/source/creative/scenes.json` — typed scene-by-scene structure used as input to `build_creative` for generative video platforms. Each scene has `order`, `duration_ms`, `description`, optional `vo` and `caption`. Renamed from "storyboard" to avoid collision with the testing-harness storyboard concept; description disambiguates from `reference-asset.json` `purpose: "storyboard"` (which describes a reference asset, not a structured plan).

- `static/schemas/source/core/assets/zip-asset.json` — new asset type for bundled creatives delivered as zip archives (HTML5 banners with index.html + CSS + JS + images, MRAID-compatible interactive ads). Carries `url`, optional `max_file_size_kb`, `entry_point`, `allowed_inner_extensions`, `backup_image_url`, and SHA-256 `digest` for integrity. Distinct from inline HTML (`html` asset) and from third-party tag URLs (`url` asset with appropriate `url_type`).

**Registry updates:**

- `static/schemas/source/creative/asset-types/index.json` — added `zip` entry pointing at the new schema
- `static/schemas/source/core/format.json` — added `IndividualZipAsset` and `GroupZipAsset` branches to the format declaration oneOf
- `static/schemas/source/core/offering-asset-group.json`, `creative-manifest.json`, `creative-asset.json`, `creative/list-creatives-response.json` — added `zip-asset.json` to manifest/asset-group oneOf branches so manifests can carry zip assets

**Doc fixes:**

- `docs/creative/channels/video.mdx` — corrected three format-definition examples that used `asset_type: "url"` + `asset_role: "vast_url"` / `"vpaid_url"`, contradicting the schema-correct `asset_type: "vast"` used elsewhere in the same file. Updated VPAID examples to use `asset_type: "vast"` with `vpaid_enabled: true` in requirements.
- `docs/creative/channels/audio.mdx:200` — same bug pattern: `asset_type: "url"` for what should be a VAST audio tag. Corrected to `asset_type: "vast"` with `delivery_type: "url"`; renamed slot key from `vast_url` to `vast_tag` for clarity.

**Why minor (not patch):** new schemas and a new asset type are additive features — patch is reserved for bug fixes only. **Why not major:** no breaking changes; v1 producers and consumers continue to work unchanged. The new `zip` asset type is purely additive — receivers that don't recognize it ignore it via standard discriminator-mismatch handling.

Tracks #3305 (v2 RFC). Phase 1 lays foundational primitives; subsequent phases build the canonical format catalog, `ProductFormatDeclaration` schema, and tools on top of these primitives.
2 changes: 1 addition & 1 deletion docs/building/by-layer/L1/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1583,7 +1583,7 @@ export async function verifyAdcpRequestSignature(req: Request, ctx: {
const { jwk } = await ctx.resolveJwk(parsed.keyid!); // throws _key_unknown
// 8: key purpose
const j = jwk as any;
if (j.use !== "sig" || !Array.isArray(j.key_ops) || !j.key_ops.includes("verify") || j.adcp_use !== "request-signing") {
if (j.use !== "sig" || !Array.isArray(j.key_ops) || !j.key_ops.includes("verify") || j.example_use !== "request-signing") {
throw new RequestSignatureError("request_signature_key_purpose_invalid");
}
// 9: revocation (BEFORE crypto verify)
Expand Down
Loading
Loading