Skip to content

mockup: adaptive refine bar for the global search results header - #1457

Merged
BigSimmo merged 8 commits into
mainfrom
claude/global-search-mockups-mrgmzl
Jul 30, 2026
Merged

mockup: adaptive refine bar for the global search results header#1457
BigSimmo merged 8 commits into
mainfrom
claude/global-search-mockups-mrgmzl

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

  • Adds /mockups/search-refine-adaptive — the selected design direction for the shared search results header (SearchResultsHeaderBand, rendered at twelve call sites). The band splits by stability rather than by kind: row one holds what is always present and must never move (the count, and the controls acting on the result set), row two holds only the active filter chips and is not rendered at all when none are applied, so the common unfiltered search is a single line.
  • Design decisions carried into the mockup, each documented in an on-page Anatomy section so the reasoning survives into any production pass:
    • No query echo. The composer already shows the query with its own clear button, so repeating it in the header spent a heading rank and roughly 90px of width on information already on screen. Removing it is also what lets row two disappear, since the row becomes purely filters.
    • No source-composition prose and no corpus size while searching. Both were the only thing making the summary row worth having; without them the row had nothing to do, so it is gone rather than padded.
    • No accent border, magnifier tile, gradient pipe rule, display-weight query or doubled count — the unmotivated chrome in the current band.
    • One control species at one height, and one label vocabulary (label + value + count), replacing the Show / Filter / Pattern / Domain split across modes.
    • Sort and Sources live outside the scroll container, so filter chips can never push them off screen.
    • An applied filter reports what it cost ("4 matches of 6"), and a filtered-to-nothing search names the blocking filter and offers the one-tap way out, so it no longer looks identical to an empty index.
    • aria-live wraps the count alone rather than the whole status span, so a refetch does not re-announce the controls.
    • On phone, sort and filtering fuse into one Refine control because three labelled controls do not fit beside the count at 390px. Sources stays reachable at both widths — dropping it on phone would regress against the shipped band, which shows it there today.
  • Controls are sized to the band's real floors (min-h-tap 44px phone, sm:min-h-10 40px desktop) through an explicit compact flag, because the phone frame renders inside a wide page where viewport sm: variants would resolve against the page rather than the frame.
  • Registers the route in docs/site-map.md via npm run sitemap:update, and adds the shared-chrome opt-out in mockups-layout-client.tsx so the shell composer cannot be mistaken for a second, real search bar over the study.

