Skip to content

compliance(media-buy): add typed proposal negotiation storyboard matrix - #6586

Merged
bokelley merged 3 commits into
adcontextprotocol:mainfrom
garvitkaushik-123:compliance/typed-proposal-negotiation
Aug 15, 2026
Merged

compliance(media-buy): add typed proposal negotiation storyboard matrix#6586
bokelley merged 3 commits into
adcontextprotocol:mainfrom
garvitkaushik-123:compliance/typed-proposal-negotiation

Conversation

@garvitkaushik-123

Copy link
Copy Markdown
Contributor

Summary

  • Add typed_proposal_negotiation.yaml — a 15-phase compliance storyboard exercising the complete AdCP 3.2 typed proposal negotiation lifecycle through refine_proposals
  • Register the scenario in the media-buy seller index.yaml

Coverage

Phase What it tests
Capability discovery proposal_refinement.supported_dimensions gate
Typed budget — satisfied revised outcome with total_budget constraint met
Typed budget — unsatisfied partial/unable with constraint_unsatisfiable and unsatisfied_constraints
Product changes include/omit map checked against commercial_terms.purchases
Alternatives Exact count with unique terms_digest values
Unsupported dimension Task-level UNSUPPORTED_FEATURE with unsupported-refinement-dimension.json details
Finalize Committed snapshot with expires_at inventory hold
Idempotent replay Same idempotency_key returns cached replayed: true response
Accept proposal_terms_digest-verified acceptance creating a MediaBuy
Amendment Draft amendment successor from accepted source
Cancellation Draft cancellation successor from accepted source
Double-finalize INVALID_STATE rejection for committed proposals
Multi-source batch Ordered results with independent per-source outcomes
Immutable lineage parent_proposal_id equals source_proposal_id on every successor

Design decisions

  • Gated on proposal_refinement.supported_dimensions presence — legacy sellers without typed negotiation are not penalized
  • Per-dimension phases use requires_capability with contains so sellers declaring a subset of dimensions skip inapplicable phases
  • Unsupported dimension phase uses skip_if to avoid false failure when the seller does support flight
  • Sample requests use the Acme Outdoor test kit identity consistent with existing storyboards

Test plan

  • Storyboard context-output path lint: clean (167 files scanned)
  • Storyboard validations path lint: clean (167 files scanned)
  • Storyboard scoping lint: all 11 refine_proposals steps carry account { brand, operator }
  • Schema validation: all 30 tests pass
  • Composed schema validation: all 400 tests pass
  • YAML parses correctly: 15 phases, all steps well-formed

Refs #6559

garvitkaushik-123 and others added 2 commits August 15, 2026 23:24
Add typed_proposal_negotiation.yaml exercising the AdCP 3.2 typed
negotiation lifecycle through refine_proposals:

- Capability discovery: proposal_refinement.supported_dimensions gate
- Typed budget constraint: satisfied (revised) and unsatisfied (partial
  with constraint_unsatisfiable)
- Product changes: include/omit map with purchase verification
- Alternatives: exact count with unique terms_digest values
- Unsupported dimension: task-level UNSUPPORTED_FEATURE rejection with
  registered error-details shape
- Finalize: committed snapshot with inventory hold and expires_at
- Idempotent replay: same idempotency_key returns cached response
- Immutable lineage: parent_proposal_id equals source on every successor
- Accept: digest-verified acceptance creating a MediaBuy
- Amendment and cancellation successors from accepted proposal
- Double-finalize: INVALID_STATE rejection for committed proposals
- Multi-source batch: ordered results with independent outcomes

Register the scenario in the media-buy seller index.yaml.

Refs adcontextprotocol#6559
@bokelley
bokelley force-pushed the compliance/typed-proposal-negotiation branch from fe71acf to f6bb086 Compare August 15, 2026 21:45
@bokelley
bokelley enabled auto-merge (squash) August 15, 2026 21:45

@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.

Ladon verdict: Request changes

Request changes — 1 blocking finding.

Blocking findings

  • static/compliance/source/protocols/media-buy/scenarios/typed_proposal_negotiation.yaml:509 — Lifecycle tail (finalize/accept/amendment/cancellation/double-finalize/multi-source) depends on context outputs produced only inside a total_budget-gated phase. A spec-valid seller lacking that dimension breaks the scenario or silently loses the storyboard's headline coverage — a reproducible bug on a load-bearing compliance path.

Medium findings

  • None.

The rest of the PR is solid: schema↔docs coherence is clean (asserted fields, enums, error codes, and the singular-proposal vs array-proposals split all match refine-proposals-response.json, proposal-refinement.json, canonical-proposal.json, and the capabilities schema), and the refine/decline scoping exemption is correct since the split schemas forbid account. Three low-severity narrative/checkbox nits (lines 578, 760, and the changeset test-plan) are noted but non-blocking. Address the capability-gated dependency at line 509 so the tail either guards on the gating dimension or does not rely on outputs a conformant seller may never produce.

Blocking findings

  • static/compliance/source/protocols/media-buy/scenarios/typed_proposal_negotiation.yaml:509 — Lifecycle tail depends on context outputs from a capability-gated (total_budget) phase; a spec-valid seller without that dimension breaks or silently loses headline coverage

@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.

Ladon verdict: Approve

Approve — prior High finding resolved, no current blocking or Medium findings.

This is a subsequent review. The prior run (request-changes) flagged one High finding: the finalize lifecycle tail depending on context outputs from a capability-gated phase (typed_proposal_negotiation.yaml:509). The developer has resolved it:

  • finalize_idempotency_key generation moved to the ungated seed_proposals phase (L347-348)
  • finalize now targets the ungated seed_proposal_id (L655/L682/L686)
  • multi_source_batch's second source now uses the ungated amendment_proposal_id (L900)

The now-orphaned budget_revised_* captures are harmless since context-output lints validate path resolution only. Net improvement over the prior pass.

Decision-table walk: no critical/high findings (row 1 no). gated_paths is false, so row 2 does not apply despite review_decision being CHANGES_REQUESTED — that stale GitHub status predates the fix and row 2 only fires when gated_paths is true. high_risk is false (rows 3, 5 no). No medium findings (rows 4, 8 no). Prior decision was request-changes, not escalate (row 6 no). No no-auto-approve team match (row 7 no). Falls through to row 9 → approve.

@bokelley
bokelley merged commit 636d461 into adcontextprotocol:main Aug 15, 2026
46 checks passed
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.

2 participants