Skip to content

Answer page: symbol off, one number per claim, no safety rail, one panel - #2388

Merged
BigSimmo merged 2 commits into
mainfrom
claude/answer-edge-to-edge-and-panels
Aug 26, 2026
Merged

Answer page: symbol off, one number per claim, no safety rail, one panel#2388
BigSimmo merged 2 commits into
mainfrom
claude/answer-edge-to-edge-and-panels

Conversation

@claude

@claudeclaudeBot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

The production half of the answer-page work approved in #2386. Everything here was drawn in /mockups/answer-chat-perfected-v2 first and signed off by the clinical owner on 2026-08-26, including "direction B" for the block beneath the answer.

  • The answer runs edge to edge. The answer-clinical-icon shield tile and its grid column are gone from plain-answer-response, the matching ps-[var(--answer-message-gutter)] is gone from the bare AnswerCard header, and --answer-message-gutter is deleted from globals.css. The tile was decorative (aria-hidden) and its column cost ~2.75rem of every line of a clinical answer on a 390px phone. There are two speakers on this surface, the person's turn is already a right-aligned bubble, and what identifies the assistant turn is the verification line above it — information rather than decoration.
  • One number per claim.maxMarksPerCluster is 1. Nothing is hidden: resolveClaimMarks already counted the remainder into overflow, +N renders it, and every source it counts sits on the rail immediately below at full tap size. That rail is also where a Review due or Outdated badge lives, per the 2026-08-24 decision that staleness is carried by the row and the drawer and never by the mark — so the one signal that must not be lost was never on the mark to begin with. This was checked in the code before the cap was changed, not assumed.
  • The safety card has no coloured rail.border-t-2 border-t-[color:var(--warning)] spanned a card that also holds Evidence gaps and Report a problem, colouring two controls that carry no state. Colour moves into the icon tile plus a severity chip built from the finding's own label, which answerSupportPriority now returns as severityLabel rather than running into the citation string. The row still renders whenever priority is set — it remains the only route to the safety-findings sheet.
  • Direction B under the answer.AnswerFollowUpSuggestions gains layout="rows" (one question per full-width row) and renders on every width; CrossModeLinksSection gains variant="line" (one collapsed row with a preview, opening to the rail it always was); questions sit above matches. Two second copies go with it: the composer dock no longer receives composerFollowUpSuggestions on the answer mode, and the dashboard no longer renders UniversalSearchAlsoMatches there. Both repeated content already on screen — the same three questions truncated onto one scrolling line, and a mode-level restatement of the record-level matches directly above it.
  • One citation fix travelling with it.cleanCitationTitle now inserts the missing space in Guideline(EMHS). Every citation label passes through that function, so the safety card, rail cards, drawer and print are fixed together. Display only — the stored title is untouched.

Verification

  • npm run test871 test files passed (871); 10502 passed | 1 skipped. Includes the repinned tests/answer-follow-up-chips.dom.test.tsx wiring contract, a new bracket-spacing case in tests/citations.test.ts, and tests/answer-claim-marks.test.ts with its overflow expectation derived from the cap rather than hard-coded.
  • npm run verify:ui — full Chromium project set. First run: 5 failed, 515 passed (18.8m). All five were this diff's, none were flakes, and each was diagnosed rather than re-run: one real ARIA defect I introduced (aria-controls pointed at a panel that only existed while expanded — caught by the smoke suite's DOM-integrity audit, fixed by keeping the panel mounted and hidden, with useId so two instances cannot collide), and four pinning the old layout, repinned to assert the same content through the new one. Re-run green — figures quoted below.
  • npx eslint on all nine changed source files — exit 0.
  • npx tsc --noEmit — no diagnostics.
  • npm run check:design-system-contract — passed (1012 production files); no ratchet moved. Status-colour boundary: colour-only status indicators 0; status-coloured numerals 0; image inversions 0.
  • npm run format then repo-wide npx prettier --check . — "All matched files use Prettier code style!"
  • Browser proof on the live answer route at 390px: no answer-clinical-icon in the DOM, answer-follow-up-suggestions present on a phone for the first time, cross-mode-links-line-trigger present, universal-also-matches absent, answer-support-card still rendering, zero page errors.

Risk and rollout

  • Risk: this is a clinical answer surface, and the item that deserves reviewer attention is the mark cap. A sentence supported by two documents now shows one number and a +1 instead of two numbers. The reasoning is in the Summary and in answer-claim-marks.ts: the remainder is counted, the rail below lists every source at full tap size, and review status was never carried by the mark. Second is the removal of two duplicate surfaces; both were second copies of content still on screen, and the mode-level panel still renders on the tools, documents, services and forms result kinds.
  • Rollback: git revert the commit. The change is additive-to-optional in shape — every removed element is a render-site deletion rather than a data change, so reverting restores the previous surface exactly.
  • Provider or production effects: none beyond the deploy itself. No provider-backed gate was run and no live service was called; all browser proof is against the local demo corpus.
  • RAG impact: no retrieval behaviour change — no file under src/lib/rag/**, no retrieval RPC, no ranking surface, no eval harness, no golden fixture. src/lib/answer-claim-marks.ts maps recorded claims onto already-ranked rail rows for display; it does not select, score or order sources.

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use
    • The verification line above the answer is unchanged in wording and placement, and every claim's route to its page is unchanged: the mark opens the drawer, and the rail lists every cited source at full tap size.
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
    • No patient-identifiable workflow is touched. Nothing here reads, writes or displays patient data.
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
    • Unchanged. No Supabase configuration, migration or project reference is modified by this diff.
  • Service-role keys and private document access remain server-only
    • No API route, client, key or access path is touched. This diff is presentation plus one display-only string normalisation.
  • Demo/synthetic content remains clearly separated from real clinical sources
    • Unchanged. The demo corpus is reached through the same isDemoMode() boundary as before, and no branch here distinguishes demo from live content.
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
    • This is the item the mark cap touches, and it holds. Review due and Outdated badges are rendered by the rail card and the drawer, not by the mark, per the recorded 2026-08-24 decision; the stale-evidence banner and the answer-level cautions are untouched; and the +N never lets a supporting source go uncounted.
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed
    • No decision-support behaviour changed. Retrieval, ranking, generation, verification and render policy are untouched; what changed is how many marks a claim shows, where three panels sit, and what colour carries a warning.

Notes


Generated by Claude Code

Everything /mockups/answer-chat-perfected-v2 argues for, applied to the live
answer surface after the clinical owner approved the look and chose "direction B"
for the block beneath the answer (2026-08-26). Written up in
docs/answer-page-redesign-handover.md §12.6–§12.8.
The assistant shield tile and its grid column are gone from plain-answer-response,
the matching ps-[var(--answer-message-gutter)] is gone from the bare AnswerCard
header, and the token itself is deleted. The tile was decorative and its column
cost about 2.75rem of every line of a clinical answer on a 390px phone. There are
two speakers here, the person's turn is already a right-aligned bubble, and what
identifies the assistant turn is the verification line above it.
maxMarksPerCluster is 1. Checked before changing, not assumed: resolveClaimMarks
already counts the remainder into overflow, +N renders it, every source it counts
is on the rail below at full tap size, and that rail is where a Review due or
Outdated badge lives — per the 2026-08-24 decision that staleness is carried by
the row and the drawer and never by the mark. The test now derives its overflow
expectation from the cap rather than hard-coding it.
The safety card loses its warning-coloured top rule, which spanned a card that
also holds Evidence gaps and Report a problem and so coloured two controls
carrying no state. Colour moves into the icon tile plus a severity chip built
from the finding's own label, now returned as severityLabel rather than run into
the citation string. The row still renders whenever priority is set; it is the
only route to the safety-findings sheet.
Direction B under the answer: AnswerFollowUpSuggestions gains layout="rows" and
renders on every width, CrossModeLinksSection gains variant="line", and questions
sit above matches. Two second copies go with it — the composer dock no longer
receives composerFollowUpSuggestions on the answer mode, and the dashboard no
longer renders UniversalSearchAlsoMatches there. Both repeated content already on
screen. Pinned so neither returns by accident.
cleanCitationTitle now inserts the missing space in "Guideline(EMHS)". Every
citation label passes through it, so the safety card, rail cards, drawer and
print are fixed together. Display only.
Verified: npm run test (871 files, 10502 passed, 1 skipped); npm run verify:ui
520 passed (18.1m) exit 0 — a first run found five failures, all this diff's,
one a real aria-controls defect I introduced and four pinning the old layout,
each diagnosed and fixed rather than re-run; eslint and tsc clean;
check:design-system-contract passed with no ratchet moved (colour-only status
indicators 0, status-coloured numerals 0); repo-wide prettier clean.
check:production-readiness still fails on pre-existing release-mode privacy debt
unrelated to this diff (#HVTYAT) — reported, not suppressed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AP3MXGx1bGeEBmFKYkeLA8
@claude
claudeBot requested a review from BigSimmo as a code ownerAugust 26, 2026 04:51
@supabase

supabaseBot commented Aug 26, 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 ↗︎.

@BigSimmo
BigSimmo enabled auto-merge (squash) August 26, 2026 04:53
@BigSimmo
BigSimmo merged commit 0b0f008 into mainAug 26, 2026
29 checks passed
@BigSimmo
BigSimmo deleted the claude/answer-edge-to-edge-and-panels branch August 26, 2026 05:02
BigSimmo pushed a commit that referenced this pull request Aug 27, 2026
… panel
Direction B from /mockups/answer-loading-redesign, applied to the live surface
after the clinical owner chose it (2026-08-27).
`AnswerProgressStepper` is gone. It was a filled accent panel carrying a 36px
icon tile, a five-circle stepper with connecting rails, a scrolling ECG trace, a
per-second elapsed counter and a Processing details disclosure — roughly 210px
of the loudest chrome in the product, occupying the answer's own position for
the four to twelve seconds before every answer, on a surface that PRs #2386 and
#2388 had just spent their whole argument quietening. It narrated the
orchestrator's five stages, which the reader is not operating, and it never
showed a single source.
`AnswerProgress` replaces it with one status line plus the arriving source rail.
The rail is the substantive half. The evidence preview already crossed the
stream boundary before the prose — trimmed, owner-scoped, governed, consumed by
the client — and was being rendered as a SECOND full panel below the stepper,
with its own icon tile, heading and three-column card grid. Two loud blocks in
the answer's position, both removed when the answer arrived. It is now a
horizontal rail of small cards drawn to look like the source rail the arrived
answer renders, mounted inside AnswerProgress rather than beside it, so nothing
is removed and nothing jumps when the answer lands.
Cards carry a dot, not a number. The preview is the top slice of retrieval in
retrieval order; the final list is rebuilt from what the answer cites and
re-capped by trust. A number assigned during the wait can point at a different
document once the answer lands, which is the precise failure the citation design
exists to prevent. Pinned by a DOM test, and stated in the rail's accessible
name for a reader who never sees the dot.
Checked while building, not assumed: `isDeliverableVerifiedUnit` pins
evidence_preview to sequence 0 and rejects a repeat, so the preview crosses once,
complete — it cannot accrue card by card. And it is gated behind
NEXT_PUBLIC_RAG_INCREMENTAL_EVIDENCE_PREVIEW_RENDER (#100 Phase 1), off by
default, so today the line carries the accrual alone via resultCount and the rail
is simply absent rather than a placeholder.
Improvements beyond the mockup:
- Retrieval counts passages and selection counts sources, never one noun for
both. Collapsing them is how a reader believes two dozen documents are behind
an answer that cites three. Pinned in tests/answer-progress.test.ts.
- `fallback` says "Assembling the answer from the sources directly" while it is
happening. Twenty of thirty answers in the 2026-08-18 blinded read were
source_only; the wait is the honest place to set that expectation.
- Processing details became "How this answer was built", shown only after a
retrying/fallback/cached run. The old disclosure held the same five stages for
every question, which is why nobody opened it.
- The elapsed counter is gone. In its place one threshold at 10s appends
"taking longer than usual" and does not tick. Nothing can be done with the
number while the search is healthy; re-drawing it every second in the position
the eye rests on is what made the wait the subject.
- SearchProgressBanner (library/document modes) loses its filled accent band and
spinning Loader2 for the same line. Fill is how this app marks a hazard.
- AnswerSkeleton drops its own status line. Found in the browser, not in a test:
it renders in the answer's body slot directly under AnswerProgress, so the
screen showed "Writing the answer…" above "Reading your question…". There is
now exactly one place that says what is happening.
- The completion dot is not green. A status hue that nothing else on the element
repeats is a colour-only signal, and it was redundant beside a line already
reading "Answer ready in 3s". Caught by check:design-system-contract.
Motion. The ECG trace, its two animation tokens, its keyframes and its
compositor rules are deleted; the indicator is a 5px dot breathing on opacity.
That choice is what holds the contract ui-phone-motion.spec.ts exists for, after
Reduce Motion set the trace to opacity 0 and left a dead panel on a physical
iPhone: a stopped dot is a complete, correct bullet, where a stopped spinner is a
fragment of a circle. The animation stays in globals.css rather than a
motion-safe: utility because html[data-motion="full"] must be able to opt back in
over the OS, which a Tailwind media variant cannot express.
tests/answer-activity-trace-css.test.ts pinned the deleted component, so it is
replaced by tests/answer-progress-indicator-css.test.ts carrying the same
regression forward against the dot — including an assertion that the trace stays
deleted, since a partial revival is how the original defect shipped.
docs/search-chrome-behaviour.md's physical-iPhone rubric named the ECG strip by
class and would have sent a tester hunting for markup that no longer exists;
docs/design-system/COMPONENTS.md named the component in its live-region adoption
note. Both updated — the second found by check:dead-code-candidate, which is the
gate doing its job.
Verified: verify:cheap exit 0 — 37 gates enforced, design-system contract passed
(1021 production files, no ratchet moved), 886 test files / 10733 tests passed;
Playwright chromium answer-progress-ui-smoke + ui-phone-motion 9 passed,
ui-universal-search 20 passed; driven in a real browser at 390px through
scoping → retrieving → retrieved(24) → ranking(4 AU, 2 WA) → generating and past
the 10s threshold, and again with the preview flag on to confirm six real cards
render, link to /documents/<id>?page=&chunk=, and carry no numbers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kHT2YKCNnUrVckTaJW6ga
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.

2 participants

@BigSimmo@claude