Skip to content

fix(spotify): empty rankings export as collected; offset-0 recently-played 404 is unavailable, not empty (0.1.57) - #635

Merged
Kahtaf merged 2 commits into
mainfrom
fix/spotify-empty-recent-top
Nov 8, 2026
Merged

Kahtaf merged 2 commits into
mainfrom
fix/spotify-empty-recent-top

Conversation

@Kahtaf

@Kahtaf Kahtaf commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

What broke

Since 0.1.56 hit RSS prod (~15:55Z, 8 Nov), 8 runs from 3 users (16:42Z to 17:46Z) failed with connector_reported_failure: "Spotify did not provide a request-bound terminal boundary; no checkpoint was saved." Every one of them asked only for recently_played_contexts + top_artists + top_tracks (or recently_played_contexts alone). These were retries. Each user had just run the full set, got those three scopes back omitted (produced 4 of 7), and asked for them again.

Root cause

The message is a red herring. The connector always ends recently_played_contexts with the spotify_recent_context_boundary_unverified skip, and each ranking with spotify_ranked_list_capped. When a stream has zero rows, that skip makes it omitted. When every requested scope is omitted, PageShim throws the first skip's text as the run error (runtime.ts: errors[0]?.reason).

The rows were zero for two reasons, both visible in the prod [spotify-diagnostic] lines and run errors (no record content was read):

  1. Rankings: userTopContent returned totalCount: 0 in both windows. No stream_failed or withheld rows. That is a complete, empty ranking, but the connector still called it "capped" and saved no checkpoint, so it could never export as "collected, none".
  2. Recently played: the endpoint returned 404 with an empty body at offset 0 (recently_played_end {"endedBy":"not_found_at_start"}). Since 0.1.55 this has been read as an empty history. It isn't reliable. User 267493… got it on 4 runs in a row (17:42Z to 17:46Z), then a page of contexts at 17:47Z. Across all runs since the deploy, 15 of 20 recently-played reads ended this way.

Fix (0.1.57)

  • A ranking whose total is 0 in every window saves a full-scan STATE and no capped skip, so it exports as an empty, produced scope (the same way playlists do since 0.1.56). New diagnostic: ranked_list_empty {stream}.
  • An offset-0 recently-played 404 ends the stream with a new retryable skip, spotify_recently_played_unavailable (retry_by_runtime), instead of the boundary skip. It is reported as unavailable, not as proven empty. New diagnostic: recently_played_unavailable {endedBy, othersRequested}. It carries no user data.
  • Non-empty rankings and recent history behave exactly as before.
  • New reason added to reason_display_messages. Ran polyfill-library-metadata:generate and connector-implementation-index:generate; the index also picks up 0.1.56's missing reason messages. Line numbers in the no-await-in-loops allowlist moved.

A run that asks only for recently played and gets the 404 still fails, now with the honest, retryable reason. Nothing was collected, so there is nothing to return.

Live test

Built bundles of main (0.1.56) and this branch, ran them in a logged-in open.spotify.com tab, and classified the results with RSS's result-classifier.cjs. The 404 and the empty rankings were simulated in the fetch shim.

Scopes Simulated main 0.1.56 this PR
recent + top x2 404 + empty top failure (produced 0, omitted 3), prod message reproduced partial (produced 2 empty, omitted 1 with the new reason)
top x2 empty top failure (omitted 2) success (produced 2, empty)
recent only 404 failure failure, new retryable reason
recent + top x2 none (real) partial, 6/95/144 rows identical
all 7 none (real) partial, produced 7 / degraded 5 identical rows and outcome

Existing Spotify tests pass (150/150 connector, 21/21 Spotify PageShim). No new unit tests, per request. One existing PageShim assertion (the empty-account case) pinned the old behaviour, empty rankings omitted and 4 streamed scopes. It now expects 6 scopes, with the rankings produced empty and recent history unavailable.

https://claude.ai/code/session_013cAazvHSyzKgPDbCjuZ4gA

…y-played 404 is unavailable, not empty (0.1.57)

Since 0.1.56, runs that asked only for recently_played_contexts,
top_artists and top_tracks failed with connector_reported_failure
"Spotify did not provide a request-bound terminal boundary; no checkpoint
was saved." (8 runs, 3 users, 16:42Z to 17:46Z on 8 Nov). Those users had
just run the full set, seen those three scopes omitted, and retried them.

That message was not the cause. The connector always ends
recently_played_contexts with a boundary skip and each ranking with a
ranked_list_capped skip. With zero rows those skips make the scope omitted,
and when every requested scope is omitted PageShim reports the first skip's
text as the run error. The rows were zero because:

- userTopContent answered totalCount 0 in both windows. That is a complete,
  empty ranking, not a capped one, but nothing said so.
- recently-played answered 404 with an empty body at offset 0, which 0.1.55
  reads as an empty history. It is not reliable: one user got it on four
  runs in a row, then a page of contexts on the next run a minute later.

Changes:
- A ranking whose total is 0 in every window saves a full-scan STATE and
  no capped skip, so it exports as an empty, produced scope (as playlists
  do since 0.1.56). Diagnostic ranked_list_empty {stream}.
- An offset-0 recently-played 404 ends the stream with the new retryable
  skip spotify_recently_played_unavailable instead of the boundary skip.
  Diagnostic recently_played_unavailable {endedBy, othersRequested}.
- A run that asked for recent + rankings now returns partial (rankings
  produced empty, recent omitted) instead of failing. A run that asked only
  for recently played and got the 404 still fails, with the honest,
  retryable reason: nothing was collected.
- Non-empty rankings and recent history are unchanged.
- Regenerated the library metadata and the implementation index (which
  also picks up 0.1.56's missing reason messages); allowlist lines moved.

Live run in a logged-in open.spotify.com tab, RSS classifier, with the
404 and the empty rankings simulated in the fetch shim:
- 3 scopes: main failure (produced 0, omitted 3); fix partial (produced 2,
  omitted 1).
- top lists only: main failure; fix success (produced 2, empty).
- recent only: failure on both; the fix's reason is the new one.
- Real, unsimulated 7 scopes and 3 scopes: identical outcome and row
  counts on main and the fix.

Claude-Session: https://claude.ai/code/session_013cAazvHSyzKgPDbCjuZ4gA
Signed-off-by: kahtaf <kahtaf@gmail.com>
@github-actions github-actions Bot added the evidence: none A touched connector has no committed replay claim yet label Nov 8, 2026
…empty rankings and an unavailable recent history

Claude-Session: https://claude.ai/code/session_013cAazvHSyzKgPDbCjuZ4gA
Signed-off-by: kahtaf <kahtaf@gmail.com>
@Kahtaf
Kahtaf merged commit 46f12e8 into main Nov 8, 2026
34 checks passed
@Kahtaf
Kahtaf deleted the fix/spotify-empty-recent-top branch November 8, 2026 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

evidence: none A touched connector has no committed replay claim yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant