Skip to content

feat(filter-contract): converge documents onto the shared filter component - #1910

Merged
BigSimmo merged 12 commits into
mainfrom
claude/filter-contract-documents-pr-f
Aug 13, 2026
Merged

feat(filter-contract): converge documents onto the shared filter component#1910
BigSimmo merged 12 commits into
mainfrom
claude/filter-contract-documents-pr-f

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

  • Stacked PR: based on claude/artifact-build-ygfit8 (PR C, feat(services): adopt the filter contract with real facets (PR C) #1882, not yet merged), because
    documents' convergence reuses the dense tier (find-a-filter, collapse-by-default, disclosure
    headers) PR C already added to ResultFilterSheet/ResultFilterFacetChips. This PR's diff
    will show PR C's commits until feat(services): adopt the filter contract with real facets (PR C) #1882 merges, then shrink automatically to just this PR's
    changes.
  • Deletes the ~500-line bespoke DocumentFilterPanel/DocumentFilterTrigger
    (src/components/clinical-dashboard/document-search-results.tsx) and rebuilds documents'
    filter sheet on the shared ResultFilterSheet/ResultFilterTrigger
    (src/components/clinical-dashboard/result-filter-control.tsx). This is the last mode in the
    docs/filter-contract.md rollout — every filter surface in the original audit now shares one
    component.
  • Adds three small, additive, optional extensions to the shared component so documents' three
    bespoke pieces have a home. All default to inert; the six modes that adopted earlier (services,
    factsheets, formulation, differentials, medication, applications, specifiers) render
    byte-identical output:
    • ResultFilterSheet gains meterContent — the N of M documents shown progress bar,
      rendered first in the body, above the find-a-filter field.
    • ResultFilterSheet gains footerOverride — replaces the entire default footer, for
      documents' "Show N documents" primary button + "Browse all sources" secondary action.
    • resultFilterGroup() gains an optional note — the "one only" annotation on the source-type
      lens group's heading, distinguishing it from the facet groups sharing the same sheet. This is
      the first sheet where a lens and facets sit side by side; services (PR C) has the identical
      shape (a substance lens beside five facet groups) without the annotation, which I filed as a
      follow-up (/issues #312) rather than in scope here.
  • toggleTagFacet narrows from (facet: SmartDocumentTagFacet) => void to (key: string) => void
    — it only ever read facet.key.
  • Two testids move from literal strings to the shared component's own
    `${testId}-x` derivation (testId="document-filter-panel" is preserved, so the many
    existing document-filter-panel assertions need no change):
    • document-filter-cleardocument-filter-panel-clear
    • document-filter-finddocument-filter-panel-find
    • document-filter-done and document-filter-browse-library stay unchanged — they're now
      custom JSX inside footerOverride, under this file's own control, not derived by the shared
      component.
  • The dead-end facet's sr-only reason text changed from documents' bespoke copy ("No documents
    match this with the current filters") to the shared component's generic message ("No matches
    with your current filters"). The guard mechanics — aria-disabled, focusable, click-blocked,
    dashed border, muted text tier — are unchanged; only the copy simplified to the one message
    every mode now shares. Updated the one DOM assertion that pinned the old copy.
  • tests/decoration-on-text.contract.test.ts's four source-scan checks (dead-end styling, facet
    hint text, find-field placeholder) moved from document-search-results.tsx to
    result-filter-control.tsx along with the markup they guard; the {facet.count}/{tab.count}
    pair collapsed into one {option.hint} check since both now render through the same code path.
    This is markup relocating, not a change to the token-policy rule these checks enforce.
  • docs/filter-contract.md's Rollout section is updated to record documents' convergence and
    close out the rollout. /issues #170 (the tracking row for this whole initiative) is updated
    to record documents as done; therapy-compass was not part of this session's scope and remains
    open on that row.

Verification

  • npm run verify:pr-local — summary: completed: check:runtime, check:installed-lock-parity, format:changed, sitemap:check, docs:check-index, docs:check-inventory, docs:check-scripts, docs:check-links, check:branch-review-ledger, check:outstanding-issues, lint, typecheck, test, build, check:rag:fixtures — failed: (none) — not reached: (none)
  • Full npm run test: Test Files 566 passed (566) / Tests 6172 passed | 4 skipped (6176)
    (after regenerating docs/design-system/adoption-manifest.json for the file's new
    ResultFilterSheet/ResultFilterTrigger usage, same as PR C).
  • npm run check:bundle-budget after a clean rm -rf .next && npm run build: production
    1306.1 KiB gzip vs baseline 1279.1 KiB (within 10% tolerance); mockups 294.5 KiB vs
    baseline 267.5 KiB (within 25% tolerance).
  • tests/document-filter-panel.dom.test.tsx (26 cases, the primary proof surface for the ported
    dense/collapse/needle/dead-end mechanics against a 2,014-document fixture) passes with only the
    two testid renames and the one copy-text assertion above.
  • Browser verification not run as npm run verify:ui — ran targeted Chromium proof instead,
    same approach as PR C/D: npm run ensure, then a Playwright script (pinned executable per
    /issues #255) against a real production build covering both triggers, source-type toggle, the
    "one only" annotation, the meter, footer commit/browse-library buttons, and 0px horizontal
    overflow at 1440/800/390/320 — 17/19 checks passed. The two that didn't (find-a-filter dense
    tier, a genuine dead-end facet) don't trip live because this environment's demo corpus (~10
    synthetic documents) is far below the >3 groups/>20 options threshold and too small to force
    a real dead end — that mechanics is what the 26-case DOM suite above proves instead, against a
    fixture sized to trip both. Also ran the existing tests/ui-smoke.spec.ts block covering all
    three document-filter-* testid sections (document search mode lists matching documents and result actions @critical) against the converged code via
    node scripts/run-playwright.mjs tests/ui-smoke.spec.ts --project=chromium --grep <name> with
    the pinned executable — 1 passed, proving the ported tier behaves identically in a real
    production Chromium journey.

Risk and rollout

  • Risk: UI-only convergence onto an already-shipping shared component; no data model, retrieval,
    or ranking changes. classifyPullRequestFiles reports clinicalRisk: false,
    operationalRisk: false, ragRanking: false, ui: true.
  • Rollback: revert this commit; DocumentFilterPanel/DocumentFilterTrigger are fully deleted so
    a revert restores them along with their original tests.
  • Provider or production effects: None.

Notes


Generated by Claude Code

Services gains its first real filtering: five typed dimensions
(catchments, age_groups, setting_flags, acuity_flags, housing_flags)
become facets with union counts, substance_flags ships as a lens (an
exact partition — every service carries exactly one of general/aod),
and a scope segment escapes a filtered-to-zero state without
discarding the query. The six query-replacing "quick filters" are
evicted from the filter sheet to AnswerSuggestionChips, closing the
navigate-kind defect docs/filter-contract.md exists to remove.
The shared filter renderer (ResultFilterSheet/ResultFilterFacetChips)
grows a dense tier — find-a-filter plus collapse-by-default — for
services' 5 groups / 24 options, resolving the open density decision
tracked as /issues #309. The OR-within-group/AND-across-group
selection algorithm is extracted from document-tags.ts into
facet-selection.ts so services and documents share one counting rule
rather than each inventing their own.
Live-registry verification that catalog_payload.tags is fully
populated on the production Supabase project is still outstanding —
rowToServiceRecord degrades conservatively to empty facets if it
isn't, and this is called out explicitly for review.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1kfPCeWWSrbprFz56UeDD
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1kfPCeWWSrbprFz56UeDD
# Conflicts:
#	docs/outstanding-issues.md
…onent
Deletes the ~500-line bespoke DocumentFilterPanel/DocumentFilterTrigger and
rebuilds documents' filter sheet on ResultFilterSheet/ResultFilterTrigger
(src/components/clinical-dashboard/result-filter-control.tsx), reusing the
dense tier (find-a-filter, collapse-by-default, disclosure headers) that PR C
already generalized from documents' own >3-groups rule. This is the last
mode in the docs/filter-contract.md rollout.
Three small additive extensions to the shared component, all optional and
inert for the six modes that adopted earlier:
- ResultFilterSheet gains meterContent (the "N of M documents shown" bar,
rendered first in the body).
- ResultFilterSheet gains footerOverride (replaces the default footer
entirely, for documents' "Show N documents" + "Browse all sources").
- resultFilterGroup() gains an optional note (the "one only" annotation on
the source-type lens, now that it shares a sheet with facet groups for
the first time).
toggleTagFacet narrows from SmartDocumentTagFacet to its key. Two testids
move from literal strings to the shared component's own derivation
(document-filter-clear -> document-filter-panel-clear, document-filter-find
-> document-filter-panel-find); document-filter-done and
document-filter-browse-library stay unchanged as custom footerOverride JSX.
The dead-end facet's sr-only reason text changed from documents' bespoke
copy to the shared component's generic message; the guard mechanics
(disabled, focusable, click-blocked) are unchanged. decoration-on-text
contract checks move to result-filter-control.tsx along with the markup
they guard.
docs/filter-contract.md's Rollout section is updated to close out; a new
/issues follow-up (#312) notes services has the same lens-beside-facets
shape without the annotation, and /issues #170 records documents as done.
Stacked on claude/artifact-build-ygfit8 (PR C, #1882, not yet merged) —
this branch's diff includes PR C's commits until #1882 merges.
@coderabbitai

coderabbitaiBot commented Aug 13, 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:52 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: 473f6464-aa0a-44d0-8cad-9bcbd8177b43

📥 Commits

Reviewing files that changed from the base of the PR and between 5ca83b7 and 5c44b00.

📒 Files selected for processing (9)
  • docs/design-system/COMPONENTS.md
  • docs/design-system/adoption-manifest.json
  • docs/filter-contract.md
  • src/components/clinical-dashboard/document-search-results.tsx
  • src/components/clinical-dashboard/result-filter-control.tsx
  • src/components/services/services-navigator-page.tsx
  • tests/decoration-on-text.contract.test.ts
  • tests/document-filter-panel.dom.test.tsx
  • tests/services-navigator-scope-empty-state.dom.test.tsx

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

@supabase

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

@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:4cefac631f

ℹ️ 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/services/services-navigator-page.tsx Outdated
Comment threadsrc/components/services/services-navigator-page.tsx Outdated
Comment threadsrc/components/clinical-dashboard/result-filter-control.tsx Outdated
Comment threadsrc/components/clinical-dashboard/document-search-results.tsx Outdated
@BigSimmo
BigSimmo enabled auto-merge August 13, 2026 10:13
@BigSimmo
BigSimmo disabled auto-merge August 13, 2026 10:23
@BigSimmo
BigSimmo marked this pull request as draft August 13, 2026 10:33
@BigSimmo
BigSimmo marked this pull request as ready for review August 13, 2026 10:37

@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:745c0181e0

ℹ️ 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/services/services-navigator-page.tsx Outdated
Comment threadsrc/components/services/services-navigator-page.tsx Outdated
Comment threadsrc/lib/registry-records.ts Outdated
@BigSimmo
BigSimmo enabled auto-merge August 13, 2026 11:19
@BigSimmo
BigSimmo merged commit c6eeafb into mainAug 13, 2026
26 checks passed
@BigSimmo
BigSimmo deleted the claude/filter-contract-documents-pr-f branch August 13, 2026 11:28
BigSimmo pushed a commit that referenced this pull request Aug 13, 2026
… band
The Codex reviewer on PR #1925 is right and my closure was wrong. Verified on
main 2d27039: result-filter-control.tsx computes
const dense = facetGroups.length > 3 || totalFacetOptions > 20
so formulation — one facet group of nine derived domains, the exact case that
opened #309 — evaluates dense=false and still renders a wrapping chip row. The
6-20 full-width tier with its right-aligned count column does not exist, and
neither does the nine-option DOM assertion the row asked for.
What PR F (#1910) delivered is the upper tier: find-a-filter and collapse for
>3 groups or >20 options, which is what documents needed. Section 5 has two
thresholds; I conflated them and would have archived the row whose specific
band is unbuilt.
Replaces the done request with an update recording the partial delivery, what
remains, and an explicit stop rule against closing on the strength of the upper
tier. #170 is unaffected — mode adoption did complete.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011btGFwWKYFWDs5McQkqz9J
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