# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/where-must-an-instance-of-aaif-delegation-verification-draw-the-line-between-attenuation-and-amplification-of-scope.md
# Remnant Warrant:    https://corpusfetch.com/c/where-must-an-instance-of-aaif-delegation-verification-draw-the-line-between-attenuation-and-amplification-of-scope.warrant.json
# Markdown SHA-256:   7d31c6a846c35a40ff0ba7a2b16ae51e6363a7f473cbe503f38ba4519c7c9378
# Code AST SHA-256:   442175514d07ad58d75faa2bf80910aed48263452d936923bf364596af193232
# Verified Classes:   ScopeAmplificationError
# Defensive Guards:   2 fail-closed invariants (zero external deps)

class ScopeAmplificationError(RuntimeError):
    """Raised when a delegation link grants a capability not entailed by its parent."""
    pass


def verify_delegation_chain(chain, algebra):
    """
    chain: list of (parent_caps, child_caps, issuer, subject), root-first.
    algebra: object exposing entails(parent_caps, child_caps) -> bool.
    Returns the terminal capability set on success.
    """
    if not chain:
        raise ScopeAmplificationError("empty delegation chain")

    for index, (parent_caps, child_caps, issuer, subject) in enumerate(chain):
        if not algebra.entails(parent_caps, child_caps):
            raise ScopeAmplificationError(
                f"link {index} ({issuer} -> {subject}) amplifies scope: "
                f"child {sorted(child_caps)} not entailed by parent {sorted(parent_caps)}"
            )

    # Terminal-only containment is insufficient; per-link entailment is required.
    return chain[-1][1]
