docs: plan-era "v1", "Task N" and "Phase N" wording restated as facts (#6277)
release / govulncheck (push) Successful in 25s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m47s
release / integration (push) Successful in 4m35s
release / android (push) Successful in 7m5s
release / Build signed APK (releases and dev) (push) Successful in 7m16s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m1s
release / Verify release artifacts (tag releases only) (push) Skipped

The marker list behind the earlier server and web passes did not catch
"for v1", "Task 5", "Phase 2" or "today: Flutter". Those comments now say
what the code does.

Corrected: coverart said "both v1 providers" ship on. There are four
providers (MBCAA, TheAudioDB, Deezer, Last.fm), and Last.fm, which needs a
key, ships off.

Non-comment tokens unchanged against HEAD: 10 Go files, 7 TS/Svelte files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 13:05:03 -04:00
co-authored by Claude Opus 5.5
parent c96231106f
commit 466912e202
17 changed files with 31 additions and 32 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ export const BROWSE_PAGE_SIZE = 50;
// Genres are the raw ID3 strings, split on [;,] server-side but otherwise
// untouched — no case folding, no synonym mapping. So "Rock" and "rock" can
// both appear, as can "Rock/Pop" beside "Rock" and "Pop". Deliberate for v1:
// the raw spread has to be visible before anyone can judge whether it needs
// both appear, as can "Rock/Pop" beside "Rock" and "Pop". Deliberate: the
// raw spread has to be visible before anyone can judge whether it needs
// normalising.
export type GenreCount = { genre: string; track_count: number };
+1 -1
View File
@@ -101,7 +101,7 @@
// The server-side filter hides this candidate on next refetch.
await client.invalidateQueries({ queryKey: qk.suggestions() });
} catch {
// Swallow for v1; the SPA will refetch on next mount and the card
// Swallowed: the SPA will refetch on next mount and the card
// stays requestable so the user can retry.
}
}
+1 -1
View File
@@ -133,7 +133,7 @@ export function useEventsDispatcher(): void {
openTrackId = trackId;
}
} catch {
// Best-effort; missed events are OK in v1.
// Best-effort; a missed event is acceptable.
}
}
}
+1 -1
View File
@@ -79,7 +79,7 @@ describe('player store — basic actions', () => {
// play anyway — tested via report later. Here, simulate the paused state:
reportTimeUpdate(0);
// manually put us in paused state by calling togglePlay twice isn't clean;
// set via the state-report API in Task 2. Instead, test the simpler case:
// it is set via the state-report API. Instead, test the simpler case:
// playQueue then togglePlay = still 'loading' (intent is to play).
togglePlay(); // from 'loading' — inverts intent; store moves to 'paused' intent
expect(player.state).toBe('paused');
+1 -1
View File
@@ -77,7 +77,7 @@
}
});
// Phase 2 prefetch: when the current track passes the halfway mark,
// Prefetch: when the current track passes the halfway mark,
// start loading the next track's bytes into a hidden <audio> element.
// The browser HTTP cache + audio buffer warm-up means the swap on
// track-end is gap-free on slow networks. Reset src when no next
+2 -2
View File
@@ -94,8 +94,8 @@
// Surface the new request on /requests right away (+ start its poll).
queryClient.invalidateQueries({ queryKey: qk.myRequests() });
} catch {
// Swallow for v1: error toasts land in a later UX pass. The card stays
// in 'requestable' so the user can retry.
// Swallowed, with no toast: the card stays in 'requestable' so the
// user can retry.
}
}
+1 -1
View File
@@ -28,7 +28,7 @@
await unflagTrack(trackID);
await client.invalidateQueries({ queryKey: qk.myQuarantine() });
} catch {
// Silent in v1; the SPA will refetch on next mount.
// Silent; the SPA will refetch on next mount.
}
}
</script>