# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/where-must-an-instance-of-a-delegated-capability-refuse-to-act-when-its-provenance-chain-is-valid-but-its-revocation-set-is-only-partially-visible.md
# Remnant Warrant:    https://corpusfetch.com/c/where-must-an-instance-of-a-delegated-capability-refuse-to-act-when-its-provenance-chain-is-valid-but-its-revocation-set-is-only-partially-visible.warrant.json
# Markdown SHA-256:   5337ae63f725322ec5163c23299e3c9479834ea84746084ca2d4414231b2fd8f
# Code AST SHA-256:   e1ce27ed794775fb1368a780910e9e72b0d9aa3ec41b5304a3ca30871cef1aeb
# Verified Classes:   DelegationRefused, Link, RevocationView
# Defensive Guards:   6 fail-closed invariants (zero external deps)

import time
from dataclasses import dataclass


class DelegationRefused(RuntimeError):
    """Raised when provenance is valid but revocation knowledge is insufficient."""
    pass


@dataclass(frozen=True)
class Link:
    issuer: str
    subject: str
    remaining_ttl_s: float
    signature_valid: bool


@dataclass(frozen=True)
class RevocationView:
    issuer: str
    staleness_bound_s: float   # max age of this view
    ancestor_closed: bool      # does it reflect ancestor-issued revocations?
    revoked: bool


def authorize_action(
    chain: list[Link],
    views: dict[str, RevocationView],
    action_reversible: bool,
    freshness_margin_s: float = 30.0,
) -> None:
    # Clause 1: provenance validity (the cheap, offline half).
    for link in chain:
        if not link.signature_valid:
            raise DelegationRefused(
                f"broken signature at hop {link.issuer}->{link.subject}"
            )

    # Clause 2: ancestor-closed coverage (the silent half).
    for link in chain:
        view = views.get(link.issuer)
        if view is None:
            raise DelegationRefused(
                f"no revocation view for issuer {link.issuer}; "
                "cannot confirm ancestor coverage"
            )
        if not view.ancestor_closed:
            raise DelegationRefused(
                f"revocation view for {link.issuer} is not ancestor-closed; "
                "ancestor revocations are invisible"
            )

    # Clause 3: freshness must dominate remaining TTL (the time half).
    min_ttl = min(link.remaining_ttl_s for link in chain)
    max_staleness = max(view.staleness_bound_s for view in views.values())
    if max_staleness + freshness_margin_s >= min_ttl:
        raise DelegationRefused(
            f"revocation staleness {max_staleness:.0f}s + margin "
            f"{freshness_margin_s:.0f}s >= min remaining TTL {min_ttl:.0f}s; "
            "authority could lapse before revocation is observable"
        )

    # Positive revocation always wins, regardless of the above.
    for issuer, view in views.items():
        if view.revoked:
            raise DelegationRefused(f"capability revoked at issuer {issuer}")

    # Irreversible actions demand extra margin; refuse if thin.
    if not action_reversible and (min_ttl - max_staleness) < 2 * freshness_margin_s:
        raise DelegationRefused(
            "irreversible action with thin freshness margin; fail closed"
        )

    # All three clauses satisfied: action is authorized.
    return None


def execute_delegated(chain, views, action_reversible):
    try:
        authorize_action(chain, views, action_reversible)
    except DelegationRefused as exc:
        # Loud, bounded refusal instead of silent privilege leak.
        return {"status": "refused", "reason": str(exc), "at": time.time()}
    return {"status": "executed", "at": time.time()}
