# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-refuse-to-merge-a-byzantine-replicated-memory-shard-the-quorum-certificate-freshness-invariant-and-the-silent-equivocation-windo.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-refuse-to-merge-a-byzantine-replicated-memory-shard-the-quorum-certificate-freshness-invariant-and-the-silent-equivocation-windo.warrant.json
# Markdown SHA-256:   c18efdd27636f35c431c828689e1fc68fbebcb2c6da34334f1fccf65da4e742a
# Code AST SHA-256:   9db8b72b61dde87772e871f48bb4d6e64064cced5424d1a5a90f8d07853ed79a
# Verified Classes:   StaleCertificateError, FenceEpochMismatchError, UnprovableFreshnessError, Frontier, Certificate
# Defensive Guards:   6 fail-closed invariants (zero external deps)

from __future__ import annotations

from dataclasses import dataclass, field


class StaleCertificateError(RuntimeError):
    """Certificate is behind the local frontier. Recoverable by frontier resync."""


class FenceEpochMismatchError(RuntimeError):
    """Certificate disagrees with local fence epoch for a writer. Safety violation."""


class UnprovableFreshnessError(RuntimeError):
    """Certificate lacks fence_epoch map while local shard has fenced writers."""


@dataclass(frozen=True)
class Frontier:
    view: int
    counters: dict[str, int]
    fenced_set: frozenset[str]
    fence_epoch: dict[str, int]


@dataclass(frozen=True)
class Certificate:
    view: int
    counters: dict[str, int]
    signers: frozenset[str]
    fence_epoch: dict[str, int] | None = None
    active_set: frozenset[str] = field(default_factory=frozenset)


def gate_merge(cert: Certificate, frontier: Frontier, quorum_size: int) -> None:
    if len(cert.signers) < quorum_size:
        raise StaleCertificateError(
            f"certificate has {len(cert.signers)} signers, need {quorum_size}"
        )

    if cert.view < frontier.view:
        raise StaleCertificateError(
            f"cert view {cert.view} < frontier view {frontier.view}"
        )

    for writer, local_ctr in frontier.counters.items():
        if cert.counters.get(writer, -1) < local_ctr:
            raise StaleCertificateError(
                f"writer {writer}: cert counter {cert.counters.get(writer)} "
                f"< frontier {local_ctr}"
            )

    if cert.fence_epoch is None:
        if frontier.fenced_set:
            raise UnprovableFreshnessError(
                f"certificate omits fence_epoch but shard has fenced writers "
                f"{sorted(frontier.fenced_set)}"
            )
        return

    for writer in frontier.fenced_set:
        if writer in cert.active_set:
            raise FenceEpochMismatchError(
                f"fenced writer {writer} appears active in certificate view {cert.view}"
            )
        if cert.fence_epoch.get(writer) != frontier.fence_epoch.get(writer):
            raise FenceEpochMismatchError(
                f"writer {writer}: cert epoch {cert.fence_epoch.get(writer)} "
                f"!= local epoch {frontier.fence_epoch.get(writer)}"
            )
