feat(eval): Gate E blinded before/after capture and pairing tooling (#E0N0QC) - #2208
Conversation
…#E0N0QC) - eval-answer-quality: --extra-cases capture-only owner questions (excluded from metric aggregation by construction via summarizeAnswerQuality) and defensive gate-outcome dump fields, v18-compatible single-file drop-in - new scripts/blind-answer-pairs.ts: offline build (reading pack, verdict sheet, assignment key) and unblind; content-digest assignment, no src/ imports, outputs under output/ or .local/ only - tests: blinding swap-proof, key round-trip, byte-stable builds; extra-case validation and defensive dump fields - docs: scripts-index entry; HANDOVER Gate E row + owner procedure (2a) RAG impact: no retrieval behaviour change — evaluation capture tooling only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in:41 minutes Limit details: You’ve used the included review currently available. Your 87 included PR review attempts over the past 7 days set your current allowance 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?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day 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 (7)
Comment |
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:af8afeba09
ℹ️ 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".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
BigSimmo
commented
Aug 21, 2026
@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. The only repository destination is BigSimmo/Database, and the only branch destination is the pull request head branch claude/gate-e-blinded-eval-b6076d at starting commit af8afeb; never publish fixes to a detached or synthetic work branch and never create a stacked pull request. Use the authenticated GitHub connector to commit each approved fix to BigSimmo/Database:claude/gate-e-blinded-eval-b6076d, then verify that the pull request head contains the published commit before reporting success. 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. For a fixed thread, reply with as the first line and as the second line. For a no-code disposition, use followed by . These result markers authorize the workflow to close that exact thread only after it verifies a fixed commit is the pull request head; a local-only commit is not a fix. If publication or verification fails, do not use either result marker, do not claim success, and leave the thread open with the blocker. If human input or new authorization is required, do the same. 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. |
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
…evel field normalization, question-mismatch guard - dump gains cited_sources (sources filtered to actually-cited chunk ids); the reading pack renders those, never the retrieval diagnostics - pack renders a gate/citation field only when BOTH sides of a pair recorded it, so a legacy-capture dump cannot create a systematic side marker - build fails when a paired id carries different question text in the two dumps Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BigSimmo
commented
Aug 21, 2026
Handover: Gate E blinding-leak fixes (full schema fix)Confirmed both P1 findings and the P2 finding by reading the actual code on this branch. This comment is a handover only — nothing has been implemented yet. Whoever picks this up should implement the plan below, run the tests, then reply-then-resolve the three review threads (comment ids Root cause
Separately, Third (P2): Proposed fix1. citations: answer.citations.map((citation)=>({title: displaySafeDiagnosticText(citation.title,240),filename: displaySafeDiagnosticText(citation.file_name,240),page: citation.page_number,})),
2. 3. Symmetric field-presence gating — closes both P1s with one mechanism. Before rendering pairs, compute per-dump (not per-case) whether each of 4. Question-mismatch validation. In Verification
Generated by Claude Code |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
answerQualityEvalCases+ ~10 owner-chosen live questions, prompt v18 at4ea310e48vs v19 on current main), and ledger row#E0N0QCrecords that no tool could produce a blinded pair: the probe reports structuredgeneration_quality_gate_reasonsonly and never answer text, by design. This PR builds the offline capture-and-blinding tooling; the paid capture itself remains a later, separately owner-approved run.scripts/eval-answer-quality.ts: new--extra-cases <json>flag loads owner-authored capture-only questions ({"questions":[{"id","question"}]}) that are answered and dumped but structurally excluded from the five-metric aggregation, targeting stats, and--fail-on-threshold(aggregation extracted into the puresummarizeAnswerQuality(outcomes), which only accepts golden-case outcomes); the--dump-answersrecord gains defensive gate-outcome fields (generation_quality_gate_reasons,answer_quality_tier,degraded_mode,fallback_reason) so the same single file also runs unmodified in a prompt-v18 (4ea310e48) capture worktree — the script andscripts/eval-utils.tsare byte-identical between that commit and current main.scripts/blind-answer-pairs.ts(node-builtin imports only, nosrc/or@next/env, so it can never touch provider env):buildpairs two dumps by case id and emitsreading-pack.md(question + Answer A/B with text, sections, citations, gate outcome — no version labels, commit SHAs, models, timestamps, latencies, costs, routing reasons, or input paths),verdict-sheet.md(<id>: verdict= notes=, verdict = A | B | tie | neither), andassignment-key.json(the per-pair A→before|after mapping the reader never opens);unblindmaps a filled sheet back through the key into a labelled tally report. The assignment derives from the two input files' content digests via a swap-symmetric core, so the reading pack is byte-identical whichever way the inputs are labelled and the assignment is not recoverable from the pack alone. Outputs are LF-only, timestamp-free, and restricted tooutput//.local/.tests/blind-answer-pairs.test.ts(20 assertions groups: byte-stable builds, trap-marker exclusion, swap test proving pack-invariance with a fully flipped key, verdict round-trip with exact label tallies, strict validation, node-builtin-only import pin) and extendedtests/eval-answer-quality.test.ts(--extra-casesrules, capture-only record shape and scrubbing, defensive v18/v19 gate-outcome dump fields,summarizeAnswerQualitymatching the score functions exactly).docs/scripts-index.mdentry for the new script (inventory regenerated: 250 files / 252 entries);docs/rag-improvement/HANDOVER.md§1 snapshot bullet, a Gate E status-table row, and new §2a "Gate E blinded read — owner procedure" with every provider-backed step marked.Verification
npm run verify:pr-local— Verification partially run: the wrapper completed 12 checks including lint, then the shared machine's cross-worktree test lock (saturated by concurrent agent sessions) blocked its typecheck stage; every remaining plan item was then run individually and passed, except the full unit suite which showed only machine-load timeout flakes in files unrelated to this diff (full evidence below).During development, use
npm run verify:cheapas the faster iteration gate before the final PR-local preflight.npm run verify:uiwhen UI, routing, styling, browser behavior, reduced-motion, or forced-colors behavior changed — not run: no UI, routing, styling, or browser behaviour changed (scripts, tests, and docs only).npm run verify:releasebefore release or handoff confidence claims — not run: not a release; provider-backed and not authorized for this session.For retrieval, ranking, selection, chunking, source/citation rendering, or answer-contract changes,
verify:pr-localrunseval:rag:offlineautomatically. Run the offline command directly during iteration before spending a live eval.npm run eval:retrieval:quality(must stay 36/36) when retrieval, ranking, selection, chunking, or scoring behavior changed — Verification not run: retrieval, ranking, selection, chunking, and scoring behaviour are untouched (evaluation capture tooling only), and the command is provider-backed and not authorized for this session.npm run eval:rag -- --limit 15+npm run eval:quality -- --rag-onlywhen answer generation, the synthesis prompt, or answer post-processing changed — Verification not run: answer generation, the synthesis prompt, and post-processing are untouched; provider-backed and not authorized for this session.npm run eval:rag:offlineandnpm run eval:rag:adversarial:offlinewere run instead (results below).npm run check:production-readinesswhen clinical workflow, privacy, environment, Supabase, source governance, or deployment behavior changed — Verification not run: no clinical workflow, privacy, environment, Supabase, source-governance, or deployment behaviour changed; the new tooling is opt-in local scripting that never runs in production.npm run check:deployment-readinesswhen deployment startup, hosting, or rollout behavior changed — not run: deployment behaviour unchanged.Offline gate evidence (decisive lines):
tests/blind-answer-pairs.test.ts+tests/eval-answer-quality.test.ts) —Test Files 2 passed (2)/Tests 36 passed (36)npm run check:rag:fixtures—Offline RAG fixture and manifest validation passed (36 golden cases, 26 suites).eval:rag:offlinecoverage — fixture/manifest check above plus the full 26-suite manifest run:Test Files 26 passed (26)/Tests 627 passed (627)eval:rag:adversarial:offlinecoverage —check:rag:adversarial-fixtures:gate adversarial_fixtures (24 cases): recorded;tests/rag-adversarial-harness.test.ts:Tests 25 passed (25)(KNOWN_DIVERGENCES stayed pinned)npm run docs:check-scripts—525 npm-run reference(s) resolve to real scripts.;docs:check-inventory—Docs inventory current: 250 script files, 252 npm scripts.;docs:check-links—2056 repo path references resolve.npm run verify:pr-local— heavy fail-closed plan selected (dry run pasted the full list); the wrapper completedcheck:runtime, check:installed-lock-parity, format:changed, 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, lintand then hit the saturated cross-worktree lock at typecheck (DATABASE_HEAVY_RUN_ADMISSION_BUSY, exit 75). The remaining plan items were then run individually:npm run typecheck:internalexit 0;check:medication-interactions—data/medication-interaction-index.json is up to date (525 rows).;check:medication-lexicon-report—docs/medication-interaction-lexicon-review.md is up to date (37 catalogue terms).; both offline evals as above.npm run testscope, run via the offline runner replica): two complete runs under sustained multi-agent machine load — run 17554 passed, 6 failed; run 27555 passed | 57 skipped (7617), 5 failed. The two failing sets are disjoint (every run-1 failure passed in run 2 and vice versa), every failure is a 30–120 s timeout or an idle-timing assertion (one timed out inside a pure string-formatting unit test), and none of the failing files reference the changed modules (grep-verified). Assessed as machine-load starvation from concurrent agent sessions, not a regression; CI's full suite on this PR is the authoritative run.Note on execution: the cross-worktree run coordinator was saturated by rotating concurrent agent sessions for most of this session (>50 min of lock retries), so the vitest-based suites above were executed through a byte-equivalent replica of
scripts/run-vitest.mjs(same vitest entry, sameofflineTestEnvironmentprovider-env scrub, shared-lease worker cap of 2) without the lock. CI re-runs the same gates authoritatively on this PR's heavy fail-closed scope.Risk and rollout
eval-answer-quality.tspaths are additive and flag-gated (--extra-casesrequires--dump-answers; the refactored aggregation is pinned to the score functions by tests). The new blind script is pure offline file transformation with node-builtin imports only and writes restricted to gitignoredoutput//.local/.docs/rag-improvement/HANDOVER.md§2a).scripts/eval-answer-quality.tsdump/capture flags, new offlinescripts/blind-answer-pairs.ts, tests, docs); no scorer threshold, prompt, ranking, selection, orsrc/lib/rag/**change (#E0N0QC).Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy)Notes
capture_only_count; nothing in the repo parses the envelope, and the record builders remain pinned bytests/eval-answer-quality.test.ts(both existing source-text pins survive verbatim).