Skip to content

Default search rankings to Relevance for bills and testimonies - #2241

Merged
Mephistic merged 3 commits into
codeforboston:mainfrom
hyphacoop:search-default-relevance
Oct 22, 2026
Merged

Mephistic merged 3 commits into
codeforboston:mainfrom
hyphacoop:search-default-relevance

Conversation

@fastfadingviolets

Copy link
Copy Markdown
Contributor

Summary

"Sort by relevance" used to be undefined & a TypeScript default, but ever since #2227, it's actually defined for bills, hearings, and testimonies. It weighs based on the score of the hit & then tiebreaks by recency for testimonies & recency of last testimony for bills. This switches the default ordering to be relevance for testimonies & bills (hearings are untouched as a chronological sort makes more sense for hearings).

Checklist

  • On the frontend, I've made my strings translate-able.
  • If I've added shared components, I've added a storybook story.
  • I've made pages responsive and look good on mobile.
  • If I've added new Firestore queries, I've added any new required indexes to firestore.indexes.json (Please do not only create indexes through the Firebase Web UI, even though the error messages may reccommend it - indexes created this way may be obliterated by subsequent deploys)

Screenshots

image image

Known issues

If you've run against limitations or caveats, include them here. Include follow-up issues as well.

Steps to test/reproduce

For each feature or bug fix, create a step by step list for how a reviewer can test it out. E.g.:

  1. Go to the home page
  2. Click on a testimony
  3. See that it's loaded with a loading spinner

@vercel

vercel Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
maple-dev Ready Ready Preview Oct 21, 2026 3:01pm UTC

Request Review

@Mephistic Mephistic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We had a chance to test this out at our last hack night - We thought the relevance sort was a noticeable improvement when using the search box, but have a product concern that default sorting by "relevance" without making it clear to the user what "relevance" actually is could make it look like we're picking and choosing winners.

This issue is most pronounced when there is no search term (e.g. the default Browse Bills page) and "relevance" is less well-defined.

The initial idea we had to bridge this user knowledge gap was to include a tooltip on/near the sort dropdown explaining "What relevance is", but now I wonder if we should also/just have a different default sort when there is no search term (e.g. keep "Most recent" sort for an empty search box, and automatically switch to "Relevance" when searching for an actual term).

@mvictor55 This is a follow-up to our discussion at hack night - would love your two cents here. Namely: Do we still need an explainer for "Relevance" if a search term is entered - and if not, should we just only use the new "Relevance" sort when there is a search term that makes it useful?

fastfadingviolets and others added 2 commits October 20, 2026 16:57
Relevance as the unconditional default ranked an empty search box by
testimony volume, the sort's tiebreaker, which reads as MAPLE picking
winners. Browse Bills now opens on "Most Recent Testimony"; typing a term
moves the dropdown to Relevance and clearing it moves it back. A query
like "liquor" expands through the legislative synonym set and matches
hundreds of bills in their full text, so with a term Relevance leads with
the strongest match instead of whichever weak body-text match has the
newest testimony.

The default index name stays the bare "bills" collection, with
billsDefaultSort (latestTestimonyAt:desc) pinned as the adapter's sort_by:
the adapter falls back to that whenever the index name has no sort
segment. The bare key stays because links.tsx deep links and the routed
URL's qs keys depend on it. Relevance is an ordinary
"bills/sort/<billsRelevanceSort>" option and the duplicate explicit
most-recent option is gone. billsRelevanceSort and the eval-shared
billsSearchParams are unchanged, so the harness sends what it did.

SortBy gains an opt-in relevanceValue prop; hearings do not pass it and
keep their chronological default. It switches only on the empty-to-term
and term-to-empty transitions, and only away from the automatic choice,
so a sort the user picked sticks. A URL that loads with a term and no
sort lands on Relevance. A relevanceHelp prop renders a QuestionTooltip
beside the dropdown saying what Relevance weighs, including that
procedural Orders sort last and ties go to testimony count.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Same change as for bills, same mechanism. Browse Testimony opens on
"Newest": the default index is the bare "publishedTestimony" collection
with testimonyDefaultSort (publishedAt:desc) pinned as the adapter's
sort_by. Relevance is an ordinary
"publishedTestimony/sort/<testimonyRelevanceSort>" option that SortBy
selects while the search box has a term, and the duplicate explicit
newest option is gone. Oldest keeps its sort in the index name. The
tooltip says testimony relevance weighs the bill number, then the author,
then the content, with ties broken by newest.

Hearings keep their date-windowed default.

The e2e sort specs gain a case per page: the default sort is selected on
load, a term moves it to Relevance, clearing returns it, and a sort picked
by hand survives typing. Both page objects get a selectedSort locator.

Closes #87

Verified: tsc is clean. The sort specs in browse-bills.spec.ts and
testimony.spec.ts pass on chromium against the local stack, 11 tests
including both new cases.

Not verified: the rest of the browse-bills and testimony e2e suites. The
behaviour in a browser against the dev search cluster, whose latestTestimonyAt is 0 so recency
row order cannot be judged there. A reload of a URL carrying a term and
the bare index key lands on Relevance, because the bare key is also what
an explicit pick of the default option writes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The tooltip explains what Relevance weighs, so it only helps when that sort
is the one in use. SortBy now renders it when the selected item is the
relevance option, which also covers a stale URL sort falling back to the
default. Browse Bills and Browse Testimony both get this through the shared
component; hearings pass no relevanceHelp and are unchanged.

Verified: tsc reports nothing in SortBy.tsx.

Not verified: the tooltip in a browser. No e2e spec asserts it, so none were
run.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@fastfadingviolets

fastfadingviolets commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor Author

Search now defaults to most recent when there's no term, and there's now a tooltip explaining what relevance is. @Mephistic could you pls re-review? 🙏

@Mephistic
Mephistic merged commit fea4c09 into codeforboston:main Oct 22, 2026
8 of 9 checks passed

This branch was successfully deployed

1 active deployment
Preview – maple-dev — 56418a81 Deployed Oct 21, 2026 by vercel[bot]
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