refactor(rag): extract the rag cluster into src/lib/rag/ (maturity X2) - #994
Conversation
…r change) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Jc1ZYHFjXjn6mE6U6riVU
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Jc1ZYHFjXjn6mE6U6riVU
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR moves RAG modules under ChangesRAG domain-directory extraction
Estimated code review effort: 3 (Moderate) | ~30 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/lib/rag/rag-query-guard.ts (1)
19-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate decision tree between the two exported guards.
shouldShortCircuitUnsupportedSearchandisUnsupportedSoftTailAnalysisrun the identical 4-condition chain, only inverting the first two branches' return value. Any change to the pattern guards must be mirrored in both functions with reversed polarity, which is easy to get wrong.♻️ Suggested extraction of the shared classification
+type UnsupportedSearchClassification = + | "pattern_guard" + | "soft_tail_ineligible" + | "soft_tail_consumer" + | "soft_tail_confidence_gate_pass" + | "soft_tail_confidence_gate_fail"; + +function classifyUnsupportedSearch(query: string, analysis: ClinicalQueryAnalysis): UnsupportedSearchClassification { + if (unavailableDocumentNoisePattern.test(query)) return "pattern_guard"; + if (clearlyOutsideCorpusMedicalPattern.test(query) && analysis.documentTitleTerms.length === 0) return "pattern_guard"; + if (!unsupportedSoftTailEligible(analysis)) return "soft_tail_ineligible"; + if (clearlyNonClinicalConsumerPattern.test(query)) return "soft_tail_consumer"; + return analysis.confidence <= 0.42 && analysis.expandedTerms.length <= 5 + ? "soft_tail_confidence_gate_pass" + : "soft_tail_confidence_gate_fail"; +} + export function shouldShortCircuitUnsupportedSearch(query: string, analysis: ClinicalQueryAnalysis) { - if (unavailableDocumentNoisePattern.test(query)) return true; - if (clearlyOutsideCorpusMedicalPattern.test(query) && analysis.documentTitleTerms.length === 0) return true; - if (!unsupportedSoftTailEligible(analysis)) return false; - if (clearlyNonClinicalConsumerPattern.test(query)) return true; - return analysis.confidence <= 0.42 && analysis.expandedTerms.length <= 5; + const classification = classifyUnsupportedSearch(query, analysis); + return classification === "pattern_guard" || classification === "soft_tail_consumer" || classification === "soft_tail_confidence_gate_pass"; } // True only for queries that would short-circuit via the soft tail itself, not a pattern guard. export function isUnsupportedSoftTailAnalysis(query: string, analysis: ClinicalQueryAnalysis) { - if (unavailableDocumentNoisePattern.test(query)) return false; - if (clearlyOutsideCorpusMedicalPattern.test(query) && analysis.documentTitleTerms.length === 0) return false; - if (!unsupportedSoftTailEligible(analysis)) return false; - if (clearlyNonClinicalConsumerPattern.test(query)) return false; - return analysis.confidence <= 0.42 && analysis.expandedTerms.length <= 5; + return classifyUnsupportedSearch(query, analysis) === "soft_tail_confidence_gate_pass"; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/rag/rag-query-guard.ts` around lines 19 - 34, Extract the shared classification logic from shouldShortCircuitUnsupportedSearch and isUnsupportedSoftTailAnalysis into a single private helper that distinguishes pattern-guard matches from soft-tail eligibility. Update both exported functions to reuse that helper while preserving their current behavior: the first should short-circuit on any guard or soft-tail match, and the second should return true only for the soft-tail match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/clinical-hazard-analysis.md`:
- Around line 47-55: Update the applyNumericVerification references in the
hazard analysis to link to its actual definition in src/lib/answer-verification
and its invocation in src/lib/rag/rag.ts around the cited call-site range,
replacing the incorrect rag.ts definition and outcome line links. Keep the
surrounding behavior description unchanged.
In `@docs/rag-injection-threat-model.md`:
- Around line 15-38: Update the documentation citations for buildRagSourceBlock
and its related prompt-field locations to reference the extracted
rag-source-block.ts module, including the sections at 70–86, 99–101, 112–125,
and 135–148. Retain rag.ts citations only for answerInstructions and
buildAnswerInput/answer-input assembly, and ensure all referenced line ranges
match the extracted implementation.
---
Nitpick comments:
In `@src/lib/rag/rag-query-guard.ts`:
- Around line 19-34: Extract the shared classification logic from
shouldShortCircuitUnsupportedSearch and isUnsupportedSoftTailAnalysis into a
single private helper that distinguishes pattern-guard matches from soft-tail
eligibility. Update both exported functions to reuse that helper while
preserving their current behavior: the first should short-circuit on any guard
or soft-tail match, and the second should return true only for the soft-tail
match.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: f344ebf5-2be1-48d1-81e6-9faf55e28cda
📒 Files selected for processing (114)
docs/clinical-hazard-analysis.mddocs/codebase-index.mddocs/deployment-architecture.mddocs/maturity-backlog-workorders.mddocs/observability-slos.mddocs/openai-cross-border-basis.mddocs/privacy-impact-assessment.mddocs/process-hardening.mddocs/rag-hybrid-findings-and-todo.mddocs/rag-injection-threat-model.mddocs/redesign/06-verification.mddocs/search-rag-master-context.mddocs/search-rag-master-plan.mddocs/tenancy-defense-in-depth-review.mdscripts/check-maintainability-budgets.mjsscripts/eval-answer-quality.tsscripts/eval-quality.tsscripts/eval-rag.tsscripts/eval-retrieval.tsscripts/eval-search-api.tsscripts/eval-search.tsscripts/eval-utils.tsscripts/warm-retrieval-cache.tssrc/app/api/answer/route.tssrc/app/api/answer/stream/route.tssrc/app/api/documents/[id]/labels/route.tssrc/app/api/documents/[id]/reviews/route.tssrc/app/api/documents/[id]/route.tssrc/app/api/documents/[id]/summarize/route.tssrc/app/api/documents/[id]/table-facts/route.tssrc/app/api/documents/bulk/reindex/route.tssrc/app/api/documents/bulk/route.tssrc/app/api/search/route.tssrc/components/clinical-dashboard/display-text.tssrc/lib/answer-verification.tssrc/lib/clinical-safety.tssrc/lib/cross-document-synthesis.tssrc/lib/rag/rag-answer-support.tssrc/lib/rag/rag-answer-text.tssrc/lib/rag/rag-cache-utils.tssrc/lib/rag/rag-cache.tssrc/lib/rag/rag-candidate-sources.tssrc/lib/rag/rag-claim-support.tssrc/lib/rag/rag-comparison.tssrc/lib/rag/rag-context-selection.tssrc/lib/rag/rag-contracts.tssrc/lib/rag/rag-document-summary-context.tssrc/lib/rag/rag-eval-cases.tssrc/lib/rag/rag-eval-diagnostics.tssrc/lib/rag/rag-extractive-answer.tssrc/lib/rag/rag-provider.tssrc/lib/rag/rag-query-guard.tssrc/lib/rag/rag-quote-verification.tssrc/lib/rag/rag-retrieval-variants.tssrc/lib/rag/rag-route-budget.tssrc/lib/rag/rag-routing.tssrc/lib/rag/rag-source-block.tssrc/lib/rag/rag-versioning.tssrc/lib/rag/rag.tssrc/lib/semantic-rerank.tssrc/lib/universal-search.tstests/anonymous-answer-cache-policy.test.tstests/answer-prose-runons.test.tstests/answer-ranking.test.tstests/answer-responsiveness-gate.test.tstests/api-validation-contract.test.tstests/architecture-boundaries.test.tstests/corpus-grounding.test.tstests/cross-tenant-staging-config.test.tstests/document-admin-rate-limit.test.tstests/document-mutation-routes.test.tstests/eval-utils.test.tstests/extractive-answer-formatting.test.tstests/private-access-routes.test.tstests/private-rag-access.test.tstests/public-access-deep.test.tstests/rag-abort-signal.test.tstests/rag-answer-fallback.test.tstests/rag-answer-support.test.tstests/rag-answer-text.test.tstests/rag-cache-invalidation.test.tstests/rag-cache-utils.test.tstests/rag-chunk-load-cache.test.tstests/rag-claim-support.test.tstests/rag-classifier-memo.test.tstests/rag-comparison.test.tstests/rag-content-accuracy.test.tstests/rag-context-budget.test.tstests/rag-document-summary.test.tstests/rag-eval-cases.test.tstests/rag-eval-source-governance.test.tstests/rag-fast-path-ordering.test.tstests/rag-generation-fingerprint.test.tstests/rag-injection.test.tstests/rag-offline-answer.test.tstests/rag-provider.test.tstests/rag-query-concurrency.test.tstests/rag-route-budget.test.tstests/rag-routing.test.tstests/rag-score.test.tstests/rag-second-stage-ranking.test.tstests/rag-shared-cache.test.tstests/rag-tail-latency.test.tstests/rag-trust.test.tstests/rag-variant-early-exit.test.tstests/railway-config.test.tstests/retrieval-access-scope.test.tstests/retrieval-hydration-scope.test.tstests/retrieval-query-variants.test.tstests/semantic-rerank.test.tstests/source-backed-recovery-cross-reference.test.tstests/source-review-route.test.tstests/universal-search.test.tsworker/main.ts
…in gaps (#2634) * deps: update browserslist to 4.28.8 so the production npm audit high clears (M19) Defect: the production dependency tree resolved browserslist 4.28.2, which carries two high advisories (GHSA-c83g-rgw3-j3cx, GHSA-73wf-gq98-2v4g), so the lockfile-gated `npm audit --omit=dev --audit-level=high` step in the safety job exits 1 on every lockfile-touching PR and on the weekly scheduled full run. Trigger: any PR that changes package-lock.json or .npmrc, or the Sunday scheduled CI run. Fix: `npm update browserslist` (owner-approved registry call, no major bump); the lock now resolves browserslist 4.28.8 and its own in-range data dependencies. No other dependency was touched. Proof: `npm audit --omit=dev` no longer lists browserslist; the remaining fast-uri high is a newer advisory outside this package's approved scope and is reported for owner decision. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * ci: give the worker's Python parsers a vulnerability signal (M20) Defect: worker/python/requirements.txt and eval/docling/requirements.txt are hash-locked but nothing reported a published CVE against a pinned parser — dependabot.yml had no pip ecosystem, and the weekly Trivy scan exited 0 inside a continue-on-error step with its summary written only to the run log. Trigger: a CVE against PyMuPDF, Pillow, pytesseract or docling, which parse attacker-supplied uploads in the ingestion worker. Fix: two pip Dependabot entries (with the hashed-lock regeneration note), and a follow-up step in docker-image.yml that writes the Trivy summary to the job summary and exits non-zero on HIGH/CRITICAL outside pull_request/merge_group runs, so the scheduled and main runs fail and notify-ci-failure.yml delivers the failure. Pull-request runs stay advisory, keeping tests/container-ci-contract.test.ts's non-blocking contract intact. Proof: tests/ci-audit-contracts.test.ts "M20" block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * ci: notify on Staging tenancy isolation failures (M25) Defect: notify-ci-failure.yml, the solo-maintainer safety net, enumerated nine workflows by name and omitted "Staging tenancy isolation", the daily cross-tenant staging harness, which itself only uploads an evidence artifact. Trigger: the daily run fails — a real cross-tenant leak on staging, or a rotated or missing CROSS_TENANT_* secret. Fix: add the workflow to the watched list; the existing head_repository and branch guard already admits scheduled runs on main. Proof: tests/ci-audit-contracts.test.ts "M25" block reads the workflow's `name:` and asserts it appears in the notifier's list. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * ci: point the live Web-Vitals default routes at pages that render (M29) Defect: the `routes` dispatch default of live-web-vitals.yml still listed `/therapy-compass`, `/dsm` and `/forms`, which have been 307 redirects onto `/?mode=<id>` since #2157 and #2308. scripts/summarise-web-vitals.mjs rejects a report whose final URL differs from the requested one, so 18 of the 30 default cells were "measured a different page" and the summarise step could never produce a verdict. The header also told the operator to record the verdict against #17, closed 2026-07-31. Trigger: dispatching "Live Web Vitals baseline" without overriding `routes`. Fix: the default now measures `/`, `/therapy-compass/search`, `/documents/search`, `/dsm/search` and `/forms/search` — the in-place result routes lighthouse-budget.json's `$routes` rationale names — and the header points at the open row via `npm run issues:update`. The summariser's fixture DEFAULT_ROUTES (and its cell names) moved with it; the summariser itself is unchanged. Proof: tests/ci-audit-contracts.test.ts "M29" block — every default route resolves to a page.tsx that does not call redirect( (the `/` shell's guarded legacy-parameter redirect excepted), the fixture equals the workflow default, and the #17 instruction is gone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * ci: digest-pin the advisory Semgrep image in sast.yml (L36) Defect: sast.yml ran `semgrep/semgrep:1.168.0` by mutable tag on every push and pull request while ci.yml's blocking ingestion gate already pinned the immutable digest of the same triage-verified image. Trigger: an upstream re-tag or registry compromise of the 1.168.0 tag; the job runs third-party code with read access to the private source tree. Fix: reference `semgrep/semgrep:1.168.0@sha256:59fbed61…`, the digest ci.yml uses (recorded as the 1.168.0 image in docs/maturity-backlog-workorders.md, X4), so the two references move together. No registry call was needed. Proof: tests/ci-audit-contracts.test.ts "L36" block asserts the advisory image is digest-pinned to the gate's digest; check:github-actions stays green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * ci: drop unused permissions from the Secret Scan workflow (L37) Defect: secret-scan.yml granted `pull-requests: read` and `security-events: write`, leftovers from gitleaks-action@v3's SARIF upload; the pinned scripts/run-gitleaks-pinned.mjs never touches either API. Trigger: compromise of a step inside the job on the private repository — least-privilege only, no functional effect today. Fix: reduce the workflow to `contents: read`. Proof: tests/ci-audit-contracts.test.ts "L37" block asserts the permissions block is exactly `contents: read` and that the runner script emits no report; `npm run check:gitleaks-pinned` self-test still passes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * ci: gate the @claude workflows on author association (L38) Defect: claude.yml and claude-backlink.yml admitted any non-bot account that could comment; the header's "collaborator" claim was not enforced at workflow level, and claude.yml's job holds contents/pull-requests/issues/ id-token write scopes. Trigger: a comment author outside the maintainer's trust boundary mentions @claude on an issue or pull request. Fix: every trigger arm now also requires the comment or review author_association to be OWNER, MEMBER or COLLABORATOR, and the header comments describe the gate that is actually enforced. Proof: tests/ci-audit-contracts.test.ts "L38" block parses each `if:` arm of both workflows and asserts the association gate is present. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * deploy: watch check-installed-lock-parity.mjs in both Railway services (L54) Defect: scripts/check-installed-lock-parity.mjs is COPYed into and executed by both Dockerfiles during `npm ci` (postinstall --write-stamp) but was not a watch pattern in railway.app.json or railway.worker.json, unlike its siblings check-node-engine.cjs and install-git-hooks.mjs. Trigger: a push that changes only that script does not rebuild either image, so the deployed image keeps a script version main no longer has until an unrelated push rebuilds it. Fix: add the script to both watchPatterns arrays. Proof: tests/ci-audit-contracts.test.ts "L54" block derives every `COPY scripts/*` from each Dockerfile and asserts the matching Railway config watches it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * deps: bring allowScripts in step with the lock (L55) Defect: package.json allowScripts still approved esbuild@0.28.1 after Dependabot #2468 pinned esbuild 0.28.2, and omitted @sentry/cli@2.58.6, which also carries a postinstall — `npm ci` warned that both scripts were "not yet covered by allowScripts". Trigger: any install; today an advisory warning, but a strict allowScripts setting would break every install path including the Railway image builds. Fix: approve esbuild@0.28.2 and @sentry/cli@2.58.6; no other key changed. Proof: tests/ci-audit-contracts.test.ts "L55" block asserts every allowScripts key matches a lock version and every non-optional package with an install script is covered. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * governance: route CODEOWNERS review to src/lib/rag/ (L91) Defect: .github/CODEOWNERS named `/src/lib/rag.ts` and `/src/lib/rag-*.ts`, neither of which exists since the RAG stack moved to `src/lib/rag/` in #994, so the protected directory was covered only by the `*` catch-all. Trigger: a collaborator joins and review routing on the RAG tree is expected to apply. Fix: replace the two dead patterns with `/src/lib/rag/`; the remaining retrieval/search patterns are unchanged and still match files. Proof: tests/ci-audit-contracts.test.ts "L91" block asserts every CODEOWNERS pattern matches an existing surface and that the RAG directory is named. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * ci: point the Codex auto-resolve high-risk list at the real deployment files (L92) Defect: the high-risk path pattern in codex-autofix-review-comments.yml named `Dockerfile`, `railway.json` and `nixpacks.toml`; the repository has `Dockerfile`, `Dockerfile.worker`, `railway.app.json` and `railway.worker.json`, and neither `railway.json` nor `nixpacks.toml`. Trigger: a pull request touching only the worker Dockerfile or either Railway config was classified low risk for routing. Fix: `/^(?:Dockerfile(?:\.worker)?|railway\.(?:app|worker)\.json)$/`. Proof: tests/ci-audit-contracts.test.ts "L92" block extracts the pattern and asserts it matches each existing deployment file and no longer names the absent ones; check:codex-autofix-workflow and the existing workflow guard tests stay green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * deps: drop the dead brace-expansion@2 override and record override rationale (L129) Defect: package.json overrides carried `brace-expansion@2: ^2.1.4`, which matches nothing (the lock holds only 1.1.18 and 5.0.9), and the two exact pins (`esbuild`, `sharp`) had no recorded reason, so the block looked reviewed when it was not. Trigger: repository hygiene; the exact `sharp` pin can also turn a routine Next patch that raises its sharp floor into an install conflict. Fix: remove the dead override and add an "Overrides rationale" table to docs/framework-dependency-modernization-checklist.md naming every remaining override, why it exists and when it can go. The exact pins themselves are kept, per the package notes; relaxing `sharp` is recorded as the exit condition. Proof: tests/ci-audit-contracts.test.ts "L129" block fails on a major-scoped override with no lock match and on an override missing from the rationale table. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * deps: hold the @types/node major in Dependabot (L20) Defect: @types/node 26.x is typechecked against a Node 24 runtime (engines, .nvmrc, both Dockerfiles, Railway images), and dependabot.yml's ignore list held only typescript and eslint majors, so nothing stopped the next major. Trigger: a contributor uses a Node-26-only API; tsc accepts it and the worker or an API route throws at runtime on Node 24. Fix (partial): add a semver-major ignore for @types/node with a comment tying it to engines.node. Pinning the devDependency back to the 24.x line needs a registry call (`npm install -D @types/node@^24`) that this package was not approved to make; it is reported for owner decision and stays tracked in docs/framework-dependency-modernization-checklist.md. Proof: tests/ci-audit-contracts.test.ts "L20" block asserts the ignore entry is present in the npm ecosystem. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t * deps: keep brace-expansion@2 as a recorded CVE pre-pin, and register the new CI suite Two of this package's own gates contradicted each other. The L129 hygiene rule removed the brace-expansion@2 override because the lock holds no 2.x copy, but tests/installed-lock-parity.test.ts pins all three brace-expansion majors to CVE-2026-14257-patched maintenance releases. Deleting the entry to satisfy the hygiene rule would quietly drop that protection for the day a transitive bump reintroduces a 2.x, so the override is restored rather than the CVE guard relaxed. The L129 rule is narrowed instead of weakened: a major-scoped override may outlive its lock match only while its row in the overrides rationale table is marked pre-pin and states why, and a second case rejects a pre-pin row naming an override package.json no longer carries, so the exemption cannot rot into a blanket one. The rationale table gains the brace-expansion@2 row with its exit condition. Separately, tests/ci-audit-contracts.test.ts reads workflow files, which tests/ci-cache-safety.test.ts requires to be listed in test:ci-workflows; it is now registered there. Verified: tests/ci-audit-contracts.test.ts, tests/installed-lock-parity.test.ts and tests/ci-cache-safety.test.ts together, 117 passed (117); check:installed-lock-parity clean; package-lock.json unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR --------- Co-authored-by: Claude <noreply@anthropic.com>
Summary
Phase 4 of the maturity backlog (
docs/maturity-backlog-workorders.md→ X2): the first real domain directory undersrc/lib, and the seam that unblocks directory-scoped boundary rules for the rest of the 197-file flat lib.rag.ts+ 21rag-*.ts) intosrc/lib/rag/viagit mv(renames preserved).@/lib/rag*→@/lib/rag/rag*(51 sites) and the relative../src/lib/rag*→../src/lib/rag/rag*(worker + tests). The../scripts/rag-offline-contract.mjsimport was deliberately left untouched.readFileSynccontract-test paths,docs/codebase-index.md, and rag path references across 13 maintained docs.Pure moves + path rewrites — no logic change, so behaviour is identical.
Verification
Full local gate, all green (run as constituent commands rather than the
verify:pr-localwrapper):npm run typecheck— pass.npm run test— 3012 pass; the only failure is the pre-existing container-onlypdf-extraction-budgetflake (a Python-subprocess deadline test with no rag dependency), which fails identically on cleanorigin/main— not a regression from this refactor.npm run lint— pass.npm run check:maintainability-budgets— pass (src/lib/rag/rag.ts5143/5238).npm run docs:check-index— pass (newsrc/lib/rag/indexed);npm run docs:check-links— pass (989 refs);npm run format:check— pass.display-text.ts, is a string helper — no JSX/markup).Risk and rollout
git log --followtraces history through the renames.Clinical Governance Preflight
This is a byte-identical relocation of the rag modules (
git mv+ import-path rewrites); no clinical behaviour, data flow, or configuration changed. Each item is preserved by construction:Clinical KB Database(sjrfecxgysukkwxsowpy)Notes
Next natural step (separate PR) is X3 — decompose
rag.tsbehind the maintainability budget, now that its siblings already sit insrc/lib/rag/. This PR intentionally does not touch logic.Generated by Claude Code
Summary by CodeRabbit