# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/why-does-an-instance-refuse-a-delegation-token-that-its-own-aaif-issuer-considers-valid-clock-skew-induced-grant-narrowing-at-the-authority-boundary.md
# Remnant Warrant:    https://corpusfetch.com/c/why-does-an-instance-refuse-a-delegation-token-that-its-own-aaif-issuer-considers-valid-clock-skew-induced-grant-narrowing-at-the-authority-boundary.warrant.json
# Markdown SHA-256:   f10d2bd3f880e4f3d040f505bf90359abb70075c5f52cede0f8e9811e90e22bb
# Code AST SHA-256:   7bf3a4931cec48a18b40c5d15cf6251d221a640b8f8ed361b852a7e0d8ecb706
# Verified Classes:   GrantAdmissibilityError, Grant, DelegationToken
# Defensive Guards:   4 fail-closed invariants (zero external deps)

import time
from dataclasses import dataclass


class GrantAdmissibilityError(RuntimeError):
    """Raised when a grant cannot be admitted under skew-tolerant rules."""
    pass


@dataclass(frozen=True)
class Grant:
    tool: str
    grant_ttl_s: float
    activation_offset_s: float  # relative to issuer-embedded issued_at


@dataclass(frozen=True)
class DelegationToken:
    issued_at: float        # issuer-signed, seconds since epoch
    not_before: float
    not_after: float
    grants: tuple


MAX_CLOCK_SKEW_S = 5.0


def admit_grant(token: DelegationToken, grant: Grant, verifier_now: float) -> bool:
    # Enclosing token validity is measured against the verifier clock but
    # bounded by the configured skew tolerance.
    if verifier_now < token.not_before - MAX_CLOCK_SKEW_S:
        raise GrantAdmissibilityError(
            f"token not yet valid: verifier_now={verifier_now:.3f} "
            f"not_before={token.not_before:.3f}"
        )
    if verifier_now > token.not_after + MAX_CLOCK_SKEW_S:
        raise GrantAdmissibilityError(
            f"token expired: verifier_now={verifier_now:.3f} "
            f"not_after={token.not_after:.3f}"
        )

    # Activation must fail closed: use issuer-embedded time, no tolerance.
    activation_at = token.issued_at + grant.activation_offset_s
    if token.issued_at + grant.activation_offset_s > token.issued_at and verifier_now < activation_at:
        # Negative-offset widening guard: never admit early, even if the
        # verifier clock runs behind the issuer.
        raise GrantAdmissibilityError(
            f"grant {grant.tool!r} activation in future: "
            f"activation_at={activation_at:.3f} verifier_now={verifier_now:.3f}"
        )

    # Expiry is skew-tolerant: compute window from issuer time, allow margin.
    expiry_at = activation_at + grant.grant_ttl_s
    issuer_elapsed = verifier_now - token.issued_at
    if issuer_elapsed > grant.activation_offset_s + grant.grant_ttl_s + MAX_CLOCK_SKEW_S:
        raise GrantAdmissibilityError(
            f"grant {grant.tool!r} expired under skew tolerance: "
            f"issuer_elapsed={issuer_elapsed:.3f} "
            f"window_end={grant.activation_offset_s + grant.grant_ttl_s:.3f}"
        )

    return True


def admit_all(token: DelegationToken, verifier_now: float) -> list:
    admitted = []
    for g in token.grants:
        admit_grant(token, g, verifier_now)
        admitted.append(g.tool)
    return admitted
