Project invariants
These are not style preferences. Most are covered by a drift test that fails the build. The
source is AGENTS.md; if the two
disagree, AGENTS.md wins.
- A float never touches money, in any layer.
money.Amountin Go,NUMERIC(19,4)in Postgres, a string on the wire. - Every business table has
org_id,ENABLEandFORCE ROW LEVEL SECURITY, and a policy namedorg_isolation. - Every request runs in a transaction, including reads — that is what makes the tenant setting safe under pooling.
- Vocabulary values are strings, never integers.
- The ledger is append-only. Corrections are reversals, never mutations.
accounting/reacts to semantic tags, never to state names.- Every user-facing name is a translation row, never a column on the entity.
- A claimant never picks their own approver. Grants are configured by an administrator and resolved by the system.
Drift tests
Section titled “Drift tests”A convention that is not tested drifts. Current guards: every table is tenant-isolated; every
env var read appears in .env.example; generated code matches its source of truth; every route
is behind an httpx.Authorize or declared in api/public_routes.txt; retention-bearing tables
do not grant the privilege that would let a record be erased; every advisory lock is namespaced
by a lock class; no handler reads an organization from a request header; every SECURITY DEFINER
function is allowlisted and not executable by PUBLIC.
When you add a convention, add the test that enforces it, and watch it fail once before you rely on it. A test that asserts something is absent must first show the thing would be present without the mechanism under test.