feat(media-buy): add shared budgets and bidding policy - #6088
Conversation
| | `package_id` | Seller's package identifier | | ||
| | `product_id` | Product identifier this package is purchased from. For packages created from an explicit `create_media_buy` package request, sellers MUST echo the request package's `product_id` on every response package object that represents that requested package. | | ||
| | `budget` | Hard lifetime package spend cap. In seller-optimized mode this is not a current allocation and may be absent. | | ||
| | `min_spend_target` | Soft lifetime package spend target accepted for seller-optimized allocation. | |
There was a problem hiding this comment.
Medium: This PR adds packages[].pacing to get-media-buys-response.json (base carried only pacing_index), but the package response table here documents only budget and min_spend_target. The read surface now echoes a package-level pacing field the docs don't describe — schema↔docs drift on the authoritative read surface. Add a pacing row noting it is subordinate to media-buy aggregate pacing.
| @@ -45,7 +45,12 @@ | |||
| }, | |||
| "budget": { | |||
| "type": "number", | |||
There was a problem hiding this comment.
Medium: budget is dropped from this schema's required (L221). create-media-buy-request.json's new anyOf re-requires it for fixed-mode explicit packages, but update-media-buy-request.json's new_packages[] $refs this same shape with no equivalent guard. An add_packages update against a fixed-allocation buy can now omit budget and pass schema validation where 3.1 required it — the fixed-mode budget invariant is enforced only on the create path, not on mid-flight package additions.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema paths require human/CODEOWNERS approval.
This PR modifies published protocol source under static/schemas/source/** (a deterministic hard approval gate) and review_decision is REVIEW_REQUIRED, not APPROVED. Per decision rule row 2, the outcome must be escalate until a real human/CODEOWNERS approval lifts the gate.
No blocking (critical/high) findings were reported. The reviewer classified the change as Normative (non-breaking): additive BudgetAllocation discriminated model, aggregate budget/pacing, package caps, a new capability flag, and a new update_budget_allocation action, with wire changes that are additive or relaxations, a correct minor changeset, and a properly discriminated oneOf. Two Medium coherence/validation gaps remain (see below) but do not on their own change the outcome — the gated-paths gate is the controlling trigger.
Gated files requiring human/CODEOWNERS review include: static/schemas/source/core/budget-allocation.json (added) and the modified media-buy.json, package.json, proposal.json, planned-delivery.json, product-allocation.json, optimization-goal.json, media-buy-features.json, index.json, plus the media-buy request/response schemas.
Medium findings for the human reviewer to weigh:
- docs/media-buy/task-reference/get_media_buys.mdx:84 — packages[].pacing added to response but undocumented in the package table (schema↔docs coherence gap).
- static/schemas/source/media-buy/package-request.json:47 — budget no longer required on new_packages[] for fixed-allocation buys.
Once a CODEOWNERS/human approval sets review_decision to APPROVED, this can fall through to the normal table (no blocking findings present).
Medium findings
- docs/media-buy/task-reference/get_media_buys.mdx:84 — packages[].pacing added to get-media-buys-response but undocumented in get_media_buys package table
- static/schemas/source/media-buy/package-request.json:47 — budget no longer required on new_packages[] for fixed-allocation buys
Why human review
- Touches gated protocol source under static/schemas/source/** (e.g. budget-allocation.json, media-buy.json, proposal.json, package.json) — hard approval gate; review_decision is REVIEW_REQUIRED, not APPROVED. Human/CODEOWNERS review required.
- Two medium schema↔docs coherence/validation gaps to verify: get_media_buys.mdx:84 (packages[].pacing undocumented) and package-request.json:47 (budget no longer required on new_packages[] for fixed allocation).
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/budget-allocation.json (added) matches
static/schemas/source/**; static/schemas/source/core/media-buy-features.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/media-buy.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/optimization-goal.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/package.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/planned-delivery.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/product-allocation.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/proposal.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/media-buy-valid-action.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/get-media-buy-delivery-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/get-media-buys-response.json (modified) matchesstatic/schemas/source/**; static/sc
…(truncated)…
|
Ladon cannot review this PR until merge conflicts are resolved. |
Summary
BudgetAllocationmodel with backward-compatible fixed allocation and seller-optimized shared budgetsBiddingPolicyat media-buy and package scope for manual bids, auction ceilings, average-cost controls, and ROAS controlsMotivation
AdCP 3.1 requires explicit package budgets and splits buyer price intent across package
bid_price, pricing-optionmax_bid, and monetaryoptimization_goalstargets. Platforms that optimize one campaign budget and strategy across multiple ad sets or line items cannot express that behavior without vendor extensions.This gives 3.2 one portable placement story: objective functions stay in
optimization_goals; budget allocation, pacing, and bidding execution policy live at the scope where they are authored.Budget semantics
total_budgetis the hard aggregate lifetime capbudgetremains a hard cap, never a current allocationmin_spend_targetis softBidding semantics
biddingis a complete inherited default; packagebiddingis a complete override, never a field mergebid_amountis a manual auction bid;max_bidis the only hard per-auction ceilingcost_perdistinguishes averagecapfromtarget;roasdistinguishesfloorfromtargetcost_perresolves against the primary optimization goal, whilebid_amount/max_bidresolve against the selected pricing option's auction unitBIDDING_PLACEMENT_CONFLICTAMBIGUOUS_BIDDING_POLICYmax_bid, packagebid_price, and monetary goal targets are deprecated with deterministic normalization rulesValidation
Notes
Daily/hourly caps remain out of scope; the new budget is a lifetime media-buy total. The bidding block represents numeric portfolio policy but not shared provider portfolio identity or lifecycle across media buys; that requires a future provider-neutral resource/reference.