Skip to content

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.Amount in Go, NUMERIC(19,4) in Postgres, a string on the wire.
  • Every business table has org_id, ENABLE and FORCE ROW LEVEL SECURITY, and a policy named org_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.

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.