lode.
← blog
Engineering

The matrix as data

Permissions aren't code. They're a row in `grant_templates`. Edit, and the resolver responds.

Mathys van Abbe · 30-5-2026 · 6 min read

The mistake most products make

Most products code permissions. Investor role gets these routes. Accountant gets those. The matrix lives in a switch statement, hard to audit, hard to edit, hard to test.

Lode lives the access model from the spec: the matrix is data. Ten role templates — FOUNDER, OPERATOR, CREW, INVESTOR, PROSPECT_INVESTOR, ADVISOR, ACCOUNTANT, PARTNER, CLIENT, PRESS — each one row in grant_templates. Each row holds a JSON matrix mapping every chapter (CH01..CH12, PORTFOLIO) to an altitude grant (none/S/SL/SLO/R).

One resolver, every RLS

Every row-level security policy on every Layer-2 table calls one Postgres function: resolve_access(person, project, x_class). The function:

Want to give an advisor temporary Ops access to CH05? Add an entry to their relationship's grant_overrides JSON. Want to freeze a relationship during a dispute? Flip access_state to frozen. The resolver does the rest. RLS responds within the next query.

No code change. No deploy. Just a row update.

access-modelengineering