fix(visual-baseline): close a real capture race in the search results ribbon - #2562
Conversation
… ribbon A five-agent nondeterminism audit of the five visual-baseline capture targets (dashboard-shell, dashboard-shell-phone, search-results-band(-phone), document-viewer, therapy-compass-home) found one live, unmitigated race: SearchResultsHeaderBand is unconditionally in the DOM before its backing /api/registry/records fetch resolves, so settle()'s visibility check could pass while the ribbon still showed its loading spinner instead of the settled match count and controls. Fixed by waiting for the ribbon's own data-status attribute to clear "loading"/"refetching" before capture. Every other class audited (time, data ordering, animation, fonts/async, environment) was confirmed already neutralized by the suite's existing settle() contract or structurally unreachable from these five targets' default render state — see the new docs/design-system/GATES.md §6a for the per-class findings and what is deliberately left open. This container has no working browser (Chromium revision drift: the preinstalled binary is revision 1194, the installed playwright-core expects 1234, and the org egress policy blocks downloading a replacement), so this fix is offline-typechecked and lint-clean only, not run against the suite locally. The hosted visual-baseline CI job is the first real proof.
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
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 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
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_713be5d5-7afa-4e15-86d9-ae0048aec95f) |
Summary
docs/design-system/adoption-manifest.json'svisualBaselineStatus/remoteStatus). Two findings changed the shape of this PR — both explained below — so what actually ships here is a nondeterminism fix and a documented handoff, not a committed baseline.1194; the installedplaywright-core(1.62.1) expects revision1234. Downloading the correct revision failed:cdn.playwright.devreturned403from this session's egress proxy — confirmed via the proxy's own status endpoint as an organization policy denial, which its README says explicitly not to retry or route around. The repo's ownscripts/check-playwright-browser-revision.mjsalready detects and fails closed on exactly this condition (tracked as#255). No local capture was possible.docs/design-system/adoption-manifest.json'svisualBaselinePolicyrequires the committed baseline's provenance to besource.kind: "hosted-ci-artifact"from the real GitHub Actionsvisual-baselinejob onubuntu-24.04, plusreview.status: "approved"by a named human reviewer (reviewerType: "human") — enforced byvalidateLinuxVisualBaselineSetinscripts/generate-design-system-adoption.mjs. The six candidate PNGs already committed attests/__screenshots__/linux/are stillreview.status: "pending"/reviewerType: "automated"from an August 18 CI run — that's the actual reasonvisualBaselineStatusstill readsnot-committed, and only a human looking at real images can change that.tests/ui-visual-baseline.spec.tssuite (5 conceptual capture targets, 6 test entries) for every class of capture nondeterminism (time, data ordering, animation, fonts/async, environment), a real fix for the one live bug found, and a written record of what's covered and what's deliberately still open. Full findings:docs/design-system/GATES.md§6a.search-results-band/search-results-band-phonecould capture the results ribbon mid-fetch (loading spinner, no filter/sort controls) or settled (real match count, controls) depending on CI scheduling jitter, because the suite'ssettle()helper never waited for the ribbon's backing/api/registry/recordsfetch to resolve. AddedwaitForRibbonSettled, which polls the ribbon's owndata-statusattribute until it clears"loading"/"refetching"before capture.visual-baselineCI job produces a fresh candidate artifact, someone needs to actually look at the six images and runnpm run design-system:baselines:adopt -- --from <artifact-dir> --run-id <id> --head <sha> --reviewed-by "<name>" --write, then flipdocs/design-system/adoption-contract.json's baseline status and regenerate the manifest.Verification
npm run check:design-system-contract— passed, GATES.md figures block current, adoption/design-sync contracts both check cleannpx tsc --noEmit— no errors on the changed spec filenpx eslint tests/ui-visual-baseline.spec.ts— cleannpx vitest run tests/check-docs-links.test.ts— 7/7 passednpm run format— run and committednpm run verify:pr-local,npm run verify:ui,npm run test:e2e:visual— no working Chromium in this container (revision drift#255+ blocked download host, see above). This is the one thing I could not prove locally; the hostedvisual-baselineCI job on this PR is the first real test of the fix.npm run verify:release— provider-backed, not run without explicit approval.Risk and rollout
src/lib/rag/, retrieval RPCs, ranking, or golden fixtures.Adversarial checks (ran against this diff before opening the PR)
src/components/clinical-dashboard/master-search-header.tsx— rendered as a sibling before#main-contenton every shell route, so a visual break in the shared search header/composer is invisible to all six test entries on every route.ServiceCardinsrc/components/services/services-navigator-page.tsx(rendered insidedata-testid="service-search-results", a sibling below the ribbon) — thesearch-results-bandtargets clip to[data-testid="search-query-ribbon"]only, so the actual result cards are never captured.<header data-document-sticky-header>insrc/components/DocumentViewer.tsx(~line 1166) — deliberately painted over before comparison (to avoid an unrelated fix: audit P0 RAG cache, synopsis parity, and safety hardening #278-style diff), so a regression inside it (back link, breadcrumb, section-index controls) is invisible by design.waitForRibbonSettled's logic is sound (thedata-statusattribute is a faithful, closed six-value proxy for fetch state), traced why it cannot hang for the full 20s timeout on every run (demo mode has no Supabase key configured, so auth resolves to"unconfigured"synchronously rather than"loading", and the registry API short-circuits to a synchronous demo fixture), and found no other correctness issue in the diff. Same agent independently produced the three blind-spot findings above.Notes
docs/design-system/GATES.md§6a has the full per-nondeterminism-class findings (what was checked, what's already covered and why, what's genuinely fixed, what's left open for a future pass — a missing global clock pin, and an unproven/api/setup-statusrace with a degraded-mode banner).origin/mainat session start; merged before this work (brings in, among other things, an unrelated already-landed fix for a previously-recorded pinned-clock defect — confirmed unrelated to this suite, different component tree, not reachable from any of the 5 capture targets).🤖 Generated with Claude Code
https://claude.ai/code/session_01BstBbK4vj1YmEpqqFSjcHv
Generated by Claude Code
Note
Low Risk
Test-only Playwright harness and design-system documentation; no production or app runtime changes.
Overview
Addresses flaky search-results-band / search-results-band-phone captures where the suite could screenshot the query ribbon while registry data was still loading (spinner, no filter/sort row) instead of the settled UI.
Adds
waitForRibbonSettledintests/ui-visual-baseline.spec.ts, wired asprepareon both search-band targets. It polls[data-testid="search-query-ribbon"]untildata-statusis no longerloadingorrefetching, instead of relying onsettle()visibility alone.Documents the five-target nondeterminism audit in
docs/design-system/GATES.md§6a: what was fixed, what was already mitigated, and known gaps (no global clock pin, unproven/api/setup-statusrace). Does not commit new baseline PNGs; hosted CI plus human adoption remains the path tocommitted.Reviewed by Cursor Bugbot for commit ecc7a1e. Configure here.