Explore: search reports a partial catalog's miss as "no results", and an artist outside the artifact is unfindable by name #260

Open
opened 2026-09-25 14:26:05 +00:00 by yonlu · 1 comment
Owner

What happens

Explore's search reads explore_index and nothing else: SearchIndex.Search
is a local FTS query with no upstream fallback, and the only lazy resolution
that exists is EnsureArtistDiscography, which is keyed on an MBID and
therefore only reachable by navigating to an artist you already have an id
for. So an artist outside the downloaded catalog's coverage cannot be found by
typing their name, and the page says only:

No results found for "…"

which reports "this does not exist" for what is really "this is not in the
catalog you have". Compare catalog-scope-notice, which exists precisely so a
detail page admits which of the four things it is showing.

Why it is not just a small catalog

cmd/indexexport -artists 50000 (the default in index-artifact.yml) cuts the
artifact to the top 50,000 artists and their release groups and recordings, so
this is bounded coverage by design. Measured on the published artifact:
1,077,893 rows — 50,000 artists, 268,953 release groups, 758,940 recordings —
from 2,048,280 source rows.

The gap is narrow and specific: an artist the user owns files by is covered
by PopulateLocalCrossReferences, and one they have opened is covered by
the lazy fetch. What falls through is an artist the user neither owns nor has
viewed — which is exactly the case a search is for. Long-tail artists are the
normal shape of a personal library, so this reads as "Explore is broken" rather
than "Explore is partial".

Options, none of which is obviously right

  1. Say so. A search that matched nothing in a partial catalog should offer
    something ("Not in the downloaded catalog — look up upstream?"), which is
    the same move catalog-scope-notice makes one page over.
  2. Search upstream on a miss: the MusicBrainz artist search endpoint behind a
    confirmation, since it is a network round trip per keystroke-submitted
    query rather than a local index read.
  3. Widen the artifact. --artists is a size dial (41 MB compressed at 50k, a
    few hundred MB of the 135 MB comes from aliases and the recording rows), and
    it is the only dial that makes the index itself bigger for everyone.

(1) is the honest minimum and does not depend on the other two.

Found while fixing #258, where a broken artifact import made this look like the
whole catalog was missing.

## What happens Explore's search reads `explore_index` and nothing else: `SearchIndex.Search` is a local FTS query with no upstream fallback, and the only lazy resolution that exists is `EnsureArtistDiscography`, which is keyed on an **MBID** and therefore only reachable by *navigating to* an artist you already have an id for. So an artist outside the downloaded catalog's coverage cannot be found by typing their name, and the page says only: > No results found for "…" which reports "this does not exist" for what is really "this is not in the catalog you have". Compare `catalog-scope-notice`, which exists precisely so a detail page admits which of the four things it is showing. ## Why it is not just a small catalog `cmd/indexexport -artists 50000` (the default in `index-artifact.yml`) cuts the artifact to the top 50,000 artists and their release groups and recordings, so this is bounded coverage by design. Measured on the published artifact: 1,077,893 rows — 50,000 artists, 268,953 release groups, 758,940 recordings — from 2,048,280 source rows. The gap is narrow and specific: an artist the user **owns files by** is covered by `PopulateLocalCrossReferences`, and one they have **opened** is covered by the lazy fetch. What falls through is an artist the user neither owns nor has viewed — which is exactly the case a *search* is for. Long-tail artists are the normal shape of a personal library, so this reads as "Explore is broken" rather than "Explore is partial". ## Options, none of which is obviously right 1. Say so. A search that matched nothing in a partial catalog should offer something ("Not in the downloaded catalog — look up upstream?"), which is the same move `catalog-scope-notice` makes one page over. 2. Search upstream on a miss: the MusicBrainz artist search endpoint behind a confirmation, since it is a network round trip per keystroke-submitted query rather than a local index read. 3. Widen the artifact. `--artists` is a size dial (41 MB compressed at 50k, a few hundred MB of the 135 MB comes from aliases and the recording rows), and it is the only dial that makes the *index* itself bigger for everyone. (1) is the honest minimum and does not depend on the other two. Found while fixing #258, where a broken artifact import made this look like the whole catalog was missing.
Author
Owner

Refining this, because the filed version implies you can detect "not in the
catalog" and that is the part that is wrong.

There are three states and they are independent:

  1. No catalog at all — the download was refused (metered, default), failed,
    or the merge has not finished. Every search misses. This is a fact about the
    app, it is cheap to ask, and the page already asks it: explore-view
    renders state: 'no-index' for the shelves, pointing at Settings. The search
    result area does not consult it, so an empty catalog reports
    No results found for "…" for every query in the one window a first-run user
    is most likely to type in. That asymmetry is the defect, and only this state
    is a defect of detection.
  2. A partial catalog — top 50,000 artists by indexexport's default. A miss
    here may or may not mean the entity exists upstream, and that is not
    decidable locally
    . So the fix is not to detect it but to stop asserting the
    stronger claim: say what is known ("not in the catalog you have") and offer
    the lookup. Same move catalog-scope-notice already makes on the detail
    pages, and why option (1) above is the honest minimum.
  3. Present catalog, entity genuinely absent — a typo. "No results" is
    complete and correct.

So the work splits: (1) is code — one condition the search empty state reads
from the same source the shelves use; (2) vs (3) is wording, and no amount of
code will separate them without an upstream call.

Worth noting for (1): the window is small now that #258 is fixed, because the
merge is ~50 s from a cold start — but it was permanent before, which is part
of why this read as "Explore is broken" rather than "Explore is still filling
in".

Refining this, because the filed version implies you can *detect* "not in the catalog" and that is the part that is wrong. There are three states and they are independent: 1. **No catalog at all** — the download was refused (metered, default), failed, or the merge has not finished. Every search misses. This is a fact about the *app*, it is cheap to ask, and the page already asks it: `explore-view` renders `state: 'no-index'` for the shelves, pointing at Settings. The search *result* area does not consult it, so an empty catalog reports `No results found for "…"` for every query in the one window a first-run user is most likely to type in. That asymmetry is the defect, and only this state is a defect of detection. 2. **A partial catalog** — top 50,000 artists by `indexexport`'s default. A miss here may or may not mean the entity exists upstream, and that is **not decidable locally**. So the fix is not to detect it but to stop asserting the stronger claim: say what is known ("not in the catalog you have") and offer the lookup. Same move `catalog-scope-notice` already makes on the detail pages, and why option (1) above is the honest minimum. 3. **Present catalog, entity genuinely absent** — a typo. "No results" is complete and correct. So the work splits: (1) is code — one condition the search empty state reads from the same source the shelves use; (2) vs (3) is wording, and no amount of code will separate them without an upstream call. Worth noting for (1): the window is small now that #258 is fixed, because the merge is ~50 s from a cold start — but it was *permanent* before, which is part of why this read as "Explore is broken" rather than "Explore is still filling in".
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yonlu/yellowjacket#260