ADR-0038 — RLS tenant context is transaction-local (pooling-safe)

V1 Freeze (2026-06-12): Accepted. Blocker-4 resolution. New ADR created to close the highest-confidence security trap in the pre-freeze review: Row-Level Security tenant context interacting unsafely with connection pooling.

Context

ADR-0007 makes Postgres Row-Level Security the tenant-isolation boundary: each request sets a tenant context and RLS policies filter by it. The pre-freeze review (review §5.1) flagged a concrete, catastrophic footgun that ADR-0007 left unresolved: how the tenant context interacts with connection pooling.

This must be decided before any multi-tenant code is written, because it dictates the shape of every database access in platform/db.

Decision

Consequences

Positive

Negative / costs

Alternatives considered

Verification

Two CI tests guard I3:

  1. Forged-tenant_id test (from ADR-0007): app-layer code sets a mismatched tenant id → RLS still blocks cross-tenant reads/writes.
  2. Pooled-connection bleed test (new): drive two tenants’ requests across a transaction-mode pool small enough to force connection reuse → assert tenant B never observes tenant A’s rows, and a query issued without the wrapper returns zero rows.