Summary
Implement the SDK layer for AdCP's product → proposal → live-MediaBuy action model introduced by adcontextprotocol/adcp#6750 and the accompanying 3.2 schema changes.
The buyer should be able to answer three different questions without manually joining protocol objects:
- Product
allowed_actions[]: could this product support the change?
- Proposal
commercial_terms.change_terms[]: what did the accepted deal promise?
- MediaBuy
available_actions[]: what is executable now?
The seller should have one resolver that derives the third surface from the first two plus current status and caller authorization, rather than constructing three drifting declarations.
Protocol compatibility
available_actions[].terms_ref shipped in AdCP 3.1 and remains an opaque compatibility field through 3.x.
- AdCP 3.2 adds
change_term_id as the unambiguous link to accepted_proposal.commercial_terms.change_terms[].term_id.
- Never reinterpret an arbitrary 3.1
terms_ref as a proposal-term identity.
- When a 3.2 compatibility payload emits both as aliases, require equality.
- 3.2 adds
seller_managed, proposal allowed_statuses, and portable budget/flight/package-count/effective-timing constraints.
- The entire absence of proposal
change_terms means legacy_unknown; an explicit array means omitted actions are not negotiated.
Buyer API
Add a cohesive action assessment API (exact naming is maintainers' choice) with a discriminated result such as:
type ActionAvailability =
| { status: 'available_now'; action: MediaBuyAction; route: MediaBuyTask; mode: MediaBuyActionMode }
| { status: 'wrong_status'; action: MediaBuyAction; allowedStatuses: MediaBuyStatus[] }
| { status: 'not_negotiated'; action: MediaBuyAction }
| { status: 'unsupported_by_product'; action: MediaBuyAction }
| { status: 'currently_unavailable'; action: MediaBuyAction }
| { status: 'legacy_unknown'; action: MediaBuyAction };
Expected public behavior:
- Assess product actions without presenting advisory templates as promises.
- Assess proposal rights, including status scope, mode, SLA, typed constraints, opaque conditions, and contract reference.
- Explain current action availability by joining accepted terms with the live buy.
- Preserve
unknown when seller-only conditions or missing legacy information prevent a decision.
- Extend existing mutation decomposition/preflight to check portable constraints when enough current state is available.
- Route an executable action to
control_media_buy, refine_proposals, or sync_creatives from canonical action metadata.
- Treat
seller_managed as the standard async task lifecycle, not as a disclosed approval/HITL process.
- Continue using revision/idempotency safeguards and refresh from
ACTION_NOT_ALLOWED.currently_available_actions after races.
Seller API
Provide a resolver/builder that:
- materializes proposal change terms from product templates only when the seller explicitly accepts them as binding;
- computes current
available_actions[] from accepted change terms, MediaBuy status, account authorization, governance delegation, and seller policy;
- guarantees an available action cannot exceed the accepted term's mode, SLA, status scope, or typed constraints;
- emits
change_term_id for 3.2 and an explicit 3.1 compatibility projection where requested;
- validates unique action/term identities and action/task/constraint compatibility;
- uses the existing canonical state-machine helpers rather than creating approval-specific MediaBuy statuses.
Tests
Add fixtures and tests for:
- AdCP 3.1.19
terms_ref input and valid_actions[] fallback;
- a released 3.2 beta bundle without the new fields;
- current 3.2
change_term_id, seller_managed, status scope, and each typed constraint kind;
- both alias fields equal, both unequal, and a 3.1 opaque value that coincidentally resembles a term ID;
- product-supported but not negotiated;
- negotiated but wrong status;
- negotiated and available immediately;
- negotiated seller-managed action sent through the wrong route;
- opaque conditions producing
currently_unavailable/unknown rather than false approval;
- stale revision race followed by a current action-set echo;
- active → paused projections and terminal-state empty projections;
- mixed multi-action requests where one action is blocked;
- generated types, ESM/CJS exports, and tree-shakeable browser use.
Package and run the new media_buy_seller/change_rights_state_projection compliance scenario and the expanded compact lifecycle scenario from the matching AdCP bundle.
Acceptance criteria
- A buyer can render “possible / promised / available now” and explain a blocked action without reimplementing protocol joins.
- A seller can derive correct action surfaces through one SDK resolver.
- Legacy 3.1 remains readable, but no compatibility heuristic grants authority.
- JavaScript API behavior has parity requirements documented for adcp-client-python.
Upstream: adcontextprotocol/adcp#6750
Summary
Implement the SDK layer for AdCP's product → proposal → live-MediaBuy action model introduced by adcontextprotocol/adcp#6750 and the accompanying 3.2 schema changes.
The buyer should be able to answer three different questions without manually joining protocol objects:
allowed_actions[]: could this product support the change?commercial_terms.change_terms[]: what did the accepted deal promise?available_actions[]: what is executable now?The seller should have one resolver that derives the third surface from the first two plus current status and caller authorization, rather than constructing three drifting declarations.
Protocol compatibility
available_actions[].terms_refshipped in AdCP 3.1 and remains an opaque compatibility field through 3.x.change_term_idas the unambiguous link toaccepted_proposal.commercial_terms.change_terms[].term_id.terms_refas a proposal-term identity.seller_managed, proposalallowed_statuses, and portable budget/flight/package-count/effective-timing constraints.change_termsmeanslegacy_unknown; an explicit array means omitted actions are not negotiated.Buyer API
Add a cohesive action assessment API (exact naming is maintainers' choice) with a discriminated result such as:
Expected public behavior:
unknownwhen seller-only conditions or missing legacy information prevent a decision.control_media_buy,refine_proposals, orsync_creativesfrom canonical action metadata.seller_managedas the standard async task lifecycle, not as a disclosed approval/HITL process.ACTION_NOT_ALLOWED.currently_available_actionsafter races.Seller API
Provide a resolver/builder that:
available_actions[]from accepted change terms, MediaBuy status, account authorization, governance delegation, and seller policy;change_term_idfor 3.2 and an explicit 3.1 compatibility projection where requested;Tests
Add fixtures and tests for:
terms_refinput andvalid_actions[]fallback;change_term_id,seller_managed, status scope, and each typed constraint kind;currently_unavailable/unknown rather than false approval;Package and run the new
media_buy_seller/change_rights_state_projectioncompliance scenario and the expanded compact lifecycle scenario from the matching AdCP bundle.Acceptance criteria
Upstream: adcontextprotocol/adcp#6750