Wire differentials, services and medications catalogues into search modes - #323
Merged
Merged
Conversation
…odes Differentials search mode previously rendered a hard-coded acute-confusion demo fixture regardless of the query, and never touched the imported 232-record catalogue. Now: - Add scored, alias-aware rankers (rankDifferentialRecords, rankPresentationWorkflows) and an adaptive composer that leads with a presentation workflow when it matches about as strongly as the best diagnosis, otherwise interleaves by score. - Return scored `matches` from GET /api/differentials for both kinds and rank live owner rows directly (replacing the snapshot-intersect). - Add useDifferentialSearch hook and rewire the Differentials search view to render real query-driven catalogue results with loading/empty/error states, functional kind filters, and accurate catalogue copy. - Accept empty document-evidence payloads in differentials mode instead of erroring, and gate the results view on search submission. - Medications: replace the hard-coded acamprosate row highlight and filter literals with rank-driven equivalents; add a name-prefix boost. - Services already searched the imported catalogue; unchanged. Verified: focused vitest suites, verify:cheap (1108 tests), ui-tools.spec.ts chromium (36 passed) against the live dev server. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015UuyyMMegXxTeEJsyR741t
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
The phone gap assertion measured medication-home one animation frame after visibility, racing the post-hydration check that hides the smart-search hint/prompt rows (restored in #318) and shrinks the portaled composer from 111px to 61px. CI measured the transient state (bottomGap 110.95 < topGap 134) and failed deterministically; fresh local loads reproduced it 3 in 4 runs. Poll until two consecutive measurements match so the guard asserts the settled layout at both widths. Verified 5/5 passes with --repeat-each=5 against a dev server running with the CI env vars. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015UuyyMMegXxTeEJsyR741t
BigSimmo
marked this pull request as ready for review
July 6, 2026 12:38
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
Bugbot Autofix prepared fixes for all 3 issues found in the latest run.
- ✅ Fixed: Stale source evidence after query edit
- Source evidence now tracks the query that produced documentMatches and is hidden when the live composer text no longer matches.
- ✅ Fixed: Filter treats first row as best
- Result rows now use the global best-match id and catalogue rank instead of the filtered list index.
- ✅ Fixed: Catalogue failure shows empty-match UI
- The empty-results state is skipped when catalogue search fails so only the failure alert is shown.
You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit eda08d6. Configure here.
…re UI - Hide source evidence when the composer query no longer matches the query that produced documentMatches - Style and rank rows by global catalogue position, not filtered-list index - Skip empty-match UI when catalogue search fails so only the alert shows
… state - Track the query the current document evidence was fetched for and treat evidence from a different query as pending, so live-edited catalogue results never render under a stale "Source-backed" panel. - Style the overall top-ranked result as best match instead of whichever row is first in a kind-filtered list. - Render a distinct catalogue-failure card (retry/browse links, alert role) instead of showing the "No catalogue matches" empty state when the catalogue fetch errors or is unauthorized. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015UuyyMMegXxTeEJsyR741t
Both this branch and the Bugbot autofix addressed the same three review findings. Resolution keeps this branch's implementation (the dashboard states which query the document evidence belongs to, rather than inferring it from match-array identity, and the catalogue-failure card carries the browse/retry actions) and adopts the autofix's global-rank numbering for kind-filtered rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015UuyyMMegXxTeEJsyR741t
BigSimmo
enabled auto-merge
July 6, 2026 13:20
…ankers Main's #325 added its own snapshot-only rankDifferentialRecords(query) on the shared rankCatalogRecords primitive while this branch shipped a records-parameter variant that the /api/differentials route uses to rank live owner rows. Resolution keeps one ranker built on the shared primitive with the records-first signature (matching the medication and service rankers): title x8 + hinge/safety x3 fields, alias expansion surfaced as a "symptom alias" reason via a new `expanded` signal, exact/compact/phrase bonuses, and urgency as a tie-break only. The primitive also gains an optional prefixValues/prefixBonus so the medication ranker keeps this branch's name-prefix boost, and the universal-search differentials domain passes the snapshot explicitly. Test suites from both sides are retained on the unified signature. Verified post-merge: verify:cheap (1152 tests), format:check, chromium ui-tools 36/36 and ui-universal-search 3/3 against the live dev server. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015UuyyMMegXxTeEJsyR741t
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
src/lib/differentials.tsgains scored, alias-aware rankers (rankDifferentialRecords,rankPresentationWorkflows) and an adaptive composer (composeDifferentialSearchResults) that leads with a presentation workflow when it matches about as strongly as the best diagnosis (followed by its candidate diagnoses in ranked order), otherwise interleaves by score. Urgency (emergent/urgent) only nudges tie-breaks — it never outranks a stronger text match.GET /api/differentialsreturns scoredmatches({record|workflow, score, reasons}) for both kinds, mirroring the medications API, and ranks live owner rows directly instead of the previous O(n²) snapshot-intersect.records/presentations/total/governancekeep their existing semantics (additive change).useDifferentialSearch(query)hook fetches diagnosis + presentation matches in parallel with the sibling hooks' auth/401 handling; the Differentials results view now renders real query-driven results with loading/empty/error states, functional All/Presentations/Diagnoses filters with real counts, real tag-overflow chips (no more fake+2), and accurate catalogue copy (the "synthetic demonstration content" banner is replaced bydifferentials-catalogue-notice)./api/searchdocument-evidence call is kept and runs in parallel.acamprosaterow highlight and alcohol/acamprosate/baclofen filter literals are replaced with rank-driven equivalents, andrankMedicationRecordsgains a +5 name-prefix boost (reason"name prefix").Verification
npm run verify:cheap— pass (lint, typecheck, 1108 vitest tests; only pre-existing warnings)npm run verify:ui— targeted equivalent: fulltests/ui-tools.spec.tson chromium against the live dev server, 36/36 passed (includes the rewritten differentials search spec asserting a real catalogue result row); prescribing smoke spec also passednpm run verify:release— not run (not a release/handoff change)npm run format:check— passnpm run eval:retrieval:quality— not run: needs live keys unavailable in this environment. Note: this change does not modify document-retrieval ranking/selection/chunking/scoring (src/lib/rag.ts,retrieval-selection.tsuntouched); it adds catalogue-side rankers and client wiring only. Please run locally before merge if you want the 23/23 confirmation.npm run eval:rag/eval:quality— not applicable (answer generation untouched)npm run check:production-readiness— runs clean apart from expected missing-secret findings in this no-secrets environment (no Supabase/OpenAI env configured)npm run check:deployment-readiness— not applicableClinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy) — no env/project changesNotes
rankMedicationRecords/rankServiceRecordspattern (field-weighted term matching with reasons), plus catalogue alias expansion (e.g. "confused" → confusion/delirium/encephalopathy) surfaced as asymptom aliasreason./differentials/presentationsand/differentials/diagnosesstream pages (still static cards), and debouncing the per-keystroke catalogue fetches (matches the existing medications behaviour).🤖 Generated with Claude Code
https://claude.ai/code/session_015UuyyMMegXxTeEJsyR741t
Generated by Claude Code
Note
Medium Risk
Changes clinical decision-support result ordering and copy from static demo to relevance-ranked catalogue content; document-evidence flows are preserved but users may rely on ranked catalogue rows before source search.
Overview
Differentials search replaces the hard-coded acute-confusion demo with query-driven results from the imported catalogue (diagnoses and presentations). New
rankDifferentialRecords/rankPresentationWorkflowsscoring (alias expansion, urgency tie-breaks) andcomposeDifferentialSearchResultsadapt ordering (presentation-led when it matches strongly).GET /api/differentialsnow returns optionalmatcheswithscoreandreasons, ranking owner rows in one pass instead of intersecting snapshot search.The UI adds
useDifferentialSearch, real loading/empty/error states, All / Presentations / Diagnoses filters, and catalogue copy instead of demonstration banners.ClinicalDashboardshows ranked results after submit even with zero document evidence, and treats an empty corpus in differentials mode as empty evidence rather than a blocking error.Prescribing drops hard-coded medication highlights/filters in favor of rank-based selection and adds a name-prefix boost to
rankMedicationRecords. Tests and UI specs updated accordingly.Reviewed by Cursor Bugbot for commit eda08d6. Configure here.