Proposed (STA-842). It extends
0327 decision 9 (isolation is
the database’s). OS tenancy gate A, gap G2.
Context
Theancestor policy shows rows at or below the session’s granted paths. Templates seeded at the platform or product
node (checklist templates, default documents) sit above a tenant’s path, so a tenant could not read them, and the
tenancy migration left checklist_templates without a policy as a shortcut.
Decision
t.rowLevelSecurity(column, { setting, match: "inherited" })on anltreecolumn writes theancestorpolicypol_<table>_<column>(reads and writes at or below a granted path) and a second, select-only policypol_<table>_<column>_inherited:column @> array(granted paths), true when the row’s path is an ancestor of, or equal to, a granted path.- Read only by construction. Postgres ORs permissive policies per command, so the select-only policy widens reads
and nothing else: insert, update and delete still pass only the
ancestorpolicy. A tenant reads the platform’s template and copies it; it never edits it. - Both policies match no row while the setting is unset or
''. Each statement carries its inverse.
Consequences
- Seeded rows are written by a session granted at their own node (the platform’s seeding job), never by a tenant.
- The
@>array scan is not GiST-indexed; the tables that takeinheritedare small catalogues of templates.
Enforcement
planned —packages/data/database/src/core/functions/__tests__/compile-migration.function.test.ts.