Goal
Add a capability-gated proposal-negotiation storyboard matrix for AdCP 3.2 so implementors can test correctness, experiment with counteroffers, and compare their behavior with the public training seller.
Parent program: #6556
Related compact lifecycle suite: #6432
Protocol implementation: #6547
Required storyboard coverage
Capability and preflight
- Ask-only seller accepts
ask revision.
- Explicitly unsupported typed dimension causes task-level
UNSUPPORTED_FEATURE for the entire mixed batch with no mutation.
- Advertised
max_alternatives violation causes task-level VALIDATION_ERROR with no mutation.
- Protocol boundaries: 10 alternatives accepted when the seller ceiling permits; 11 rejected; 25 refinements accepted; 26 rejected.
Typed revision outcomes
- Budget satisfied, absent, wrong currency, below/above bounds.
- Product include/omit satisfied and unsatisfied.
- Structured criteria replacement with omitted criteria inherited.
- Exact alternative count with unique
terms_digest values.
- Fewer distinct alternatives reported as
partial / alternatives_unavailable.
- Duplicate alternatives or false
revised claims fail validation.
- Commercial refusal, uninterpreted ask, unsupported dimension when capabilities are unknown, and source unavailable.
- Ordered multi-source batch with a valid mix of revised, partial, and unable results.
Lifecycle, mutation, and retry
- Every successful revision creates a new immutable proposal and leaves the source unchanged.
- Exact replay returns the same outcome; changed payload under the same idempotency key conflicts.
- Finalize creates a committed proposal with
expires_at and unchanged terms/digest.
- Multi-finalize is atomic on success and failure; no partial holds.
- Acceptance before and after expiry.
- Amendment and cancellation successors from an accepted proposal.
Experimentation support
- Provide a stable training-agent test kit/profile whose deterministic responses match the storyboard fixtures.
- Document how SDK maintainers run the matrix against local buyer/seller implementations.
- Capture identifiers and proposal lineage so a developer can inspect every transition.
- Include negative variants that intentionally violate one invariant and explain the expected failure.
Acceptance criteria
- Scenarios are gated by advertised 3.2 lifecycle/capability support and do not penalize legacy or ask-only sellers for undeclared typed behavior.
- Current
/sales floors and required-clean assertions include the negotiation core.
- Storyboard lint, fixture-resolution, contradiction, context-entity, and 3.0 compatibility checks remain green.
- The same matrix runs against the public training seller and is consumable by official SDK integration tests.
Additional required coverage (contract hardening in #6547, efe48f522e)
New typed constraints
cpm, impressions, and flight each satisfied and violated; violated drafts must appear as partial/unable with constraint_unsatisfiable and the failing key echoed in unsatisfied_constraints.
- Co-occurring failures (violated constraint + alternatives shortfall) must use
constraint_unsatisfiable, with the shortfall visible only through proposals.length.
Rejection and error shapes
- Undeclared-dimension rejection is now a MUST: task-level
UNSUPPORTED_FEATURE before any mutation, with details matching error-details/unsupported-refinement-dimension.json.
- Capability dimension name is
product_changes (renamed from product_selection).
Holds
- Failing finalize entry returns
unable/hold_unavailable; otherwise-eligible siblings return unable/batch_aborted; no partial finalize batches.
- Double-finalize of a held draft fails task-level with
INVALID_STATE.
Integrity
- Every returned proposal carries
parent_proposal_id equal to source_proposal_id.
terms_digest recomputes from RFC 8785 JCS of commercial_terms; a tampered digest or duplicate-terms "alternatives" must fail validation.
Goal
Add a capability-gated proposal-negotiation storyboard matrix for AdCP 3.2 so implementors can test correctness, experiment with counteroffers, and compare their behavior with the public training seller.
Parent program: #6556
Related compact lifecycle suite: #6432
Protocol implementation: #6547
Required storyboard coverage
Capability and preflight
askrevision.UNSUPPORTED_FEATUREfor the entire mixed batch with no mutation.max_alternativesviolation causes task-levelVALIDATION_ERRORwith no mutation.Typed revision outcomes
terms_digestvalues.partial/alternatives_unavailable.revisedclaims fail validation.Lifecycle, mutation, and retry
expires_atand unchanged terms/digest.Experimentation support
Acceptance criteria
/salesfloors and required-clean assertions include the negotiation core.Additional required coverage (contract hardening in #6547,
efe48f522e)New typed constraints
cpm,impressions, andflighteach satisfied and violated; violated drafts must appear aspartial/unablewithconstraint_unsatisfiableand the failing key echoed inunsatisfied_constraints.constraint_unsatisfiable, with the shortfall visible only throughproposals.length.Rejection and error shapes
UNSUPPORTED_FEATUREbefore any mutation, withdetailsmatchingerror-details/unsupported-refinement-dimension.json.product_changes(renamed fromproduct_selection).Holds
unable/hold_unavailable; otherwise-eligible siblings returnunable/batch_aborted; no partial finalize batches.INVALID_STATE.Integrity
parent_proposal_idequal tosource_proposal_id.terms_digestrecomputes from RFC 8785 JCS ofcommercial_terms; a tampered digest or duplicate-terms "alternatives" must fail validation.