Uh oh!
There was an error while loading. Please reload this page.
feat(rag): codify the vector store as a migration + assert it exists (#481) - #495
Conversation
…481, part of #482) `course_chunks`, the `match_course_chunks` RPC and `CREATE EXTENSION vector` appeared in ZERO .sql files in this repo, yet all three are live in staging and production. Any database replayed purely from `python -m db.migrate` — local Supabase, the E2E stack, a fresh environment — therefore had RAG dead end to end, silently: retrieve_chunks swallows the RPC failure into [], _get_catalog_chunk degrades to "", indexing failures vanish into a fire-and-forget log line. The tutor just answers ungrounded, with no error, no metric and no user-visible signal. Migration 0039 codifies the extension, the table, its indexes and the RPC. Shape verified against LIVE production and staging by reading a real row and calling the RPC — columns, the 768-dim embedding, and the RPC's exact parameter and return names — rather than from the design doc, which describes intent while the database is what the code actually talks to. (The code's _OUTPUT_DIM is 768 and matches; a 3072-dim probe is rejected by the live RPC.) Every statement is IF NOT EXISTS / CREATE OR REPLACE, mirroring 0032's reconcile pattern, so it is a no-op where the objects already exist. Adds a `ragstore` oracle asserting the store EXISTS — the gap the issue names ("nothing in the suites or oracles asserts the table exists"). It checks the extension, the table and the RPC, deliberately not their contents: an empty course_chunks is normal on a fresh stack, a missing one is the bug. It also counts rows with a NULL embedding, which led to the write-path half. index_document_chunks upserted records whose embedding never landed — match_course_chunks ranks by vector distance and skips NULLs, so those rows were unretrievable by construction while still counting toward the "indexed N chunks" the caller logs. That is how a total embedding outage read as a complete success. It now drops them, logs how many, and reports only what was really indexed (part of #482). Two tests changed because they pinned that bug rather than a contract: test_index_document_chunks_handles_embedding_failure asserted the NULL rows were upserted, and the function-mode egress test asserted the same shape incidentally — its real subject, the absence of transport egress, is unchanged. part of #481 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Deploying with |
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs | frontend-staging | ff79618 | Commit Preview URL Branch Preview URL | Jul 31 2026, 07:38 AM |
| "ciphertext": lambda args: gather.run_ciphertext(args), | ||
| "logscan": lambda args: gather.run_logscan(args), | ||
| "orphans": lambda args: gather.run_orphans(args), | ||
| "ragstore": lambda args: gather.run_ragstore(args), |
Uh oh!
There was an error while loading. Please reload this page.
Warning Review limit reached
Next review available in:43 seconds Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
course_chunks, thematch_course_chunksRPC andCREATE EXTENSION vectorappear in zero.sqlfiles in this repo — yet all three are live in staging and production. Any database replayed purely frompython -m db.migratetherefore had RAG dead end to end, silently:retrieve_chunksswallows the RPC failure into[]_get_catalog_chunkdegrades to""The tutor just answers ungrounded, with no error, no metric and no user-visible signal.
Migration 0039
Codifies the extension, table, indexes and RPC. Shape verified against live production and staging, not from the design doc — I read a real row and called the RPC to confirm the columns, the 768-dim embedding, and the RPC's exact parameter and return names. The doc describes intent; the database is what the code actually talks to.
Worth noting from that probe: the live RPC rejects a 3072-dim vector and the code's
_OUTPUT_DIMis 768 — they match, so there's no latent dimension bug.Every statement is
IF NOT EXISTS/CREATE OR REPLACE, mirroring 0032's reconcile pattern, so it's a no-op where the objects already exist.The
ragstoreoracleCloses the gap the issue names — "nothing in the suites or oracles asserts the table exists." It checks the extension, the table and the RPC, and deliberately not their contents: an empty
course_chunksis normal on a fresh stack, a missing one is the bug.The write-path half (part of #482)
The oracle also counts NULL-embedding rows, which led back to the cause.
index_document_chunksupserted records whose embedding never landed — butmatch_course_chunksranks by vector distance and skips NULLs, so those rows were unretrievable by construction while still counting toward the "indexed N chunks" the caller logs. That is how a total embedding outage read as a complete success. It now drops them, logs how many, and reports only what was really indexed.Two tests changed because they pinned that bug rather than a contract.
test_index_document_chunks_handles_embedding_failureasserted the NULL rows were upserted; the function-mode egress test asserted the same shape incidentally, though its real subject — absence of transport egress — is unchanged. Both now assert the corrected behaviour, and a new test covers the partial-failure case.Verification — the from-empty replay, which is the whole point
A normal e2e cycle would not prove this:
e2e-upruns against a database that already has the objects. So this ransupabase db reset(drops and replays every migration from scratch) and then asked the new oracle whether the store survived:Backend:
pytest1526 passed, 32 skipped ·ruff checkclean.part of #481