You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is the third leg of the audience-data-movement story:
RFC: audience activation method (Snowflake / LiveRamp / direct API / clean rooms) #4324 — receive-side declarations. A seller (or any destination) declares the rails audience data can reach it on, with its address on each: sync_audiences, tmp_identity_match, file_transfer, dataset_query (+ consumer_identities[]), clean_room, platform_distribution (+ destination_ref).
This RFC — provider-initiated delivery. An operator directs a signal agent to deliver licensed segment membership to a destination. Provider-owned/licensed data, signals posture, priced through the existing signal pricing surface.
The gap this closes was flagged in review on #6540: activate_signal supports destinations of type: "agent" (agent_url), but how membership actually reaches that seller is unspecified. For type: "platform" destinations the provider↔platform rails are pre-integrated and out of view; for agent destinations there is no assumed integration — yet the plausible rails are exactly the ones #4324/#6540 defined. The core/ factoring of the activation-method and source schemas was done so this RFC could consume them rather than fork them.
Role model: who directs the flow, who licenses the data
The same company can occupy three protocol positions on these rails, and the position is determined by who directs the flow and who licenses the data — never by the company name:
Position
Directed by
Data interest
Protocol surface
Rails vendor
either party
none — pure transport
vendor on an activation-method or source entry
Signal agent
buyer/operator
provider-owned or licensed product
Signals protocol + this RFC's delivery leg
Seller's upstream supplier
seller
licensed to the seller
out of protocol — surfaces only as the seller's own signal inventory (signal_targeting_options, included_signals)
A data-marketplace vendor operating distribution rails illustrates all three: as rails, it appears as a platform_distribution vendor on a seller's #4324 declaration while a buyer distributes its own audience (#6540). As a signal agent, an operator licenses a marketplace segment and directs delivery to a destination (this RFC). As the seller's supplier, the seller sources marketplace segments into its own targeting taxonomy — the buyer does nothing, no signals-protocol interaction occurs, and the segments surface as ordinary seller signal options. That third mode is deliberately out of scope here: seller-controlled sourcing is the seller's business, invisible to the wire.
flowchart TB
subgraph CORE["shared core/ schemas"]
AAM["audience-activation-method.json\n(rails + addresses)"]
SRC["audience-source.json\n(delivery descriptor: kind + vendor + ref)"]
end
subgraph LEG1["#4324 — declare (receive side)"]
SELLER["Seller product / capabilities:\naudience_activation.methods[]"]
end
subgraph LEG2["#6540 — buyer-initiated (own data)"]
BUYER["Buyer grants share /\ninitiates distribution"]
SYNC["sync_audiences\naudience.source = {kind, vendor, ref}"]
end
subgraph LEG3["this RFC — provider-initiated (licensed data)"]
OP["Operator: activate_signal\ndestination type=agent"]
SA["Signal agent:\nsignals.delivery_methods[]"]
DEP["Deployment reports\ndelivery descriptor"]
end
SELLER -- "publishes rails + addresses" --> AAM
BUYER -- "reads seller address" --> SELLER
BUYER --> SYNC
SYNC -- "pointer, never payload" --> SRC
OP -- "resolves destination's rails" --> SELLER
OP --> SA
SA -- "delivers over matching rail" --> DEP
DEP -- "same descriptor shape" --> SRC
Loading
One declaration serves both initiating parties: the seller's #4324 entry is the address, whether the buyer is pushing its own audience or a signal agent is delivering a licensed segment on the operator's instruction. The seller does not need to know which kind of counterparty is on the other end of the rail.
Proposal
1. Signal agents declare delivery_methods
New optional array in the signals capability block of get_adcp_capabilities, reusing the core/audience-activation-method.json pattern vocabulary read from the send side:
Send-side readings: sync_audiences = "I can push to AdCP sellers"; platform_distribution = "I can initiate distribution on this vendor's rails to any declared destination"; dataset_query = "I can publish a share on this vendor for the destination to read"; clean_room = "I can land output in this vendor's room". Receiver-specific fields (destination_ref, consumer_identities, bind_expiry_days) are not declared by the signal agent — they belong to the destination and are resolved at activation time from the destination's #4324 declaration. Compatibility is pattern+vendor intersection between the signal agent's delivery_methods and the destination's audience_activation.methods.
2. Agent-destination activation resolves a rail
For activate_signal destinations of type: "agent", the signal agent resolves the destination's audience_activation (via the agent_url's capabilities/catalog) and selects a mutually supported rail. The operator MAY pin one by including a delivery_method (pattern + optional vendor) on the destination entry; otherwise selection is agent-discretion with the destination's preferred_method honored when compatible. No intersection → the destination entry fails with the existing unsupported-path error semantics rather than silently activating something unreachable.
3. Deployments carry a delivery descriptor
Each agent-destination deployment in the activation response (and subsequent status reads) carries a delivery object shaped like core/audience-source.json — {kind: "dataset" | "platform_segment", vendor, locator | segment_ref} — identifying what the signal agent actually shipped. This descriptor is the join key on the destination side: the seller's deployment of the segment keys off it, exactly as a buyer-bound audience keys off the same shape in #6540. The activation_key contract is unchanged — the descriptor explains how membership arrives; the key remains how you target it.
4. Destination-side surfacing stays role-correct
A provider segment delivered this way surfaces on the seller as signal inventory (targetable through signal targeting, reported through signal deployment status) — not as a buyer audience in sync_audiences discovery. The posture boundary from #6540 holds in both directions: buyer-owned data moved by anyone binds as an audience; provider-licensed data delivered by a signal agent deploys as a signal. Same rails, different shelves.
Open questions for WG
Rail selection authority. Is agent-discretion-with-operator-pin the right default, or should the operator always choose? Agent discretion minimizes operator plumbing; explicit pin aids reproducibility and cost control (rails have different economics).
Delivery economics. Distribution/egress costs vary by rail. Does the existing signal pricing surface absorb this (delivery cost priced into the signal), or does a rail-dependent fee need declaration? Lean absorb-in-v1.
tmp_identity_match as a delivery rail. Runtime identity match is a fundamentally different mechanism (no membership file moves at all). Probably excluded from delivery_methods; worth one sentence saying why.
Out of scope
Seller-controlled sourcing of marketplace segments (out of protocol by design — see role model).
Background
This is the third leg of the audience-data-movement story:
sync_audiences,tmp_identity_match,file_transfer,dataset_query(+consumer_identities[]),clean_room,platform_distribution(+destination_ref).sourcereference onsync_audiences. Buyer-owned data, DPA posture, no pricing.The gap this closes was flagged in review on #6540:
activate_signalsupports destinations oftype: "agent"(agent_url), but how membership actually reaches that seller is unspecified. Fortype: "platform"destinations the provider↔platform rails are pre-integrated and out of view; for agent destinations there is no assumed integration — yet the plausible rails are exactly the ones #4324/#6540 defined. Thecore/factoring of the activation-method and source schemas was done so this RFC could consume them rather than fork them.Role model: who directs the flow, who licenses the data
The same company can occupy three protocol positions on these rails, and the position is determined by who directs the flow and who licenses the data — never by the company name:
vendoron an activation-method or source entrysignal_targeting_options,included_signals)A data-marketplace vendor operating distribution rails illustrates all three: as rails, it appears as a
platform_distributionvendor on a seller's #4324 declaration while a buyer distributes its own audience (#6540). As a signal agent, an operator licenses a marketplace segment and directs delivery to a destination (this RFC). As the seller's supplier, the seller sources marketplace segments into its own targeting taxonomy — the buyer does nothing, no signals-protocol interaction occurs, and the segments surface as ordinary seller signal options. That third mode is deliberately out of scope here: seller-controlled sourcing is the seller's business, invisible to the wire.flowchart TB subgraph CORE["shared core/ schemas"] AAM["audience-activation-method.json\n(rails + addresses)"] SRC["audience-source.json\n(delivery descriptor: kind + vendor + ref)"] end subgraph LEG1["#4324 — declare (receive side)"] SELLER["Seller product / capabilities:\naudience_activation.methods[]"] end subgraph LEG2["#6540 — buyer-initiated (own data)"] BUYER["Buyer grants share /\ninitiates distribution"] SYNC["sync_audiences\naudience.source = {kind, vendor, ref}"] end subgraph LEG3["this RFC — provider-initiated (licensed data)"] OP["Operator: activate_signal\ndestination type=agent"] SA["Signal agent:\nsignals.delivery_methods[]"] DEP["Deployment reports\ndelivery descriptor"] end SELLER -- "publishes rails + addresses" --> AAM BUYER -- "reads seller address" --> SELLER BUYER --> SYNC SYNC -- "pointer, never payload" --> SRC OP -- "resolves destination's rails" --> SELLER OP --> SA SA -- "delivers over matching rail" --> DEP DEP -- "same descriptor shape" --> SRCOne declaration serves both initiating parties: the seller's #4324 entry is the address, whether the buyer is pushing its own audience or a signal agent is delivering a licensed segment on the operator's instruction. The seller does not need to know which kind of counterparty is on the other end of the rail.
Proposal
1. Signal agents declare
delivery_methodsNew optional array in the
signalscapability block ofget_adcp_capabilities, reusing thecore/audience-activation-method.jsonpattern vocabulary read from the send side:Send-side readings:
sync_audiences= "I can push to AdCP sellers";platform_distribution= "I can initiate distribution on this vendor's rails to any declared destination";dataset_query= "I can publish a share on this vendor for the destination to read";clean_room= "I can land output in this vendor's room". Receiver-specific fields (destination_ref,consumer_identities,bind_expiry_days) are not declared by the signal agent — they belong to the destination and are resolved at activation time from the destination's #4324 declaration. Compatibility is pattern+vendor intersection between the signal agent'sdelivery_methodsand the destination'saudience_activation.methods.2. Agent-destination activation resolves a rail
For
activate_signaldestinations oftype: "agent", the signal agent resolves the destination'saudience_activation(via theagent_url's capabilities/catalog) and selects a mutually supported rail. The operator MAY pin one by including adelivery_method(pattern + optional vendor) on the destination entry; otherwise selection is agent-discretion with the destination'spreferred_methodhonored when compatible. No intersection → the destination entry fails with the existing unsupported-path error semantics rather than silently activating something unreachable.3. Deployments carry a delivery descriptor
Each agent-destination deployment in the activation response (and subsequent status reads) carries a
deliveryobject shaped likecore/audience-source.json—{kind: "dataset" | "platform_segment", vendor, locator | segment_ref}— identifying what the signal agent actually shipped. This descriptor is the join key on the destination side: the seller's deployment of the segment keys off it, exactly as a buyer-bound audience keys off the same shape in #6540. Theactivation_keycontract is unchanged — the descriptor explains how membership arrives; the key remains how you target it.4. Destination-side surfacing stays role-correct
A provider segment delivered this way surfaces on the seller as signal inventory (targetable through signal targeting, reported through signal deployment status) — not as a buyer audience in
sync_audiencesdiscovery. The posture boundary from #6540 holds in both directions: buyer-owned data moved by anyone binds as an audience; provider-licensed data delivered by a signal agent deploys as a signal. Same rails, different shelves.Open questions for WG
bind_expiredtreatment in RFC: external audience sources — pass-through references on sync_audiences #6540.tmp_identity_matchas a delivery rail. Runtime identity match is a fundamentally different mechanism (no membership file moves at all). Probably excluded fromdelivery_methods; worth one sentence saying why.Out of scope
Related