# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-refuse-a-federated-trust-anchor-update-the-epoch-skew-signature-replay-boundary.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-refuse-a-federated-trust-anchor-update-the-epoch-skew-signature-replay-boundary.warrant.json
# Markdown SHA-256:   df9af4d9b7b54af64facc7e79da55dd65a9f42138b2b88b00a714d9c12d4f1a2
# Code AST SHA-256:   2a2b588e5361d6f05b4a5f82b2773976fcc3b90129d257b6e2ad4301b4ab494b
# Verified Classes:   TrustEpochViolation, AnchorDoc, IssuerState, FederationTrustStore
# Defensive Guards:   4 fail-closed invariants (zero external deps)

import time
from dataclasses import dataclass, field
from typing import Dict, Optional


class TrustEpochViolation(RuntimeError):
    """Raised when a federated trust-anchor document cannot be placed
    on the receiver's per-issuer epoch chain without ambiguity."""


@dataclass
class AnchorDoc:
    issuer: str
    epoch: int
    prev_root_digest: str
    root_digest: str
    signature: bytes
    issued_at: float


@dataclass
class IssuerState:
    watermark: int = 0
    root_digest: Optional[str] = None
    reconcile_pending: bool = False
    reconcile_deadline: float = 0.0


class FederationTrustStore:
    def __init__(self, skew_bound_s: float = 30.0) -> None:
        self._state: Dict[str, IssuerState] = {}
        self._skew_bound = skew_bound_s

    def _get(self, issuer: str) -> IssuerState:
        if issuer not in self._state:
            # Cold start: no watermark. Caller must have provisioned out of band.
            raise TrustEpochViolation(
                f"no provisioned trust anchor for issuer {issuer!r}; "
                "cannot bootstrap from an inbound document"
            )
        return self._state[issuer]

    def evaluate(self, doc: AnchorDoc, now: Optional[float] = None) -> str:
        now = time.time() if now is None else now
        st = self._get(doc.issuer)

        if now - doc.issued_at > self._skew_bound:
            # Document too old to be trusted as current; could be a slow replay.
            raise TrustEpochViolation(
                f"anchor for {doc.issuer!r} epoch {doc.epoch} is "
                f"{now - doc.issued_at:.1f}s old, exceeds skew bound "
                f"{self._skew_bound}s"
            )

        if doc.epoch <= st.watermark:
            return "reject_replay"

        if doc.prev_root_digest != st.root_digest:
            # Fork or forged chain: never pick a branch silently.
            raise TrustEpochViolation(
                f"chain fork for {doc.issuer!r}: incoming prev_root "
                f"{doc.prev_root_digest!r} != cached root {st.root_digest!r} "
                f"at watermark {st.watermark}"
            )

        gap = doc.epoch - st.watermark
        if gap == 1:
            st.watermark = doc.epoch
            st.root_digest = doc.root_digest
            st.reconcile_pending = False
            return "accept"

        # gap > 1: ambiguous zone. Do NOT accept, do NOT silently drop.
        if not st.reconcile_pending:
            st.reconcile_pending = True
            st.reconcile_deadline = now + self._skew_bound
        elif now > st.reconcile_deadline:
            raise TrustEpochViolation(
                f"reconcile deadline exceeded for {doc.issuer!r}: "
                f"watermark {st.watermark}, incoming epoch {doc.epoch}, "
                f"cannot verify intermediate chain"
            )
        return "defer_reconcile"
