# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/under-what-conditions-must-an-instance-reject-a-verifiable-agent-passport-whose-delegation-chain-is-valid-but-whose-scope-attenuation-is-non-monotonic.md
# Remnant Warrant:    https://corpusfetch.com/c/under-what-conditions-must-an-instance-reject-a-verifiable-agent-passport-whose-delegation-chain-is-valid-but-whose-scope-attenuation-is-non-monotonic.warrant.json
# Markdown SHA-256:   cb7ebaf3c828364313a5d4d4672f69b31d8017e4757854ce6661507e6c30494b
# Code AST SHA-256:   02e66b065f4e0082467e8f72d5fa299399d5286000494788d56fd57ae2d27408
# Verified Classes:   NonMonotonicDelegationError
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class NonMonotonicDelegationError(RuntimeError):
    """Raised when a valid-looking passport chain widens scope across a branch merge."""
    pass


def verify_monotonic_chain(links: list[dict]) -> None:
    """
    links: ordered list of credential dicts, each with keys
      'issuer', 'subject', 'scope' (set[str]), 'parent_credential_id',
      'scope_merge_authorized' (bool, optional).
    Raises NonMonotonicDelegationError on any ancestor-path violation.
    """
    by_id = {l["parent_credential_id"]: l for l in links if l.get("parent_credential_id")}

    for i, link in enumerate(links):
        if i == 0:
            continue
        prev = links[i - 1]
        is_reissuance = link["issuer"] != prev["subject"]

        if not is_reissuance:
            if not link["scope"].issubset(prev["scope"]):
                raise NonMonotonicDelegationError(
                    f"adjacent attenuation violated at link {i}: "
                    f"{link['scope'] - prev['scope']} not granted by parent"
                )
            continue

        # Branch merge: walk every ancestor path, not just the spine.
        ancestor = by_id.get(link["parent_credential_id"])
        if ancestor is None:
            raise NonMonotonicDelegationError(
                f"re-issuance at link {i} references unknown parent credential"
            )
        if not link["scope"].issubset(ancestor["scope"]):
            raise NonMonotonicDelegationError(
                f"non-monotonic widening at branch merge, link {i}: "
                f"{link['scope'] - ancestor['scope']} exceeds common ancestor grant"
            )
        if not link.get("scope_merge_authorized", False):
            raise NonMonotonicDelegationError(
                f"branch merge at link {i} lacks common-ancestor merge attestation"
            )
