← Back to Blog

From paper standards to enforced gates

·7 min read

An audit of pyRPC’s engineering practices produced a humbling conclusion: every standard we claimed already existed somewhere in the repo, and none of them were enforced. Ruff was configured but not installed. Types were the entire value proposition, yet nothing type-checked anything. Examples demonstrated correctness that nothing verified. The gaps were all enforcement, never presence. This post is the map of how each gap got closed, and what the closing surfaced.

The audit

  • Ruff: a complete [tool.ruff] section in pyproject.toml, zero installations, zero runs. Running it locally failed because it was not a dependency.
  • Type checking: no mypy or pyright for Python; no tsc gate for any package.
  • ESLint: covered the docs site only. The published TypeScript packages had no lint config at all.
  • Coverage: pytest ran blind; no measurement, no threshold.
  • Dependencies: no Dependabot or Renovate over either lockfile.
  • Matrix: one Python version, one operating system.
  • Docs and examples: twelve example apps plus dozens of code blocks, none executed by anything.

The rule we applied

Every gate had to satisfy three properties before it could merge. First, it must pass honestly on day one: no blanket ignores to make numbers look clean, no skipping the work. Second, whatever current style we chose to accept gets encoded as documented configuration rather than silent exception. Third, the local command and the CI command must be identical, because gates that only exist in CI get discovered last, by whoever is furthest from their desk.

What enforcement immediately caught

The strongest argument for this work is what fell out in the first days:

  • Ruff’s very first autofix pass broke a re-export in core decorators, and then its F821 check caught the mistake in my own hand-fix minutes later. Linters guard the linter’s operator too.
  • mypy’s first run flagged the ASGI transport claiming dict-only payloads while v0.13 batching returns lists. A real contract drift shipped one release earlier.
  • The Windows CI legs crashed on first-run tsconfig bootstrap, exposing an npm.cmd execution bug in jsonc-edit. Fixed upstream in 0.2.1 within the hour.

The shape of the solution

Seven new or changed pieces now compose the gate set: a ruff job, a mypy job over all five Python packages’ sources, per-package tsc via new typecheck scripts, ESLint flat config over packages, pytest-cov with a hard floor at 78 percent against a measured 80, Dependabot across pip, npm, docs, and Actions, and a nine-leg OS x version matrix. Two new scripts bring examples and documentation into CI as executable checks. CONTRIBUTING.md now lists the local equivalent of every gate so nobody discovers them in a red X.

Deliberately deferred

Type checking tests (src only today), compiling docs TypeScript blocks, and linting the twelve examples are all known follow-ups. Naming them matters: deferred work should be visible, not forgotten. The alternative, pretending the gates cover everything, would poison trust in the gates themselves.

The deeper lesson generalizes beyond this repo: a standard that nothing enforces is a rumor you tell contributors. Rumors drift; gates do not.