# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/why-does-an-instance-of-a-federated-agent-fail-authorization-after-its-home-trust-registry-rotates-a-did-document-s-verification-method-but-the-peer-s.md
# Remnant Warrant:    https://corpusfetch.com/c/why-does-an-instance-of-a-federated-agent-fail-authorization-after-its-home-trust-registry-rotates-a-did-document-s-verification-method-but-the-peer-s.warrant.json
# Markdown SHA-256:   636a960490363dd11ff2e527603b6b1a745382c6a73977e1084735f2c8d238c5
# Code AST SHA-256:   db1c14afeb962f785d3788fa026e5cabc92baa1bb4d287429b8ef8e23f41acca
# Verified Classes:   KeyRetiredError, KeySubstitutedError
# Defensive Guards:   2 fail-closed invariants (zero external deps)

class KeyRetiredError(RuntimeError):
    """Raised when a credential's signing key is absent from the issuer's current DID document."""
    pass


class KeySubstitutedError(RuntimeError):
    """Raised when the DID document's key material differs from the key that signed the credential."""
    pass


def authorize_federated_credential(credential, did_document, status_list) -> bool:
    fragment = credential.proof.verification_method  # e.g. "did:web:issuer#key-1"

    if status_list.is_revoked(credential.id):
        return False  # ordinary revocation, single-channel

    method = did_document.find_verification_method(fragment)
    if method is None:
        # Status list said "not revoked", but the signing key is no longer
        # authorized. This is soft revocation via rotation; never retry.
        raise KeyRetiredError(
            f"verification method {fragment} absent from current DID document; "
            f"credential {credential.id} was retired by key rotation, not revocation"
        )

    if method.public_key_multibase != credential.proof.verification_key_multibase:
        raise KeySubstitutedError(
            f"key material for {fragment} changed; possible compromise of {credential.issuer}"
        )

    return True
