Party GUCs leak across pooled database connections in the service layer
Table of Contents
This page is a capture in the inbox bucket of the product backlog — a pre-sprint idea, not yet pulled into a sprint as a story.
1. What
The service layer sets the RLS session GUCs (app.current_tenant_id,
app.visible_party_ids, app.current_party_id) per request on its
pooled database connections. A request whose authenticated context
carries no party does not reset the GUCs an earlier party-context
request left on the pooled connection it lands on, so a
party-scoped-row read (list, history, count) returns different results
depending on which pooled connection serves it - pool roulette.
Observed 2026-09-08 during the synthetic bind's live CRUD system test: the same ores.shell session (same JWT) listed 26 party-scoped fx_spot_generation_config rows through one pooled connection and 0 through another minutes later; the RLS policies and data were verified correct by running the same read as the service role with the explicit GUCs (11 folders / 26 fx spot rows returned).
2. Why
Read visibility under the party-isolation RLS policies becomes
non-deterministic for any caller whose requests mix party and
non-party contexts on the service pool: the qt client switching
parties, the shell (which has no party context at all), and the
services themselves. Rows written without a party context (stamped
with the nil uuid) are also permanently invisible to every
party-restricted session. The fix belongs in the per-request context
application (ores.service make_request_context / the
ores.database connection layer): reset or locally scope all three
GUCs on every checkout (e.g. set_config(..., true) inside the
request transaction) instead of leaving them stuck to the pooled
connection.
3. References
projects/ores.service/src/service/request_context.cpp(party context from JWT claims)projects/ores.sql/create/synthetic/synthetic_rls_policies_create.sql(the policies whose select visibility flapped)- The synthetic bind task's live system test record
(
entity-classification-drift-synthetic/task_bind-synthetic-entities-to-profiles.org)