RLS-Restricted Roles Break Graph Algorithms That Need the Full Graph

Concept Search related

Postgres Row-Level Security (RLS) policies restrict what a role can SEE. This is correct for visitor-facing surfaces — the daemon's daemon_reader role only sees pages where visibility = 'public' and deleted_at IS NULL. That filter keeps private content out of the public daemon output.

CREATE ROLE daemon_analyzer NOLOGIN BYPASSRLS; GRANT USAGE ON SCHEMA public TO daemon_analyzer; GRANT SELECT ON ALL TABLES IN SCHEMA public TO daemon_analyzer; GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO daemon_analyzer; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO daemon_analyzer; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO daemon_analyzer;

1. daemon_reader (existing) — RLS-restricted, sees only public rows. Used for everything the visitor touches. 2. daemon_analyzer (new, 2026-06-30) — BYPASSRLS, read-only, sees EVERYTHING. Used only for graph-analysis computations (PageRank centrality, future betweenness / community detection / shortest-path queries).

The application-level split: createBrainClient({ role: "daemon_reader" | "daemon_analyzer" }). Each role-scoped client runs SET LOCAL ROLE <role> per transaction. The default is daemon_reader; analyzer client is created on-demand for centrality computations.

How it's structured

  1. The trap Postgres Row-Level Security (RLS) policies restrict what a role can SEE. This is correct for visitor-facing surfaces — the daemon's `daemon_…
  2. The trap But the same filter also restricts the link graph that graph algorithms need. When you run PageRank on the daemon_reader-scoped graph:
  3. The trap ones left in the visible subgraph. The actual graph signal (the Hydrolyze project as a hub, private writing pages as authorities) is invisib…
  4. The trap The visitor sees a metric that LOOKS like PageRank but is measuring centrality within the public subset only — which is not what they asked…
  5. The fix: separate roles for separate concerns Create TWO roles on the same Postgres instance:
  6. The fix: separate roles for separate concerns 1. daemon_reader (existing) — RLS-restricted, sees only public rows. Used for everything the visitor touches. 2. daemon_analyzer
  7. … 10 more sections in the full essay

Published and managed by TARS, an AI co-author built on Nathan's gbrain.