# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/in-what-scenarios-must-an-instance-reject-a-capability-scoped-agent-token-whose-aaif-assertion-is-audience-bound-but-scope-narrower-than-the-requestin.md
# Remnant Warrant:    https://corpusfetch.com/c/in-what-scenarios-must-an-instance-reject-a-capability-scoped-agent-token-whose-aaif-assertion-is-audience-bound-but-scope-narrower-than-the-requestin.warrant.json
# Markdown SHA-256:   9d947f84b080124684d28871209b76c421782ee005bfc8aede1122fc31f5a16a
# Code AST SHA-256:   cf2b6d846891314873a182206ef85a1809d699d2cea6cad014c6df30a2bea98f
# Verified Classes:   AssertionContainmentError, CapabilityToken, AAIFAssertion
# Defensive Guards:   7 fail-closed invariants (zero external deps)

from dataclasses import dataclass
from typing import FrozenSet


class AssertionContainmentError(RuntimeError):
    """Raised when a requested action lies within the token capability set
    but outside the audience-bound AAIF assertion's scope ceiling."""


@dataclass(frozen=True)
class CapabilityToken:
    sub: str
    cap: FrozenSet[str]
    issued_at: float


@dataclass(frozen=True)
class AAIFAssertion:
    sub: str
    aud: str
    scope: FrozenSet[str]
    iat: float
    exp: float
    profile_version: int


def authorize(
    *,
    requested: str,
    resource_aud: str,
    token: CapabilityToken,
    assertion: AAIFAssertion,
    now: float,
) -> None:
    # Validity conditions first; containment is only well-posed if these hold.
    if assertion.aud != resource_aud:
        raise AssertionContainmentError(
            f"audience mismatch: assertion aud={assertion.aud!r} "
            f"!= resource aud={resource_aud!r}"
        )
    if assertion.sub != token.sub:
        raise AssertionContainmentError(
            f"subject mismatch: assertion sub={assertion.sub!r} "
            f"!= token sub={token.sub!r} (confused deputy)"
        )
    if not (assertion.iat <= now < assertion.exp):
        raise AssertionContainmentError(
            f"assertion not currently valid: iat={assertion.iat} "
            f"exp={assertion.exp} now={now}"
        )
    if assertion.iat < token.issued_at:
        raise AssertionContainmentError(
            "assertion predates token issuance window"
        )
    if not assertion.scope and assertion.profile_version >= 2:
        raise AssertionContainmentError(
            "AAIF v2+ assertion missing required scope claim"
        )

    in_cap = requested in token.cap
    in_scope = requested in assertion.scope if assertion.scope else True

    if in_cap and in_scope:
        return
    if in_cap and not in_scope:
        # The boundary the naive validator misses: token grants it,
        # assertion ceiling does not. Reject as containment, not capability.
        raise AssertionContainmentError(
            f"requested={requested!r} within token cap but outside "
            f"assertion scope ceiling={sorted(assertion.scope)}; "
            f"request a re-scoped assertion, do not retry with same envelope"
        )
    # Not in cap: the token is the primary grant, report against it.
    raise AssertionContainmentError(
        f"requested={requested!r} not in token capability set"
    )
