# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-structural-signals-indicate-an-erasure-vs-ttl-race-in-scoped-memory-tool-apis.md
# Remnant Warrant:    https://corpusfetch.com/c/what-structural-signals-indicate-an-erasure-vs-ttl-race-in-scoped-memory-tool-apis.warrant.json
# Markdown SHA-256:   f42bc911de40dcf344df679f9e81a81ea638ebd8e0cb064db462aedb4f14ada2
# Code AST SHA-256:   10a314150541b36628f665508c5ffef07acfdf96b78740040344c5f64863e119
# Verified Classes:   ErasureCascadeIncompleteError
# Defensive Guards:   1 fail-closed invariants (zero external deps)

class ErasureCascadeIncompleteError(RuntimeError):
    """Raised when a forget request cannot prove derived-store cascade ran."""
    pass


DERIVED_STORES = ("embedding_cache", "inverted_index", "scope_replica")


def forget(scope: str, key: str, store, watermark: dict) -> dict:
    tombstone = store.get_tombstone(scope, key)
    target_seq = store.current_sequence()

    # Replay of an already-completed erasure: safe to short-circuit.
    if tombstone and tombstone["reason"] == "erasure" and watermark.get((scope, key), -1) >= tombstone["seq"]:
        return {"status": "erased", "replayed": True}

    # Absent-in-primary is a cascade trigger, never terminal success.
    if tombstone is None and not store.has_live(scope, key):
        reason = "absent"
    elif tombstone and tombstone["reason"] == "ttl_expiry":
        reason = "ttl_expired"
    else:
        reason = "live"

    cascaded, skipped = [], []
    for derived in DERIVED_STORES:
        backend = store.derived(derived)
        if backend is None or not backend.registered(scope, key):
            raise ErasureCascadeIncompleteError(
                f"derived store {derived!r} cannot be enumerated for ({scope},{key}); "
                f"erasure obligation unsatisfiable, reason={reason}"
            )
        if backend.contains(scope, key):
            backend.purge(scope, key)
            cascaded.append(derived)
        else:
            skipped.append(derived)

    watermark[(scope, key)] = target_seq
    return {"status": "erased", "reason": reason, "cascaded": cascaded, "skipped": skipped}
