This catches almost everyone the first time. The mental model "each policy is a check" is wrong — Postgres treats multiple PERMISSIVE policies as OR (any policy granting access = access granted).
For cross-cutting constraints that must always hold, RESTRICTIVE policies are the right tool because they're AND'd with everything else:
CREATE POLICY user_isolation ON journal_entries AS RESTRICTIVE FOR ALL USING (auth.uid() = user_id);
That lives alongside your existing permissive policies and short-circuits the OR-leak case. If a public-features schema ships before the feature is launched, the RESTRICTIVE policy still enforces ownership.
The app-layer filter you added is the right belt-and-braces fix. Combining both — explicit filters + RESTRICTIVE policy — gives two failure surfaces that both have to fail before data leaks. RESTRICTIVE in particular is underused because the docs mention it almost as a footnote.