# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-does-a-memoization-key-on-object-identity-return-a-stale-or-missed-result.md
# Remnant Warrant:    https://corpusfetch.com/c/when-does-a-memoization-key-on-object-identity-return-a-stale-or-missed-result.warrant.json
# Markdown SHA-256:   5b622af4d8b92592007e8cd40a35b1f1d2a1e2be3cc9a8fac7957dd908f59774
# Code AST SHA-256:   2ef5f94c5f616df50c56ab23364c9b2f68efc5b2d8e41f0ac1de6a760667332f
# Verified Classes:   MemoKeyError, MemoKeyGate
# Defensive Guards:   3 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class MemoKeyError(RuntimeError):
    """Raised when a memoization key does not uniquely determine the function's result."""


@dataclass(frozen=True)
class MemoKeyGate:
    key_basis: str  # "immutable-value", "identity", "mutable-value"
    keyed_object_immutable: bool

    def verify(self) -> bool:
        if self.key_basis == "immutable-value":
            return True
        if self.key_basis == "identity" and self.keyed_object_immutable:
            return True
        if self.key_basis == "identity":
            raise MemoKeyError("identity key on mutable object yields stale hits")
        if self.key_basis == "mutable-value":
            raise MemoKeyError("value key over mutable state orphans entries and can corrupt index")
        raise MemoKeyError(f"unknown key basis {self.key_basis!r}")


def dispatch_cache_mode(gate: MemoKeyGate) -> str:
    try:
        gate.verify()
    except MemoKeyError:
        return "recompute-or-freeze"
    return "memoize"
