# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/which-invariants-prevent-credential-chain-collapse-across-aaif-delegated-capability-tokens.md
# Remnant Warrant:    https://corpusfetch.com/c/which-invariants-prevent-credential-chain-collapse-across-aaif-delegated-capability-tokens.warrant.json
# Markdown SHA-256:   dfa40e5851ac7fb37c92559a11b3e0e39d2487d491e671916c06f3a111735415
# Code AST SHA-256:   4af4f52de3f8b376adc465131c34f9d4f35adf59e3a4595266bff9ee981ce497
# Verified Classes:   ScopeCollapseError, ScopedToken
# Defensive Guards:   6 fail-closed invariants (zero external deps)

class ScopeCollapseError(RuntimeError):
    """Raised when a delegated capability token's effective scope is not a
    subset of the meet of all ancestor scopes, or when use-time expiry /
    depth invariants are violated across the chain."""
    pass


class ScopedToken:
    def __init__(self, resource_pattern, action_set, expiry, delegation_depth):
        self.resource_pattern = resource_pattern
        self.action_set = frozenset(action_set) if action_set is not None else frozenset()
        self.expiry = expiry
        self.delegation_depth = delegation_depth


def _subset(child, parent):
    # resource_pattern subset check is domain-specific; assume comparable here
    return (child.resource_pattern <= parent.resource_pattern
            and child.action_set <= parent.action_set)


def verify_chain(chain, now, requested_action, requested_resource):
    if not chain:
        raise ScopeCollapseError("empty chain: no trusted root")

    root = chain[0]
    # Invariant 1: meet of all ancestor scopes, computed by replay from root.
    effective = ScopedToken(root.resource_pattern, root.action_set,
                            root.expiry, root.delegation_depth)
    for i, hop in enumerate(chain[1:], start=1):
        # Invariant 2: absence is not permission (enforced in constructor).
        if not _subset(hop, effective):
            raise ScopeCollapseError(
                f"hop {i}: scope {hop.action_set} on {hop.resource_pattern} "
                f"exceeds ancestor meet {effective.action_set} on "
                f"{effective.resource_pattern}"
            )
        effective = ScopedToken(
            hop.resource_pattern,
            hop.action_set,
            min(effective.expiry, hop.expiry),
            min(effective.delegation_depth, hop.delegation_depth),
        )

    # Invariant 3: use-time expiry meet.
    if now >= effective.expiry:
        raise ScopeCollapseError(
            f"chain expired at {effective.expiry} (now={now}); "
            f"terminal token expiry alone is insufficient"
        )

    # Invariant 4: depth at use.
    if effective.delegation_depth < 0:
        raise ScopeCollapseError("delegation depth exhausted")

    if requested_action not in effective.action_set:
        raise ScopeCollapseError(
            f"action {requested_action!r} not in effective set "
            f"{set(effective.action_set)}"
        )
    if not (requested_resource <= effective.resource_pattern):
        raise ScopeCollapseError(
            f"resource {requested_resource!r} outside effective pattern"
        )
    return True
