Skip to content

feat(adagents): inline-resolution path for publisher_properties selectors + directory inverse-lookup wrapper #749

@bokelley

Description

@bokelley

Two related pieces of SDK work coming out of adcp#4825 and adcp#4823.

Part 1 — Inline-resolution path for publisher_properties selectors

adcp#4825 (spec PR adcp#4827) endorses parent-file inline resolution: when a parent file's top-level properties[] entries carry a publisher_domain matching one in the selector's publisher_domains[], the consumer MAY satisfy the selector from those inline properties without per-child adagents.json fetches.

This SDK has two related bugs at adcp/adagents.py:953-957:

  1. Returns raw selector dicts instead of resolved properties. get_properties_by_agent(cafemedia_data, "https://interchange.io") returns 1 selector dict instead of the 6,843 inline properties.

  2. No publisher_domains[] fan-out. _resolve_agent_properties doesn't expand the compact-form publisher_domains[] array into per-domain resolution. This is the bug adcp#4825's triage identified as orthogonal to the spec change.

Both need fixing. The fix:

if authorization_type == "publisher_properties":
    selectors = agent.get("publisher_properties", [])
    if not isinstance(selectors, list):
        return []
    resolved: list[Property] = []
    parent_properties = adagents_data.get("properties", []) or []
    for selector in selectors:
        if not isinstance(selector, dict):
            continue
        domains = _selector_domains(selector)  # publisher_domain | publisher_domains
        for domain in domains:
            inline = _resolve_inline(selector, parent_properties, domain)
            if inline is not None:
                resolved.extend(inline)
                continue  # inline succeeded; skip federated fetch
            resolved.extend(_resolve_federated(selector, domain))
    return resolved

_resolve_inline returns None (not []) when no matched property carries the expected publisher_domain, so federated fallback fires. Empty inline match with at least one inline candidate counts as a real empty resolution.

Divergence rule (from spec): if both paths resolve to the same (publisher_domain, property_id) and disagree, federated wins; SDK SHOULD log the divergence.

Revocation: inline path MUST honor revoked_publisher_domains[] on the parent file.

Part 2 — Directory inverse-lookup wrapper

adcp#4823 (spec PR adcp#4828) defines GET /v1/agents/{agent_url}/publishers. SDK needs a wrapper:

def fetch_agent_authorizations_from_directory(
    agent_url: str,
    directory_url: str = "https://agenticadvertising.org",
    *,
    since: datetime | None = None,
    status: list[str] = ["authorized"],
    cursor: str | None = None,
    limit: int = 200,
    timeout: float = 30.0,
) -> AgentDirectoryLookup:
    """Inverse of fetch_agent_authorizations — returns the publishers
    that authorize this agent, sourced from the AAO directory's index.

    Mirrors the existing AdAgentsValidationResult provenance fields
    (discovery_method, manager_domain) so consumers can route directory-
    sourced and per-domain results through the same code path.
    """

Return type mirrors the response envelope schema. Iterator support for paginated responses is a plus.

Acceptance

Part 1:

  • get_properties_by_agent(cafemedia_data, "https://interchange.io") returns the 6,843 inline properties matching tags ∋ "raptive_managed" and publisher_domain ∈ publisher_domains[...], not the selector dicts.
  • publisher_domains[] compact form is fanned into per-domain resolution.
  • When inline and federated diverge, SDK logs the divergence and uses the federated result.
  • Parent-file revoked_publisher_domains[] revokes inline matches for that domain.

Part 2:

  • fetch_agent_authorizations_from_directory returns spec-conformant AgentDirectoryLookup with discovery_method, manager_domain, properties_authorized, properties_total, signing_keys_pinned, status, last_verified_at per publisher.
  • Cursor pagination handled transparently or exposed as iterator.
  • Reuses AdAgentsValidationResult provenance fields where the vocabulary overlaps.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions