Skip to content

Meta: capability-claim contract scenarios — close the gap between what agents declare and what they do #4637

@bokelley

Description

@bokelley

Pattern

A recurring shape is emerging across the storyboard scenarios: for every non-trivial capability an agent declares, there should be a requires_capability-gated scenario that proves the claim is honest end-to-end.

Without this, the capability surface in get_adcp_capabilities and product-level capabilities (metric_optimization, conversion_tracking, etc.) is a self-attestation with no contract test. An adapter can declare `media_buy.conversion_tracking` and still silently drop log_event calls; a product can declare `supported_reach_units: ["households"]` and still ignore reach_unit on the goal.

The pattern that closes this:

  1. Buyer establishes the precondition (sync the thing the capability is about).
  2. Buyer creates a buy whose goal/targeting references the precondition.
  3. Buyer references an invented value → seller MUST reject with INVALID_REQUEST and error.field set (anti-façade).
  4. Delivery reporting carries the metric/breakdown that the goal asked for.

This is the same logic as the upstream_traffic anti-façade check, generalized from "did you forward the bytes" to "did the buy mode connect end-to-end."

Tracking backlog

Scenario Gate What it certifies
media_buy_seller/performance_buy_flow (CPA) media_buy.conversion_tracking present Draft in flight per #4569. sync_event_sources → buy → log_event → CPA delivery + per-creative conversion breakdown.
media_buy_seller/performance_buy_flow_roas media_buy.conversion_tracking.supported_target_kinds includes per_ad_spend ROAS / value-max buy works end-to-end. Delivery returns roas + conversion_value. Requires a new capability bit — see "Capability bits to add" below.
media_buy_seller/audience_buy_flow audience-sync specialism OR product accepts targeting_overlay.audience_ids sync_audiences → buy references audience_id → unknown id rejected → delivery breaks down by audience_id. Sibling to performance_buy_flow on the audience side.
media_buy_seller/event_dedup_flow media_buy.conversion_tracking.multi_source_event_dedup: true Two event sources fire the same event_id → exactly one attributed conversion. Catches sellers who advertise dedup but don't actually dedupe.
media_buy_seller/reach_buy_flow product metric_optimization.supported_metrics includes reach Reach goal with reach_unit in supported_reach_units accepted. Mismatched reach_unit rejected. target_frequency band honored. Delivery returns reach + frequency.
media_buy_seller/completed_views_buy_flow product metric_optimization.supported_metrics includes completed_views Goal with view_duration_seconds in supported_view_durations accepted. Mismatched duration rejected. Delivery returns completed_views + completion_rate.
media_buy_seller/clicks_buy_flow product metric_optimization.supported_metrics includes clicks CPC target accepted. Delivery returns clicks + cost_per_click + per-creative click breakdown. Universal but valuable — many sellers report clicks at buy level without per-creative attribution.
media_buy_seller/frequency_cap_enforcement (TBD — depends on whether a frequency-cap capability bit exists) Buy with targeting_overlay.frequency_cap set; delivery shows observed frequency ≤ cap.
media_buy_seller/attention_buy_flow product supported_metrics includes attention_seconds / attention_score + vendor declaration Vendor-attributed attention reported in delivery. Vendor-gated; not all sellers participate.

Capability bits to add (small follow-up RFCs)

These are blockers for some of the scenarios above. Filing them separately so the storyboards can land on stable gates:

  1. media_buy.conversion_tracking.supported_target_kinds: [\"cost_per\", \"per_ad_spend\", \"maximize_value\"] — parallels the product-level metric_optimization.supported_targets declaration. Without it, the runner can't gate performance_buy_flow_roas distinctly from CPA.
  2. media_buy.frequency_capping (or similar) if not already present — gate for frequency_cap_enforcement.

Runner dependency

All of these depend on the runner accepting a present: matcher on requires_capability for presence-only capability objects (e.g., conversion_tracking). Filed as adcp-client#1811.

Priority order

Strongest signal-to-effort wins first:

  1. performance_buy_flow (CPA) — in flight per RFC: performance-sales specialism — is conversion-driven selling distinct from sales-social? #4569.
  2. event_dedup_flow — cap bit already exists (multi_source_event_dedup); only the scenario is missing. Highest leverage for least spec change.
  3. audience_buy_flow — paired with performance_buy_flow as the two halves of "what kind of non-guaranteed buy is this." Shipping one without the other only certifies half the story.
  4. reach_buy_flow — upper-funnel's equivalent of "performance." supported_reach_units already exists.
  5. performance_buy_flow_roas — blocked on the supported_target_kinds cap bit (1) above.
  6. clicks_buy_flow, completed_views_buy_flow — useful but lower urgency; they're variants of "metric goal X works."
  7. attention_buy_flow, frequency_cap_enforcement — vendor-gated and cap-bit-blocked respectively; ship when constituency is real.

What this issue is for

A single tracking issue so scenario adds reference a coherent pattern rather than being filed as one-offs. Sub-issues link back here. Closing this issue is contingent on the priority-1-through-4 scenarios shipping.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions