Skip to content

Answer page: replace the source capsule, sheets and table column with a rail and a drawer - #2362

Merged
BigSimmo merged 4 commits into
mainfrom
claude/answer-page-redesign-review-4ufdl5
Aug 25, 2026
Merged

Answer page: replace the source capsule, sheets and table column with a rail and a drawer#2362
BigSimmo merged 4 commits into
mainfrom
claude/answer-page-redesign-review-4ufdl5

Conversation

@BigSimmo

@BigSimmoBigSimmo commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replace the answer page's four separate source surfaces with one source rail under the answer and one source drawer behind every row. The rail lists every cited document — index badge, title, page, support level, review status — and each row opens a drawer carrying that document's support statement, cited passage, tables, images, and the route back to the original PDF. New modules: answer-source-rail.tsx, answer-source-drawer.tsx, and the shared leaf answer-source-rows.ts.
  • Remove the "Sources" capsule and its popover/sheet pair from answer-content.tsx; the cited list is now on the page rather than one tap behind a chip.
  • Remove the Clinical notes sheet and the five-tab Evidence sheet from answer-result-surface.tsx. Their per-source content (claims, quotes, tables, images) is what the drawer carries; the quote cards' "ask a follow-up" action moved into the drawer with the passage it asks about.
  • Remove the wide-screen table column. Tables fold into the source drawer, attached to the source they were cited from, with anything unmatched falling to the first source so no table becomes unreachable.
  • Reduce AnswerSupportSummaryCard to the answer-level strip: the priority/safety row, an evidence-gaps disclosure built from renderModel.warnings, and a "Report a problem" disclosure wrapping the existing AnswerFeedbackPanel. Evidence gaps and feedback are statements about the answer rather than about any one document, so they stayed on the card instead of following the per-source content into the drawer.
  • The safety-findings sheet is unchanged and still reachable.answerSupportPriority returns a safety-findings priority ahead of everything else and its trigger lives inside this card, so the card renders whenever priority is set. Removing it outright would have removed the only route to safety-critical source findings.
  • Retarget the compactCitations preference at the rail: it collapses to a single chip that expands on tap. The zero-source "No direct source found" warning stays worded in every mode — compact must never hide a missing-source signal.
  • Extend tests/rendered-text-formatting.test.ts to scan the three new modules, so the raw-render guards that covered the capsule preview travel with the code rather than being escaped by the move.

This implements the four owner decisions recorded in docs/answer-page-redesign-handover.md §10 on 2026-08-24, and the design drawn at /mockups/answer-chat-perfected-v2. Rows are min-h-12 (48 px) throughout; they are deliberately not min-h-11.

Two things the redesign costs, both known and accepted:

  • A short answer on a phone is taller than it was, because the rail lists sources inline where the capsule was a single chip. The two phone-geometry guards now measure the rail as real content the same way they already measure the also-matches panel and the answer-card support label; the flat 8 px unexplained-overflow allowance is unchanged. The rail row was also compacted so title and metadata share one 48 px tap target rather than stacking a control on a separate caption line.
  • Reaching a table now means opening the drawer for the source that table came from, rather than reading it in a column beside the answer. That is the accepted cost recorded against decision 2.

Old code is deliberately left in place rather than deleted in this change: source-preview-popover.tsx, sourceCapsuleDisplay, ClinicalNotesChecklistPanel, and MobileEvidenceSheetContent all stay on disk and stay pinned by their existing tests. Their removal is staged as a separate change in handover §8, after the threshold-scan question in §10a has been re-checked against real answers.

Verification

  • npm run test — 834 files, 10048 passed | 1 skipped, 0 failed. docs/design-system/adoption-manifest.json was regenerated with npm run design-system:adoption:update (the Sheet consumer moved from answer-content.tsx to answer-source-drawer.tsx).
  • npx tsc --noEmit — clean.
  • npm run lint — clean at --max-warnings 0.
  • npm run format — run, and the result is committed. npx prettier --check . on the pushed tree: All matched files use Prettier code style!
  • npm run ensure — server confirmed at the URL it printed; never assumed a port.
  • Chromium: every answer-surface test this diff touches was run and passes — the @criticaldemo answer flow reaches a source-backed answer, both Copy control matches the visible clinical table viewports, phone short answer stays top-aligned with no phantom scroll into black, and phone answer result keeps the edge dock and shared chrome synchronized on a short runway. The full --project=chromium --grep-invert "@quarantine|@mockup" sweep (561 tests) was still running locally when this PR was opened; its result is reported in a follow-up comment. CI's Production UI job is the authoritative run.
  • npm run arbiter -- test returned RUN "test" — rag scope never defers — CI's own routing treats it as heavy, so the full suite was run rather than deferred.
  • npm run check:dead-code-candidate -- --diff origin/main reports FAIL with 4 refusals, and the refusals are the tool's re-export blind spot rather than deletions: sourceCapsuleDisplay, sourceStatusDotTone and sourceStatusShortLabel were moved to answer-source-rows.ts and re-exported from answer-content.tsx, which the per-file scan does not follow. tests/status-semantics.dom.test.tsx and tests/answer-preferences.dom.test.tsx import them from the original path and pass, which is the direct evidence they still resolve. The fourth, SourcePreviewContent, was module-private and its only "pin" is a mention inside a comment. Nothing was tuned to make this pass, and the gate is not wired into CI.
  • Not run: npm run eval:retrieval:quality, npm run eval:rag, npm run eval:quality, npm run verify:release, npm run check:production-readiness — all provider-backed, and no retrieval, ranking, selection, chunking, scoring, or answer-generation code is touched by this diff.

Risk and rollout

  • Risk: This is the whole source-checking surface of the answer page replaced at once, with no feature switch — that was the owner's explicit choice. The failure a clinician would feel is a cited document becoming harder to reach, so the tests deliberately assert reachability rather than appearance: every table the clipboard quotes must be openable, a source-only answer must still list its documents and open the drawer, and focus must return to the rail row the drawer was showing.
  • Rollback: revert this commit. No migration, no stored state, no configuration, and no data shape changes.
  • Provider or production effects: None. No Supabase, OpenAI, or Railway call is added, removed, or altered.
  • RAG impact: none — no file under src/lib/rag/, no retrieval RPC, no ranking surface, and no golden fixture is touched. classifyPullRequestFiles returns ragRanking: false for this diff.

Clinical Governance Preflight

Completed because this change alters source rendering and document access on the answer surface, even though classifyPullRequestFiles returns clinicalRisk: false for these paths.

  • Source-backed claims still require linked source verification before clinical use. The drawer's support sentence is explicit about how far a page goes — it states the claim directly, supports only part of it, or is merely related — and it has a null case: opened from the source list rather than from a claim, it says so instead of asserting a claim that was never made. Every row and the drawer both link to the original PDF.
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval. This change moves existing owner-scoped answer content between components; it adds no new document, upload, export, or sharing path.
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy). No Supabase configuration, migration, or client code is touched.
  • Service-role keys and private document access remain server-only. All three new modules are client components that render data already present in the answer render model; none reads an environment variable or issues a request.
  • Demo/synthetic content remains clearly separated from real clinical sources. The demo corpus path is unchanged; the Chromium coverage above exercises it through the same isDemoMode() fallback as before.
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative. Review status is carried in two places rather than one: the rail row keeps the existing status dot and its worded label, and the drawer adds an explicit warning panel on a review_due or outdated source telling the reader to confirm the passage against a current source. Per decision 1, staleness is never encoded in the reference mark's colour alone. Unknown metadata still falls to the muted tone through the unchanged sourceStatusDotTone.
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed. This is a presentation change to how existing cited evidence is laid out; it introduces no new clinical claim, no new recommendation, and no change to what the system asserts or to any answer's content.

Notes

  • The support card's two new disclosures set aria-controls only while their panel is in the DOM. Pointing it at an absent id was caught by expectDomIntegrity's broken-ARIA audit during this work, not guessed at.
  • The rail renders as role="list" divs rather than an <ol>. It sits inside plain-answer-response, where a ui-smoke guard asserts the primary answer reads as prose and not as a bullet list; the source-capsule preview it replaced used the same idiom for the same reason.
  • The row's accessible name restates the support level and review status, because an aria-label replaces the row's own text — without them a screen reader would hear the title and page but never that the document is outdated.
  • An answer can carry a table with no cited source to hang it off (dedupeVisualEvidence only filters against the primary sources when there are some). Those render in place rather than being lost with the column.
  • answerViewMode in ClinicalDashboard.tsx is write-only for now and carries a comment saying so. Its only reader was the clinical-notes panel; the state and its resets stay until that panel is removed in the follow-up, so a view mode does not have to be rebuilt from scratch.
  • Still open from the handover, unchanged by this PR: §10a's threshold-scan question — Essentials collected every dose and cut-off into one list, and the new surface has no equivalent. Nothing is lost, but the scan is. It should be re-checked against real answers before the old panel is deleted.

Generated by Claude Code


Note

Medium Risk
This is a full replacement of how clinicians reach cited PDFs, passages, and tables on the answer surface with no feature flag; regressions would affect verification workflows, though RAG and backend paths are unchanged.

Overview
Replaces the answer page’s four separate source UIs (Sources capsule + popover/sheet, Clinical notes sheet, Evidence sheet, and the desktop table column) with a single source rail under the prose and a shared AnswerSourceDrawer opened from each row. Shared cited-document logic lives in answer-source-rows.ts (up to six rows); the rail and drawer both consume it so lists do not drift.

NaturalLanguageAnswer drops inline source preview chrome and wires onOpenSource into the surface-owned drawer. StagedAnswerResultSurface removes clinical-notes/evidence sheets and the table aside; tables, passages, images, and “ask about this passage” follow-up move into the drawer (uncited-only tables still render inline). AnswerSupportSummaryCard is trimmed to safety/priority, collapsible evidence gaps from renderModel.warnings, and Report a problem feedback; clinical-notes and evidence entry points are gone. ClinicalDashboard stops passing evidence-map props and makes answerViewMode write-only pending panel removal.

Tests add answer-source-rail.dom.test.tsx, extend formatting guards to the new modules, and retarget ui-smoke/stress flows to rail → drawer behavior (focus return, paging, tables in drawer).

Reviewed by Cursor Bugbot for commit ded3adc. Configure here.

… a rail and a drawer
The answer page carried four separate places to check a source: a "Sources"
capsule opening a popover on desktop and a sheet on phone, a five-tab Evidence
sheet, a Clinical notes sheet, and a sticky table column on wide screens. That
is four mental models for one question — where did this come from? — and the
design study found it is why the page reads as busy rather than trustworthy.
Replace all four with one source rail under the answer and one drawer behind
every row. The rail lists each cited document with its index badge, title, page,
support level and review status; the drawer carries that document's support
statement, cited passage, tables, images, and the route back to the original
PDF. Implements the four owner decisions recorded in the handover on 2026-08-24.
New modules answer-source-rail.tsx, answer-source-drawer.tsx and the shared leaf
answer-source-rows.ts. The drawer is built on the existing ui/sheet, so the
portal, focus trap, late focus return and phone/desktop split are the ones every
other product overlay uses.
AnswerSupportSummaryCard becomes the answer-level strip: the priority/safety
row, an evidence-gaps disclosure from renderModel.warnings, and a "Report a
problem" disclosure wrapping the existing AnswerFeedbackPanel. Gaps and feedback
are statements about the answer rather than about any one document, so they stay
on the card instead of following per-source content into the drawer. The safety
findings sheet is unchanged and still reachable: answerSupportPriority returns a
safety priority ahead of everything else and its trigger lives in this card.
The quote cards' follow-up action moved into the drawer with the passage it asks
about, rather than being dropped with the sheet that used to host it. A table
whose chunk matches no cited source falls to the first source, and an answer
carrying tables with no cited source at all renders them in place, so no table
can become unreachable.
compactCitations now collapses the rail to a chip that expands on tap. The
zero-source "No direct source found" warning stays worded in every mode.
Four defects the gates caught, fixed rather than worked around:
- the rail's <ol> tripped the ui-smoke guard that the primary answer must read
as prose and not a bullet list, so it uses the role="list" idiom the capsule
preview used for the same reason
- both new disclosures pointed aria-controls at ids absent while collapsed
- the row's aria-label replaced its own text, silencing the support level and
review status; the accessible name now restates both
- a table with no cited source had no drawer to live in
A short phone answer is taller than it was, because the rail lists sources
inline where the capsule was one chip. The row was compacted so title and
metadata share a single 48px tap target, and the two phone-geometry guards now
measure the rail as real content the same way they already measure the
also-matches panel and the answer-card support label. The flat 8px
unexplained-overflow allowance is unchanged.
Old code is left in place rather than deleted: source-preview-popover.tsx,
sourceCapsuleDisplay, ClinicalNotesChecklistPanel and MobileEvidenceSheetContent
all stay pinned by their existing tests. Their removal is staged separately,
after the threshold-scan question is re-checked against real answers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AP3MXGx1bGeEBmFKYkeLA8
@supabase

supabaseBot commented Aug 24, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitaiBot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 46 minutes.

View limit details

Limit details: You’ve used the included review currently available. Your 103 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.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b81e5615-2ad5-443f-846b-e377b2dd3eab

📥 Commits

Reviewing files that changed from the base of the PR and between 5dd4e31 and c49c839.

⛔ Files ignored due to path filters (1)
  • docs/design-system/adoption-manifest.json is excluded by !docs/**
📒 Files selected for processing (13)
  • src/components/ClinicalDashboard.tsx
  • src/components/clinical-dashboard/answer-content.tsx
  • src/components/clinical-dashboard/answer-result-surface.tsx
  • src/components/clinical-dashboard/answer-source-drawer.tsx
  • src/components/clinical-dashboard/answer-source-rail.tsx
  • src/components/clinical-dashboard/answer-source-rows.ts
  • src/components/clinical-dashboard/answer-thread-turn.tsx
  • src/components/clinical-dashboard/evidence-panels.tsx
  • tests/answer-source-rail.dom.test.tsx
  • tests/answer-support-priority.dom.test.tsx
  • tests/rendered-text-formatting.test.ts
  • tests/ui-smoke.spec.ts
  • tests/ui-stress.spec.ts

Comment @coderabbitai help to get the list of available commands.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix prepared fixes for all 3 issues found in the latest run.

  • ✅ Fixed: Feedback hidden on clean answers
    • The support card now mounts whenever onSubmitFeedback is wired, so a clean high-trust answer still shows Report a problem.
  • ✅ Fixed: Duplicate rail IDs break focus
    • Prior-turn rails no longer emit drawer return-focus ids, and each rail list uses a unique useId so getElementById restores the live row.
  • ✅ Fixed: Images attach to wrong source
    • Images now follow the table rule: attach by matching chunk id, otherwise only the first source, never every row that shares a document.

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit ded3adc. Configure here.

Comment threadsrc/components/clinical-dashboard/answer-result-surface.tsx Outdated
Comment threadsrc/components/clinical-dashboard/answer-source-rail.tsx Outdated
Comment threadsrc/components/clinical-dashboard/answer-source-drawer.tsx

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:ded3adcbf4

ℹ️ 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".

Comment threadsrc/components/clinical-dashboard/answer-source-rail.tsx
Comment threadsrc/components/clinical-dashboard/answer-result-surface.tsx Outdated
@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@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/answer-page-redesign-review-4ufdl5 at starting commit ded3adc; 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/answer-page-redesign-review-4ufdl5, 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.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Left a non-blocking comment and did not approve. Cursor Bugbot reported 3 unresolved issues that need human review. No additional reviewers were assigned.

Open in WebView Automation

Sent by Cursor Approval Agent: Pull Request Router and Approver

@github-actions

Copy link
Copy Markdown
Contributor

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Production UI (1)needs investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #13803 (failure).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

@chatgpt-codex-connector

Copy link
Copy Markdown

This request touches a high-risk clinical source-rendering path and requires xhigh reasoning effort under the repository’s reasoning-effort policy.

Please select xhigh in the Cloud reasoning control, then resubmit the same request with the exact marker:

[xhigh-confirmed]

No repository inspection, edits, tests, commits, pushes, thread replies, or resolutions were performed.

View task →

…ent.
Keep Report a problem on clean high-trust answers, stop prior-turn rails from stealing drawer focus restore, and attach images by chunk with an unmatched-S1 sink.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Left a non-blocking comment and did not approve. Cursor Bugbot still has unresolved findings that need human review on this head. No additional reviewers were assigned.

Open in WebView Automation

Sent by Cursor Approval Agent: Pull Request Router and Approver

The three `clinical table mobile expansion` cases were rewritten for the drawer
in the previous change but never re-run on their own; the full Chromium sweep
found them red. Two causes, both mine:
The test opened the first rail row and expected a table there, but a table hangs
off the source it was cited from, which is not necessarily the best match. It
now searches the rows the way the sibling `demo answer flow` test already did.
Its focus-trap assertions looked the full-screen table dialog up by name. That
became ambiguous once the nested dialog opened inside the source drawer, because
the drawer is a dialog too and carries the document's name — so the lookup could
resolve to the drawer instead. They now use the handle
`openMobileTableFullscreen` already returns; the assertions are unchanged.
Also adds a case pinning that evidence gaps stay answer-level: they are listed
on the support card rather than against any one cited source.
The three source fixes for the review findings landed on this branch
concurrently from the Cursor autofix agent. Its versions are equivalent to the
ones written here and its `showInlineSupportCard` condition is the better of the
two — it names the rows that would render rather than hard-coding true — so they
are kept as pushed rather than duplicated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AP3MXGx1bGeEBmFKYkeLA8

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Left a non-blocking comment and did not approve. Cursor Bugbot still has unresolved findings that need human review on this head. No additional reviewers were assigned.

Open in WebView Automation

Sent by Cursor Approval Agent: Pull Request Router and Approver

cursor[bot]
cursorBot approved these changes Aug 24, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Prior Cursor Bugbot findings on this PR are resolved, and no remaining configured signal requires human review. No reviewers were assigned.

Open in WebView Automation

Sent by Cursor Approval Agent: Pull Request Router and Approver

@BigSimmo
BigSimmo merged commit 7db16eb into mainAug 25, 2026
32 checks passed
@BigSimmo
BigSimmo deleted the claude/answer-page-redesign-review-4ufdl5 branch August 25, 2026 00:31
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@BigSimmo@claude@cursoragent