fix(app): rank the deep catalog tail after fuzzy results - #309
Merged
Conversation
4 tasks
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
force-pushed
the
align/search-exact-weave
branch
from
July 27, 2026 23:20
13dd6db to
4e23644
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
matrixleads 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:certain2strong1deep0[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 betweenstronganddeep. trakt/trakt-workers#1325 pinsdeepat0precisely so a client bucketing on>= 0.5stays correct, and web ships the same constant.Failure containment. The exact pass shares a
coroutineScopewith 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.Longcarries them fine.Verification
./gradlew :app:compileInternalDebugKotlin- BUILD SUCCESSFUL./gradlew :tv:compileInternalDebugKotlin- BUILD SUCCESSFUL./gradlew openApiGenerateclean; confirmed the generated model still decodesscoreaskotlin.Longand that the integer bands round-trip through the productionJsonconfig./gradlew ktlintCheck- not run, task does not exist in this projectweave()is private and the module has no search test infra. Web covers the equivalent split insplitExactByConfidence.spec.ts.Safe to ship now
The API filters the
deepband 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.