Skip to content

fix(api): read the live trending rows in Discover Weekly - #1026

Merged
dylanjeffers merged 1 commit into
mainfrom
fix/discover-weekly-stale-trending-rows
Aug 24, 2026
Merged

fix(api): read the live trending rows in Discover Weekly#1026
dylanjeffers merged 1 commit into
mainfrom
fix/discover-weekly-stale-trending-rows

Conversation

@dylanjeffers

Copy link
Copy Markdown
Contributor

/users/:id/discover-weekly (shipped in #1025) returns an empty mix for every user in production. Verified against prod across six accounts — all returned {"data": []}.

Root cause

Two bugs compounded.

track_trending_scores holds two populations:

rowsread bymedian track age
genre-carrying/tracks/trending, /tracks/trending/underground~4 days (max 12)
null/empty genrethis endpoint, and /feed/for-you~5–6 years

The candidate CTEs matched only the null-genre rows, so every candidate was ancient — then the 365-day age cutoff in the filter stage dropped all of them. Empty result, every time.

Measured on prod: the 18 out-of-network tracks in deadmau5's for-you feed ranged from 1822 to 2175 days old, while /tracks/trending top-100 ranged 0–10 days.

Fix

Drop the genre predicate from both candidate CTEs, so they read the live rows the same way the trending endpoints do. The age cutoff stays but is no longer load-bearing.

Why no test caught it

Every existing test seeded score rows without a genre, so the fixtures only ever exercised the stale-population path. Adds one that seeds a genre-carrying row — the shape that actually reaches the query in production.

Related, not fixed here

/users/:id/feed/for-you uses the same genre IS NULL OR genre = '' predicate on its trending and underground candidate sources (lines 327 and 346). It doesn't return empty because it has in-network and playlist sources to fall back on, but its trending candidates are very likely the same 5–6-year-old tracks — being ranked by a scorer with a 48-hour recency half-life. Worth a separate look.

🤖 Generated with Claude Code

The endpoint shipped in #1025 returned an empty mix for every user in
production. Two bugs compounded.
track_trending_scores holds two populations: rows carrying a genre, which
the trending job keeps current (median track age ~4 days), and rows with
a null/empty genre, which are stale -- in production those resolve to
tracks five to six years old. The candidate CTEs matched only the
null-genre rows, so every candidate was ancient, and the 365-day age
cutoff in the filter stage then dropped all of them.
GET /tracks/trending and /tracks/trending/underground read the live rows
by omitting the genre filter entirely; this now does the same. The age
cutoff stays and is no longer load-bearing, since the live pool tops out
around twelve days old.
Every existing test seeded score rows without a genre, which is why none
of them caught this. Adds one that seeds a genre-carrying row -- the
shape that actually reaches the query in production.
Note: /users/:id/feed/for-you has the same null-genre predicate on its
trending and underground candidate sources, so it is very likely feeding
on the same stale rows. Not touched here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dylanjeffers
dylanjeffers merged commit 5ae068b into mainAug 24, 2026
2 checks passed
@dylanjeffers
dylanjeffers deleted the fix/discover-weekly-stale-trending-rows branch August 24, 2026 20:47
dylanjeffers added a commit to AudiusProject/apps that referenced this pull request Aug 24, 2026
Wires `GET /users/:id/discover-weekly` into the Explore page on web and
native, rendered as a collection card so the mix reads like a playlist.
Depends on [api#1025](AudiusProject/api#1025)
and [api#1026](AudiusProject/api#1026) — both
merged and live in production.
## What's here
- `useDiscoverWeekly` — a plain `useQuery`, not infinite. The mix is a
fixed-size artifact, not a lineup you scroll; there is no page 2.
- `sdk.users.getDiscoverWeekly` — hand-written pending the next SDK
regen, same as `getSuggestedFollows` in #14562, since `npm run gen`
pulls the spec from a running node.
- Web section (desktop + mobile web) and a parallel native section,
since `packages/mobile` composes its own Explore screen.
## Three decisions worth reviewing
**The artwork is a checked-in asset.** The mix has no `playlist_id` to
hang cover art on — Audius playlists are on-chain entities and the mix
is computed per request. Styled to sit alongside the Hot & New playlist
art.
**Clicking plays instead of navigating.** No permalink to navigate to,
so the card queues all 30 starting at the top. Closest thing to playlist
behavior without a route.
**No section heading or Carousel.** One card, so the scroll affordance
is dead weight and a heading would repeat the card's own title.
## Known gaps
- **The card has playlist affordances without playlist substance** —
can't be favorited, reposted, shared, or linked to. Closing that needs
the stored track-list per `(user, year, week)`, which would also fix the
mid-week drift noted in api#1025.
- **Not visually verified in the running app** at time of opening — the
section is signed-in-only.
## Verification
`tsc` and eslint clean across web, mobile, and sdk. The one `common`
error (`getDiscoverWeekly` not on `UsersApi`) is the known SDK-dist
parity issue — the built `dist/index.d.ts` types `sdk.users` as the
generated class, so the already-merged `useSuggestedFollows` produces an
identical error. Resolves on the next regen.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@dylanjeffers