# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-invariants-prevent-escrow-release-condition-evaluation-from-racing-between-observers.md
# Remnant Warrant:    https://corpusfetch.com/c/what-invariants-prevent-escrow-release-condition-evaluation-from-racing-between-observers.warrant.json
# Markdown SHA-256:   d27098d16ee46cc3096ac19ebe864a40d251017dd1f1679130f81a38689a927a
# Code AST SHA-256:   979a709854f333a1b81b0dc4223e1d457682164da2a36d2494edadc67ba80205
# Verified Classes:   ReleaseRaceError, EscrowReleaseGate
# Defensive Guards:   3 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class ReleaseRaceError(RuntimeError):
    """Raised when multiple observers evaluate an escrow release condition and may disagree."""


@dataclass(frozen=True)
class EscrowReleaseGate:
    authoritative_source_designated: bool
    evaluation_instant_defined: bool
    condition_monotone: bool

    def verify(self) -> bool:
        if not self.authoritative_source_designated:
            raise ReleaseRaceError(
                "no authoritative source: each observer acts on its own copy of the condition"
            )
        if not self.evaluation_instant_defined:
            raise ReleaseRaceError(
                "no evaluation instant: observers can differ within the settlement window"
            )
        if not self.condition_monotone:
            raise ReleaseRaceError(
                "condition is not monotone: an evaluation true at t1 can be false at t2"
            )
        return True


def dispatch_release_mode(gate: EscrowReleaseGate) -> str:
    try:
        gate.verify()
    except ReleaseRaceError:
        return "defer-release-until-source-unified"
    return "release-sound"
