Skip to content

feat(schemas): completion_source qualifier — seller_attested vs vendor_attested completion_rate (closes #3861)#3877

Merged
bokelley merged 2 commits into
mainfrom
bokelley/completion-source-qualifier
May 2, 2026
Merged

feat(schemas): completion_source qualifier — seller_attested vs vendor_attested completion_rate (closes #3861)#3877
bokelley merged 2 commits into
mainfrom
bokelley/completion-source-qualifier

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 2, 2026

Summary

Closes #3861 with Option C from the issue (qualifier slot, not metric split).

completion_rate is dual-natured: the seller witnesses completion via player events; third-party vendors independently attest via SDK callbacks, panel methodology, or server-side beacon validation. The two paths can yield materially different rates — especially in SSAI environments. Same metric_id, two semantics — exactly the case the taxonomy doc addresses.

The qualifier slot established by #3576 is the right home. Adding completion_source as a second qualifier key (alongside viewability_standard) proves the pattern is generalizable, not viewability-specific.

Schema

Added: enums/completion-source.json — closed enum ["seller_attested", "vendor_attested"].

Updated (qualifier now carries two keys — viewability_standard and completion_source):

How it works

Buyer commits to "85% completion_rate by Nielsen" via:

  • performance_standards: { metric: "completion_rate", threshold: 0.85, vendor: { domain: "nielsen.com" } }
  • committed_metrics: { scope: "standard", metric_id: "completion_rate", qualifier: { completion_source: "vendor_attested" }, committed_at: "..." }

Delivery report:

  • If Nielsen attests 87% → metric_aggregates row { metric_id: "completion_rate", qualifier: { completion_source: "vendor_attested" }, value: 0.87, ... } matches the contract; clean.
  • If only seller-attested completion (player events) is reported → missing_metrics row { scope: "standard", metric_id: "completion_rate", qualifier: { completion_source: "vendor_attested" } } flags the missing vendor commitment.

Vendor identity is anchored on performance_standard.vendor BrandRef, not duplicated on the metric row — same pattern as MRC viewability for DV/IAS.

Why Option C (vs A or B from the issue)

  • Option A (just document) leaves the type-level ambiguity. Buyer agents can't dispatch reliably.
  • Option B (split into seller_completion_rate / verified_completion_rate) is breaking-ish; existing reports use completion_rate; tooling needs migration.
  • Option C (qualifier) uses the established graduated-metric pattern. Minimal new surface. Aligns with the atomic-unit framing. Confirmed by Brian as proxy-WG call.

Files

  • static/schemas/source/enums/completion-source.json (new)
  • static/schemas/source/core/package.json — qualifier description + completion_source field
  • static/schemas/source/media-buy/package-request.json — qualifier description + completion_source field
  • static/schemas/source/media-buy/get-media-buy-delivery-response.json — qualifier blocks in metric_aggregates and missing_metrics
  • docs/media-buy/task-reference/create_media_buy.mdx — committed_metrics qualifier section now lists both keys
  • docs/media-buy/task-reference/get_media_buy_delivery.mdx — qualifier vocabulary + missing_metrics example updated
  • .changeset/completion-source-qualifier.md — minor

Test plan

  • Schema validates (build:schemas during commit hook)
  • TypeScript build passes
  • Doc renders cleanly

Related

🤖 Generated with Claude Code

bokelley and others added 2 commits May 2, 2026 15:22
…endor-attested completion_rate

Closes #3861 with Option C — qualifier slot, not metric split.

completion_rate is dual-natured: seller witnesses via player events;
third-party vendors independently attest via SDK callbacks / panel
methodology / server-side beacon validation. The two paths can yield
materially different rates (especially in SSAI). The qualifier slot
established in #3576 is the right home.

Schemas added:
- enums/completion-source.json: ["seller_attested", "vendor_attested"]

Schemas updated (qualifier slot now carries two keys —
viewability_standard and completion_source):
- core/package.json committed_metrics.qualifier
- media-buy/package-request.json committed_metrics.qualifier
- media-buy/get-media-buy-delivery-response.json
  aggregated_totals.metric_aggregates.qualifier (just shipped in #3848)
- media-buy/get-media-buy-delivery-response.json
  by_package[].missing_metrics.qualifier

Vendor identity is anchored on the matching performance_standard.vendor
BrandRef, not duplicated on the metric row — same pattern as MRC
viewability for DV/IAS.

Reconciliation: the atomic-unit join (scope, metric_id, qualifier)
extends naturally. completion_rate rows now carry completion_source
the way viewable_rate rows carry viewability_standard.

Doc updates: create_media_buy.mdx and get_media_buy_delivery.mdx
list both qualifier keys with their conditional-required semantics
and the symmetric missing_metrics flagging behavior.

Backwards compatible (additive; closed-vocab so new keys ship explicitly
in subsequent minors).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per product-expert review on PR #3877: the binary seller/vendor enum
was correct as the primary trust-source axis, but the descriptions
needed to address real-world measurement topology that doesn't cleanly
split:

- Walled gardens (YouTube, Spotify) where seller IS the measurement
  vendor — now explicitly collapses to seller_attested by trust-model
  logic (same party served and counted).
- IAB-certified first-party podcast measurement (Podtrac on Podtrac's
  own platform, Triton on its own, Art19 on its own) — also seller_attested.
- The same vendor on third-party inventory (Podtrac on a non-Podtrac
  publisher) — vendor_attested.
- Panel measurement (Nielsen, Edison) — vendor_attested even though
  methodology differs from SDK callback (methodology granularity is
  a separate dimension; reserved for future qualifier keys if needed).

Also clarifies the transparency-without-gate use case: buyer who wants
vendor-attested completion for transparency without an accountability
threshold MAY commit a vendor metric via vendor_metrics on the product
rather than committed_metrics with this qualifier.

The trust axis is named explicitly: "who is independent of the seller's
revenue interest," not "who runs the SDK."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit 15cbd99 into main May 2, 2026
18 checks passed
@bokelley bokelley deleted the bokelley/completion-source-qualifier branch May 2, 2026 19:30
bokelley added a commit that referenced this pull request May 2, 2026
closes #3857) (#3884)

* feat(schemas): unify outcome measurement into the row-shape vocabulary (closes #3857)

Outcome metrics (incremental_sales_lift, brand_lift, foot_traffic,
conversion_lift, brand_search_lift) collapse into the existing
available-metric.json + qualifier-slot pattern. Attribution methodology
and window become qualifier keys. outcome_measurement field on product
is deprecated.

Why: outcome_measurement was always the same conceptual category as the
seller-reported attribution-derived metrics already in delivery-metrics
(conversions, conversion_value, roas). The two surfaces existed because
the protocol predated the unified row-shape vocabulary established by
#3576 / #3848. With the qualifier slot proven generalizable (#3877),
the collapse is clean.

Schemas added:
- enums/attribution-methodology.json:
  ["deterministic_purchase", "probabilistic", "panel_based", "modeled"]

Schemas updated:
- available-metric.json: adds 5 outcome metrics
- delivery-metrics.json: adds 5 scalar properties
- Qualifier slot expanded at all 5 sites (committed_metrics, missing_metrics,
  metric_aggregates, package-request, performance-feedback) with
  attribution_methodology (string enum) and attribution_window (structured
  duration — first object-valued qualifier key)
- outcome-measurement.json: deprecated, migration table in description
- product.json outcome_measurement field: deprecated

No separate attributed_sales metric — that's conversion_value with
qualifier.attribution_methodology: "deterministic_purchase". The unified
pattern handles the deterministic/probabilistic/modeled split via
qualifier, not parallel metric IDs.

attribution_window in the qualifier slot is the first object-valued
qualifier key. Established that qualifier values can be structured
(not just string enums). Window isn't disambiguating "which version" the
way viewability_standard does — it's parameterizing — but the join-on-
(metric_id, qualifier) pattern handles same-metric-different-window
correctly so placement works.

Doc updates: commerce-media.mdx shows new pattern alongside legacy field;
media-products.mdx, create_media_buy.mdx, get_media_buy_delivery.mdx
reflect the four-key qualifier vocabulary.

Migration: existing outcome_measurement payloads work for one minor.
New implementations use reporting_capabilities.available_metrics +
qualifier on commit. Removed at next major.

Deferred: reporting_frequency / reporting_format migration to a
reporting_capabilities extension (separate concern from per-metric).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(schemas): brand_lift dimension qualifier + object-valued canonicalization + Walmart migration

Three fixes per protocol + product review on PR #3884:

1. (Product, real bug) brand_lift as scalar oversimplifies — Kantar,
   Upwave, Cint, DV all report awareness/consideration/favorability/
   purchase_intent/ad_recall as separate measurements with their own
   sample sizes. Single scalar would force vendors to pick one or
   composite. Fix: add lift_dimension qualifier key (5th key in the
   slot). Same pattern as completion_source / viewability_standard.

2. (Protocol) Object-valued qualifier canonicalization — first
   object-valued qualifier (attribution_window) needs a canonicalization
   rule for the join. Added to qualifier description: heterogeneous
   value types; consumers MUST dispatch on key name; structured-value
   qualifiers join on canonical (key-sorted) deep equality. Schema
   description on attribution_window explicitly forbids shorthand
   strings ("14d") and calls out the object shape.

3. (Protocol) attributed_sales discoverability — buyer agents searching
   available_metrics for "attributed_sales" won't find conversion_value.
   Fix: outcome-measurement.json migration table now explicitly maps
   Walmart Connect's attributedSalesIn14Days → conversion_value +
   qualifier.attribution_methodology + qualifier.attribution_window
   with the canonical example. Same pattern called out for Amazon DSP,
   Kroger Precision, Criteo Retail Media.

Plus: rate-style metric inheritance note in qualifier description
(per protocol expert) — when a rate carries attribution_methodology
qualifier, it applies to the underlying conversions/events.

Plus: third-party retail measurement guidance (Circana, NielsenIQ, IRI
for retail MMM; Kantar/Upwave for brand lift on retail-media inventory)
in outcome-measurement migration description — performance_standards.
vendor is the escape hatch for non-seller-vendor cases.

Files updated:
- enums/lift-dimension.json (new)
- core/package.json: qualifier description tightened, lift_dimension added
- core/delivery-metrics.json: brand_lift description updated
- core/outcome-measurement.json: migration table expanded
- core/performance-feedback.json: lift_dimension added to metric.qualifier
- media-buy/package-request.json: lift_dimension added
- media-buy/get-media-buy-delivery-response.json: lift_dimension added
  to metric_aggregates and missing_metrics qualifier blocks
- get_media_buy_delivery.mdx: qualifier vocabulary updated to 5 keys
- changeset: reflects all three fixes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EvgenyAndroid pushed a commit to EvgenyAndroid/adcp that referenced this pull request May 17, 2026
…umbrella update

Round 3 of @bokelley's third-sibling framing on adcontextprotocol#4616
(issuecomment-4470049814): the epistemic-model table maps 1:1 onto
delivery measurement, not just signals. The strawman's shape was
already cross-axis, but the descriptions buried measurement as a
secondary axis. Promoting it to first-class.

Changes are description + examples only — no structural change to the
primitive, the fidelity enum, or the conversion schema.

system-reference.json:

  - Description rewritten to explicitly enumerate the four primary
    axes (identity / taxonomy / geographic / measurement). Calls out
    measurement currencies (Nielsen P18-49) AND methodology sources
    (panel / set_top_box / ACR / census / server_logs / SDK per the
    construction-methodology row in adcontextprotocol#4616) as distinct measurement-
    side use cases.
  - `system` examples list extended with `nielsen_p_18_49` and
    `measurement_source` to surface the measurement axis.
  - Two new top-level examples: a measurement currency
    (`nielsen_p_18_49:P18-49:2025`) and a measurement-source row
    (`measurement_source:set_top_box`) — the latter is the canonical
    adcontextprotocol#2041 use case.

system-reference-fidelity.json:

  - Description expanded to name two consumer types: buyer agents
    activating signals, and measurement consumers accepting delivery
    reports. Adds "methodology sources" to the generalized axis list.

system-reference-conversion.json:

  - Description expanded to name the two surfaces (signal deployments
    + delivery measurement). References adcontextprotocol#3877's `completion_source`
    qualifier as shipped prior art for the D3 seller-attested vs
    vendor-attested split.
  - New example: STB measurement projected to Nielsen P18-49
    currency via Samba TV methodology — the measurement-side analog
    of the existing signal-side panel projection example.

Changeset updated to reflect the broadened scope.

Strawman remains shape-only — no row-level adoption, no structural
change to the primitive. adcontextprotocol#2041 / adcontextprotocol#4472 / adcontextprotocol#4475 / identity-substrate
RFCs still adopt independently against whatever shape D1 settles on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

completion_rate is both seller-counted (metric) and threshold-verified (verification) — split or document?

1 participant