Coverage for src / lexigram / contracts / ai / relay / ratelimit.py: 0%
11 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""Rate-limit contracts for the relay gateway.
3A counter is a fixed-window atomic ``take`` matched to new-api's Redis
4Lua semantics: the counter is incremented, the window expiry is set on
5first increment, and the decision is returned atomically. Bursts of up
6to 2x the limit at a window boundary are intentional.
7"""
9from __future__ import annotations
11from dataclasses import dataclass
12from typing import Protocol, runtime_checkable
15@dataclass(frozen=True, slots=True)
16class RelayRateLimitDecision:
17 """Outcome of one ``take`` against a rate-limit window.
19 Attributes:
20 allowed: Whether the caller may proceed within the window.
21 count: The counter value after this take, 1-based.
22 ttl_seconds: Remaining seconds in the window.
23 """
25 allowed: bool
26 count: int
27 ttl_seconds: int
30@runtime_checkable
31class RelayRateLimitCounterProtocol(Protocol):
32 """Atomic fixed-window counter backend.
34 ``take`` must behave atomically for a given ``key``: increment,
35 set/refresh expiry on first increment, compare against ``limit``,
36 return the decision plus the current window TTL.
37 """
39 async def take(
40 self, key: str, limit: int, window_seconds: int
41 ) -> RelayRateLimitDecision: ...
44__all__ = ["RelayRateLimitCounterProtocol", "RelayRateLimitDecision"]