# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-reject-a-delegated-capability-token-despite-a-cryptographically-valid-aaif-delegation-chain.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-reject-a-delegated-capability-token-despite-a-cryptographically-valid-aaif-delegation-chain.warrant.json
# Markdown SHA-256:   959a268cddae25a901f31e44e918bdfeba71b9f14922c1beb089d2972c7c34aa
# Code AST SHA-256:   5b642828b19a01fcfa1cc9521105e03812d7d6b1fcd1d64a5569559a0db997aa
# Verified Classes:   DelegationAttenuationError
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class DelegationAttenuationError(RuntimeError):
    """Raised when a delegation chain widens authority on any claim dimension."""
    pass


def validate_chain(chain: list[dict]) -> None:
    """
    chain[0] is the root attestation; chain[-1] is the leaf presented to the
    resource server. Each link: {"issuer": str, "claims": dict, "can_delegate": bool}
    """
    if not chain:
        raise DelegationAttenuationError("empty delegation chain")

    # Pass 1: union of all claim dimensions anywhere in the chain.
    dimensions = set()
    for link in chain:
        dimensions.update(link["claims"].keys())

    # Pass 2: every dimension must be present and monotonically narrowed.
    for dim in dimensions:
        ancestor_value = None
        for idx, link in enumerate(chain):
            claims = link["claims"]
            if dim not in claims:
                # Absence in a descendant is a widening (elision). Fail closed.
                if idx > 0:
                    raise DelegationAttenuationError(
                        f"dimension '{dim}' elided at link {idx} "
                        f"(issuer={link['issuer']}); attenuation widened"
                    )
                continue
            value = claims[dim]
            if ancestor_value is not None and not _is_subset(value, ancestor_value):
                raise DelegationAttenuationError(
                    f"dimension '{dim}' widened at link {idx} "
                    f"(issuer={link['issuer']}): {value!r} not within {ancestor_value!r}"
                )
            ancestor_value = value

    # Re-delegation rights must be explicit on every non-leaf link.
    for idx, link in enumerate(chain[:-1]):
        if not link.get("can_delegate", False):
            raise DelegationAttenuationError(
                f"link {idx} (issuer={link['issuer']}) lacks can_delegate "
                f"but a further link exists"
            )


def _is_subset(child, parent) -> bool:
    if isinstance(child, (set, frozenset)) and isinstance(parent, (set, frozenset)):
        return child.issubset(parent)
    if isinstance(child, list) and isinstance(parent, list):
        return set(child).issubset(set(parent))
    if isinstance(parent, (set, frozenset, list)):
        return child in parent
    return child == parent
