Query system¶
Two things exist and they are not interchangeable:
- The tenant plane is queried through
TenantRepositoryand the raw-SQL guard. This is the only path to tenant-routed rows. - The compiler (
jdlib.query) exists for engines without an ORM, and refuses tenant-plane tables outright (ADR-1). Full page:capabilities/query.md.
Why both¶
The repository is an ORM path with RLS underneath it; the compiler is a specification-to-SQL path
for analytical engines that have no ORM to route through. Letting the compiler reach the tenant
plane would create a second, weaker path to the same rows - so the policy declares the tenant
plane and the compiler refuses it, and a test asserts that refusal for projects, tasks and the
audit tables.
The compiler's contract¶
- The allow-list is enforced at parse time: an unknown table, column or operator is refused before anything is rendered or connected.
- Values are never text: they are bound parameters, and
CompiledQuery.__repr__redacts them. - The scope predicate is the compiler's: a caller's own
tenant_idfilter is ANDed with it, not substituted for it. - Complexity is bounded: column count, filter count, IN-list size, page size.
Evidence¶
A live test runs the compiled statement through the connector against a real database and asserts that tenant A sees only tenant A's rows and that a cross-tenant filter returns nothing.