Skip to content

feat(adagents): clarify publisher_properties resolution — managed-network pattern needs inlined-properties path #4825

@bokelley

Description

@bokelley

Empirical evidence

Pulled https://cafemedia.com/.well-known/adagents.json (2.6 MB, `last_updated: 2026-05-14`, contact: Raptive). It is the largest known AAO-conformant file in production and represents the canonical "managed network" delegation pattern (~6,800 publisher properties under one operator). Structure:

{
  \"\$schema\": \"https://adcontextprotocol.org/schemas/v3/adagents.json\",
  \"authorized_agents\": [
    {
      \"url\": \"https://interchange.io\",
      \"authorization_type\": \"publisher_properties\",
      \"authorized_for\": \"Official sales agent for Raptive US display inventory\",
      \"publisher_properties\": [{
        \"selection_type\": \"by_tag\",
        \"property_tags\": [\"raptive_managed\"],
        \"publisher_domains\": [\"recipeswithessentialoils.com\", \"cravethegood.com\", ... 6800 total]
      }]
    }
  ],
  \"properties\": [
    {
      \"property_id\": \"5bd748df...\",
      \"property_type\": \"website\",
      \"identifiers\": [{\"type\": \"domain\", \"value\": \"recipeswithessentialoils.com\"}],
      \"publisher_domain\": \"recipeswithessentialoils.com\",
      \"tags\": [\"raptive_managed\"]
    },
    ... 6843 total inline properties
  ],
  \"tags\": {\"raptive_managed\": {\"name\": \"Raptive Managed\", ...}}
}

The gap

Per the spec at /schemas/3.1.0-beta.1/core/publisher-property-selector.json:

"the same `property_tags` predicate is resolved against each listed publisher's adagents.json"

This is the federated resolution model: to enumerate cafemedia's authorized inventory, a resolver must fetch each of the 6,800 child publishers' adagents.json files, follow their delegation chains, and find properties matching the selector. Operationally infeasible at managed-network scale — 6,800 HTTP fetches per agent-authorization check.

Cafemedia's pragmatic answer: inline the properties in the parent file with a publisher_domain field on each property record. The selector + publisher_domains list + property_tags list unambiguously identifies which inline properties belong to which child. But the spec doesn't currently endorse this resolution path.

Result today

The Python SDK at adcp/adagents.py:953-957 handles publisher_properties by returning the raw selector dicts:

if authorization_type == \"publisher_properties\":
    publisher_props = agent.get(\"publisher_properties\", [])
    if not isinstance(publisher_props, list):
        return []
    return [p for p in publisher_props if isinstance(p, dict)]

So get_properties_by_agent(cafemedia_data, \"https://interchange.io\") returns 1 dict (the selector), not the 6,843 actual properties. Downstream consumers (the Prebid Sales Agent's _count_total_properties at src/services/aao_lookup_service.py:249) get nonsense counts ("1 / 1 authorized" instead of "6843 / 6843").

Proposal — pick one

Option A (recommended): Extend the spec to recognize the inline-with-publisher_domain resolution path. When a parent file (a) contains a publisher_properties selector AND (b) has top-level properties[] entries with publisher_domain fields matching the selector's publisher_domains, the resolver MAY satisfy the selector from the parent file's inline properties — no per-child fetch required. Keeps federated resolution as a fallback for files that don't inline.

Option B: Spec stays as-is (strictly federated). Then cafemedia and every future managed network needs to either (i) restructure each of 6,800 child domains to publish their own adagents.json, or (ii) the SDK adds a pragmatic "check parent file first" extension that's nonconformant per spec. This is the worse outcome — pushes complexity onto every operator.

Option C: Spec defines an explicit "managed network" authorization_type that says "properties are inlined in this file with publisher_domain field" — distinct from cross-publisher federation. Cleanest but breaks cafemedia's current file shape and requires migration.

Why this is urgent

Cafemedia is the production reference. Their file has been static-ish since at least 2026-05. Every downstream consumer either:

  • Reports broken property counts (current SDK behavior)
  • Hits 6,800 HTTP fetches to enumerate the network (strict spec compliance)
  • Forks the SDK with a private "parent file inline lookup" extension

The Prebid Sales Agent (prebid/salesagent#511) hit this trying to onboard Raptive.

Companion tickets

References

  • _resolve_agent_properties SDK gap: adcp/adagents.py:909-959
  • Selector schema: https://adcontextprotocol.org/schemas/3.1.0-beta.1/core/publisher-property-selector.json
  • Live cafemedia file: https://cafemedia.com/.well-known/adagents.json (HTTP 200, 2.6 MB)

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.enhancementNew feature or requestneeds-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, hygiene

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Shipped

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions