Skip to content

feat(media-buy): add per-package daily_budget_cap with budget_capping capability - #5990

Open
garvitkaushik-123 wants to merge 3 commits into
adcontextprotocol:mainfrom
garvitkaushik-123:feat/daily-budget-cap
Open

feat(media-buy): add per-package daily_budget_cap with budget_capping capability#5990
garvitkaushik-123 wants to merge 3 commits into
adcontextprotocol:mainfrom
garvitkaushik-123:feat/daily-budget-cap

Conversation

@garvitkaushik-123

@garvitkaushik-123 garvitkaushik-123 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the Agreed (pending WG ratification) design from RFC #5983 — bokelley's Secretariat memo plus the TZ-C timezone convergence. Buyers running against client-approved daily authorizations (agency) or ROAS floors (performance) had no protocol path to bound per-day spend; pacing: "even" is a leaky approximation that fails under mid-flight budget changes. Closes the gap documented in #4429.

Changes

Schema Field
package-request.json daily_budget_cap (number, media-buy currency) + optional budget_cap_timezone
package-update.json same (PATCH: applied from next cap-day forward, not retroactive)
core/package.json echoes accepted daily_budget_cap + resolved budget_cap_timezone — this is the shape create-media-buy-response and update-media-buy-response reference
get-media-buys-response.json same echo on its inline package shape
get-adcp-capabilities-response.json new media_buy.budget_capping object (supported_periods, enforcement, effective_timezone, buyer_timezone_override)

Response echo lands on every read surface: core/package.json covers create_media_buy + update_media_buy responses, and the inline get_media_buys package shape covers reads.

Design points, matching the memo:

  • Orthogonal to pacing — the cap is the ceiling the pacing engine operates within; pacing: "asap" + a cap is valid and coherent.
  • Undeclared support → UNSUPPORTED_FEATURE (never silent-drop), same contract as frequency_capping and account_financials.
  • Enforcement strength advertised (hard/soft) so buyers aren't surprised by soft-vs-hard differences.
  • TZ-C (seller billing timezone). Day boundary = budget_capping.effective_timezone, which MUST equal get_account_financials.timezone when financials are available — the cross-surface consistency rule bokelley raised in the last comment. DST transition days = one local calendar day carrying the full cap. Buyer override only when buyer_timezone_override: true.
  • Full implementation scope per the memo — package-update.json + response echo are in-scope here, not a follow-up.

Deliberately out of scope (open WG items in the RFC)

  • daily_impression_cap parity — an explicit open WG vote; both experts lean defer. supported_periods is an array so future periods (hour/week) are additive.
  • 3.1 pull-in vs Spec Backlog — a milestone/timing call for the WG; the schema is ready either way.
  • update_media_buy action-vocabulary mappingdaily_budget_cap changes are not mapped to a gated available_actions[] entry, consistent with impressions (also an unmapped per-package delivery control). Happy to add an action if the WG wants cap changes separately gated.

This is the ratification-pending design; happy to adjust to the WG's final vote on the open items.

Test plan


Per @bokelley's comment: #5984 has merged, so this branch is now rebased on main and the create_media_buy "known gap: no daily cap" note is rewritten to document daily_budget_cap (with the pacing-approximation fallback kept for sellers without support). The note lands atomically with the feature.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argus is not auto-reviewing this PR because it modifies protected paths that require human review (static/schemas/source/media-buy/get-media-buys-response.json, static/schemas/source/media-buy/package-request.json, static/schemas/source/media-buy/package-update.json, static/schemas/source/protocol/get-adcp-capabilities-response.json). A human reviewer should review and merge this PR; Argus will resume on subsequent PRs once these changes land on main.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argus is not auto-reviewing this PR because it modifies protected paths that require human review (static/schemas/source/core/package.json, static/schemas/source/media-buy/get-media-buys-response.json, static/schemas/source/media-buy/package-request.json, static/schemas/source/media-buy/package-update.json, static/schemas/source/protocol/get-adcp-capabilities-response.json). A human reviewer should review and merge this PR; Argus will resume on subsequent PRs once these changes land on main.

@bokelley

Copy link
Copy Markdown
Contributor

Release-line classification: this is a legitimate additive feature with a minor changeset, so it is queued for 3.2 rather than 3.1.5. Please keep it open pending the remaining WG ratification items; once #5984 lands, update the known-gap note when this feature is finalized.

