Skip to content

RFC: signal delivery methods — provider-initiated membership delivery to agent destinations #6552

Description

@bokelley

Background

This is the third leg of the audience-data-movement story:

  • RFC: audience activation method (Snowflake / LiveRamp / direct API / clean rooms) #4324receive-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).
  • RFC: external audience sources — pass-through references on sync_audiences #6540buyer-initiated movement. The buyer moves its own data (grant a share, initiate a distribution) and binds the result via a source reference on sync_audiences. Buyer-owned data, DPA posture, no pricing.
  • This RFCprovider-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:

"signals": {
  "delivery_methods": [
    { "pattern": "sync_audiences" },
    { "pattern": "platform_distribution", "vendor": { "domain": "liveramp.com" } },
    { "pattern": "dataset_query", "vendor": { "domain": "snowflake.com" } }
  ]
}

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

  1. 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).
  2. 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.
  3. Deployment status vocabulary. Agent-destination deployments need arrival semantics (delivered / awaiting-read / failed) with days-scale distribution latency acknowledged, mirroring the bind_expired treatment in RFC: external audience sources — pass-through references on sync_audiences #6540.
  4. 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

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.needs-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, hygienesignalsIssue concerns the signals protocol domain

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions