Skip to content
Jonathan Hazeley
All projects

Personal project · 2025–2026

Architecture Enforced by Gates, Not Convention

A multi-tenant referral platform whose architecture boundaries are enforced by AST gates in CI, with capability-based spend control and a tenancy isolation proof that runs as a test.

  • Python
  • PostgreSQL
  • Databricks
  • AST analysis
  • GitHub Actions
packages split on a network-and-secrets axis
7

packages split on a network-and-secrets axis

AST gates failing CI on a boundary violation
4

AST gates failing CI on a boundary violation

tenancy isolation proof, not asserted
Executed

tenancy isolation proof, not asserted

The problem

Architecture documents describe intent, and codebases drift from that intent within months. On a system that holds tenant data, spends real money on outbound messaging, and touches PII, drift is not a tidiness problem. It is the mechanism by which credentials end up importable from a package that talks to the public internet. Code review catches this unreliably, because reviewers check whether the change is correct, not whether it crossed a line drawn a year ago.

The approach

I split the system into seven packages along a network-and-secrets axis, then wrote four AST gates (AR001–AR004) that fail CI when a package imports across a boundary it should not, so the boundary is checked by a machine on every commit rather than remembered by a person. Spend is capability-based: nothing sends without a SendWarrant, which bounds the blast radius of a bug to whatever that warrant permits. Tenant isolation is Postgres row-level security with an executed proof rather than an assertion in a design doc, and the Databricks medallion layers are parity-proven against the public NPPES archive. A meta-test asserts that CI covers every gate, so adding a gate and forgetting to wire it up also fails.

The outcome

The boundaries hold, and they hold without depending on anyone remembering them: the only version of an architecture rule that survives contact with a deadline. The pattern generalizes well beyond this project: the meta-test that checks CI covers every gate is the piece I have carried into other work, because a gate nobody runs is indistinguishable from no gate at all.