… capability

Implements the ratification-pending design from RFC adcontextprotocol#5983. Buyers had no
protocol path to bound per-day spend — only budget, pacing, and flight window,
none a hard daily ceiling (the gap documented in adcontextprotocol#4429).

- package-request.json / package-update.json: daily_budget_cap (number, media
  buy currency) + optional budget_cap_timezone override. Orthogonal to pacing.
- get-media-buys-response.json: echo daily_budget_cap + resolved
  budget_cap_timezone per package for enforcement verification.
- get-adcp-capabilities-response.json: media_buy.budget_capping capability
  (supported_periods, enforcement hard/soft, effective_timezone,
  buyer_timezone_override), modeled on frequency_capping. Undeclared support
  MUST reject daily_budget_cap with UNSUPPORTED_FEATURE.

Timezone anchors to the seller billing boundary: effective_timezone MUST equal
get_account_financials.timezone when financials are available (TZ-C). Scope is
day-only; daily_impression_cap parity deferred per the RFC's open WG questions.

Closes adcontextprotocol#5983
Audit follow-up. The response echo was added only to the inline package shape
in get-media-buys-response.json, so create_media_buy and update_media_buy
responses (which $ref core/package.json) did not echo the accepted cap — a
scope gap given the field must be verifiable on every read surface.

- Add daily_budget_cap + budget_cap_timezone to core/package.json (covers
  create-media-buy-response and update-media-buy-response).
- Drop the invented x-echo key from get-media-buys-response (prose MUST-echo
  is the contract; x-echo is not an established convention in this repo).
- Align package-update daily_budget_cap currency phrasing with its budget
  sibling ("currency specified by the pricing option").
- Add a core/package.json regression case.
…et_cap field

adcontextprotocol#5984 (merged) documented "no per-day cap field" as a known gap. This feature
adds the field, so the note now describes daily_budget_cap — orthogonal to
pacing, seller-billing-timezone boundary, capability-gated — and keeps the
pacing-approximation fallback for sellers without support. Adds the field to
the Budget & Pacing Controls table.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argus is not auto-reviewing this PR because it modifies protected paths that require human review (static/schemas/source/core/package.json, static/schemas/source/media-buy/get-media-buys-response.json, static/schemas/source/media-buy/package-request.json, static/schemas/source/media-buy/package-update.json, static/schemas/source/protocol/get-adcp-capabilities-response.json). A human reviewer should review and merge this PR; Argus will resume on subsequent PRs once these changes land on main.

@sangilish

Copy link
Copy Markdown
Contributor

TZ-C captures the reconciliation issue well. Because the effective_timezone MUST equal get_account_financials.timezone rule spans two task responses and cannot be enforced by JSON Schema, should this PR add a conformance invariant/storyboard, or explicitly track one, for the mismatch case? The current schema tests cover presence and response echo, but two individually valid responses can still violate the cross-surface contract.

@bokelley

Copy link
Copy Markdown
Contributor

@sangilish — valid observation. The schema tests here confirm each response is individually well-formed, but they can't catch the cross-surface mismatch (two conformant responses that together violate the effective_timezone == get_account_financials.timezone rule).

Recommendation: track separately rather than fold into this PR.

Two reasons:

  1. The PR is pending WG ratification on the core fields. Coupling a conformance storyboard to this merge adds review surface and risks blocking the schema on compliance-tooling review — these are different concerns for different reviewers.
  2. Cross-surface storyboards work best against ratified, stable semantics. Drafting one pre-ratification risks churn if the constraint wording or field names shift before the WG vote finalizes.

The right artifact is a follow-up compliance suite issue along the lines of: "conformance storyboard: verify budget_capping.effective_timezone equals get_account_financials.timezone when both surfaces are queried in the same session."

One thing @garvitkaushik-123 could do before merge: add a [ ] Cross-surface timezone storyboard → tracked in #N checkbox to the test plan block. That makes the gap visible at merge and signals it's intentionally deferred (not forgotten), consistent with how the other out-of-scope items are handled above.


Generated by Claude Code

@bokelley

Copy link
Copy Markdown
Contributor

Filed #6010 as the follow-up compliance suite issue ("conformance storyboard: verify budget_capping.effective_timezone equals get_account_financials.timezone in the same session") and added the [ ] Cross-surface timezone storyboard → tracked in #6010 checkbox to the test plan above.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants