Skip to content

feat(media-buy): external audience sources on sync_audiences (#6540) - #6857

Open
bokelley wants to merge 4 commits into
mainfrom
sync-audiences-external-sources
Open

feat(media-buy): external audience sources on sync_audiences (#6540)#6857
bokelley wants to merge 4 commits into
mainfrom
sync-audiences-external-sources

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Implements #6540 — the runtime leg of the audience-activation surface (#4324 / #6549), experimental under the same media_buy.audience_activation feature id. WG approved the audience work for 3.2 as experimental.

What this adds

An audience on sync_audiences carries either inline member deltas or a source reference — a pointer to buyer data the seller ingests over a declared activation rail. Data never transits AdCP.

  • core/audience-source.json (new, experimental): dataset (grantee-identified share the seller reads — Snowflake Secure Data Sharing, Databricks D2D, BigQuery authorized views; optional declarative access_expires_at) | platform_segment (binds a vendor-distributed segment to an audience_id; segment_ref is the vendor's ID as issued to the buyer, seller owns the ingest-side mapping).
  • Request: source on the audience object; schema-enforced mutual exclusion with add/remove.
  • Response: source echo (never credentials) with access_status (active/unavailable) and columns_read; last_synced_at schema-required exactly when counts populate (ready/too_small) so every count has an anchor — first-read-pending (processing) and failed-first-ingest stay legal.
  • SOURCE_ACCESS_FAILED on both error-code surfaces, error.field-keyed recovery: bad reference (fix request) vs. missing grant (grant + retry) vs. vendor outage (backoff).
  • Docs: full external-sources section on sync_audiences (flows, canonical column contract, refresh vs. replication lag, latency band); present-tense updates to every "until RFC: external audience sources — pass-through references on sync_audiences #6540 lands" placeholder; canonical experimental-list row extended.
  • Tests: tests/audience-external-sources.test.cjs (12) wired into the chain.

Normative rules from the RFC review threads

  1. Transport fixed at creation — cross-transport upserts rejected with CONFLICT (error.field: audience_id); convert by delete-and-recreate.
  2. Loss of source access MUST NOT change audience status — the seller cannot distinguish revocation from expiry from a transient outage (all three observables are a failed read), so membership freezes at last successful read and stays targetable, last_synced_at freezes, and failed re-reads MUST NOT emit suspended (reserved for consent/policy causes, which remain orthogonal). Health reports via source.access_status.
  3. Access expiry is not deletion — bounds the access window, not retention; DPA governs; teardown stays delete: true.
  4. Single pane — sourced audiences appear in discovery identically to pushed ones; no new list task.
  5. Capability gate — source kinds map 1:1 to declared activation patterns; undeclared kinds → UNSUPPORTED_FEATURE; credential material → CREDENTIAL_IN_ARGS; grantee-identified flows only.

Validation

Schema build, 12/12 new tests, example validation, error-code lint (both enum surfaces), oneOf audit, and compliance links all green on a tree rebased onto the merged #6549.

Closes #6540.

🤖 Generated with Claude Code

Runtime leg of the audience-activation surface, experimental under
media_buy.audience_activation. Audiences carry either inline member
deltas or a source reference (core/audience-source.json): dataset
(grantee-identified share the seller reads) or platform_segment
(binds a vendor-distributed segment). Response echoes the source with
access_status and columns_read; counts anchor to last_synced_at.
Transport fixed at creation; loss of source access never changes
audience status; access expiry is not deletion. New SOURCE_ACCESS_FAILED
error code with error.field-keyed recovery.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread static/schemas/source/media-buy/sync-audiences-response.json Outdated
@aao-secretariat aao-secretariat Bot added the ladon/needs-human-review Ladon has escalated this PR for human review. label Aug 25, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated schema paths require human/CODEOWNERS approval.

This PR adds an experimental runtime leg of audience activation (#6540): a new discriminated core/audience-source.json, a source request field with schema-enforced mutual exclusion vs add/remove, a response source echo, and a new SOURCE_ACCESS_FAILED error code. Schema, changeset scope (minor, protocol-scoped), oneOf discrimination, and schema↔docs coherence largely hold. No critical or high findings were reported, so the diff itself is not blocking.

However, this PR modifies/adds files under static/schemas/source/**, which are under a hard, deterministic approval gate (gated_paths: true), and review_decision is REVIEW_REQUIRED — not APPROVED. Per decision rule row 2, the outcome must be escalate until a real human/CODEOWNERS approval satisfies the gate.

Medium findings (non-blocking, worth a look during human review):

  • static/schemas/source/media-buy/sync-audiences-response.json:116 — last_synced_at description overstates its requirement relative to its own if/then and the docs (normative-text mismatch).

Escalation reasons:

  • Gated schema paths touched (e.g. static/schemas/source/core/audience-source.json, static/schemas/source/media-buy/sync-audiences-request.json, sync-audiences-response.json, enums/error-code.json) and review_decision is REVIEW_REQUIRED. Human/CODEOWNERS approval required before merge.

Medium findings

  • static/schemas/source/media-buy/sync-audiences-response.json:116 — last_synced_at description overstates requirement vs its own if/then and the docs

Why human review

  • Gated paths touched under static/schemas/source/** (audience-source.json added; sync-audiences-request/response.json, error-code.json, audience-activation-method.json modified) and review_decision is REVIEW_REQUIRED — human/CODEOWNERS approval required before this can merge.
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/audience-activation-method.json (modified) matches static/schemas/source/**; static/schemas/source/core/audience-source.json (added) matches static/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/sync-audiences-request.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/sync-audiences-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

… schema-graph growth

New 3.2 wire code needs a held-for-next-minor entry in the error-code
drift registry, and core/audience-source.json adds one definition to the
media-buy tool graph (583→584 instances, 152→153 unique) — pins updated
to acknowledge the deliberate growth.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated schema paths require human/CODEOWNERS approval.

This PR modifies/adds files under static/schemas/source/** (audience-source.json added; sync-audiences-request/response.json, error-code.json, audience-activation-method.json modified), which sit behind a hard, non-overridable approval gate. review_decision is not APPROVED (unknown/none), so per decision rule row 2 the gate is not satisfied and the outcome must be escalate.

No blocking (critical/high) findings surfaced in this run. The prior medium finding on sync-audiences-response.json:116 is outside the current delta and not re-raised. The delta since the prior pass — a new SOURCE_ACCESS_FAILED disposition (held-for-next-minor, target 3.2) plus definition-count bumps (583→584, 152→153) for the single new audience-source definition — is internally consistent and lint-valid. This is a net-clean iteration, but the gated-paths gate still stands until a human/CODEOWNERS approval is recorded.

Escalation reasons:

  • Gated paths touched under static/schemas/source/** and review_decision is not APPROVED — human/CODEOWNERS review required before merge.

Why human review

  • Touches gated paths under static/schemas/source/** (audience-source.json added; sync-audiences-request.json, sync-audiences-response.json, error-code.json, audience-activation-method.json modified) and review_decision is not APPROVED — human/CODEOWNERS approval required before this can merge (decision rule row 2, hard gate).
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/audience-activation-method.json (modified) matches static/schemas/source/**; static/schemas/source/core/audience-source.json (added) matches static/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/sync-audiences-request.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/sync-audiences-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

@bokelley

Copy link
Copy Markdown
Contributor Author

Databricks technical review is now incorporated into this branch:

  • Separates the advertised Delta Sharing recipient identity (consumer_identities[]) from the shared-object locator (share://<provider>/<share>/<schema>.<object>).
  • Allows Databricks-to-Databricks or Open Sharing with OIDC token federation; classic bearer-token sharing remains excluded, and no credential traverses AdCP.
  • Documents the recipient-property row-filter pattern for multi-publisher datasets and the freeze-at-last-success behavior after access is revoked or expires.
  • Corrects the last_synced_at requirement wording and adds coverage for the Databricks locator convention.

Latest main is merged and the prior conflict is resolved. Focused audience/schema/docs checks and the complete schema suite pass. The two unrelated transient local gate failures also passed immediately in isolation. GitHub CI is rerunning; the remaining intentional gate is human/CODEOWNERS approval for static/schemas/source/**.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated-paths hard gate unsatisfied (review_decision is not APPROVED).

This is a very large additive protocol PR (~379 files) touching the published spec surface under static/schemas/source/** plus a substantial Addie server refactor and 7 new DB migrations. Deterministic Ladon gates all pass per the reviewer: no dist/** artifact mutations, new oneOf schemas carry explicit discriminators, changesets are additive minor/patch with no hand-edited version, and enum/error-code additions are purely additive with no removed/renamed values or optional→required flips. No Critical/High/Medium code-level finding surfaced.

However, decision-table row 2 fires: gated_paths: true (.github/workflows/** and static/schemas/source/** files modified) AND review_decision is not APPROVED (unknown/none). This is a hard, non-overridable approval gate — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

Additionally, per the repo constitution's Breaking-class / Normative-class governance, a spec-surface change of this scope (including a guidance→normative cadence-gate promotion) routes to human ratification, not auto-approval. This is consistent with the prior escalate outcome, which stands: no findings were resolved-away that would change the gate, and the gating condition still holds.

Escalation reasons:

  • Touches gated paths under static/schemas/source/** and .github/workflows/**; review_decision is not APPROVED — human/CODEOWNERS approval required before merge (row 2, hard gate).
  • Spec-surface change subject to the constitution's human-ratification governance for protocol additions.

Why human review

  • Gated paths touched (static/schemas/source/, .github/workflows/) and review_decision is not APPROVED — human/CODEOWNERS approval required before merge (decision rule row 2, hard gate).
  • Large additive protocol spec-surface change subject to the constitution's human-ratification governance; auto-approval is not permitted without recorded human/CODEOWNERS approval.
  • This PR touches a path under a hard, non-overridable approval gate (.github/workflows/deploy.yml (modified) matches .github/workflows/**; .github/workflows/training-agent-storyboards.yml (modified) matches .github/workflows/**; static/schemas/source/compliance/comply-test-controller-request.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/asset-union.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/daast-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/daast-tracker-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/display-tag-asset.json (added) matches static/schemas/source/**; static/schemas/source/core/assets/html-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/javascript-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/pixel-tracker-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/url-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/vast-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/vast-tracker-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/audience-activation-method.json (modified) matches static/schemas/source/**; static/schemas/source/core/audience-source.json (added) matches static/schemas/source/**; static/schemas/source/core/canonical-format-option.json (modified) matches static/schemas/source/**; static/schemas/source/core/committed-metric.json (modified) matches static/schemas/source/**; static/schemas/source/core/creative-asset.json (modified) matches static/schemas/source/**; s

…(truncated)…

@bokelley
bokelley enabled auto-merge (squash) August 27, 2026 06:36
@bokelley
bokelley requested a review from a team August 27, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ladon/needs-human-review Ladon has escalated this PR for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: external audience sources — pass-through references on sync_audiences

1 participant