# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-happens-when-an-instance-presents-a-delegated-scope-token-whose-delegation-chain-exceeds-the-verifier-s-maximum-hop-depth.md
# Remnant Warrant:    https://corpusfetch.com/c/what-happens-when-an-instance-presents-a-delegated-scope-token-whose-delegation-chain-exceeds-the-verifier-s-maximum-hop-depth.warrant.json
# Markdown SHA-256:   a50e7c184e4306fea846273b3c47934564cdb68e39cfc7470d04f1e9c265e1d0
# Code AST SHA-256:   c01790b135774d1bbf4a9a879829c7ff3838dbb17faff60dfd61f4cd112489f2
# Verified Classes:   DelegationDepthExceeded, ScopeAttenuationViolation, DelegationEdge
# Defensive Guards:   4 fail-closed invariants (zero external deps)

from dataclasses import dataclass
from typing import Sequence


class DelegationDepthExceeded(RuntimeError):
    """Raised when a fully valid delegation chain exceeds the verifier's max depth.

    This is a structural/topology failure, not a credential failure. It is
    terminal and must not be retried with the same token.
    """

    def __init__(self, observed_depth: int, max_depth: int, chain_ids: Sequence[str]):
        self.observed_depth = observed_depth
        self.max_depth = max_depth
        self.chain_ids = tuple(chain_ids)
        super().__init__(
            f"delegation chain depth {observed_depth} exceeds verifier max "
            f"{max_depth}; chain={list(self.chain_ids)}"
        )


class ScopeAttenuationViolation(RuntimeError):
    """Raised when an edge widens scope relative to its parent edge."""


@dataclass(frozen=True)
class DelegationEdge:
    agent_id: str
    scope: frozenset
    signature_valid: bool


def verify_delegated_scope_token(
    chain: Sequence[DelegationEdge],
    max_delegation_depth: int,
    root_trusted: bool,
) -> frozenset:
    """Validate a DST chain in full. Never truncates.

    Returns the effective (fully attenuated) scope on success.
    """
    if not root_trusted:
        raise PermissionError("root agent credential not anchored in trust store")

    # Validate every edge before any depth decision, so that depth exhaustion
    # is never used to mask a signature or attenuation failure.
    for edge in chain:
        if not edge.signature_valid:
            raise PermissionError(f"invalid signature at edge {edge.agent_id}")

    for parent, child in zip(chain, chain[1:]):
        if not child.scope.issubset(parent.scope):
            raise ScopeAttenuationViolation(
                f"edge {child.agent_id} widens scope beyond {parent.agent_id}"
            )

    observed_depth = len(chain) - 1  # edges below the root
    if observed_depth > max_delegation_depth:
        # Terminal. Do NOT truncate. Do NOT collapse into PermissionError.
        raise DelegationDepthExceeded(
            observed_depth=observed_depth,
            max_depth=max_delegation_depth,
            chain_ids=[edge.agent_id for edge in chain],
        )

    return chain[-1].scope
