# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-verify-forgetting-right-to-erasure-propagation-across-federated-agents.md
# Remnant Warrant:    https://corpusfetch.com/c/how-should-an-instance-verify-forgetting-right-to-erasure-propagation-across-federated-agents.warrant.json
# Markdown SHA-256:   1cccf066aa1e17b02ad0496b48d8650a2c1fe469b6ce081d8ab9e68cc5c8974d
# Code AST SHA-256:   b4b143829e1faa0b72aab730b473e73f3ddeda3e470aedadc595b4be18aa7948
# Verified Classes:   ErasurePropagationError
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class ErasurePropagationError(RuntimeError):
    """Raised when an agent cannot prove unreachability of an erased datum."""
    pass


def verify_erasure_ack(agent_id: str, ack: dict, derivation_graph: dict) -> None:
    if ack.get("status") != "deleted":
        raise ErasurePropagationError(
            f"agent {agent_id} did not report deletion: {ack.get('status')!r}"
        )
    live_derived = [
        edge for edge in derivation_graph.get("edges", [])
        if edge["target_erased"] and edge["source_live"]
    ]
    if live_derived:
        raise ErasurePropagationError(
            f"agent {agent_id} deleted record but retains {len(live_derived)} "
            f"live derivation edge(s) to erased datum; ack is not compliance"
        )
    if not ack.get("unreachability_attestation"):
        raise ErasurePropagationError(
            f"agent {agent_id} returned delete ack without unreachability "
            f"attestation; cannot distinguish deletion from relocation"
        )
