Skip to content

RFC: Cell-grain delivery reporting — companion to #5969 #6014

Description

@EvgenyAndroid

Status: Filed
Companion to: #5969 (geo_cells / geo_cells_exclude targeting)
Sibling companion: #6013 (Cell Interoperability and Execution Conversion)
Filed by: @EvgenyAndroid, in collaboration with @nwoodman-spec
Design: @EvgenyAndroid (stated on #5969) — write-up, resolution rules, requested/executed/reported model, and the privacy-suppression resolution in section 6 are Nathan Woodman's
Target: a PR against static/schemas/source/core/geo-delivery-metrics.json and get-media-buy-delivery-response.json


0. Provenance

The design here is not Nathan's — it was stated by @EvgenyAndroid on #5969: add
cell as a fifth geo_level and inherit the existing per-level apparatus, rather
than introduce a parallel by_cell[] array, because a parallel array would
duplicate four surfaces that would then drift. Sellers report at the requested,
capability-declared resolution and silent parent-cell rollup is prohibited, so
coarsening becomes the buyer's exact operation over the cell hierarchy.

That design was referenced on #5969 with a placeholder issue number that was
never replaced, leaving gate (b) of the Option X versus Option Y decision open in
the record — the product expert's deferral recommendation on #5969 was
conditioned on this companion existing. Nathan Woodman wrote up the design in
full below; this issue closes that gap.

1. Why the loop has to close

Cell targeting without cell reporting is a half-closed loop. The primary stated
use case for #5969 is geographic incrementality measurement with enforceable
treatment and holdout assignment, and that use case cannot be read out if delivery
comes back at a coarser or different geography than the one assignment was made
in. Targeting at cell grain and reporting at market-code grain measures a
geography that was never targeted.

This is also the single most common platform constraint in practice: delivery and
outcome reporting returned only at a coarser native geography, which makes the
executed-versus-reported gap unmeasurable from reporting alone.

2. Scope

In scope. Adding cell as a reporting dimension, the conditional validation
that comes with it, the capability declaration for it, the rules governing
resolution of the returned rows, and the provenance fields that let a buyer check
delivery against intent.

Out of scope. Any change to geo_cells targeting itself, the conversion rules
that sit in the sibling companion, and any accreditation of measurement
methodology performed on top of these rows.

3. The shape: a fifth level, not a parallel array

The delivery response already carries a complete per-level geographic apparatus:
by_geo with conditional per-level validation, reporting_dimensions.geo,
supports_geo_breakdown, and mandatory truncation flags.

Adding cell inherits all of it:

  • one new geo_level enum value
  • one conditional validation branch for the cell case
  • one request field addition
  • one capability extension

A parallel by_cell[] array would restate four surfaces that would then diverge
from their by_geo equivalents on the first change to either. The conditional
branch is the cheaper and more durable shape.

The cell case requires three fields that other levels do not: the cell system,
the resolution, and the cell identifier. The identifier alone is insufficient
because resolution is only recoverable from the token for systems that encode it,
and the spec should not assume that of a custom system.

{
  "geo_level": "cell",
  "cell_system": "h3",
  "cell_system_id": null,
  "resolution": 8,
  "cell": "882a100d25fffff",
  "impressions": 14203,
  "spend": 218.44
}

cell_system_id is required and non-null when cell_system is custom,
matching the custom_system_id treatment on the targeting side.

4. Resolution rules

Report at the requested resolution. A seller returns rows at the resolution
the buyer requested and the seller declared support for, not at a resolution of the
seller's choosing.

Silent parent rollup is prohibited. Returning resolution 6 rows against a
resolution 8 request, with no indication that coarsening occurred, is
non-conformant. Coarsening is the buyer's operation, and it is exact over the cell
hierarchy, so nothing is gained by the seller performing it and information is
lost.

Declared rollup is permitted and is a different thing. Section 6 covers the
one case where a seller must coarsen.

Mixed resolutions in a single response must be explicit. If any row is
returned at a resolution other than the requested one, every such row carries its
own resolution field and a reason, and the response carries a flag that the
result set is not resolution-uniform. A consumer that aggregates a mixed-resolution
set without detecting it will double count, because a parent and its children in
the same set describe the same ground twice.

5. Requested, executed, and reported are three different geographies

This is where this companion and the conversion companion meet, and it is the
reason the two are worth reading together.

A buyer requests a cell. A seller without native cell support executes a polygon,
a circle, or a native identifier. The report then attributes impressions to
something. If the report says "cell" while the media ran against a circumscribed
circle that overshot the cell, or against a postal crosswalk that only
approximates it, the report is not wrong so much as unfalsifiable.

Delivery rows should therefore preserve, alongside the metrics:

Field Why
requested cell system, identifier, and resolution The ask, unmodified
executed geometry type Circle, polygon, native identifier, or native cell
conversion mode Containment mode and circle mode, per the conversion companion
effective radius or executed polygon What actually ran, including any platform rounding applied on ingest
crosswalk source and vintage For native-identifier execution, with valid_from and valid_to
attribution basis Whether impressions were attributed by executed footprint or by re-assignment back to the requested cell

That last row matters more than it looks. A seller that executes on circles and
then re-assigns impressions back to requested cells is performing an inverse
conversion, and that inverse is not exact. Whether the numbers in a row are
measured or apportioned changes what a lift estimate means, and it should not be
inferable only from context.

For incrementality, frequency management, and treatment-control separation, the
difference between these geographies is material rather than cosmetic. The clean
statement is that the requested unit, the executed footprint, and the reported
attribution unit coincide in a native implementation and diverge during adoption,
which is the entire period this spec is actually for.

6. Privacy suppression collides with the no-rollup rule

This is the one genuine tension in the design and it needs resolving in the spec
rather than in each implementation.

Cell-grain reporting terminates in counts attributable to small areas. Standard
practice is a k-anonymity floor, enforced by suppressing cells below the threshold
or by rolling them up until the merged population clears it. Rollup is exactly what
section 4 prohibits.

Both rules are correct and they are not actually in conflict, because the
prohibition is on silent rollup. The resolution:

  1. A seller MAY suppress or coarsen a row to satisfy a stated privacy floor.
  2. It MUST NOT do so silently. A coarsened row carries its actual resolution and a
    reason distinguishing privacy coarsening from every other cause.
  3. Suppression and truncation are different states and MUST be distinguishable.
    Truncation means the response was cut for size. Suppression means the data
    exists and was withheld. A buyer computing coverage needs to tell these apart,
    and a suppressed-cell count must be reported rather than inferred from absence.
  4. The privacy floor itself should be declarable in capability, so a buyer can
    discover before spending that a design will not be readable at the resolution
    they intend to analyze at.

Three further constraints follow from the underlying privacy model and are worth
stating so implementers do not reach for resolution alone:

  • Resolution is not a privacy control by itself. A resolution floor without an
    audience floor still exposes sparse geographies, where a coarse cell holding
    three households is as exposed as a fine cell in a dense city. The risk is driven
    by the count inside the cell, not its area. Both floors must be enforced together.
  • Temporal grain is part of the same problem. A cell that clears a threshold
    aggregated over a month can fall below it sliced to one hour of one day. The
    minimum aggregation window is a floor on query granularity, not only on spatial
    resolution. This matters directly here because the unit this RFC serves is
    spatial and temporal.
  • Threshold suppression alone is defeated by repeated queries. Differencing
    across overlapping cell sets or successive time windows reconstructs a
    below-threshold value. Whether the spec addresses query budgets or explicitly
    places them out of scope, it should not leave the impression that a per-row
    threshold is sufficient.

7. Capability declaration

Supporting cell targeting does not imply supporting cell reporting, and the
reverse also holds. The two are declared independently, consistent with the Fix 3
prose already accepted on #5969.

A reporting capability declaration needs the systems supported, the resolutions
supported per system, whether the seller can report at the requested resolution or
only at a floor of its own, and the privacy floor from section 6. Resolutions
should follow the same absence-means-all and minItems: 1 semantics that Option C
established on the targeting side, so the two halves do not diverge in style.

8. Open questions for the WG

  1. Should a seller that supports cell targeting but not cell reporting be required
    to say so explicitly in capability, or is absence sufficient? Absence is
    consistent with the targeting side, but the asymmetry is more consequential here
    because the buyer discovers it only after delivery.
  2. Is attribution basis, measured against executed footprint versus apportioned
    back to requested cells, a required field or a recommended one? It is required
    in this draft, which is a stronger position than the rest of the document takes.
  3. Does the privacy floor belong in this companion or in a separate privacy
    section applying to all reporting dimensions? Cell grain surfaces it most
    sharply but does not own the problem.
  4. Should the temporal dimension be addressed here at all, or does it wait for the
    separate temporal convention work? Section 6 touches it because suppression is
    jointly spatial and temporal, but the unit's time axis is a larger subject.

9. Supporting material

The requested-versus-executed model, the conversion quality metrics that make the
gap in section 5 measurable, and the privacy and minimum-aggregation material
behind section 6 are documented elsewhere with tested reference implementations.
That documentation is being prepared for publication and will be linked here once
it is up.

Offered as input, not as a dependency.

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.media-buyIssue concerns the media-buy protocol domainneeds-wg-reviewBlocked on a working-group decision — surface in WG meeting agendasrfcProtocol change — auto-adds to roadmap boardschemaJSON Schema source-of-truth: definitions, codegen artifacts, validation, hygienespec / protocol

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions