refactor(rag): decompose rag.ts part 2 (extractive-answer, retrieval-variants, cache) — move-only - #347
Conversation
…ag-extractive-answer.ts (move-only) Move 1 of rag.ts decomposition part 2. The extractive-answer family (L) and the answer-quality/reasoning-effort family (M) are mutually entangled on main, so per the part-1 coupling notes they move together as one module — keeping the L<->M entanglement internal (no cross-module cycle). Lines 3954-5503 moved verbatim (byte-identical modulo the `export` keyword added to the 9 functions that now cross the module boundary; verified empty block diff otherwise). rag.ts imports the 12 names it still calls and re-exports the 6 that tests import. Per the part-1-sanctioned "accept back-edges" option, the module imports 9 call-time helpers back from rag.ts (evidenceTextForGate, rankMemoryCardsForAnswer, deriveConfidence, scoreValue, machineReadableFallbackAnswer, buildAnswerScoreExplanations, buildIndexingQuality, collectMemoryCards, fallbackReasonFromRouting) — 6 gained an `export` keyword. The aliased citations import (citationFromResult as resultCitation) travels with the module; 5 imports orphaned by the move removed from rag.ts. rag.ts 7,550 -> 6,025 lines. Gate: tsc clean (no new errors vs baseline), focused vitest 75/75, lint (no new warnings), prettier clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…family to rag-retrieval-variants.ts (move-only) Move 2 of rag.ts decomposition part 2 (retrieval-side). Lines 1999-2283 moved verbatim (byte-identical modulo the `export` keyword added to 5 declarations that now cross the module boundary; verified empty block diff otherwise): retrieval query-variant builder, alias normalization/expansion, live rag_aliases fetching, owner-scope guards (assertGlobalSearchAllowed, ownerScopeForDocumentFilteredRetrieval), weak-text-match relaxation, and the text-candidate budget. rag.ts imports the 11 names it still calls and re-exports the 6 that retrieval-query-variants.test.ts imports. Back-edges to rag.ts: SearchChunksArgs (type-only, no runtime cycle) and shouldShortCircuitUnsupportedSearch (one call-time value fn, gained an `export`; belongs to the soft-tail family that stays). 4 imports orphaned by the move (retrievalOwnerFilter, queriedZoneColour, isDemoMode, isLocalNoAuthMode) removed from rag.ts. rag.ts 6,025 -> 5,730 lines. Gate: tsc clean (no new errors vs baseline), focused vitest 102/102 (incl. retrieval-query-variants.test.ts exercising the moved builders), lint (no new warnings), prettier clean. Golden retrieval eval is a pre-merge gate; see PR notes on the current environment (OpenAI quota exhausted + live text-RPC returning 0 candidates) blocking a clean 36/36 run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… golden eval Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (move-only) Move 3 (final) of rag.ts decomposition part 2. The cache functionality is interleaved in rag.ts with the query-classifier, unsupported-soft-tail, and query-expansion regions, so this is a multi-region verbatim move: four contiguous regions assembled into rag-cache.ts, each byte-identical to source (verified; diff shows only the `export` keyword added to 11 declarations that now cross the module boundary): - cache maps/consts (answerCache, answerInflight, searchCache, cacheIndexingVersionCache, …) - cache-key helpers (scopeKey, normalizedCacheQuery, cacheIndexingVersionCacheKey) - main cache block (modeKey…invalidateRagCachesForDocumentMutation: get/set answer+search, shared-cache, cacheIndexingVersion, stableHash, retrievalPlanCacheQuery, invalidation) - context-packing (sourceContextPackLimit, packedContextCacheKey, packAdjacentSourceContext), grouped here per the part-1 note because it needs stableHash + committed-generation. rag.ts imports the 12 names it still calls (incl. the answerInflight map) and re-exports the 4 consumed elsewhere (invalidateRagCachesForOwner/…ForDocumentMutation via API routes; packedContextCacheKey + retrievalPlanCacheQuery via tests). Back-edges to rag.ts: SearchChunksArgs + SearchTelemetry (type-only, no runtime cycle) and one call-time value fn retrievalPlanForQueryClass (gained an `export`). 3 imports orphaned by the move (queryCacheKeyForStorage, ragCacheKeyMatchesOwner, createHash) removed from rag.ts. rag.ts 5,750 -> 5,108 lines (7,550 at part-2 start; -2,442 / -32% across the 3 moves). Gate: tsc clean (no new errors vs baseline), focused vitest 118/118, lint (no new warnings; module 0), prettier clean. Golden retrieval eval is a pre-merge gate; see PR notes — currently blocked by an eval-owner/corpus data mismatch (docs are owner_id=null, RAG_EVAL_OWNER_ID owns 0), independent of this branch (pristine origin/main fails identically). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pus data blocker root cause Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This pull request has been ignored for the connected project Preview Branches by Supabase. |
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Uh oh!
There was an error while loading. Please reload this page.
… debt Ran check:supabase-project (live mode) then eval:retrieval:quality with the new public-sentinel default owner (no RAG_EVAL_OWNER_ID set): cases=36, failed_cases=0, latency_failed_cases=0, document_recall@5=1, content_recall@5=1, top_k_hit_rate=1. A direct read-only probe confirmed all 2065 documents are owner_id=NULL. This settles the PR #347 part-2 eval debt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BdP9DwsGdvtEvyVh3juYZ5
BigSimmo
commented
Jul 7, 2026
✅ Golden retrieval eval now GREEN — blocker was eval-owner config, root-caused and fixedThe earlier 0-candidates failure was not the OpenAI quota and not this branch — it was the eval owner. The corpus docs are Fix: set 36/36, Combined with the byte-identical block moves, 1,230-test parity, and the earlier pristine-eval equivalence, moves 5–7 are confirmed behavior-neutral. Remaining before merge: |
BigSimmo
commented
Jul 7, 2026
✅ All final gates now green (environment fixed)Root-caused and fixed the environment blockers, then ran the full gate set:
NetMoves 5–7 are behavior-neutral by every available measure: byte-identical block moves, 1,239-test parity, 36/36 golden retrieval eval, healthy answer metrics, and pristine-eval equivalence. |
…h gate Adds the 2026-07-08 follow-up: DEFAULT_EVAL_OWNER_ID + resolveEvalOwnerId() are now shared across all read/eval scripts (item 1), with a one-line sentinel-fallback warning (item 3). Records the live eval:quality --rag-only result closing #347's answer-path gate (item 2): cases=44, unsupported_correct=1.0, citation_failure=0.0455, numeric_grounding=0.0227 (all identical to #343 baseline); grounded_supported=0.90, with the 5 failing cases all in #343's documented latency/route live-variance set. Corrects the earlier overstatement so #348 reads as closing the retrieval half only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BdP9DwsGdvtEvyVh3juYZ5
…7zoww refactor(eval): share public-sentinel owner default across read/eval scripts; close#347 answer-path gate
rag.ts decomposition — part 2 (moves 5–7)
Continues the
src/lib/rag.tsdecomposition (part 1 = #341). Move-only, zero behavior change — every extraction is a verbatim, byte-identical block move (verified: the diff between each moved region and the deleted region is empty except for theexportkeyword added to declarations that now cross a module boundary).Branched off
origin/main(8878151aa, includes #341 + retrieval-correctness #343). One module per commit, each with its own gate.Moves
rag-extractive-answer.tsrag-retrieval-variants.tsfetchEnabledRagAliases, owner-scope guards, weak-match relaxation, text-candidate budget.rag-cache.tsstableHash, invalidation,packAdjacentSourceContext.rag.ts: 7,550 → 5,108 lines (−2,442, −32%). It now holds the orchestrator + retrieval-diagnostics + classifier + coverage-gate + memory/enrichment + query-logging.Cycle handling (per the approved part-1 "accept back-edges" path)
rag.ts(evidenceTextForGate,rankMemoryCardsForAnswer,deriveConfidence,scoreValue,machineReadableFallbackAnswer,buildAnswerScoreExplanations,buildIndexingQuality,collectMemoryCards,fallbackReasonFromRouting).SearchChunksArgs(type-only) +shouldShortCircuitUnsupportedSearch(1 value fn).SearchChunksArgs/SearchTelemetry(type-only) +retrievalPlanForQueryClass(1 value fn).All back-edges are used only at call-time (never at module top-level), so the
rag.ts ↔ modulecycles are runtime-safe; there is noimport/no-cyclelint rule. Helpers that had to cross a boundary gained anexportkeyword (visibility-only, no logic change); imports orphaned by each move were removed fromrag.ts.Gates (per move)
tsc clean (no new errors vs baseline), focused vitest (75 → 102 → 118), lint (no new warnings; each new module has 0), prettier clean.
Behavior-preservation proof
fast-check— see below — not a test regression.)typecheck: 0 errors inrag.tsor any new module (identical to the pristineorigin/mainbaseline).origin/mainwith the moved modules made inert — confirming the moves change no retrieval behavior.The task's mandated final gates can't produce clean numbers in this environment; each is a pre-existing infra/data state, proven independent of these commits:
eval:retrieval:quality(36/36) — blocked by an eval-owner/corpus data mismatch. Every retrieval layer returns 0 (text_candidates:0,hybrid_vector:0, …). Direct Supabase probe (valid service key): 2,065 docs / 69,334 chunks present, butowner_id = null(global), whileRAG_EVAL_OWNER_IDowns 0 docs — and owner-scoped retrieval now fail-closes on a null owner (privacy hardening). Pristineorigin/mainfails identically (byte-for-byte), so this is not a regression. Restoring OpenAI credits fixed embeddings (embedding:1now succeeds) but not this. To run a real 36/36: assign the corpus docs to the eval owner, or point the eval at the owner that owns them / enable global search.eval:quality -- --rag-only— depends on the same retrieval, so all answers degrade to source-only/unsupported (not a meaningful grounded-supported measurement) until (1) is fixed.verify:cheap—check:runtime✅,sitemap:check✅,lint✅ (0 errors);typecheck/testfail only becausefast-check(a declared devDep,^4.8.0) isn't installed in this localnode_modules.npm ciin CI installs it → green there. Not mutated here to avoid disturbing the shared, multi-worktreenode_modules.Before merge: run
eval:retrieval:quality(must be 36/36,failed_cases=0) andeval:quality -- --rag-onlyonce the eval-owner/corpus config is fixed (or in CI), and confirmverify:cheapgreen afternpm ci.Clinical governance preflight
This PR is a pure move-only refactor of retrieval/answer-composition code with zero behavior change (byte-identical moves + 1,230-test parity + pristine-eval equivalence). No ingestion, ranking, source-rendering, privacy, or clinical-output logic is altered. The golden retrieval eval remains a hard pre-merge gate (blocked as above).
🤖 Generated with Claude Code