Skip to content

feat(api): Weekly Rotation rolls over Wednesday and stays stable once shared - #1034

Merged
dylanjeffers merged 1 commit into
mainfrom
feat/weekly-rotation-share
Sep 8, 2026
Merged

feat(api): Weekly Rotation rolls over Wednesday and stays stable once shared#1034
dylanjeffers merged 1 commit into
mainfrom
feat/weekly-rotation-share

Conversation

@dylanjeffers

@dylanjeffers dylanjeffers commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Why

Weekly Rotation is becoming shareable (audius.co/explore/weekly-rotation/:handle: AudiusProject/apps#14587 and AudiusProject/og#6). Two things on the API side had to change for a shared link to mean anything.

What

Rollover moves to Wednesday 00:00 UTC (was the ISO week boundary, Monday). Product call from Michael's Weekly Rotation thread: Monday already belongs to the other weekly surfaces and Friday is Spotify's. The period is still identified by an ISO (year, week) pair, it's the ISO week shifted forward two days, so cache keys, the jitter seed and share links keep their shape. weeklyRotationPeriod / weeklyRotationPeriodStart are inverses and tested as such.

Listener history is frozen at the rollover instant. Plays, saves, reposts and follows are now read as of the period's start (@periodStart) rather than the request. Before this, playing a track from the mix met the played-exclusion and removed it on the next cache miss, so a mix shared on Wednesday was a different, shorter list by Thursday. The mix has to survive being listened to.

Still drifts mid-week: the trending candidate pool and engagement counts. Freezing those needs a stored snapshot table; not in scope here.

Tests

  • TestWeeklyRotationPeriod: rollover instant, one second before it, Monday/Tuesday belonging to the previous period, non-UTC input, the 2026/2027 year boundary, and a round trip over every hour of 2026.
  • TestV1UsersWeeklyRotationKeepsTracksPlayedThisPeriod: a play dated now leaves the track in the mix; a play from 8 days ago still excludes.
  • Existing fixtures dated their history 8 days back so they predate any possible rollover.

All eight weekly-rotation tests pass against the compose DB.

Not in this PR

Michael's thread also describes the mix as new music from artists you follow / have liked. The shipped ranking does the opposite on purpose (followed artists demoted, For You is the in-network surface). Needs a product decision before anyone touches the scoring.

🤖 Generated with Claude Code

…at the rollover

Two changes so the mix can be linked and revisited.

Rollover moves from the ISO week boundary (Monday 00:00 UTC) to Wednesday
00:00 UTC. Product call: Monday already belongs to the other weekly
surfaces and Friday is Spotify's day. The period is still identified by an
ISO (year, week) pair -- it is the ISO week shifted forward two days -- so
cache keys, the seed, and share links keep their shape.

The listener's history (plays, saves, reposts, follows) is now read as of
the period's start instant rather than the request. Before, playing a
track from the mix met the played-exclusion and dropped it on the next
cache miss, so a mix shared on Wednesday was a different, shorter list by
Thursday. A shareable artifact has to survive being listened to. The
candidate pool and engagement counts still drift mid-week; freezing those
needs a stored snapshot.

Adds a pure test for the period math (rollover instant, year boundary,
non-UTC input, a full year of round trips) and a regression test that a
track played inside the current period stays in the mix.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@dylanjeffers
dylanjeffers merged commit fcd2f07 into main Sep 8, 2026
2 checks passed
@dylanjeffers
dylanjeffers deleted the feat/weekly-rotation-share branch September 8, 2026 23:14
dylanjeffers added a commit to AudiusProject/apps that referenced this pull request Sep 8, 2026
## What

A Weekly Rotation can now be shared. Share produces
`audius.co/explore/weekly-rotation/:handle`, which shows that listener's
mix to anyone (the endpoint is public, no auth), and unfurls with a 2x2
collage of the mix's first four tracks rendered by
`og.audius.co/weekly-rotation/:handle?week=YYYY-WW`.

The bare `/explore/weekly-rotation` stays the signed-in user's own mix.
Under `/explore` rather than `/:handle/weekly-rotation` because
`/:handle/:slug` is the track permalink pattern.

## By package

**common**
- `ShareType` / `ShareModalRequest` / `ShareContent` gain
`weeklyRotation`. The content is just the listener (`User`): there's no
entity behind the mix, the link is a function of the handle.
- `useWeeklyRotation({ userId })` takes an optional target user;
defaults to the viewer.
- `Share` / `ShareToTwitter` analytics get a `weeklyRotation` kind.
- `WEEKLY_ROTATION_USER_PAGE` + `weeklyRotationPage(handle)`. Copy says
Wednesday: the rollover moved (api PR).

**web**
- Share button next to Play. The share modal builds the link from the
handle and copies it directly with the same `Share` event the sagas
emit, there being no social saga for a non-entity.
- Handle route registered in both router trees. The page resolves the
handle via `useUserByHandle`, titles as "{name}'s Weekly Rotation" for
someone else's mix, and only the handle route gets `og:image` +
canonical (the bare route is per-viewer and shouldn't be indexed as
anyone's).
- New Vike SSR entry `ssr/weekly-rotation`
(`/explore/weekly-rotation/@handle`): fetches the user for the name,
emits the collage URL as `og:image`, `summary_large_image`. The bare
route still falls to the explore handler, which now has a
`weekly-rotation` entry in `exploreMap`.
- `utils/weeklyRotationPeriod.ts`: dependency-free mirror of the API's
Wednesday-shifted ISO week, used by SSR (which avoids
`@audius/common/utils`) and the client. Same test cases as the Go side
so they can't drift apart. 7 vitest cases.

**mobile**
- Share icon in the top bar. Drawer offers DM, X, Copy Link, and the
system sheet. No Instagram/TikTok/Snapchat story rows: those need a
single streamable mp3 for the FFmpeg background video, which a mix
doesn't have.
- `WeeklyRotationScreen` takes an optional `handle` param;
`explore/weekly-rotation/:handle?` added to the explore deep-link map.

## Verified

- `tsc` clean in common, web, mobile. ESLint clean on every touched
file.
- `weeklyRotationPeriod.test.ts` passes.
- The collage endpoint was rendered locally against prod (see og PR).

## Not verified

- Mobile share drawer and deep link compile but were not exercised on a
simulator.

## Depends on

- AudiusProject/og#6 for the collage route (until deployed, `og:image`
500s and unfurlers show no image).
- AudiusProject/api#1034 for the Wednesday rollover and week-stable
history. Without it the shared mix can shrink mid-week as the owner
listens.

## Product note

Michael's Weekly Rotation thread describes the mix as new music from
artists you follow / have liked. The shipped ranking does the opposite
on purpose. Not changed here; flagged on the api PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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.

1 participant