Mockup only. No production route, component or behaviour is touched, and /mockups/* returns 404 in production.

Verification

  • npm run verify:pr-local — exit 0. Build compiled in 37.0s, 1695 static pages generated, client-bundle secret scan passed, check:rag:fixtures passed (36 golden cases, 21 suites), unit suite 434 files / 4563 passed / 4 skipped.
  • npm run verify:cheap — exit 0 across the &&-joined chain of 27 static gates plus lint, typecheck and the full offline unit suite, including sitemap:check and check:design-system-contract.

UI verification not run: npm run verify:ui cannot run in this container — the installed Playwright package expects a browser build (chromium_headless_shell-1234) that is not present, and only chromium-1194 is available. Verified directly in that Chromium instead against the local dev server: route returns 200 with no page errors, and the adaptive row was confirmed mounting and unmounting across the unfiltered, one-filter, three-filter, zero and failed states, with Add filter correctly disabling once every filter is applied. This is a mockup route, excluded from the production journeys verify:ui covers.

RAG impact: no retrieval behaviour change — this adds a design-scratch mockup route only and touches nothing under src/lib/rag/**, clinical-search, retrieval-selection, ranking-config, answer-ranking, the eval harness or the golden fixture. check:rag:fixtures passed unchanged.

Risk and rollout

  • Risk: None to production behaviour. /mockups/** is development-only, noindexed, and 404s in production; the only shared file touched is mockups-layout-client.tsx, where the change is one additional pathname flag guarding chrome visibility for this route alone.
  • Rollback: Revert the single commit. No migrations, no data, no config.
  • Provider or production effects: None. No Supabase, OpenAI, CI or deployment surface was touched, and no provider-backed gate was run.

Notes

  • Mockups are exempt from the token, type-scale and button-wiring gates. Promoting this to production means re-checking every control against them, and raising anything that lands deep in a sheet to 48px per the ui-smoke rule.
  • Three things need deciding before this becomes production, and are listed on the page itself: the per-filter counts assume facet counts the band is not passed today (a real prop change across all twelve call sites, not styling); removing the query echo depends on the composer staying persistently visible with a working clear affordance on every mode; and fusing sort into Refine on phone hides the active sort value at rest, which should be an explicit decision rather than an omission.
  • The height change between one and two rows wants a transition, and needs checking against docs/search-chrome-behaviour.md if the band ever becomes sticky.

Generated by Claude Code

Adds /mockups/search-refine-adaptive, the selected direction for the shared
results header (SearchResultsHeaderBand, rendered at twelve call sites).

The band splits by stability rather than by kind. Row one holds what is always
present and must never move — the count, and the controls acting on the result
set. Row two holds only the active filter chips and is not rendered at all when
none are applied, so the common unfiltered search is a single line.

Settled in design review and reflected here:

- No query echo. The composer already shows the query with its own clear
  button, so repeating it spent a heading rank and ~90px of width. Removing it
  is also what lets row two disappear, since the row becomes purely filters.
- No source-composition prose and no corpus size while searching. Both were the
  only reason the summary row existed; without them the row is gone.
- No accent border, magnifier tile, gradient pipe rule, display-weight query or
  doubled count.
- One control species at one height and one label vocabulary
  (label + value + count), replacing Show / Filter / Pattern / Domain.
- Sort and Sources sit outside the scroll container, so filter chips can never
  push them off screen.
- An applied filter reports what it cost ("4 matches of 6"); a filtered-to-
  nothing search names the blocking filter and offers the one-tap way out, so it
  no longer looks identical to an empty index.
- aria-live wraps the count alone rather than the whole status span.

Controls are sized to the band's real floors (min-h-tap 44px phone,
sm:min-h-10 40px desktop) via an explicit compact flag, because the phone frame
renders inside a wide page where viewport variants would resolve incorrectly.

Mockup only — no production route, component or behaviour is touched, and
/mockups/* 404s in production.

Verified: npm run verify:cheap exit 0 (27 static gates && lint && typecheck &&
test — 434 files, 4563 passed). Route checked in Chromium at localhost:4598:
200, no page errors, and the adaptive row confirmed mounting and unmounting
across the unfiltered, one, three, zero and failed states.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JdPa3mHCX5ZQZZvU5GHU3r
@supabase

supabase Bot commented Jul 30, 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

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 58 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 99b918bb-1c01-4b64-8a2b-6d477ba69079

📥 Commits

Reviewing files that changed from the base of the PR and between 3054d68 and a6f2281.

📒 Files selected for processing (5)
  • docs/site-map.md
  • src/app/mockups/mockups-layout-client.tsx
  • src/app/mockups/search-refine-adaptive/page.tsx
  • src/components/search-refine-adaptive-mockups.tsx
  • tests/search-refine-adaptive-mockups.dom.test.tsx

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

@BigSimmo
BigSimmo marked this pull request as ready for review July 30, 2026 14:06
@BigSimmo
BigSimmo enabled auto-merge (squash) July 30, 2026 14:06

@chatgpt-codex-connector chatgpt-codex-connector Bot 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: 46cd597617

ℹ️ 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 thread src/components/search-refine-adaptive-mockups.tsx Outdated
@BigSimmo

Copy link
Copy Markdown
Owner Author

@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. 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. After fixing or dispositioning a thread, reply in that thread with as the first line, followed by a concise summary; that marker authorizes the workflow to close that exact thread. If human input or new authorization is required, do not use the marker and leave the thread open with the blocker. 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.

@BigSimmo
BigSimmo disabled auto-merge July 30, 2026 14:11
@BigSimmo
BigSimmo enabled auto-merge (squash) July 30, 2026 14:14
BigSimmo and others added 3 commits July 30, 2026 22:14
…e region

Codex review, P2. On the searching -> error transition the count region was
switched to aria-live="off", so a screen-reader user whose focus is elsewhere
was never told the search had failed, nor that Retry had appeared — left
waiting on a result that was not coming.

The region now escalates to role="alert" / aria-live="assertive" on failure and
stays polite otherwise, so an in-flight search still does not interrupt but a
failure always reaches the user. Failure is the one transition that must not be
muted.

This mirrors aria-live="off" as set by the shipped band
(search-results-header-band.tsx), so the same defect exists in production today.
Out of scope for a mockup PR; captured for the production pass rather than fixed
here.

Adds a focused DOM assertion covering the transition. Verified non-vacuous:
restoring aria-live="off" fails it with "Unable to find an accessible element
with the role alert".

Verified: npm run verify:cheap exit 0 (437 files, 4575 passed, 4 skipped).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JdPa3mHCX5ZQZZvU5GHU3r
…mzl' into claude/global-search-mockups-mrgmzl
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex couldn't complete this request. Try again later.

@BigSimmo
BigSimmo disabled auto-merge July 30, 2026 14:26
@BigSimmo
BigSimmo enabled auto-merge (squash) July 30, 2026 14:35
@BigSimmo
BigSimmo disabled auto-merge July 30, 2026 14:38
@BigSimmo
BigSimmo enabled auto-merge (squash) July 30, 2026 14:58
@BigSimmo
BigSimmo disabled auto-merge July 30, 2026 15:21
@BigSimmo
BigSimmo enabled auto-merge (squash) July 30, 2026 15:27
@BigSimmo
BigSimmo merged commit e79e499 into main Jul 30, 2026
25 checks passed
@BigSimmo
BigSimmo deleted the claude/global-search-mockups-mrgmzl branch July 30, 2026 15:31
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
…ecord

The two Services viewport-anchor data points from PR #1457 were dropped when the
withdrawn #149 row and its id allocation were restored. They are unrelated to
that decision, so this puts them back and changes nothing else.

#149 stays exactly as set: archived as a withdrawn record, with issues:next-id
preserved at 150 so the id is retired rather than reused.

Restored to #146: the test failed once more on head c739340 (anchorTop expected
-138, received -7) then passed on 9da02d9 and a6f2281 across all three shards
with the spec byte-identical — six data points, two failures, shard 1 only, both
failures on a mockups-only PR. Notes that the 131px delta is roughly 2x the 64px
viewport shrink rather than sub-pixel drift, which constrains the element
attribution that row already asks for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JdPa3mHCX5ZQZZvU5GHU3r
BigSimmo added a commit that referenced this pull request Jul 30, 2026
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…#1481)

* issues: capture the production live-region defect; record the landed #1457 review

Adds #147 — `search-results-header-band.tsx` sets aria-live="off" when faulted,
so a clinical search that fails while focus is elsewhere is announced to nobody
and the user is never told Retry appeared. Affects all twelve call sites that
render the band. Raised by Codex against the copied line on PR #1457, fixed
there, and confirmed to exist unchanged in production. The merged mockup carries
the proven pattern and a non-vacuous assertion to port.

Appends two further data points to #146 from PR #1457: the Services viewport
anchor failed once more on head c739340 (expected -138, received -7) and then
passed on two later heads with the diff byte-identical — six data points, two
failures, shard 1 only. Both failures landed on a PR touching only mockups,
which strengthens the unchanged-code reading. Notes that the 131px delta is
roughly 2x the 64px shrink rather than sub-pixel drift.

Records the prlanded verification for PR #1457 in the branch review ledger:
squash e79e499, content diff against the branch tip empty, and the late
aria-live/role="alert" commit confirmed present on main rather than orphaned by
the squash.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JdPa3mHCX5ZQZZvU5GHU3r

* issues: withdraw #149 — the live-region defect was false, and the fix was worse

Codex caught this on PR #1481 and it is correct. I filed #149 claiming a failed
clinical search is announced to nobody because the count span sets
aria-live="off" when faulted. I never checked whether another node makes the
announcement. It does.

search-results-header-band.tsx mounts a fault panel with role="alert" carrying
the failure title, body and Retry (lines 407-414), and the mute is deliberate,
documented in place: "While faulted the live region is silenced
(aria-live='off') and the freshly-mounted fault role='alert' below makes the
single announcement, rather than both speaking."
tests/search-results-header-band.dom.test.tsx already pins exactly that with
singular role queries that throw on duplicates.

Escalating the count span in production, as #149 recommended, would have added a
second alert beside the fault panel — a duplicate announcement and a broken
test. The row is withdrawn to the archive rather than deleted, with the reasoning
recorded so nobody re-files it.

The mockup is unaffected: search-refine-adaptive-mockups.tsx has no fault panel,
so there the count span is the only announcement channel and its escalation is
correct. It simply does not port to production.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JdPa3mHCX5ZQZZvU5GHU3r

* docs: record PR 1481 review

* docs: preserve issue 149 allocation

* docs: format withdrawn issue record

* issues: restore the #146 data points lost while preserving the #149 record

The two Services viewport-anchor data points from PR #1457 were dropped when the
withdrawn #149 row and its id allocation were restored. They are unrelated to
that decision, so this puts them back and changes nothing else.

#149 stays exactly as set: archived as a withdrawn record, with issues:next-id
preserved at 150 so the id is retired rather than reused.

Restored to #146: the test failed once more on head c739340 (anchorTop expected
-138, received -7) then passed on 9da02d9 and a6f2281 across all three shards
with the spec byte-identical — six data points, two failures, shard 1 only, both
failures on a mockups-only PR. Notes that the 131px delta is roughly 2x the 64px
viewport shrink rather than sub-pixel drift, which constrains the element
attribution that row already asks for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JdPa3mHCX5ZQZZvU5GHU3r

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to 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