Skip to content

Conformance and Development

ameyaborkar edited this page Jun 10, 2026 · 4 revisions

Conformance & development

How it stays in lock-step with the core

throttlekit-py never re-implements an algorithm — but it does vendor a contract, and that contract must not drift from the Node core it tracks. Two mechanisms keep it honest.

1. The drift-gate (checksums). scripts/sync_contract.py vendors, with sha256 checksums, from the core repo:

  • contract/ — the dev/test artifacts: throttlekit.proto (→ the gRPC stubs) and golden-vectors.json. The vendored proto now declares the read-only Monitor service (GetSnapshot + Watch) and the Fleet lease door (Reserve) alongside RateLimiter, so the generated stubs cover the MonitorBackend and FleetBackend doors too; golden-vectors.json now carries the lease suites in addition to the rateLimit ones.
  • src/throttlekit/_scripts/ — the runtime Lua the RedisBackend executes (shipped in the wheel), with the core's manifest.json (which carries each script's sha256).

tests/test_contract.py fails if any vendored byte diverges from its pinned checksum, or if the pinned contractVersion moves unexpectedly.

2. The behavioral proof (golden vectors). The real guarantee isn't the bytes — it's the behavior:

  • tests/test_redis_backend.py replays every rate-limit golden vector — the full, time-parametrized timeline — through the Python client → vendored Lua → real Redis, and asserts every reply field equals the Node oracle bit-for-bit. (Because the direct path puts an explicit now in ARGV, it can do the rigorous time-parametrized replay the cross-process service door can't.)
  • tests/test_service_backend.py starts a real throttlekit-server and asserts the clock-independent behavior over gRPC — a cold burst admits exactly burst then denies; debit spends a budget then refuses; admit holds a concurrency slot, releases it, heart-beats a long hold, and the server reclaims an abandoned one.
  • tests/test_lease_spender.py replays every golden lease vector — a scripted interleave of lease grants and local spends — through the Tier-2 LeaseSpender, asserting each reply (an allow Decision, or None = "refresh needed") matches the Node core's twoTier(leased, windowCoupled) L1 path bit-for-bit. This is the same kind of byte-lock the rate-limit vectors get, now extended to the leased-budget spend the FleetBackend draws against.

So a Python decision is the Node core's decision — verified, not hoped for.

Develop

git clone https://github.com/AmeyaBorkar/throttlekit-py
cd throttlekit-py
python -m venv .venv && . .venv/Scripts/activate    # or .venv/bin/activate on POSIX
pip install -e .[dev]

python scripts/sync_contract.py   # vendor proto + vectors + Lua from ../throttlekit (the core)
python scripts/gen_proto.py       # generate the gRPC stubs from the vendored proto
pytest                            # unit + contract; the Redis/service tests skip if their backend is absent
ruff check . && ruff format --check . && mypy

The generated gRPC stubs (src/throttlekit/_generated/) are build artifacts — git-ignored, regenerated by gen_proto.py, and produced at build time by a hatchling hook so they ship in the wheel (you don't commit them).

Running the conformance suites

  • RedisBackend conformance needs a reachable Redis: it uses THROTTLEKIT_REDIS_URL or the project default redis://localhost:6380, and skips cleanly when neither is up.

    docker run -d --name tk-redis-6380 -p 6380:6379 redis:7-alpine
  • ServiceBackend integration needs node on PATH and a built server. Point THROTTLEKIT_REPO at your local core checkout (it defaults to ../GreenfeildProject), then build the server once:

    ( cd "$THROTTLEKIT_REPO/server" && npm ci && npm run build )
    pytest -m integration

Both integration suites are skipped (not failed) when their backend isn't available, so a bare pytest is always green.

Continuous integration

.github/workflows/ci.yml runs on every push and PR:

  • Lint & formatruff check + ruff format --check (one run; ruff's target version is pinned).
  • Types & tests (py 3.10 / 3.11 / 3.12 / 3.13)mypy --python-version + pytest across the matrix, with a Redis service container so the cross-language test_redis_backend.py vector replay runs on every version (not just locally). The pure-Python test_lease_spender.py lease-vector replay runs here too (it needs no backend).
  • Contract drift-gate — a standalone, pure-Python pytest tests/test_contract.py, so vendored-contract drift is its own blocking red check (no gRPC / Redis / Node needed) — it covers the vendored proto (now incl. the Fleet/Monitor services), the rateLimit and lease golden vectors, and the runtime Lua checksums.
  • Build hook & wheel import — builds the real wheel, asserts the generated gRPC stubs are inside it (scripts/check_wheel_stubs.py), and imports both doors from a clean install — catching stub-packaging regressions on every PR.

Releasing

Releases are tag-driven and publish to PyPI via trusted publishing (OIDC) — no long-lived API token. Push a vX.Y.Z tag and release.yml builds + smoke-tests the wheel, publishes over OIDC (skip-existing), and cuts the GitHub Release from the CHANGELOG. The full procedure — including the one-time PyPI trusted-publisher setup — is in RELEASING.md.

See also

  • The axes — the client surface these suites exercise.
  • The core's Polyglot & Python wiki page — the design from the Node side.
  • research/polyglot/ — the design + decision records for the whole polyglot arc.
  • The cross-repo battle test — a multi-process distributed workload that drives every axis through both backends against a real Redis-backed 3-server fleet (distributed cap exactness, the windowCoupled overshoot bound, crash-reclaim, heartbeat, one-oracle/two-door state sharing); the committed logs/ hold a green 11/11 run.