# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/why-does-an-instance-forget-a-memory-it-successfully-wrote-distinguishing-tombstone-committed-forgetting-from-write-side-eviction-in-read-write-forget.md
# Remnant Warrant:    https://corpusfetch.com/c/why-does-an-instance-forget-a-memory-it-successfully-wrote-distinguishing-tombstone-committed-forgetting-from-write-side-eviction-in-read-write-forget.warrant.json
# Markdown SHA-256:   bfe2b60086cbc92a637816fcf47c0d5b045c2963e1951a64cbea8f2905ac399e
# Code AST SHA-256:   d1ac0abb885b36be8008391f50cfdaea5b202aa68118ec7577de17bde84c4058
# Verified Classes:   HalfReclaimedSlotError
# Defensive Guards:   1 fail-closed invariants (zero external deps)

class HalfReclaimedSlotError(RuntimeError):
    """Raised when a write targets a slot whose value record was reclaimed
    by tombstone-watermark GC but whose retention record (version/tombstone)
    still survives. Re-writing here risks a second reclamation."""
    pass


def safe_rewrite(memory, key, value, *, clear_tombstone=False):
    """
    Guard a write-after-forget against the half-reclaimed-slot boundary.

    memory must expose:
      read(key)          -> {'status': 'OK'|'NOT_FOUND', 'value': ...}
      probe(key)         -> {'value_present': bool, 'retention_present': bool,
                             'version': int|None, 'tombstone_seq': int|None}
      write(key, value, *, clear_tombstone: bool, expected_version: int|None)
    """
    probe = memory.probe(key)
    value_present = probe["value_present"]
    retention_present = probe["retention_present"]

    if value_present:
        # Normal overwrite path; no tombstone involved.
        return memory.write(key, value, clear_tombstone=False,
                            expected_version=probe["version"])

    if retention_present and not clear_tombstone:
        # Half-reclaimed slot: value gone, tombstone/version survives.
        # A plain write would land on a slot still governed by an old
        # tombstone_seq and could be swept by the next GC watermark pass.
        raise HalfReclaimedSlotError(
            f"key={key!r} has surviving retention record "
            f"(version={probe['version']}, tombstone_seq={probe['tombstone_seq']}) "
            f"but no value record. A plain re-write is unsafe; pass "
            f"clear_tombstone=True (or migrate to a new key) to supersede "
            f"the tombstone generation before writing."
        )

    if retention_present and clear_tombstone:
        # Explicit undelete: bump generation above the GC watermark.
        return memory.write(key, value, clear_tombstone=True,
                            expected_version=probe["version"])

    # Fully absent: both records gone, safe fresh write.
    return memory.write(key, value, clear_tombstone=False, expected_version=None)
