Skip to content

fix(app): rank the deep catalog tail after fuzzy results - #309

Merged
michaldrabik merged 3 commits into
mainfrom
align/search-exact-weave
Jul 28, 2026
Merged

fix(app): rank the deep catalog tail after fuzzy results#309
michaldrabik merged 3 commits into
mainfrom
align/search-exact-weave

Conversation

@vladjerca

@vladjerca vladjerca commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Why

Media search runs an exact pass alongside the fuzzy one and placed every exact hit first. Right for an unambiguous hit, wrong for a title dozens of entries share: searching matrix leads with the obscure entries literally titled "Matrix" instead of The Matrix, which does not match the query exactly at all, so it can only come from the fuzzy pass and gets pushed down.

Aligns with trakt-web, which is the reference for this surface (trakt/trakt-web#3014).

Change

Weave (GetSearchResultsUseCase.kt). Exact hits bucket on the confidence score the API assigns them:

band score placement
certain 2 leads
strong 1 leads
deep 0 trails the fuzzy results

[confident] + [fuzzy] + [deep], deduped by the existing type+trakt-id key. Applies to all three media arms (combined, shows, movies). Scores are only comparable within one source, so this buckets on a threshold rather than sorting across sources by raw score.

The threshold is 0.5, deliberately fractional so it sits between strong and deep. trakt/trakt-workers#1325 pins deep at 0 precisely so a client bucketing on >= 0.5 stays correct, and web ships the same constant.

Failure containment. The exact pass shares a coroutineScope with the fuzzy one, so any failure there cancelled its sibling and took the whole search down instead of degrading to fuzzy-only results. It only ever enriches the fuzzy results, so it now fails soft. Matches web (catchError) and iOS.

No DTO or spec change: the bands are whole numbers, so the generated val score: kotlin.Long carries them fine.

Verification

  • ./gradlew :app:compileInternalDebugKotlin - BUILD SUCCESSFUL
  • ./gradlew :tv:compileInternalDebugKotlin - BUILD SUCCESSFUL
  • ./gradlew openApiGenerate clean; confirmed the generated model still decodes score as kotlin.Long and that the integer bands round-trip through the production Json config
  • ./gradlew ktlintCheck - not run, task does not exist in this project
  • No automated test coverage for the weave; weave() is private and the module has no search test infra. Web covers the equivalent split in splitExactByConfidence.spec.ts.
  • Not manually exercised on a device

Safe to ship now

The API filters the deep band out of the response today, so the third bucket is simply always empty until that filter comes off. Ordering of what ships today is unchanged for unique titles; shared titles stop being pinned above fuzzy results.

Deferred

From the parity report, not in this PR: no trending pass woven into query results (web inserts it between confident-exact and fuzzy), no garbage filter for released-without-year / empty-genres entries, exact-pass limit is 20 vs web's 50, and Android TV runs no exact pass at all.

Media search runs an exact pass alongside the fuzzy one and placed every exact
hit first. That is right for an unambiguous hit and wrong for a title dozens of
entries share: searching "matrix" leads with obscure entries literally titled
"Matrix" instead of The Matrix, which matches the query fuzzily and gets pushed
down.

Bucket exact hits on the confidence score the API assigns them. An unambiguous
hit (a unique title, or one pinned down by an explicit year) keeps leading; a
title shared with other entries and carrying no following trails the fuzzy
results. Niche titles stay reachable without displacing the results people
actually mean. Scores are only comparable within a single source, so this
buckets on a threshold rather than sorting across sources by raw score.

Also lets the exact pass fail soft. It shares a `coroutineScope` with the fuzzy
call, so any failure there cancelled its sibling and took the whole search down
rather than degrading to fuzzy-only results.

Matches trakt-web's weave.
@vladjerca
vladjerca force-pushed the align/search-exact-weave branch from 13dd6db to 4e23644 Compare July 27, 2026 23:20
@michaldrabik
michaldrabik merged commit 90f7dec into main Jul 28, 2026
@michaldrabik
michaldrabik deleted the align/search-exact-weave branch July 28, 2026 07:50
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