feat(rag): B1 telemetry gap assessment + B2 offline adversarial harness (packet S5) - #2056
Conversation
…ss (packet S5) B1 (docs/rag-improvement/README.md §B1): the four dashboard questions map to existing rag_queries.metadata fields except verification-stage latency — verification_latency_ms was measured into latencyTimings and dropped at the persistence boundary. It now ships behind RAG_TELEMETRY_EXTENDED (typed in env.ts, default false) through the allow-listed numeric projection in src/lib/rag/rag-answer-telemetry-metadata.ts; rag.ts shrinks by 3 lines (the three tail latency fields extract into the new module). Canary-absence tests prove contaminated inputs cannot push a registered canary token into emitted telemetry, flag on or off. Phoenix decision record closed as deferred. B2 (README §B2, plain-Vitest substitute; no dependency change): new command eval:rag:adversarial:offline validates the S4 fixture contract then runs tests/rag-adversarial-harness.test.ts over the 24 synthetic cases with a mocked Supabase client and provider, a stubbed-throwing fetch, a measured per-case round-trip ceiling, and per-case canary-absence assertions on every persisted rag_queries row. Three fixture expectations diverge from current pipeline behaviour and are pinned in a self-expiring KNOWN_DIVERGENCES register; two provider-failure expectations are recalibrated in the fixture with rationale. Routed by scripts/ci-change-scope.mjs to RAG-surface PRs only (new safety-job step + verify:pr-local selection + scope self-tests). Also reconciles the S1 canary answer-gate denominator to 44/44 against run 32025082010's own report (baseline-record §3). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019JLzXeRzE8zze3SoCoo5SH
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in:19 minutes Limit details: You’ve used all 1 included review currently available under your plan. You completed 94 included PR reviews in the past 7 days; at that activity level, included reviews refill at 1 review per hour. Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. 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 Run ID: 📒 Files selected for processing (20)
Comment |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019JLzXeRzE8zze3SoCoo5SH
…e HANDOVER status-table conflict) Conflict was the §2 status table: PR #2048 added the S1d packet row and recorded the S1b canary pair on main while this branch updated the S5 row. Resolution keeps main's table (S1d + S1b/S4/T4 updates) and re-applies the S5 row (#2056) and the S5-reconciled 44/44 answer-gate denominator on the S1 row's evidence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019JLzXeRzE8zze3SoCoo5SH
Uh oh!
There was an error while loading. Please reload this page.
…5/S6 status-table and scripts-index conflicts) Both sides kept: main's S5 row (PR #2056, corrected to merged 093f934 per the table's update rule) and this branch's S6 row (PR #2057); scripts-index counts regenerated from the merged package.json (246 files / 251 scripts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XX3AXYHiGXiFfL2VGFiEMn
…ps (#2061) * docs(rag): mark S5 merged, re-key S2's blocker, queue the S5 follow-ups - HANDOVER: S5 row Merged (PR #2056, merge 093f934, post-merge canary run 32049952885); S2 row now blocked on S1c + S1d (each with its own canary). - COORDINATION §7: S5 and D2 in the done list; wave 1 without S5; follow-ups. - Four immutable inbox requests: the three self-expiring KNOWN_DIVERGENCES pins from tests/rag-adversarial-harness.test.ts (P2 issues) and the owner decision on enabling RAG_TELEMETRY_EXTENDED in production (P3 task). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(ledger): record the D3 S5 follow-up review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
docs/rag-improvement/README.md§B1 (stage timeout rate, fallback rate, candidate-count distribution, p50/p95 stage latency) were mapped against what PR feat(rag): record the structured generation-quality verdict on fallback (#231 phase 1) #1899 and earlier instrumentation already persist torag_queries.metadata. Three are fully answerable today; the single proven gap isverification_latency_ms, which was measured intolatencyTimings(rag.tsfinalizeAnswer) but dropped at the persistence boundary. It now ships behind the new typed flagRAG_TELEMETRY_EXTENDED(src/lib/env.ts, defaultfalse) through an allow-listed numeric projection in the new modulesrc/lib/rag/rag-answer-telemetry-metadata.ts— only allow-listed keys, only finite numbers, so free text can never pass.rag.tsshrinks by 3 lines (the three tail latency fields extract into the module; 4359/4362 against the maintainability budget), with byte-identical metadata keys when the flag is off.tests/rag-telemetry-canary-absence.test.tsimports the realcanaryRegistryfrom the S4 fixtures and proves contaminated timings objects (canary tokens as values under allow-listed keys, as extra keys, and as keys themselves) never reach the emitted object, flag on or off, and thatsummarizeGenerationQualityAnswerShape(PR feat(rag): record the structured generation-quality verdict on fallback (#231 phase 1) #1899) stays canary-free.eval:rag:adversarial:offlinerunsscripts/check-rag-adversarial-fixtures.mjsfirst (fail-closed on missing/invalid fixture, proven: removing the fixture exits 1 before any test) and thentests/rag-adversarial-harness.test.ts, which drives all 24 S4 cases throughanswerQuestionWithScopewith a mocked Supabase client and provider module. Every case asserts: zero network attempts (fetchstubbed to throw), a measured per-case Supabase round-trip ceiling of 14 (breach fails with the breakdown), the fixture's behaviour/citation/forbidden-substring contract via deterministic assertion helpers (tests/helpers/rag-adversarial-assertions.ts, unit-tested intests/rag-adversarial-assertions.test.ts), and canary absence across the entire capturedrag_queriesinsert row.cite-mismatched-attribution: the offline document-match listing cites every retrieved document;scope-other-owner-documentandscope-guessed-chunk-id: review fallbacks cite in-scope evidence / echo query text instead of refusing). The tenancy invariant held in all three (no cross-scope read, no identifier echo). They are pinned in a self-expiringKNOWN_DIVERGENCESregister: the harness asserts the normative contract still fails and the observed behaviour stays exactly as pinned, so movement in either direction goes red. Two provider-failure expectations were recalibrated in the fixture itself with in-file rationale (provider-malformed-payload→error_contained, matching the observed safe containment;provider-refusal-prose-as-answer→ the genuinely retrieved chunk joins the citation allow-list, since citing real evidence on failure is this repository's designed conservative shape). The fixture validator stays green.scripts/ci-change-scope.mjsgains the adversarial validator/contract/harness paths inragEvalPatternsplus four new self-test cases;.github/workflows/ci.ymladds one step to the existing requiredsafetyjob gated onrag_eval_changed == 'true';scripts/verify-pr-local.mjsselects the command for the same scope (pinned in its plan self-test). Non-RAG PRs never run the harness.baseline-record.md§3 flagged the 44-vs-45 discrepancy and named S5 as the place to resolve it. Canary run 32025082010's own report (job 95372702769) printsAnswer Metrics | Cases | 44,Failing Answer Cases — None, and exactly 44 diagnostics rows; HANDOVER's "45/45" was a transcription error and is corrected.origin/main; S1 evidence corrected to 44/44);docs/rag-improvement/data-flow-register.mdsink row and known-gap Bump vitest from 4.1.6 to 4.1.7 #4 updated;docs/scripts-index.mdand generated inventory refreshed.RAG impact: no retrieval behaviour change — offline harness and allow-listed telemetry only. The
rag.tsdiff extracts three metadata fields into a pure projection module with identical flag-off output; no retrieval, ranking, routing, gating, or prompt logic is touched, and the fixture edits change test expectations only. No canary pair required.Verification
npm run verify:pr-local— heavy offline scope selected (script + RAG-surface changes fail closed). Decisive closing summary, verbatim:completed: check:runtime, check:installed-lock-parity, format:changed, check:npm-ci-dry-run, sitemap:check, docs:check-index, docs:check-inventory, docs:check-scripts, docs:check-links, check:branch-review-ledger, check:outstanding-issues, check:ledger-write-discipline, check:github-actions, check:ci-scope, check:gitleaks-pinned, check:ci-triage, check:pr-policy, check:gate-manifest, check:skills, check:pr-mergeability, check:verification-plan, lint, typecheck, test, build, eval:rag:offline, eval:rag:adversarial:offline, check:medication-interactions, check:medication-lexicon-report — failed: (none) — not reached: (none).npm run eval:rag:adversarial:offline— decisive lines:Test Files 1 passed (1)/Tests 25 passed (25)/Offline adversarial fixture validation and regression harness passed.Fail-closed proof: with the fixture file temporarily removed the command exits 1 before any test runs.npm run check:rag:adversarial-fixtures—Adversarial fixture contract passed (24 synthetic cases, 8 categories, 6 canaries).after the two expectation recalibrations; assertion-helper suiteTests 13 passed (13).node scripts/check-maintainability-budgets.mjs—src/lib/rag/rag.ts: 4359/4362 lines.node scripts/ci-change-scope.mjs --self-test—CI change scope self-test passed.(4 new adversarial routing cases);node scripts/verify-pr-local.mjs --self-test—PR-local verification plan self-test passed.npm run check:production-readiness— run in this credential-free environment; the two FAIL items are the documented provider capability gaps (Missing server environment variables: NEXT_PUBLIC_SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEYandMissing OPENAI_API_KEY), not regressions from this diff — no provider credentials exist in this session by design.npm run eval:retrieval:qualitynot run: provider-backed and not required — no retrieval, ranking, selection, chunking, or scoring behaviour changed.Risk and rollout
rag_queries.metadatalatency fields into a pure module plus one flag-gated additional numeric field; flag-off output is byte-identical and pinned by test. Everything else is eval scripts, tests, CI routing, and docs. The main residual risk is harness brittleness on future RAG changes, which is the point of the gate — and it runs only on RAG-surface PRs.RAG_TELEMETRY_EXTENDED=falseis the whole-surface rollback for the B1 field (it is also the default, so no action is needed unless the flag was enabled); the harness and routing revert with the commit.Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy)Notes
eval:rag:adversarial:offlinestep is the routed RAG-surface gate with the fail-closed validator front-end.KNOWN_DIVERGENCESentries are candidate/issuesfollow-ups (review-fallback citation/echo behaviour on scope-shaped and attribution-shaped requests); each register entry self-expires when pipeline behaviour reaches the fixture's normative expectation.Proposed HANDOVER edits for S6/S7 (handoff — last section by design)
For the coordinator to apply (or the next session to carry into
docs/rag-improvement/HANDOVER.md):reportKeysix-field convention — S6's benchmark reports should stamp the identical field set and order (pinned bytests/rag-adversarial-fixtures.test.ts). Suggested packet note: reusescripts/rag-adversarial-contract.mjs'sreportKeyFieldsexport rather than restating the list.scripts/eval-rag-adversarial-offline.mjsshows the validator-then-runner shape./issues: (a) the three pinned adversarial divergences; (b) enablingRAG_TELEMETRY_EXTENDED=truein production is an owner decision once a dashboard consumer exists — until then the flag stays false.Generated by Claude Code