Search: the \"All N in …\" links drop or mangle the query, so they rarely open the N results they promise #506

Closed
opened 2026-10-01 10:47:10 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading how search builds its per-group links and comparing them with the list pages they open.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at core/search.py:560-562 (more_url in search) and core/search.py:532-543 (GROUPS); the other locations have not moved. Since #316 the Reminders group links to the calendar's agenda narrowed to reminders (_reminders_address, core/search.py:522-525), still without the query.

When a search group has more than five hits, the results page offers "All N in ". The link is built in three ways that each break the promise in its text.

  • Where: core/search.py:547-549, search (more_url = f"{more_url}?q={query}"); core/search.py:519-530, GROUPS, where eight of the ten groups set takes_query to False; templates/core/search.html:60-67, the link; applications/views.py:88-94, ApplicationFilterMixin.filter_queryset; jobs/views.py:95-102, the companies list's q.

1. The query is not encoded

more_url pastes the cleaned query into the address as it is. A query holding &, #, + or % changes what the target receives: for R&D the link is /jobs/companies/?q=R&D, so the companies page reads q=R and a stray empty D. A # starts a fragment, a + becomes a space. The page then narrows by something the person did not type.

Listings, People, Reminders, Text you sent, Letters, CVs, Files and Career record link to their list with no query. "All 48 in Listings" opens every listing.

3. The two that pass q filter different fields

The applications list matches posting__title, posting__company__name and posting__location; search matches title, company name and the timeline's summary and body. The companies list matches name, location, industry and identifier; search also matches notes and website. A phrase found only in timeline notes or company notes gives "All 12 in Applications" and an empty table.

  • Why it matters: the link is the way from a search to the full answer, and for most queries it shows a different set from the one it counts, or none of it.
  • Fix: build the link with urlencode({"q": query}). For a group whose list cannot take the query, drop the "All N" link or point it at the search page with a kind= parameter that lists the whole group, paged; search already computes it. Make the q filters of the applications and companies lists match the fields search_applications and search_companies use (moving both onto those functions' conditions), or word the link so it does not promise N.

Related to #313 (open), which changes the header's search box but not these links.

Done when

  • tests/test_search.py has tests that a query containing & and # round-trips through more_url unchanged, that no group's link opens a list unfiltered while promising N, and that the number of rows on the linked applications page equals the group's total for a query that matches only timeline text.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading how search builds its per-group links and comparing them with the list pages they open. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `core/search.py:560-562` (`more_url` in `search`) and `core/search.py:532-543` (`GROUPS`); the other locations have not moved. Since #316 the Reminders group links to the calendar's agenda narrowed to reminders (`_reminders_address`, `core/search.py:522-525`), still without the query. When a search group has more than five hits, the results page offers "All N in <group>". The link is built in three ways that each break the promise in its text. - **Where:** `core/search.py:547-549`, `search` (`more_url = f"{more_url}?q={query}"`); `core/search.py:519-530`, `GROUPS`, where eight of the ten groups set `takes_query` to `False`; `templates/core/search.html:60-67`, the link; `applications/views.py:88-94`, `ApplicationFilterMixin.filter_queryset`; `jobs/views.py:95-102`, the companies list's `q`. ## 1. The query is not encoded `more_url` pastes the cleaned query into the address as it is. A query holding `&`, `#`, `+` or `%` changes what the target receives: for `R&D` the link is `/jobs/companies/?q=R&D`, so the companies page reads `q=R` and a stray empty `D`. A `#` starts a fragment, a `+` becomes a space. The page then narrows by something the person did not type. ## 2. Eight groups link to an unfiltered list Listings, People, Reminders, Text you sent, Letters, CVs, Files and Career record link to their list with no query. "All 48 in Listings" opens every listing. ## 3. The two that pass `q` filter different fields The applications list matches `posting__title`, `posting__company__name` and `posting__location`; search matches title, company name and the timeline's `summary` and `body`. The companies list matches name, location, industry and identifier; search also matches `notes` and `website`. A phrase found only in timeline notes or company notes gives "All 12 in Applications" and an empty table. - **Why it matters:** the link is the way from a search to the full answer, and for most queries it shows a different set from the one it counts, or none of it. - **Fix:** build the link with `urlencode({"q": query})`. For a group whose list cannot take the query, drop the "All N" link or point it at the search page with a `kind=` parameter that lists the whole group, paged; search already computes it. Make the `q` filters of the applications and companies lists match the fields `search_applications` and `search_companies` use (moving both onto those functions' conditions), or word the link so it does not promise N. Related to #313 (open), which changes the header's search box but not these links. ## Done when - `tests/test_search.py` has tests that a query containing `&` and `#` round-trips through `more_url` unchanged, that no group's link opens a list unfiltered while promising N, and that the number of rows on the linked applications page equals the group's `total` for a query that matches only timeline text.
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 10:47:10 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#506
No description provided.