Also matches: rebuild the cross-mode panel and put it on every mode - #2640
Conversation
The panel that offers "here is where else this query lands" was carried by nine of the seventeen modes and looked like a flat strip pinned under the results. This makes it a proper surface and gives it to every mode. Design - The section is now a recessed tray on --surface-subtle holding raised mode cards, instead of a bevelled bar at the same elevation as the results above it. card-recipes.ts already records why the old border + --shadow-inset pair read flat: two edge treatments on one surface. - Each mode card goes vertical — identity row, full-width result rows, footer link. The old horizontal `tile | titles | View all` row squeezed the titles into the middle third and truncated them at every width, which is why "Mental Health Hospital in the Home" arrived as "Mental Health Hospital in th…". Titles now get the whole card and clamp at two lines. - Result rows are real 48px tap rows with their own hover and focus states, and the footer reads "View all in <Mode>", matching the cross-mode typeahead. - Loading is a skeleton grid in the real card geometry, so the tray no longer collapses to one text line and snap-opens when matches land. - Layout is 1 / 2 / 4 columns across phone, tablet and wide desktop. Four columns inside a 1024px well leaves no room for a two-line clinical title, so the tablet band holds two columns all the way to xl. - The visible aria-live node is replaced by an sr-only role="status" announcer (SPEC §9.2 — a live region is never visible content), and the accent follows the recorded option-C study: tile plus code chip, title in heading colour. Coverage - Added the panel to DSM, Specifiers, Calculators, Factsheets, Dictionary, Sources and On Call. - Prescribing no longer suppresses it. That early return was written when the panel sat ABOVE the medication results and displaced the count, patient strip and primary matches on a phone; the mount has since moved below the result list, so the reason is spent. ui-stress now pins its position under those results instead of pinning it out. - Answer keeps its own CrossModeLinksSection on the answer surface and is recorded as the one deliberate exemption. - tests/universal-also-matches-mode-coverage.test.ts registers all seventeen modes, so a mode either mounts the panel or carries a written reason. A merge resolution has silently dropped one of these mounts before (#1804). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQ7yPfVVVh62WursxM6mbF
The sr-only status node rendered one fixed string, so a screen reader was told "No additional matches in other modes." while four populated mode cards sat on screen. It now reports the pending state, the match count, or the empty state, and the visible empty paragraph keeps the empty wording of its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQ7yPfVVVh62WursxM6mbF
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_47c5de5e-5e77-4286-8c8e-e3e08261506b) |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Prescribing declares `resultKind: "documents"` on purpose — it searches the indexed sources rather than a forms table — so ClinicalDashboard's documents arm matched it and mounted a second panel over the one MedicationPrescribingWorkspace already renders under the medication list. `/?mode=prescribing` shipped two. This is the other half of why the old `modeId !== "prescribing"` early return existed. The previous commit read it as a positioning decision only, which was incomplete: it was also the de-duplication for this shared result kind. The workspace keeps the mount, because only it knows where the medication result list ends. The exclusion names the mode rather than the result kind, because the kind is shared and the ownership is not. tests/ui-stress.spec.ts caught it by asserting the count is exactly one; the coverage test now carries an offline guard for the same duplicate, verified to fail with the exclusion removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQ7yPfVVVh62WursxM6mbF
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_9c99190b-089e-49f0-a770-5e50b9273ca1) |
Two rows per card, not three. The identity row is now itself the link into that mode, which is where a reader would tap anyway, and the separate footer link is gone with it. That removes a 48px row per card — four rows of pure chrome across the panel on a phone — and the panel loses roughly a third of its height at every width without touching a single tap target. The short code chip drops out of the accessible name (aria-hidden): it abbreviates the mode name the link already says in full, so it only made the name longer. An sr-only "View all in " keeps the link's purpose in its name. `sm:min-h-compact-meta` rather than `sm:min-h-0` on that row: stepping an interactive control below the tap floor at the sm band is counted as new debt by check:design-system-contract, which caught it. 40px is the sanctioned floor for a dense meta row, and the 36px icon tile already sets the real height, so this is the same pixels with the rule met rather than dodged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQ7yPfVVVh62WursxM6mbF
The tab said the same thing three ways. A tinted count badge sat beside the label reading "4", the line under it read "4 related modes", and desktop wore a third pill saying it again on the right. That stacked subtitle was also the only reason the tab needed two rows. One meta string now, right-aligned after a hairline rule: label, rule, status. The rule is the editorial section-header device, and it is what lets the status sit hard against the trailing edge at any width without a second line, so phone and desktop finally wear the same header instead of two designs of it. The mark is quieter too — a hairline square with the glyph carrying the accent, rather than a saturated block competing with the four category tiles directly below it. Chevron down to the icon scale's md step and pulled to the edge, so it reads as an affordance rather than a button. Copy: "Tap to open" replaces "Tap to browse related modes", which no longer fits one line on a narrow phone. No `duration-*` on the chevron transition: check:design-system-contract counts a hardcoded motion utility as debt, and it caught the one I had written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQ7yPfVVVh62WursxM6mbF
…nto claude/gifted-franklin-8jdn1h
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_cb093334-6dbf-40da-87c8-eee70e7211e2) |
Summary
CrossModeLinksSectionand is the one recorded exemption.Design changes
--surface-subtleholding raised mode cards on--surface-raised+--e1. Previously it wasborder-lux+--shadow-inset, whichcard-recipes.tsalready documents as reading flat: two edge treatments on one surface.tile | titles | View allrow squeezed titles into the middle third and truncated them at every width, which is why "Mental Health Hospital in the Home" arrived as "Mental Health Hospital in th…". Titles get the whole card and clamp at two lines.smup). The footer reads "View all in <Mode>", matching the cross-mode typeahead's existing wording.xl. Four columns inside a 1024px content well leaves no room for a two-line clinical title, so the tablet band holds two columns all the way up toxl.aria-livenode is replaced by ansr-only role="status"announcer (SPEC §9.2 — a live region is never visible content). It reports pending / count / empty rather than one fixed string.also-matches-accent-mockups.tsxis annotated as shipped.Prescribing — and the two defects found while verifying
Both were mine, both were caught by running the gates rather than by reasoning, and both are fixed in the commits on this branch. Recording them because the second one changes the stated reason for a decision this repo already had.
The announcer contradicted the screen (
b2c5610). Therole="status"node rendered one fixed string, so a screen reader was told "No additional matches in other modes." while four populated mode cards were on screen. It now reports the real state.Prescribing mounted the panel twice (
96d9749). Prescribing declaresresultKind: "documents"deliberately — it searches the indexed sources, not a forms table — soClinicalDashboard's documents arm matched it and mounted a second panel over the oneMedicationPrescribingWorkspacealready renders under the medication list./?mode=prescribingshipped two.This is the half of the original
modeId !== "prescribing"early return that the first commit read wrongly. That commit described the suppression as purely positional (the panel used to sit above the medication results). It was also the de-duplication for this shared result kind. The workspace now owns the single mount, because only it knows where the medication result list ends, and the exclusion names the mode rather than the result kind, because the kind is shared and the ownership is not.tests/ui-stress.spec.tscaught it by asserting the count is exactly one. The coverage test also carries an offline guard for the same duplicate, and that guard was mutation-verified: removing the exclusion fails it withexpected '…' to contain 'searchMode !== "prescribing"'.Verification
All results below are from the current head (
96d9749).npm run lint— exit 0.[gate-receipts] recorded a pass for "lint:internal" (7028 input files).npm run typecheck(tsc --noEmit -p tsconfig.json) — exit 0, no diagnostics.npx vitest run— full offline suite:Test Files 3 failed | 1147 passed | 1 skipped (1151),Tests 3 failed | 16858 passed | 2 expected fail | 3 skipped (16866). The three failures (rag-plan-package-parity,privacy-readiness-contract,clinical-hazard-controls) were reproduced on a stashed clean tree and are pre-existing onmain, not this PR's.Focused re-runs after each fix:
tests/universal-also-matches-mode-coverage.test.ts20/20, plusaudit-navigation-auth-regressionsandmedication-prescribing-workspace.dom— 3 files / 42 tests passed.npm run check:design-system-contract— passed. It caught a real defect mid-change (a--text-softdecoration-alias consumer), corrected to--decoration-soft.npm run check:type-scale,check:icon-scale,check:mockups,check:diff-integrity— all passed. diff-integrity:PASS — 11 changed test file(s), 115 -> 119 test case(s), against base 6cfaa94c8.npx prettier --check .— whole tree: "All matched files use Prettier code style!", committed.Browser (focused, not the full gate).
npm run plan:browserselectedlevel: fullfor this diff, so the complete Chromium suite is CI's to run and was not run locally. What did run locally, against an isolated production build:tests/ui-universal-search.spec.ts— 20 passed (40.0s). Covers the panel's own contracts: after the owning results in the DOM, phone-deferred fetch until expansion, absent on Answer, once on Favourites and the legacy Tools URL.tests/ui-tools-search-mode-mockup.spec.ts— 15 passed, including no horizontal overflow at 320 / 390 / 639 / 768 / 1440 / 1920.tests/ui-stress.spec.ts— 3 passed (12.1s) after the duplicate fix. This is the file whose medication assertion this PR rewrites, and the run before the fix failed it:expect(locator).toHaveCount(expected) failed … Expected: 1 Received: 2.Caveat that matters: this container has Playwright chromium-1194 against the repo's pinned 1234, so the runner's preflight fails closed (feat(ui): compact phone bottom search bar on search/result views #255/chore(deps-dev): bump prettier from 3.9.1 to 3.9.4 #312). These runs used
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATHpointed at the 1194 headless shell — a different browser build from the pinned one. Treat them as real evidence for behaviour, not as a substitute for CI's pinned run.npm run verify:pr-local— Verification not run: the local heavy-run coordinator was held by the browser runs, and it mirrors whatpr-requiredruns on this PR. Every gate it aggregates for this scope is listed above, run directly.Visual proof was also taken directly: the panel screenshotted at 390 / 834 / 1440 px in light and dark, plus the loading state, against the dev server with a mocked
/api/search/universal. That is what surfaced the title truncation and a 2px row/footer misalignment.Note on the red
PR requiredonb2c5610: that run reportedCANCELLED with no failing job: coverage production-ui. Pushing96d9749cancelled those two mid-flight (cancel-in-progress), and the aggregate stays red on a cancelled job because a cancelled job verified nothing. Nothing failed on it —static,safety,build,production-ui-critical,lighthouse-budgetandcaring-contacts-dball reported success. The workflow's own message says to look for the newer run on the current head SHA, which is the one that counts.Risk and rollout
/api/search/universalonly after submission, and on phones only after the reader expands it, so the added mounts add no speculative requests on narrow viewports. The realistic failure mode is cosmetic, or a duplicate mount — which is now covered offline and in the browser.supabase/changes.universal-search-mode-context.tsand the retrieval libraries are unchanged.Clinical Governance Preflight
Not applicable in substance — presentation and mount points only, not ingestion, answer generation, ranking, source rendering, document access or clinical output. For completeness:
Clinical KB Database(sjrfecxgysukkwxsowpy) — no Supabase config touched.Notes
96d9749's mount is a one-line change and the coverage test's exemption map is where the reason would be recorded.tests/universal-also-matches-mode-coverage.test.tsexists because this mount is the part that goes missing: a merge resolution silently dropped the Forms mount once before (recorded in the merge-loss audit for Remove cross-mode “Also matches in other modes” panel and related mounts/tests #1804), and nothing failed when it did.🤖 Generated with Claude Code
https://claude.ai/code/session_01JQ7yPfVVVh62WursxM6mbF
Note
Low Risk
Changes are presentation and mount wiring on search result pages; universal search still runs only after submission (and on phones after expand), with offline and browser tests guarding duplicate prescribing mounts.
Overview
Rebuilds the cross-mode “Also matches” panel so it reads as a recessed tray under primary results: new vertical mode cards (full-width titles, identity row as “view all”, skeleton loading), responsive 1 / 2 / 4 columns, and sr-only status text that matches pending vs populated vs empty states.
Rolls the panel out on DSM, Specifiers, Calculators, Factsheets, Dictionary, Sources, and On Call, and re-enables it for prescribing below the medication list in
MedicationPrescribingWorkspaceinstead of suppressing fetches/render in the component. Prevents a duplicate panel on/?mode=prescribingby excluding prescribing fromClinicalDashboard's universal mount (prescribing shares the documents result kind). Answer stays exempt via its own cross-mode links.Adds
tests/universal-also-matches-mode-coverage.test.tsso every app mode either mountsUniversalSearchAlsoMatchesor documents why not; page unit tests mock the panel to avoid auth coupling.Reviewed by Cursor Bugbot for commit 33a8532. Configure here.