Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions .changeset/available-installment-statuses-canonical.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"adcontextprotocol": minor
---

Move the experimental `available_installment_statuses` (`media_buy.installment_lifecycle`, #8116) from `core/reporting-capabilities.json` to `core/canonical-reporting-capabilities.json` (adcp#8501). The definition, `x-status: experimental` and `x-added-in: 3.3.0` are unchanged.

`core/reporting-capabilities.json` is used only by the deprecated `get_products` product, and 3.3 adds no field that exists only on a deprecated task. The canonical product's reporting capabilities, returned by `list_products`, `request_proposals` and `refine_proposals`, already carry `supports_installment_breakdown`, and the opened schema (DR-0036) now takes the status list beside it.

**This changes 3.3.0-beta.0 through beta.5.** The betas are immutable. A seller built from one declares `available_installment_statuses` on the canonical product's `reporting_capabilities` and stops sending it on a `get_products` product. The installment lifecycle docs and experimental status page say where it lives.
6 changes: 3 additions & 3 deletions docs/media-buy/media-buys/optimization-reporting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1701,7 +1701,7 @@ A `by_installment` row can follow one installment from plan to proof. `installme
- **Publication.** `publication` has a required `published_at` and a `posts[]` array with at least one entry. Each entry is a [`published_post`](https://adcontextprotocol.org/schemas/v3/core/assets/published-post-asset.json) reference, one per place the installment was published, so cross-posts are separate entries and a buyer can pass an entry to [`sync_creatives`](/docs/creative/task-reference/sync_creatives) for paid amplification. Optional `evidence` is a capture or archive of the live post. Optional `verified_by` names an independent verifier; when it is absent the record is seller-reported. `publication` MUST be absent on `scheduled`, `tentative`, `postponed`, `cancelled`, and `live` rows. Sellers SHOULD populate it on each `by_installment` row for a digital installment they report as `published`.
- **Not a billing event.** `publication` is seller-reported evidence. Billing follows the accepted terms, and invoices surface through [`get_account_financials`](/docs/accounts/tasks/get_account_financials).
- **No notification.** There is no new notification type. A buyer reads publication from the next reporting fire or from `get_media_buy_delivery`, and a change-feed seller records a `delivery_report` change.
- **Not reported versus not delivered.** `reporting_capabilities.available_installment_statuses` lists the statuses a seller reports and is meaningful only with `supports_installment_breakdown: true`. A status that is not listed is not reported, so the absence of such rows proves nothing. `published`, `aired`, and `live` are delivery statuses and need not be listed. A seller that has committed to `publication` and cannot yet produce it reports `{ "scope": "standard", "metric_id": "publication" }` in `by_package[].missing_metrics`.
- **Not reported versus not delivered.** `available_installment_statuses` on a canonical product's `reporting_capabilities` (`core/canonical-reporting-capabilities.json`, returned by `list_products`, `request_proposals`, and `refine_proposals`) lists the statuses a seller reports and is meaningful only with `supports_installment_breakdown: true`. The deprecated `get_products` product does not carry it ([adcp#8501](https://github.com/adcontextprotocol/adcp/issues/8501)). A status that is not listed is not reported, so the absence of such rows proves nothing. `published`, `aired`, and `live` are delivery statuses and need not be listed. A seller that has committed to `publication` and cannot yet produce it reports `{ "scope": "standard", "metric_id": "publication" }` in `by_package[].missing_metrics`.
- **Compatibility.** Rows with no `installment_status` stay valid. Sellers MUST NOT send rows with `installment_status` `scheduled`, `tentative`, `postponed`, or `cancelled` to callers pinned below AdCP 3.3, because AdCP 3.2 validators require `impressions` on every installment row. A caller with no declared pin is treated as pinned below 3.3, and reporting webhooks follow the pin of the registration that receives them. Sellers also MUST NOT send `available_installment_statuses` to those callers, so their view of the capability is unchanged. 3.2 validators ignore `publication` and `installment_status` on delivery rows. A `published` row that reports views and omits `impressions`, as in the example below, is subject to the general rule for optional `impressions`: a seller MUST NOT omit it toward a caller pinned below AdCP 3.3 and instead omits the row.
- **Registry.** A seller that returns `installment_status`, `publication`, or `available_installment_statuses` MUST list `media_buy.installment_lifecycle` in `experimental_features` on [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities). These fields apply to `by_installment` only, not to `by_installment_property`.

Expand Down Expand Up @@ -1782,11 +1782,11 @@ A `by_installment` row can follow one installment from plan to proof. `installme
}
```

A seller that reports these rows declares them in the product's reporting capabilities:
A seller that reports these rows declares them in the canonical product's reporting capabilities:

```json
{
"$schema": "https://adcontextprotocol.org/schemas/v3/core/reporting-capabilities.json",
"$schema": "https://adcontextprotocol.org/schemas/v3/core/canonical-reporting-capabilities.json",
"available_reporting_frequencies": ["daily"],
"expected_delay_minutes": 240,
"timezone": "America/New_York",
Expand Down
2 changes: 1 addition & 1 deletion docs/media-buy/task-reference/get_media_buy_delivery.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1046,7 +1046,7 @@ The optional `creative_id` identifies the creative that aired, matching the pack

Delivery metrics on a spot row are optional. Omission means the metric is not yet available in the package's current `measurement_window`, or the product did not declare it in `supports_spot_breakdown.available_metrics`. A later window may return the same `spot_id` with impressions populated. An explicit `impressions: 0` is a measured zero; it does not mean pending or unavailable, and `null` is invalid.

**Experimental in AdCP 3.3: installment lifecycle.** `by_installment` rows MAY carry `installment_status` (`scheduled`, `tentative`, `live`, `postponed`, `cancelled`, `aired`, `published`) and, for a digital installment reported as `published`, a `publication` record: `published_at`, `posts[]` (one [`published_post`](https://adcontextprotocol.org/schemas/v3/core/assets/published-post-asset.json) reference per place it was published, so cross-posts are separate entries), optional `evidence`, and optional `verified_by` (absent means seller-reported). A row with no `installment_status` is a delivery row, as in AdCP 3.2. A `postponed` installment keeps its `installment_ref` with a new `scheduled_at`. A `cancelled` row omits `impressions` and other delivery metrics, and its `spend` reflects only what the accepted terms bill; a seller that declares `cancelled` MUST report a sold installment that will not run as `cancelled` rather than drop the row. `publication` is evidence, not by itself a billing event, and is read from the next reporting fire or from this task. Sellers declare the statuses they report in `reporting_capabilities.available_installment_statuses`, so a missing row is not read as non-delivery. A response served below AdCP 3.3 carries no `scheduled`, `tentative`, `postponed`, or `cancelled` rows ([Serving an older pin](/docs/reference/versioning#serving-an-older-pin)). See [Installment lifecycle and proof of publication](/docs/media-buy/media-buys/optimization-reporting#installment-lifecycle-and-proof-of-publication).
**Experimental in AdCP 3.3: installment lifecycle.** `by_installment` rows MAY carry `installment_status` (`scheduled`, `tentative`, `live`, `postponed`, `cancelled`, `aired`, `published`) and, for a digital installment reported as `published`, a `publication` record: `published_at`, `posts[]` (one [`published_post`](https://adcontextprotocol.org/schemas/v3/core/assets/published-post-asset.json) reference per place it was published, so cross-posts are separate entries), optional `evidence`, and optional `verified_by` (absent means seller-reported). A row with no `installment_status` is a delivery row, as in AdCP 3.2. A `postponed` installment keeps its `installment_ref` with a new `scheduled_at`. A `cancelled` row omits `impressions` and other delivery metrics, and its `spend` reflects only what the accepted terms bill; a seller that declares `cancelled` MUST report a sold installment that will not run as `cancelled` rather than drop the row. `publication` is evidence, not by itself a billing event, and is read from the next reporting fire or from this task. Sellers declare the statuses they report in `available_installment_statuses` on the canonical product's `reporting_capabilities`, so a missing row is not read as non-delivery. A response served below AdCP 3.3 carries no `scheduled`, `tentative`, `postponed`, or `cancelled` rows ([Serving an older pin](/docs/reference/versioning#serving-an-older-pin)). See [Installment lifecycle and proof of publication](/docs/media-buy/media-buys/optimization-reporting#installment-lifecycle-and-proof-of-publication).

**Experimental in AdCP 3.3: spot lifecycle.** `spot_status` (`scheduled`, `aired`, `preempted`, `makegood`) lets one `spot_id` track from plan to as-run. `aired_at` is required only on `aired` and `makegood` rows, and on rows with no `spot_status`, which mean `aired`. `scheduled` and `preempted` rows carry `scheduled_at` and no `aired_at`. `makegood` rows carry `replaces_spot_id`, the `spot_id` of the preempted spot; a planned replacement carries it from `scheduled` onward, so the link is visible before it airs. Metrics on a `scheduled` row, such as `grps`, are expectations, not delivery, and are not part of package totals. `break_position` (`position_in_break`, `spots_in_break`, optional `break_id`) places a spot in its commercial break. `supports_spot_breakdown.available_statuses` and `supports_break_position` tell the buyer which of these the seller reports, so a missing row or field is not read as non-delivery. A response served below AdCP 3.3 carries no `scheduled` or `preempted` rows, because AdCP 3.2 requires `aired_at` on every row ([Serving an older pin](/docs/reference/versioning#serving-an-older-pin)). See [Spot lifecycle, makegoods, and break position](/docs/media-buy/media-buys/optimization-reporting#spot-lifecycle-makegoods-and-break-position) for the full rules and a plan-to-as-run example.

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/experimental-status.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Schemas marked with `x-status: experimental` are the authoritative source. The c
| `media_buy.gender_targeting` | Core `demographics.gender` predicates, product gender capabilities and overlay support/requirements, exact gender and mixed age/gender targeting resolution, the gender capability rollup, authoritative signal gender metadata, and the `sex_gender` governance classification — see [Core gender targeting](/docs/media-buy/advanced-topics/targeting#core-gender-targeting-33). Stable age targeting is excluded. | New portable gender contract without multi-party adoption evidence. Canonical demographic delivery reporting remains age-only in 3.3; this experiment does not add gendered delivery readback. |
| `media_buy.product_identity` | The experimental `Product.identity` declaration on [`get_products`](/docs/media-buy/product-discovery/media-products) and [`list_products`](/docs/media-buy/task-reference/list_products) results, plus reach-unit coherence in delivery reporting | Product-level identity availability, the boundary between modeled and identifier-backed reach, and the methodology disclosure remain new cross-channel interoperability semantics. The field is deliberately product-scoped so mixed addressable and non-addressable inventory remains truthful while implementers validate the disclosure and reporting behavior. |
| `media_buy.match_keys` | The `core/match-key.json` shape and `enums/match-key-use.json`, `media_buy.supported_match_keys` on [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities), `Product.identity.match_keys`, and `match_keys` on TMP provider registration (#8375). See [Match keys and cross-publisher frequency capping](/docs/media-buy/specification#match-keys-and-cross-publisher-frequency-capping-experimental). | Identity resolution now varies by surface and can change between browser and OS releases without a spec change. The use split (`frequency_cap` vs `identity_match`), the compatibility rule for counting a cap across sellers, and the surface qualifier need integration experience with real identity graphs and TMP deployments before freezing. |
| `media_buy.installment_lifecycle` | The `installment_status` and `publication` fields on `by_installment[]` rows of [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery), the `core/installment-publication.json` schema, the `available_installment_statuses` declaration in product `reporting_capabilities`, the `publication` value in `enums/available-metric.json`, and the `installment_delivery` param of `simulate_delivery` in `comply_test_controller` (#8088; see [Installment lifecycle and proof of publication](/docs/media-buy/media-buys/optimization-reporting#installment-lifecycle-and-proof-of-publication)) | Installment lifecycle and proof of post for creator posts, newsletter editions, and podcast episodes, parallel to `media_buy.spot_lifecycle`. Validated so far by one adopter, Availnet, a creator marketplace. The publication record is seller-reported evidence; a notification when an installment publishes is planned for 3.4 and may reshape how buyers learn of publication. |
| `media_buy.installment_lifecycle` | The `installment_status` and `publication` fields on `by_installment[]` rows of [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery), the `core/installment-publication.json` schema, the `available_installment_statuses` declaration in the canonical product's `reporting_capabilities` (`core/canonical-reporting-capabilities.json`), the `publication` value in `enums/available-metric.json`, and the `installment_delivery` param of `simulate_delivery` in `comply_test_controller` (#8088; see [Installment lifecycle and proof of publication](/docs/media-buy/media-buys/optimization-reporting#installment-lifecycle-and-proof-of-publication)) | Installment lifecycle and proof of post for creator posts, newsletter editions, and podcast episodes, parallel to `media_buy.spot_lifecycle`. Validated so far by one adopter, Availnet, a creator marketplace. The publication record is seller-reported evidence; a notification when an installment publishes is planned for 3.4 and may reshape how buyers learn of publication. |
| `media_buy.spot_lifecycle` | The `spot_status`, `scheduled_at`, `replaces_spot_id`, and `break_position` fields on `by_spot[]` rows of [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery), the `enums/spot-status.json` enum, and the `available_statuses` and `supports_break_position` declarations on `supports_spot_breakdown` in product `reporting_capabilities` (#5683, #8009; see [Spot lifecycle, makegoods, and break position](/docs/media-buy/media-buys/optimization-reporting#spot-lifecycle-makegoods-and-break-position)) | Report-time half of linear-TV preemption and makegoods, validated so far by one Dutch linear TV pilot and one US broadcast operator. Contract-time preemption criteria and an interactive replacement-offer flow are planned for 3.4 and may reshape the status vocabulary, the makegood linkage, and how plan rows reconcile with broadcast as-run logs. |
| `media_buy.delivery_projection` | The optional `projection` object on top-level `by_package[]` rows of [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery#delivery-projection) (schema: `core/delivery-projection.json`) and the `delivery-projection-basis` and `delivery-projection-end-state` enums (#5850) | Advisory forward-looking projection of a package's end-of-flight delivery, with one production adopter so far. The `complete` / `early_exhaustion` materiality split was authored during implementation rather than ratified in the brief, and the `basis` method-class vocabulary is expected to grow. Sellers declare the feature id in `experimental_features`; there is no capability field to gate it, because the object appears only on delivery responses. |
| `media_buy.reporting_delivery` | **Reliable Reporting 1.0**: [`get_reporting_status`](/docs/media-buy/task-reference/get_reporting_status), opt-in [`sync_reporting_status`](/docs/media-buy/task-reference/sync_reporting_status), [`sync_reporting_receipts`](/docs/media-buy/task-reference/sync_reporting_receipts), `sync_accounts.reporting_delivery_configs[]`, reporting notifications, and the `media_buy.reporting_delivery` capability block | Proper-name AdCP 3.2 reporting reliability surface (#6911), explicitly discovered through `reliable_reporting_version: "1.0"`. Core, Managed Delivery, and Reconciled Billing have separate capability-gated conformance storyboards. The [consumer-status migration](/docs/reference/migration/reliable-reporting-status-loop) is an active breaking-change notice: current source adds an opt-in task, which becomes required Core only in the next eligible minor after October 24, 2026. Its `content_mismatch` status, stale-`received` grace window, buyer posting deadline, issue lifecycle fields, escalation contact, the reserved `authoritative_party` field ([#7440](https://github.com/adcontextprotocol/adcp/issues/7440)), and the optional report-definition `source.custody` field, new in 3.3 ([#8185](https://github.com/adcontextprotocol/adcp/issues/8185)) are all additive within that experimental surface. [Superseded snapshot compaction](/docs/reference/migration/3-2-to-3-3#superseded-reporting-snapshots-may-be-compacted) ([#8081](https://github.com/adcontextprotocol/adcp/issues/8081)) is a second active breaking-change notice: sellers may compact older superseded snapshot content only in the next eligible minor after November 20, 2026. Multi-party production operation and provider-specific compatibility still need implementation experience before freezing. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
"supports_property_breakdown": { "type": "boolean" },
"supports_collection_breakdown": { "type": "boolean" },
"supports_installment_breakdown": { "type": "boolean" },
"available_installment_statuses": {
"type": "array",
"x-status": "experimental",
"x-added-in": "3.3.0",
"items": { "$ref": "/schemas/enums/installment-status.json" },
"uniqueItems": true,
"description": "Installment lifecycle statuses this product reports in by_installment. Meaningful only with supports_installment_breakdown: true. Absent, or an empty array, means by_installment carries delivery rows only, with no installment_status, as in AdCP 3.2. When present, a status that is not listed is not reported, so the absence of such rows proves nothing and a buyer MUST NOT read it as nothing scheduled, postponed, or cancelled. 'published', 'aired', and 'live' are delivery statuses and need not be listed. Sellers MUST NOT emit this field to callers pinned below AdCP 3.3, or to callers with no declared pin."
},
"supports_collection_property_breakdown": { "type": "boolean" },
"supports_installment_property_breakdown": { "type": "boolean" },
"supports_placement_property_breakdown": { "type": "boolean" },
Expand Down
Loading
Loading