# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-structural-signals-indicate-the-delegated-authority-scope-in-a2a-v1-0-agent-card-discovery-has-silently-exceeded-the-trust-boundary-at-cross-orga.md
# Remnant Warrant:    https://corpusfetch.com/c/what-structural-signals-indicate-the-delegated-authority-scope-in-a2a-v1-0-agent-card-discovery-has-silently-exceeded-the-trust-boundary-at-cross-orga.warrant.json
# Markdown SHA-256:   0e4ede707ebbb50ed672dad5765278bd9231a4385b2832eaf9244922f7fb49d9
# Code AST SHA-256:   4e9137d2d02fb725065262b3d16ac5ff5b1f3a125fab8750c20bac1a94b5a563
# Verified Classes:   DelegatedScopeBoundaryError, DelegationExtension, AgentCard
# Defensive Guards:   3 fail-closed invariants (zero external deps)

import dataclasses
from typing import Optional


class DelegatedScopeBoundaryError(RuntimeError):
    """Raised when a federated agent card's advertised scope would be
    propagated as asserted authority across a trust-domain boundary."""


@dataclasses.dataclass(frozen=True)
class DelegationExtension:
    uri: str
    required: bool
    delegation_chain_depth: int
    delegation_chain: tuple[str, ...]
    advertised_scopes: tuple[str, ...]


@dataclasses.dataclass(frozen=True)
class AgentCard:
    provider_org: str
    security_schemes: tuple[str, ...]
    delegation: Optional[DelegationExtension]


def resolve_delegated_scopes(
    card: AgentCard,
    caller_trust_domain: str,
    caller_possessed_schemes: frozenset[str],
) -> frozenset[str]:
    """Resolve which scopes the caller may *request* via delegated exchange.

    Returns the empty set when no delegation chain exists; the caller must
    then perform a direct exchange under its own identity.
    """
    if card.delegation is None:
        return frozenset()

    ext = card.delegation

    # Content-authorization scheme must be possessed by the caller; fetch-time
    # OIDC success does not imply possession of the card's declared scheme.
    missing = set(card.security_schemes) - caller_possessed_schemes
    if missing:
        raise DelegatedScopeBoundaryError(
            f"card from {card.provider_org} declares schemes {sorted(missing)} "
            f"not possessed by caller in trust domain {caller_trust_domain!r}; "
            f"refusing to treat advertised scopes as assertable"
        )

    # A zero-depth chain is an assertion that the origin will not honor
    # delegated authority from a foreign caller. Advertised scopes are a
    # candidate set only; do not propagate them.
    if ext.delegation_chain_depth == 0 or not ext.delegation_chain:
        raise DelegatedScopeBoundaryError(
            f"delegation extension {ext.uri!r} advertises depth 0 with "
            f"scopes {list(ext.advertised_scopes)}; these are candidates, "
            f"not a grant. Caller must use direct exchange."
        )

    if not ext.required and ext.delegation_chain_depth < 0:
        raise DelegatedScopeBoundaryError(
            f"malformed delegation extension {ext.uri!r}: negative depth"
        )

    # Only scopes reachable by walking the declared chain are assertable.
    chain_scopes: set[str] = set()
    for hop in ext.delegation_chain:
        chain_scopes.update(ext.advertised_scopes)
    return frozenset(chain_scopes & set(ext.advertised_scopes))
