# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/why-does-an-instance-of-an-a2a-v1-0-delegation-chain-fail-receipt-verification-when-the-chain-is-cryptographically-intact.md
# Remnant Warrant:    https://corpusfetch.com/c/why-does-an-instance-of-an-a2a-v1-0-delegation-chain-fail-receipt-verification-when-the-chain-is-cryptographically-intact.warrant.json
# Markdown SHA-256:   59a98631a9c68e516c9be1d38f8adabbf7723a5d2b276066619de169316edfcd
# Code AST SHA-256:   f4d98132cadaa157b11503c3bf4383617eccd9f9e970854e6b0e1301279bf03b
# Verified Classes:   ReceiptChainError, StructuralVerificationError, UnverifiedAuthorizationError, Receipt, RevocationWitness
# Defensive Guards:   6 fail-closed invariants (zero external deps)

from dataclasses import dataclass
from typing import Optional, Sequence


class ReceiptChainError(RuntimeError):
    """Base for receipt-chain verification failures."""


class StructuralVerificationError(ReceiptChainError):
    """Signature, hash-link, or scope-subset check failed."""


class UnverifiedAuthorizationError(ReceiptChainError):
    """Chain is structurally sound but lacks a revocation witness for at least one hop."""


@dataclass(frozen=True)
class Receipt:
    delegator: str
    delegatee: str
    scope: frozenset
    parent_hash: Optional[str]
    timestamp: int
    signature_valid: bool
    receipt_hash: str


@dataclass(frozen=True)
class RevocationWitness:
    delegator: str
    scope: frozenset
    effective_at: int
    signed: bool


def verify_chain(
    chain: Sequence[Receipt],
    witnesses: Sequence[RevocationWitness],
) -> str:
    # Phase 1: structural verification (necessary, not sufficient).
    for i, r in enumerate(chain):
        if not r.signature_valid:
            raise StructuralVerificationError(f"hop {i}: bad signature")
        if i > 0:
            if r.parent_hash != chain[i - 1].receipt_hash:
                raise StructuralVerificationError(f"hop {i}: parent hash mismatch")
            if not r.scope <= chain[i - 1].scope:
                raise StructuralVerificationError(f"hop {i}: scope escalation")
            if r.timestamp <= chain[i - 1].timestamp:
                raise StructuralVerificationError(f"hop {i}: non-monotonic timestamp")

    # Phase 2: temporal authorization verification (the boundary).
    for i in range(1, len(chain)):
        parent, child = chain[i - 1], chain[i]
        covering = [
            w for w in witnesses
            if w.delegator == parent.delegator
            and w.signed
            and w.effective_at <= child.timestamp
        ]
        # A revocation effective at or before the child's signing instant
        # that removes any scope the child exercised is a hard failure.
        for w in covering:
            if w.scope & child.scope:
                raise UnverifiedAuthorizationError(
                    f"hop {i}: scope {set(w.scope & child.scope)} revoked at "
                    f"{w.effective_at}, child signed at {child.timestamp}"
                )
        # No revocation witness and no signed liveness attestation:
        # the hop is evidentially open, not valid.
        if not covering:
            raise UnverifiedAuthorizationError(
                f"hop {i}: no revocation witness for delegator "
                f"{parent.delegator!r} covering [{parent.timestamp}, "
                f"{child.timestamp}]; authorization unverified"
            )
    return "VALID"
