# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-happens-when-an-instance-tombstones-a-memory-key-while-a-concurrent-reader-holds-a-stale-snapshot-under-scoped-retention-ttl-eviction.md
# Remnant Warrant:    https://corpusfetch.com/c/what-happens-when-an-instance-tombstones-a-memory-key-while-a-concurrent-reader-holds-a-stale-snapshot-under-scoped-retention-ttl-eviction.warrant.json
# Markdown SHA-256:   1a35e8ce366b95d9321436c4861d3361e020925dbb3ae1c086bf04d166af080d
# Code AST SHA-256:   38862f9dc317cb67440cada5cdf81e90ef1ac6fc4d0e68b6e262c25fff45fb48
# Verified Classes:   ForgottenKeyLeakError, ExpiredSnapshotError
# Defensive Guards:   5 fail-closed invariants (zero external deps)

class ForgottenKeyLeakError(RuntimeError):
    """Raised when a read would serve a value subject to a right-to-forget tombstone."""
    pass


class ExpiredSnapshotError(RuntimeError):
    """Raised when a snapshot is older than the key's TTL boundary (liveness, not safety)."""
    pass


FORGOTTEN = "FORGOTTEN"
EXPIRED = "EXPIRED"
LIVE = "LIVE"


def read_memory(store, scope, key, snapshot):
    """
    Read a key from a snapshot, enforcing the RTF invariant.

    store: object exposing state(scope, key) -> (state, tombstone_epoch)
    snapshot: object exposing value, snapshot_epoch, ttl_deadline
    """
    state, tombstone_epoch = store.state(scope, key)

    # RTF safety: a snapshot taken before the tombstone must never be served,
    # regardless of how fresh the snapshot is.
    if state == FORGOTTEN and snapshot.snapshot_epoch < tombstone_epoch:
        raise ForgottenKeyLeakError(
            f"refusing read of forgotten key scope={scope!r} key={key!r}: "
            f"snapshot_epoch={snapshot.snapshot_epoch} < tombstone_epoch={tombstone_epoch}"
        )

    if state == FORGOTTEN:
        # Snapshot was taken at or after the tombstone: the key is gone for this
        # reader too. Treat as absent, never as a cache hit.
        raise ForgottenKeyLeakError(
            f"refusing read of forgotten key scope={scope!r} key={key!r}: tombstoned"
        )

    if state == EXPIRED:
        # TTL eviction is a liveness boundary, not a safety one. A snapshot taken
        # within the window is still legal; one taken after the deadline is not.
        if snapshot.snapshot_epoch >= tombstone_epoch and snapshot.ttl_deadline >= store.now():
            return snapshot.value
        raise ExpiredSnapshotError(
            f"snapshot for scope={scope!r} key={key!r} is past TTL and must be re-resolved"
        )

    return snapshot.value


def forget_memory(store, scope, key, reason):
    """
    Apply a right-to-forget tombstone and return only after it is EFFECTIVE.
    Returns 'EFFECTIVE'; raises if the tombstone could not be made durable.
    """
    if not reason:
        raise ForgottenKeyLeakError(
            f"forget of scope={scope!r} key={key!r} requires an auditable reason"
        )
    result = store.apply_tombstone(scope, key, reason=reason, synchronous=True)
    if result.status != "EFFECTIVE":
        raise ForgottenKeyLeakError(
            f"forget of scope={scope!r} key={key!r} returned {result.status!r}, "
            f"not EFFECTIVE; RTF guarantee is not satisfied"
        )
    return "EFFECTIVE"
