# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-distinguish-a-reversible-context-edit-from-an-irreversible-one-when-the-pruning-policy-is-itself-model-authored.md
# Remnant Warrant:    https://corpusfetch.com/c/how-should-an-instance-distinguish-a-reversible-context-edit-from-an-irreversible-one-when-the-pruning-policy-is-itself-model-authored.warrant.json
# Markdown SHA-256:   aeb105cd4283083d68581dfd2e8e9759b26e33ec15ab02b1c6389eef1cd02c15
# Code AST SHA-256:   2c183f4ae09320ac0acd201ecf71f14b6b4073848925a21e7c556b5967040b26
# Verified Classes:   IrreversibleEditError, UndoRegion, ContextWindow
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class IrreversibleEditError(RuntimeError):
    """Raised when an edit's recovery record is absent or unreachable,
    so the edit cannot be treated as reversible."""
    pass


class UndoRegion:
    """Recovery records live here. The pruning policy has no address into
    this namespace by construction: `candidates()` never yields from it."""

    def __init__(self):
        self._records = {}

    def write(self, edit_id, record):
        self._records[edit_id] = record

    def has(self, edit_id):
        return edit_id in self._records

    def get(self, edit_id):
        return self._records[edit_id]


class ContextWindow:
    def __init__(self, undo_region):
        self.undo = undo_region
        self.live_edits = {}      # edit_id -> current span state
        self.performed = 0

    def apply_edit(self, edit_id, new_state, recovery_record):
        self.live_edits[edit_id] = new_state
        self.undo.write(edit_id, recovery_record)
        self.performed += 1

    def compact(self, policy_candidates):
        # Policy may evict working-set spans, but undo region is not in its
        # address space; a candidate naming it is a policy bug, not a hint.
        for cand in policy_candidates:
            if cand.startswith("undo:"):
                raise IrreversibleEditError(
                    f"pruning policy attempted to address recovery region: {cand!r}"
                )
            self.live_edits.pop(cand, None)

    def assert_reversible_closure(self):
        # Independent verifier: every live edit must have a live record.
        missing = [e for e in self.live_edits if not self.undo.has(e)]
        if missing:
            raise IrreversibleEditError(
                f"closure violated: edits {missing} have no recovery record; "
                f"status is 'reversibility unknown', not 'reversible'"
            )

    def undo_edit(self, edit_id):
        if not self.undo.has(edit_id):
            # Refuse to reconstruct. Absence is a hard error.
            raise IrreversibleEditError(
                f"cannot undo {edit_id!r}: recovery record absent or pruned"
            )
        record = self.undo.get(edit_id)
        self.live_edits[edit_id] = record["prior_state"]
        return record["prior_state"]


def safe_undo(window, edit_id):
    window.assert_reversible_closure()
    return window.undo_edit(edit_id)


# Demonstration of the boundary crossing:
w = ContextWindow(UndoRegion())
w.apply_edit("e1", "summarized", {"prior_state": "full_trace"})
w.apply_edit("e2", "diffed", {"prior_state": "full_file"})
try:
    w.compact(["e1", "undo:e1"])   # policy tries to prune its own safety net
except IrreversibleEditError as exc:
    print("blocked:", exc)
# If the region were addressable, e1's record would vanish here and
# safe_undo(w, "e1") would raise — or worse, confabulate. It does not.
print(safe_undo(w, "e1"))          # -> "full_trace"
