Skip to content

feat(reporting): provide an adapter-first ReliableReportingService and conformance kit #1172

Description

@bokelley

Summary

AdCP 3.2 Reliable Reporting now has strong low-level source, ledger, status, and buyer reconciliation primitives. The adopter experience still requires substantial orchestration: choose account/configuration scope, resolve source routing and currency, construct offerings, wire worker lifecycle, mount handlers, bridge notifications, advertise only installed tiers, and build a conformance harness.

We would like one adapter-first service API where GAM, FreeWheel, and future ad servers provide their domain hooks and the SDK owns the reliable pipeline.

Design target

Adapter authors should implement only the facts their system knows:

  • source capabilities and metric semantics;
  • fetching one frozen, closed reporting slice;
  • currency, source timezone, freshness/finality, and per-metric evidence;
  • optionally, managed-destination I/O.

The SDK should own scheduling, leases, retry/replay identity, obligation freezing, staging/sealing, manifests, revisions/adjustments, exact reads, status projections, notifications, receipts, retention, capability advertisement, and lifecycle shutdown.

An illustrative—not prescriptive—shape:

reporting = ReliableReportingService.postgres(
    pool=pool,
    account_context=resolve_account_context,
    webhook_sender=tenant_sender_resolver,
)

reporting.sources.register("gam", GAMReportingAdapter(...))
reporting.sources.register("freewheel", FreeWheelReportingAdapter(...))

platform = reporting.install(platform)

async with reporting:
    await serve(platform)

The per-adapter protocol could center on a single typed fetch_slice() returning normalized rows, watermark, coverage, and per-metric evidence. Routing should use frozen trusted account/media-buy source scope. Sync and async provider SDKs should both be easy to wrap without blocking the event loop.

Acceptance criteria

  • One high-level factory/service composes store, producer, status/consumer/receipt handlers, exact revision reads, notification worker, and lifecycle.
  • One registration interface routes frozen obligations to multiple source adapters in the same process.
  • The minimum adapter protocol is typed, small, and contains no AdCP transport concerns.
  • Common account context—currency, timezone, adapter route, source scope, reporting definition—is resolved once from trusted state and frozen at the correct lifecycle boundary.
  • Installing the service mounts/returns ready-to-use handlers for the supported AdCP tasks and produces a truthful capability block from actually configured components.
  • Startup validation catches impossible combinations (for example reconciled billing without managed delivery, webhook activity without attempt storage, or an offering with no registered source).
  • Test utilities provide a deterministic clock, in-memory stores, failure injection, and a reusable adapter conformance suite.
  • Documentation includes minimal GAM-like and FreeWheel-like adapters plus PostgreSQL production wiring.
  • Advanced adopters can replace individual stores/writers/workers without forking the orchestrator.

Related SDK gaps

This umbrella tracks:

Why this matters

The client value is not merely schema support. A publisher should be able to enable a demonstrably reliable pipeline, a buyer should be able to query and subscribe to its state, and both parties should get the same exact evidence and billing reconciliation behavior regardless of whether the underlying source is GAM, FreeWheel, or another adapter.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions