Skip to content

fix(rag): scope query-term corrector to public titles (F10)#697

Merged
BigSimmo merged 3 commits into
mainfrom
claude/audit-findings-review-phgz92
Jul 17, 2026
Merged

fix(rag): scope query-term corrector to public titles (F10)#697
BigSimmo merged 3 commits into
mainfrom
claude/audit-findings-review-phgz92

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Remediates F10 from the RAG-scalability review handover: the clinical query-term corrector leaked private title tokens across tenants.

public.correct_clinical_query_terms is SECURITY DEFINER (bypasses RLS) and runs on the live retrieval path (src/lib/rag-candidate-sources.ts, src/lib/rag.ts). It built its spell-correction vocabulary from every indexed document title regardless of owner, while the rest of retrieval is strictly owner-scoped and fail-closed (retrieval_owner_matches, docs/tenancy-defense-in-depth-review.md). The unscoped scan folded private tenants' title tokens into every caller's correction vocabulary — a cross-tenant existence side-channel for private title tokens (severity P2 / low: token existence, not content).

Fix — public titles only:

-    where d.status = 'indexed' and length(w) between 4 and 40
+    where d.status = 'indexed' and d.owner_id is null and length(w) between 4 and 40

RAG aliases are curated/global and unchanged; the function signature is unchanged, so callers and generated types need no update.

Why migration-only (important)

The fix ships as forward migration 20260717120000_corrector_public_titles_only.sql plus migration-backed tests, and deliberately does not edit supabase/schema.sql in this PR:

  • Editing schema.sql requires regenerating supabase/drift-manifest.json, which is a Docker-Postgres replay artifact (npm run drift:manifest) — Docker isn't available in the CI/agent sandbox, and tests/drift-detection.test.ts fails offline on a stale manifest.
  • The schema.sql mirror + manifest regen are therefore coupled to the live-apply step and performed together by an operator in a Docker-capable environment.
  • The migration is not applied to the live project here (confirmation-gated). Until applied, live == schema.sql == manifest (all the pre-scope version), so merging this migration file introduces no driftdb-reset-verify simply replays it into a scratch DB.

Verification

  • npx vitest run tests/drift-detection.test.ts tests/supabase-schema.test.ts65 passed (drift manifest still fresh since schema.sql is untouched; 2 new corrector tests: public-only scope, regression guard, service_role confinement)
  • npx prettier --check on the changed test — clean
  • npm run verify:pr-local — not run (no src/UI surface changed)
  • npm run verify:ui — not applicable

Clinical Governance Preflight

Touches retrieval + document access, so completed:

  • Source-backed claims still require linked source verification before clinical use — unaffected (query-correction only; retrieval remains owner-scoped and fail-closed)
  • No patient-identifiable document workflow was introduced or expanded
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only — corrector stays SECURITY DEFINER with execute confined to service_role (asserted in tests)
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative — improved: private titles no longer influence other tenants' query correction
  • Deployment classification/TGA SaMD impact checked — no clinical decision-support behavior change

Operator follow-up (Docker + confirmation-gated)

  1. Apply migration to the live project and mirror the predicate into supabase/schema.sql, then npm run drift:manifest to refresh the drift manifest — do these together.
  2. npm run check:supabase-project after applying.

No production mutations, no Supabase apply, no OpenAI/provider calls were performed in this PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FJpsbpsmjJ2tLLXFfSe9GK


Generated by Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved clinical search-term correction by only suggesting terms derived from publicly available document titles.
    • Prevented private or tenant-specific vocabulary from influencing query corrections.
  • Security
    • Restricted who can execute the query-term correction service.
  • Tests
    • Added schema/migration coverage to verify the corrected behavior, vocabulary scoping, and execution permissions.

…F10)

correct_clinical_query_terms() is SECURITY DEFINER and bypasses RLS. It built
its spell-correction vocabulary from every indexed document title regardless of
owner, while the rest of retrieval is strictly owner-scoped and fail-closed
(retrieval_owner_matches, docs/tenancy-defense-in-depth-review.md). The unscoped
scan folded private tenants' title tokens into every caller's correction
vocabulary — a cross-tenant existence side-channel for private title tokens
(low severity: token existence, not content).

Ship the fix as forward migration 20260717120000_corrector_public_titles_only.sql
that recreates the function with the title union restricted to the public corpus
(owner_id is null). RAG aliases are curated/global and unchanged; the signature is
unchanged, so callers and generated types need no update. Adds migration-backed
tests (public-only scope, regression guard against the old unscoped predicate, and
service_role execute confinement).

Migration-first on purpose: syncing supabase/schema.sql and regenerating
supabase/drift-manifest.json need the Docker replay (npm run drift:manifest) that
CI/the agent sandbox cannot run, so those are coupled to the live-apply step and
performed together by an operator. The migration is NOT applied to the live project
here (confirmation-gated); until applied, live == schema.sql == manifest, so merging
this file introduces no drift.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJpsbpsmjJ2tLLXFfSe9GK
@supabase

supabase Bot commented Jul 17, 2026

Copy link
Copy Markdown

Updates to Preview Branch (claude/audit-findings-review-phgz92) ↗︎

Deployments Status Updated
Database Fri, 17 Jul 2026 05:51:56 UTC
Services Fri, 17 Jul 2026 05:51:56 UTC
APIs Fri, 17 Jul 2026 05:51:56 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Fri, 17 Jul 2026 05:51:57 UTC
Migrations Fri, 17 Jul 2026 05:51:59 UTC
Seeding Fri, 17 Jul 2026 05:52:00 UTC
Edge Functions Fri, 17 Jul 2026 05:52:01 UTC

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60bb4470-dd04-4a4b-96ee-4936242b99ad

📥 Commits

Reviewing files that changed from the base of the PR and between 066a0ea and 983f951.

📒 Files selected for processing (2)
  • supabase/migrations/20260717120000_corrector_public_titles_only.sql
  • tests/supabase-schema.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • supabase/migrations/20260717120000_corrector_public_titles_only.sql

📝 Walkthrough

Walkthrough

Adds a migration that recreates the clinical query-term corrector using indexed public document titles and public aliases, preserves similarity-based token correction, and limits execution to service_role. Schema tests verify owner scoping and function privileges.

Changes

Public clinical query corrector

Layer / File(s) Summary
Public vocabulary correction and access control
supabase/migrations/20260717120000_corrector_public_titles_only.sql, tests/supabase-schema.test.ts
Defines token correction with similarity and length checks, limits title and alias-derived vocabulary to null-owner public records, and revokes execution from public, anon, and authenticated while granting it to service_role. Tests verify the migration predicates and privileges.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • BigSimmo/Database#694: Also addresses execution-grant hardening for public.correct_clinical_query_terms.

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: scoping the query-term corrector to public titles.
Description check ✅ Passed The description covers the summary, verification, governance, and follow-up, though it doesn't mirror every template checkbox exactly.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-findings-review-phgz92

Comment @coderabbitai help to get the list of available commands.

@BigSimmo
BigSimmo enabled auto-merge July 17, 2026 05:12

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 066a0ea52c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread supabase/migrations/20260717120000_corrector_public_titles_only.sql Outdated
@BigSimmo

Copy link
Copy Markdown
Owner Author

@codex resolve actionable Codex review findings for this pull request and current head using the repository instructions. This is the pull request's single automatic repair pass: do not perform a fresh review, create new standalone findings, or request another review. Work only the existing unresolved Codex threads on the current head. Always fix P0 and P1 findings. For P2 and lower findings, fix only clear, scoped, low-risk issues; otherwise disposition them with a concise reason. After fixing or dispositioning a thread, reply in that thread with as the first line, followed by a concise summary; that marker authorizes the workflow to close that exact thread. If human input or new authorization is required, do not use the marker and leave the thread open with the blocker. Finish only after every actionable thread is fixed or dispositioned and closed, or explicitly left open for a human decision. Do not update the branch from main, address unrelated reviews, broaden scope, or create more than one scoped fix commit. Do not use external APIs, paid services, credentials, dependency changes, or broad refactors unless explicitly authorized. Add targeted tests where behavior changes and run the narrowest relevant validation.

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

Testing

  • npx vitest run tests/supabase-schema.test.ts
  • npx prettier --check tests/supabase-schema.test.ts supabase/drift-manifest.json
  • git diff --check
  • ⚠️ npx vitest run tests/drift-detection.test.ts tests/supabase-schema.test.ts — the drift test could not load because this workspace lacks the repository dependency @next/env; the focused schema suite passed after isolating it.

View task →

@BigSimmo
BigSimmo disabled auto-merge July 17, 2026 05:24
@BigSimmo
BigSimmo enabled auto-merge July 17, 2026 05:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c286bd1c54

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread supabase/migrations/20260717120000_corrector_public_titles_only.sql Outdated
Follow-up to the corrector title scoping: the two rag_aliases reads in
correct_clinical_query_terms were still unscoped. rag_aliases carries an
owner_id (there is a rag_aliases_owner_enabled_idx), and deep-memory.ts
persists owner-scoped aliases/canonicals when a private document is indexed
(src/lib/deep-memory.ts). Because the function is SECURITY DEFINER and bypasses
RLS, a caller in another tenant could still trigger and observe corrections
toward private document-derived alias/canonical terms — the same cross-tenant
side-channel the title filter closed, via aliases.

Scope both alias selects to the public corpus (owner_id is null), matching the
title scan and the public-titles-only decision. Extends the migration-backed
test to assert the scoped alias reads and guard against the old unscoped form.
Still migration-only (schema.sql/manifest sync coupled to the Docker-gated
live-apply); schema.sql remains untouched so the drift manifest stays fresh.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJpsbpsmjJ2tLLXFfSe9GK
@BigSimmo
BigSimmo merged commit 1ffa139 into main Jul 17, 2026
20 checks passed
BigSimmo pushed a commit that referenced this pull request Jul 17, 2026
…manifest (F10)

Completes the F10 corrector tenancy fix. Migration
20260717120000_corrector_public_titles_only (merged in #697) scoped the
SECURITY DEFINER query-term corrector's vocabulary — both rag_aliases reads and
the document-title scan — to the public corpus (owner_id is null). This mirrors
that same predicate into the canonical supabase/schema.sql corrector definition
so a disaster-recovery restore or manifest/schema reconciliation cannot recreate
the unscoped, cross-tenant vocabulary (Codex review P1 on #697).

Regenerated supabase/drift-manifest.json via `npm run drift:manifest` (real
Docker Postgres replay): schema_sha256 and only the corrector function's def_hash
change (8f1094c4… → a5ebdd1e…), confirming the sole schema delta is the scoped
corrector. Offline drift-detection + schema tests pass (66).

Live apply of the migration to the Clinical KB Database project remains a
separate, confirmation-gated deploy-pipeline step (needs service-role env);
after applying, `npm run check:drift` should report clean against live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJpsbpsmjJ2tLLXFfSe9GK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants