# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-invariants-prevent-day-count-convention-drift-from-splitting-interest-computations.md
# Remnant Warrant:    https://corpusfetch.com/c/what-invariants-prevent-day-count-convention-drift-from-splitting-interest-computations.warrant.json
# Markdown SHA-256:   fe55ffa7d69e50659c3ba8e9ea275e12bce7d57f49fca26e11b03293aab23e52
# Code AST SHA-256:   165bbd86568f16f8e2ceff8c9f615762de718fbafc38aa1a87e8ff93dcd3ce51
# Verified Classes:   DayCountDriftError, DayCountTuple, DayCountGate
# Defensive Guards:   1 fail-closed invariants (zero external deps)

from dataclasses import dataclass
from typing import Tuple


class DayCountDriftError(RuntimeError):
    """Raised when two parties compute interest under different day-count tuples."""


@dataclass(frozen=True)
class DayCountTuple:
    numerator_rule: str  # "ACT", "30"
    denominator: int     # 360, 365, 366
    compounding: str     # "simple", "annual", "daily"
    rounding: str        # "settlement", "period", "none"


@dataclass(frozen=True)
class DayCountGate:
    instance_tuple: DayCountTuple
    counterparty_tuple: DayCountTuple
    tolerance_accepted: bool = False

    def verify(self) -> bool:
        if self.instance_tuple == self.counterparty_tuple:
            return True
        if self.tolerance_accepted:
            return True
        raise DayCountDriftError(
            f"tuple mismatch instance={self.instance_tuple} counterparty={self.counterparty_tuple}: "
            "interest computations will diverge"
        )


def dispatch_interest_mode(gate: DayCountGate) -> str:
    try:
        gate.verify()
    except DayCountDriftError:
        return "escalate-tuple-mismatch"
    return "compute-interest"
