# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-distinguishes-compounding-fee-bases-when-fee-cascades-are-percentage-of-percentage.md
# Remnant Warrant:    https://corpusfetch.com/c/what-distinguishes-compounding-fee-bases-when-fee-cascades-are-percentage-of-percentage.warrant.json
# Markdown SHA-256:   a4a60e0c02d74cf832a7215c853513b73d2bd93fd85b9f172d899c3c2668d7a0
# Code AST SHA-256:   514cbda883f57dd9a2f6f5a1434243eb5d3f87ed42a64e431e9abd4d66193e65
# Verified Classes:   CompoundingBaseError, FeeCascadeGate
# Defensive Guards:   3 fail-closed invariants (zero external deps)

from dataclasses import dataclass, field
from typing import Dict


class CompoundingBaseError(RuntimeError):
    """Raised when a fee cascade has an unspecified or mismatched fee base."""


VALID_BASES = ("principal_only", "principal_plus_prior_fees", "gross_of_all_fees")


@dataclass(frozen=True)
class FeeCascadeGate:
    instance_bases: Dict[str, str]
    counterparty_bases: Dict[str, str]

    def verify(self) -> bool:
        if set(self.instance_bases.keys()) != set(self.counterparty_bases.keys()):
            raise CompoundingBaseError(
                "fee sets differ between instance and counterparty"
            )
        for fee, base in self.instance_bases.items():
            if base not in VALID_BASES:
                raise CompoundingBaseError(
                    f"fee {fee!r} has invalid base {base!r}: must be one of {VALID_BASES}"
                )
            if self.counterparty_bases[fee] != base:
                raise CompoundingBaseError(
                    f"fee {fee!r} base mismatch instance={base} "
                    f"counterparty={self.counterparty_bases[fee]}"
                )
        return True


def dispatch_fee_mode(gate: FeeCascadeGate) -> str:
    try:
        gate.verify()
    except CompoundingBaseError:
        return "state-bases-before-settlement"
    return "compute-cascade"
