The problem
A money boundary the auth model said was impossible
- Money columns were revoked from the shared role entirely. Not filtered, not masked. The role has no grant on them, so no query from a client session can name them and succeed.
- Cost is re-exposed through security-definer views. Each view runs with the privileges of its owner, not the caller, and carries its own test: is this caller a member of this tenant, and does this caller hold a role that is allowed to see cost.
- A staff request returns no rows. Not a row of nulls, not a row with dashes where the number would be. Nothing. There is no shape to infer a value from, no row count to compare against, no null that tells you a number exists.
- Row-level security carries the tenant boundary underneath all of it, so the cost test never has to double as the tenancy test.
Cost that follows weight
Making the rules machine-decidable
- Float types in migrations. Weight and money are decimal or the migration does not land.
- Numeric coercion of carat or price fields in application code. No parsing a carat into a JavaScript number on the way through.
- The privileged service key outside a single file. One place holds it, and the gate fails the build if a second place imports it.
- A migration without a paired rollback.
- Destructive DDL without a stated reason recorded alongside it.
Proving the schema
Scale and delivery
- 27 migrations, each with a paired rollback
- 7,933 lines of migration SQL
- 54 row-level security policies
- 13 triggers
- 42 constraint assertions run against real violations
- 18,120 lines of TypeScript and TSX across 161 files
- 13 Playwright specs
- 9 Vitest files, 34 cases
- 11 architecture decision records
- 6-job CI pipeline