Goal
Make structured proposal negotiation straightforward to implement, teach, and verify across the official AdCP SDKs and reference tooling after #6450 / #6547.
The protocol now distinguishes mechanically verifiable dimensions (total_budget, product_changes, alternatives, and criteria) from the free-text ask, with deterministic partial/unable outcomes, immutable proposal lineage, and atomic finalization. Implementors still need reusable SDK workflows, a reference seller that exercises the complete surface, implementation guidance, and conformance scenarios.
Workstreams
Shared design requirements
- Typed helpers MUST preserve the protocol distinction between task-level errors and per-proposal
revised, partial, unable, and finalized outcomes.
- SDKs MUST validate capabilities and cardinality before mutation, including the protocol maxima of 10 alternatives and 25 refinements.
- SDKs SHOULD provide verification and orchestration primitives, but MUST NOT embed commercial policy or silently reinterpret a seller counteroffer.
- Buyer APIs MUST handle capability discovery, exact idempotent retries, changed-request retry keys, response verification, finalization, and expiry-aware acceptance.
- Seller APIs MUST support capability declaration, preflight validation, immutable successor creation, response validation, and atomic finalization hooks.
- The training agent MUST consume the TypeScript SDK primitives rather than maintaining a second incompatible implementation.
- Docs and storyboards MUST use the same scenarios and expected outcomes.
Definition of done
- All official SDK repositories expose documented, tested proposal-negotiation support for their supported client/server surfaces.
- The public training seller offers both ask-only and deterministic typed-negotiation profiles.
- An implementor can follow one guide from capabilities through negotiation, finalization, acceptance, amendment, and cancellation.
- The compliance suite covers success, counteroffer, rejection, limits, mutation safety, idempotency, and atomicity.
- A buyer agent can run the documented scenario against the training seller and pass the same assertions used by the storyboards.
Dependencies
Contract additions from the pre-merge red team (#6547, efe48f522e)
The wire contract grew before merge; every child ticket should target this surface, not the original four-dimension draft:
- Typed hard constraints now include
cpm (fixed-rate ceiling), impressions (volume floor), and flight (window bounds) alongside total_budget — all verified against commercial_terms.
- Capability dimension
product_selection was renamed product_changes; dimensions now match request fields exactly.
unsatisfied_constraints carries open string keys (no closed enum) so future dimensions are additive.
reason_code precedence: constraint_unsatisfiable wins over every other code; typed failures never use commercially_declined (ask-level refusals only). New codes hold_unavailable and batch_aborted cover finalize failures in the atomic batch; double-finalize of a held draft is task-level INVALID_STATE.
- Undeclared-dimension rejection is a MUST (task-level, pre-mutation) with a registered
error-details/unsupported-refinement-dimension.json details shape.
- Every refinement successor requires
parent_proposal_id equal to its source proposal — negotiation lineage is reconstructible from proposals alone.
terms_digest is buyer-recomputable (RFC 8785 JCS + sha256/base64url); alternative distinctness is defined on commercial_terms, not digest strings.
- New normative text: partial drafts satisfy every constraint absent from
unsatisfied_constraints; only commercial_terms is contractual; ask is untrusted input to fence from pricing authority; deterministic constraint responses form a price oracle sellers should rate-limit; legacy budget_range (soft) vs compact total_budget (hard) share a shape with inverted semantics.
Goal
Make structured proposal negotiation straightforward to implement, teach, and verify across the official AdCP SDKs and reference tooling after #6450 / #6547.
The protocol now distinguishes mechanically verifiable dimensions (
total_budget,product_changes,alternatives, andcriteria) from the free-textask, with deterministic partial/unable outcomes, immutable proposal lineage, and atomic finalization. Implementors still need reusable SDK workflows, a reference seller that exercises the complete surface, implementation guidance, and conformance scenarios.Workstreams
Shared design requirements
revised,partial,unable, andfinalizedoutcomes.Definition of done
Dependencies
Contract additions from the pre-merge red team (#6547,
efe48f522e)The wire contract grew before merge; every child ticket should target this surface, not the original four-dimension draft:
cpm(fixed-rate ceiling),impressions(volume floor), andflight(window bounds) alongsidetotal_budget— all verified againstcommercial_terms.product_selectionwas renamedproduct_changes; dimensions now match request fields exactly.unsatisfied_constraintscarries open string keys (no closed enum) so future dimensions are additive.reason_codeprecedence:constraint_unsatisfiablewins over every other code; typed failures never usecommercially_declined(ask-level refusals only). New codeshold_unavailableandbatch_abortedcover finalize failures in the atomic batch; double-finalize of a held draft is task-levelINVALID_STATE.error-details/unsupported-refinement-dimension.jsondetails shape.parent_proposal_idequal to its source proposal — negotiation lineage is reconstructible from proposals alone.terms_digestis buyer-recomputable (RFC 8785 JCS + sha256/base64url); alternative distinctness is defined oncommercial_terms, not digest strings.unsatisfied_constraints; onlycommercial_termsis contractual;askis untrusted input to fence from pricing authority; deterministic constraint responses form a price oracle sellers should rate-limit; legacybudget_range(soft) vs compacttotal_budget(hard) share a shape with inverted semantics.