feat(schemas): metric_aggregates partition — row-symmetric delivery aggregation (closes #3848)#3876
Merged
Merged
Conversation
…-symmetric with committed_metrics Closes #3848. Supersedes #3631 and #3833 (already closed). The atomic unit is now identical across contract, diff, and delivery: committed_metrics row : (scope, metric_id, qualifier, committed_at) missing_metrics row : (scope, metric_id, qualifier) metric_aggregates row : (scope, metric_id, qualifier, value, ...components) Reconciliation collapses to a row-level join on (scope, metric_id, qualifier). For each committed_metrics row, find the matching metric_aggregates row; absent matches surface as missing_metrics. Schema: - get-media-buy-delivery-response.json: aggregated_totals.metric_aggregates is a discriminated array (scope: standard | vendor) with the qualifier shape from committed_metrics, value, and inlined component fields (measurable_impressions, viewable_impressions, impressions, completed_views, spend, conversions, conversion_value, clicks). - core/package.json: committed_metrics description cross-links the new surface and articulates the row-symmetric model. Granularity: one row per (metric_id, full-qualifier-set) at finest available granularity; buyers re-aggregate up. Qualifier vocabulary: closed at contract layer (viewability_standard only); deliberate superset at delivery layer for transparency disclosures buyers don't commit to (e.g., tracker_firing pending #3832). Unqualified metrics stay top-level (impressions, spend, media_buy_count). Per-buy totals stays flat — single-qualifier by definition; only the cross-buy aggregate spans qualifiers. Doc updates: get_media_buy_delivery.mdx adds an Aggregated metric partitions section explaining the reconciliation join, granularity rule, qualifier-vocabulary asymmetry, per-buy / aggregate divergence, and value-typing dispatch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three blockers from protocol-expert review on PR #3876, two doc tightenings from product-expert review: 1. additionalProperties drift (high confidence): committed_metrics items use additionalProperties: false; metric_aggregates items used true. Real divergence beyond the documented value+components delta. Tightened to false on both branches for full row symmetry. 2. Per-metric component gap (high confidence): required: [scope, metric_id, value] admitted viewable_rate: 0.7 with no measurable_impressions/viewable_impressions. Added if/then enforcement for the four highest-traffic metrics (viewable_rate, completion_rate, cost_per_acquisition, roas). Catches 90% of misuse without combinatorial explosion. Other metrics rely on prose- described components; full oneOf-on-metric_id deferred. 3. "Superset" claim was misleading (high confidence): both surfaces are additionalProperties: false today with identical content. Reframed as "closed today, expected to diverge in future minors as transparency disclosures ship delivery-only" — describes future divergence, not current state. 4. Top-level / metric_aggregates mutual exclusion needed explicit MUST (product expert): for any metric_id appearing in metric_aggregates, the top-level scalar MUST be omitted (not zeroed). Sellers MUST NOT emit both. Added to schema description and doc. 5. Qualifier-set drift across reports needed a doc sentence (product expert): when a campaign gains a new qualifier mid-flight, prior periods' rows remain valid at their original granularity; buyers SHOULD NOT retroactively repartition. Added to schema description and doc. Also softened the "solves apples-to-oranges" framing in the changeset per product expert: this PR ships the structure; sellers actually emitting partitioned rows requires a forcing function from the contract surface plus seller adoption. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #3848 (and supersedes the already-closed #3631 / #3833). Adds
aggregated_totals.metric_aggregatestoget_media_buy_delivery— a qualifier-aware delivery rollup row-symmetric withpackage.committed_metricsandby_package[].missing_metrics.The atomic unit is now identical across contract, diff, and delivery:
Reconciliation collapses to a row-level join on
(scope, metric_id, qualifier).Why
The taxonomy doc's "atomic unit" claim becomes load-bearing in code. Today, contract and diff use the row shape; delivery aggregation uses bespoke per-metric scalars. With this PR, all three surfaces share one shape — buyer reconciliation code becomes one path instead of three.
Solves the apples-to-oranges sum problem at the aggregate layer: MRC and GroupM viewability never combine into a single rate. Future qualifier-aware metrics (completion threshold; attention methodology if it standardizes) plug in with no schema change.
Design decisions (per #3848)
value, matching the per-buyviewabilityblock's flat shape.(metric_id, full-qualifier-set)at the finest available granularity. Buyers re-aggregate up.tracker_firingpending Tracker firing path (client / server / mixed) — is this a buyer concern AdCP needs to model, and where? #3832).impressions,spend,media_buy_count);metric_aggregatesonly for metrics with non-empty qualifier sets.totalsstays flat — each individual buy is single-qualifier by definition; only the aggregate spans qualifiers.oneOfdiscriminated onmetric_iddeferred — current schema does not enforce per-metric required components in JSON Schema (would be 31+ branches). Required fields documented in the description; future minor can tighten viaoneOfif conformance testing demands.Files
static/schemas/source/media-buy/get-media-buy-delivery-response.json— addsmetric_aggregatesarraystatic/schemas/source/core/package.json—committed_metricsdescription cross-links the new surfacedocs/media-buy/task-reference/get_media_buy_delivery.mdx— adds "Aggregated metric partitions" section.changeset/metric-aggregates.md— minorTest plan
Related
metric_aggregatespartition toaggregated_totals— qualifier-aware delivery rollups symmetric tocommitted_metrics#3848 — origin issue (this PR closes it)committed_metrics/missing_metrics(the contract-side row shape this mirrors)🤖 Generated with Claude Code