# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-structural-signals-indicate-that-a-provenance-tracked-forget-operation-has-not-actually-severed-the-derived-memory-edge.md
# Remnant Warrant:    https://corpusfetch.com/c/what-structural-signals-indicate-that-a-provenance-tracked-forget-operation-has-not-actually-severed-the-derived-memory-edge.warrant.json
# Markdown SHA-256:   58e017bffbdee055b70068908ac0da7ea91e5bb9d16b4710027ada6313d7faad
# Code AST SHA-256:   ea5c56ec04a5145712d36cac4eb4b89f304ed906167afb49e8910ea4e74916be
# Verified Classes:   IncompleteErasureError
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class IncompleteErasureError(RuntimeError):
    """Raised when a forget operation reports success but content remains recoverable."""
    pass


def verify_forget(memory, erased_id: str) -> None:
    """Post-forget reconstruction probe. Raises if any access path recovers content."""
    # 1. Any surviving record with a dangling edge to erased_id => failure.
    for rec in memory.scan_provenance_refs(erased_id):
        if rec.provenance_resolved is False:
            raise IncompleteErasureError(
                f"dangling provenance to {erased_id} on record {rec.id}; "
                f"content still served via read()"
            )

    # 2. Transitive descendants must be gone or tombstoned.
    for desc in memory.descendants_of(erased_id):
        payload = memory.read(desc.id)
        if payload is not None and payload.get("tombstone") is not True:
            raise IncompleteErasureError(
                f"derived record {desc.id} survives forget of {erased_id}"
            )

    # 3. Vector index must not return the erased record for its own vector.
    hits = memory.vector_query(memory.vector_of(erased_id), k=1)
    if hits and hits[0].id == erased_id:
        raise IncompleteErasureError(
            f"embedding for {erased_id} still recoverable via vector index"
        )


def forget_or_escalate(memory, record_id: str) -> dict:
    memory.forget(record_id)
    try:
        verify_forget(memory, record_id)
    except IncompleteErasureError as exc:
        # Do not downgrade to a warning: an unproven erase is a pending erase.
        raise IncompleteErasureError(
            f"forget({record_id}) reported ok but failed verification: {exc}"
        ) from exc
    return {"status": "erased", "record_id": record_id, "verified": True}
