# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-does-a-global-token-bucket-let-one-client-starve-the-rest.md
# Remnant Warrant:    https://corpusfetch.com/c/when-does-a-global-token-bucket-let-one-client-starve-the-rest.warrant.json
# Markdown SHA-256:   7a5bac2a7bfa92a25124b9abe9293042a37c6979809be9b0fea72a62ade13227
# Code AST SHA-256:   8da62eb2a87bb23b9db9a7d8cc9db403f9d56720d0088a2c6e5d1f79d9d1220b
# Verified Classes:   FairShareError, FairShareGate
# Defensive Guards:   2 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class FairShareError(RuntimeError):
    """Raised when a shared rate limiter cannot prevent one client from consuming all capacity."""


@dataclass(frozen=True)
class FairShareGate:
    per_client_limit: int
    active_clients: int
    global_cap: int
    per_client_buckets: bool

    def verify(self) -> bool:
        if not self.per_client_buckets:
            raise FairShareError("global bucket only: allocation is arrival-order dependent")
        required = self.per_client_limit * self.active_clients
        if self.global_cap < required:
            raise FairShareError(
                f"global cap {self.global_cap} < sum of per-client limits {required}: "
                "contention shifts to the cap"
            )
        return True


def dispatch_limiter_mode(gate: FairShareGate) -> str:
    try:
        gate.verify()
    except FairShareError:
        return "weighted-fair-queue"
    return "per-client-buckets"
