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
11 changes: 11 additions & 0 deletions .changeset/budget-floor-recovery-details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"adcontextprotocol": minor
---

Add optional budget period, constrained-budget locator, constraint cause, and
contributing field details to BUDGET_TOO_LOW errors so buyers can distinguish daily and lifetime minimums
and identify bid-dependent floors without confusing a budget minimum with a
rejected bid. Existing budget error details remain valid;
daily_budget_cap remains a hard ceiling. This implements the error-recovery
portion of #8685; daily minimum discovery and averaged-budget execution remain
proposed for 4.0.
105 changes: 104 additions & 1 deletion docs/building/by-layer/L3/error-handling.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,114 @@ For `UNSUPPORTED_FEATURE` rejecting an unsupported or removed targeting dimensio

| Code | Recovery | Description | Resolution |
|------|----------|-------------|------------|
| [`BUDGET_TOO_LOW`](/docs/building/verification/compliance-catalog#error-code-budget-too-low) | correctable | Budget below seller's minimum | Increase budget or check `capabilities.media_buy.limits` |
| [`BUDGET_TOO_LOW`](/docs/building/verification/compliance-catalog#error-code-budget-too-low) | correctable | Budget below seller's minimum | Use `field` and the budget floor details below to adjust the constrained budget or its contributing bid |
| [`BUDGET_EXHAUSTED`](/docs/building/verification/compliance-catalog#error-code-budget-exhausted) | terminal | Account or campaign budget fully spent | Buyer must add funds or increase budget cap |
| `CREATIVE_NOT_FOUND` | correctable | Referenced creative does not exist in the library | Verify `creative_id` via [`list_creatives`](/docs/creative/task-reference/list_creatives), or register it via [`sync_creatives`](/docs/creative/task-reference/sync_creatives) |
| [`CREATIVE_REJECTED`](/docs/building/verification/compliance-catalog#error-code-creative-rejected) | correctable | Creative failed content-policy, brand-safety, or accessibility review | Revise according to the applicable policy or validated accessibility criteria |

#### Budget floor recovery

In AdCP 3.3, sellers can describe a budget rejection using the optional fields
in [`error-details/budget-too-low.json`](https://adcontextprotocol.org/schemas/v3/error-details/budget-too-low.json).
The enclosing `error.field` retains its existing meaning and, when `issues[]`
is present, continues to mirror the first issue's pointer in JSONPath-lite
form. Details can identify the constrained budget separately:

| Field | Meaning |
|---|---|
| `minimum_budget` | The minimum acceptable budget amount in `currency`; not the increment to add or a minimum bid. |
| `budget_field` | The constrained budget in the request's target scope, in JSONPath-lite form. May name a retained budget omitted from an update. |
| `basis` | `daily` or `lifetime`. Omission means the period is undeclared. |
| `constraint` | `product_minimum` for a product/pricing-option minimum, or `effective_bid_floor` when the effective bid determines the minimum. Other non-empty values may describe seller-specific constraints. |
| `related_field` | A contributing request field, such as an explicitly authored bid. Omitted when the floor comes from a seller default with no corresponding request field. |

Use `budget_field` as the budget locator when present; otherwise use
`error.field` only when it unambiguously names a budget control. In an update,
`packages[i]` indexes a submitted request row, whose `package_id` identifies
the existing package. It never indexes the current-state readback array. Read
and reconcile a retained budget before choosing a change to it.

For a bid-dependent floor, `minimum_budget` is the computed required budget
after resolving the proposed request's inherited bidding policy and package
overrides. The buyer can evaluate raising the budget or lowering the contributing
bid, subject to its existing authorization. `bid` is a cause, not a duration
value for `basis`. A seller evaluates a combined budget/bid change against the
resulting state rather than either field's previous value.

For example, a lifetime package budget can be rejected with this error:

```json
{
"$schema": "https://adcontextprotocol.org/schemas/v3/core/error.json",
"code": "BUDGET_TOO_LOW",
"message": "Package lifetime budget is below the selected pricing option's minimum",
"recovery": "correctable",
"field": "packages[0].budget",
"details": {
"minimum_budget": 500,
"currency": "GBP",
"basis": "lifetime",
"constraint": "product_minimum"
}
}
```

For a product whose daily minimum depends on the manual bid, this package row
in a [`control_media_buy`](/docs/media-buy/task-reference/control_media_buy)
request raises the bid to 30 GBP while retaining a daily cap of 25 GBP:

```json
{
"$schema": "https://adcontextprotocol.org/schemas/v3/media-buy/package-control.json",
"package_id": "pkg_stream",
"bidding": { "bid_amount": 30 }
}
```

If that row is `packages[0]`, the seller can preserve the submitted bid's issue
pointer while identifying the retained daily cap separately:

```json
{
"$schema": "https://adcontextprotocol.org/schemas/v3/core/error.json",
"code": "BUDGET_TOO_LOW",
"message": "The proposed bid requires a daily budget of at least 30 GBP",
"recovery": "correctable",
"field": "packages[0].bidding.bid_amount",
"issues": [
{
"pointer": "/packages/0/bidding/bid_amount",
"message": "The bid exceeds the retained daily budget",
"keyword": "maximum"
}
],
"details": {
"minimum_budget": 30,
"currency": "GBP",
"budget_field": "packages[0].daily_budget_cap",
"basis": "daily",
"constraint": "effective_bid_floor",
"related_field": "packages[0].bidding.bid_amount"
}
}
```

The amount is a budget floor; applying 30 GBP to the bid would not repair the
retained cap. If a media-buy bid update affects packages absent from the
request, the seller omits a package `budget_field` rather than inventing a
request index. A root budget locator is appropriate only when the constrained
budget is actually at media-buy scope. When no locator identifies the budget
unambiguously, the amount remains diagnostic: the buyer reads authoritative
state and reconciles the affected budgets, or seeks clarification. It does
not apply the amount to the bid or infer package identity from array ordering.

These details do not introduce a new budget control. `basis: "daily"` describes
the constrained daily field and does not change its spend
guarantees: `daily_budget_cap` remains a hard ceiling. A buyer must not assume
that an undeclared budget period is lifetime, or treat a bid-driven floor as a
reason to increase spending automatically. Earlier details containing only
`minimum_budget` and `currency` remain valid.

### System

| Code | Recovery | Description | Resolution |
Expand Down
12 changes: 12 additions & 0 deletions docs/reference/roadmap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ Named milestones group roadmap items that will ship together in a future major v

v4.0 is the next **breaking-changes accumulation window**, targeted for early 2027 under the [release cadence policy](/docs/reference/versioning#release-cadence). Breaking changes are gathered here so the ecosystem can plan a single migration window rather than chase per-minor deprecations. Items listed below are committed floor requirements for v4.0; additional items will be added here as RFCs are accepted.

The proposed development sequence is to finish 3.3, then develop 4.0 as the next
feature release for the early-2027 target while maintaining 3.3. The 18-month
major-release spacing commitment applies from 4.0 onward, not to the 3.x-to-4.0
transition. Each removal still needs its own deprecation notice period.

[Budget constraints and averaged daily budgets (#8685)](https://github.com/adcontextprotocol/adcp/issues/8685)
are a candidate for this window: per-currency daily minimums, distinct averaged
pacing targets, and explicit daily-only authorization need coordinated changes
to canonical pricing and accepted purchase records. Optional budget-error
recovery details can ship in 3.3. The execution model remains a proposal rather
than a committed 4.0 floor requirement.

| Area | Item |
|---|---|
| Security (floor) | [Mandatory request signing for spend-committing operations (RFC 9421)](https://github.com/adcontextprotocol/adcp/issues/2307) — the 3.0 optional profile in `security.mdx` becomes required. Agents MUST sign spend-committing operations; sellers MUST verify. |
Expand Down
8 changes: 7 additions & 1 deletion docs/reference/versioning.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -318,13 +318,19 @@ AdCP publishes the following named policy so implementers can plan:

| Commitment | Window |
|---|---|
| **Major releases (breaking)** | minimum 18 months apart |
| **Major releases after 4.0 (breaking)** | minimum 18 months apart |
| **Next major (4.0)** | target early 2027 |
| **Support for previous major after successor GA** | minimum 12 months |
| **Deprecation notice before removal** | minimum 6 months |

Within a version, releases land every 6–8 weeks early in the cycle and stretch toward quarterly as the version stabilizes. Release count within a version is not fixed.

The 18-month major-release spacing commitment applies from 4.0 onward. It does
not govern the 3.x-to-4.0 transition or delay the established early-2027 target.
The proposed development sequence is to finish 3.3, then develop 4.0 as the next
feature release. Deprecation notice and prior-major support commitments remain
applicable.

### Support window for previous major

When a new major ships, the prior major receives security patches for at least 12 months after successor GA. Security patches (CVE fixes and security advisories) are backported for the full window; feature work is not. The exact end-of-life date for each version is published on a per-version sunset page and linked from the transition note that accompanies the successor's GA release.
Expand Down
6 changes: 3 additions & 3 deletions docs/snippets/compliance-error-codes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ description: "Canonical AdCP error codes with recovery classifications, remediat
| `BUDGET_CAP_REACHED` | correctable | raise max_spend, or reduce max_creatives/max_variants, to produce the remaining items |
| `BUDGET_EXCEEDED` | correctable | reduce requested amount or increase budget allocation |
| `BUDGET_EXHAUSTED` | terminal | buyer must add funds or increase budget cap |
| `BUDGET_TOO_LOW` | correctable | increase budget or check capabilities.media_buy.limits |
| `BUDGET_TOO_LOW` | correctable | inspect the budget floor details; reconcile the constrained budget, then adjust that budget or its contributing bid within existing authorization |
| `CAMPAIGN_SUSPENDED` | transient | wait for the escalation to resolve; contact the plan operator if the suspension persists |
| `CATALOG_LIMIT_EXCEEDED` | correctable | remove unused catalogs, or contact the seller to raise the limit |
| `COMMITTED_RESOURCE_PURGED` | terminal | do not automatically retry with the same or a fresh idempotency_key; reconcile through the resource read task and seller audit or operator records before deciding whether to initiate a new operation |
Expand Down Expand Up @@ -378,9 +378,9 @@ Account or campaign budget has been fully spent. Distinct from BUDGET_TOO_LOW (r

<Accordion title="BUDGET_TOO_LOW — correctable">

**Suggested action:** increase budget or check capabilities.media_buy.limits
**Suggested action:** inspect the budget floor details; reconcile the constrained budget, then adjust that budget or its contributing bid within existing authorization

Budget is below the seller's minimum. Recovery: correctable (increase budget or check capabilities.media_buy.limits).
Budget is below the seller's minimum. Optional recovery details follow error-details/budget-too-low.json: minimum_budget and currency describe the floor; basis distinguishes daily and lifetime budgets, constraint identifies its cause, budget_field identifies the constrained budget when error.field instead names a contributing bid, and related_field can identify that bid. error.field retains its existing consistency with issues[0].pointer. Without an unambiguous budget locator, the amount is diagnostic; reconcile current state before choosing a change. Recovery: correctable (adjust the constrained budget or contributing bid within the buyer's authorization).

</Accordion>
<a id="error-code-campaign-suspended"></a>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"test:canonical-reference-resolver": "node --test --test-force-exit --test-timeout=30000 tests/canonical-reference-resolver.test.cjs",
"test:canonical-pixel-ratio": "node --test --test-force-exit --test-timeout=30000 tests/canonical-image-pixel-ratio-vectors.test.cjs tests/canonical-display-acceptance-vectors.test.cjs",
"test:premium-display-formats": "node --test --test-force-exit --test-timeout=30000 tests/premium-display-format-validation.test.cjs",
"test:error-handling": "node tests/check-error-handling.cjs",
"test:error-handling": "node tests/check-error-handling.cjs && node --test --test-force-exit tests/budget-too-low-details.test.cjs",
"test:get-creative-features-contract": "node --test --test-force-exit --test-timeout=30000 tests/get-creative-features-idempotency.test.cjs",
"test:composed": "node tests/composed-schema-validation.test.cjs && npm run test:get-creative-features-contract",
"test:rejection-arm-mutex": "node tests/rejection-arm-mutual-exclusion.test.cjs",
Expand Down
Loading
Loading