setQueueFromTracks now sets the audio source before broadcasting queue/mediaItem, so AudioService stops emitting the previous track's metadata mid-swap (fb95a46).
Prefetcher pre-warms cover bytes + palette for the next N tracks via flutter_cache_manager and the palette extractor; _scheduleSwap takes a fast sync path when the warm cache hits.
Playback stream errors now skip to next instead of leaving the UI claiming the broken track is still playing.
Reverted the Wear MediaSession surface expansion — Pixel Watch 2 stopped showing controls when we advertised setRating. Kept the dormant LikeBridge wiring for a future re-attempt.
CacheFiller (60085b1)
Background sweeper that walks cached_artists / cached_albums for missing relations and fills them via /api/artists/:id + /api/albums/:id. 10s initial delay, 5-minute interval, 200ms throttle between requests. Pre-warms covers for newly discovered albums.
Offline mutation queue (335940c + wiring)
New cached_mutations drift table + MutationQueue.enqueue + MutationReplayer (3s initial drain, 1min periodic, 5-attempt drop). Likes / quarantine / add-to-playlist / Lidarr request+cancel now write their optimistic local state to drift first, attempt the REST call, and queue on failure — so the user's intent persists across network loss instead of getting rolled back.
cacheFirst hang fix (5511f87)
Added a coldFetchAttempted flag + yield-after-fetch so populates that write to the watched table but produce no rows for the filter (Liked tab on a fresh install) don't spin forever waiting for a re-fetch that would never reveal new data.
Test fixes
Cancel one-shot Timers on CacheFiller / MutationReplayer dispose (d27dd69).
Drop eager connectivityProvider listener in MutationReplayer.start(); the 3s initial + 1min ticker + post-enqueue nudge cover reconnect (f6ee837).
Capture cacheFirst stream Future before feeding controller in tests (67bacac).
Test plan
CI green on dev (analyze + tests)
Smoke test on device: track change feels instant, mini bar doesn't flicker
Toggle airplane mode mid-like / mid-add-to-playlist; verify drift state persists and replays on reconnect
## Highlights
**Player track-change feel**
- `setQueueFromTracks` now sets the audio source before broadcasting queue/mediaItem, so AudioService stops emitting the previous track's metadata mid-swap (`fb95a46`).
- Prefetcher pre-warms cover bytes + palette for the next N tracks via `flutter_cache_manager` and the palette extractor; `_scheduleSwap` takes a fast sync path when the warm cache hits.
- Playback stream errors now skip to next instead of leaving the UI claiming the broken track is still playing.
- Reverted the Wear MediaSession surface expansion — Pixel Watch 2 stopped showing controls when we advertised setRating. Kept the dormant LikeBridge wiring for a future re-attempt.
**CacheFiller (`60085b1`)**
- Background sweeper that walks `cached_artists` / `cached_albums` for missing relations and fills them via `/api/artists/:id` + `/api/albums/:id`. 10s initial delay, 5-minute interval, 200ms throttle between requests. Pre-warms covers for newly discovered albums.
**Offline mutation queue (`335940c` + wiring)**
- New `cached_mutations` drift table + `MutationQueue.enqueue` + `MutationReplayer` (3s initial drain, 1min periodic, 5-attempt drop). Likes / quarantine / add-to-playlist / Lidarr request+cancel now write their optimistic local state to drift first, attempt the REST call, and queue on failure — so the user's intent persists across network loss instead of getting rolled back.
**cacheFirst hang fix (`5511f87`)**
- Added a `coldFetchAttempted` flag + yield-after-fetch so populates that write to the watched table but produce no rows for the filter (Liked tab on a fresh install) don't spin forever waiting for a re-fetch that would never reveal new data.
**Test fixes**
- Cancel one-shot Timers on `CacheFiller` / `MutationReplayer` dispose (`d27dd69`).
- Drop eager `connectivityProvider` listener in `MutationReplayer.start()`; the 3s initial + 1min ticker + post-enqueue nudge cover reconnect (`f6ee837`).
- Capture `cacheFirst` stream Future before feeding controller in tests (`67bacac`).
## Test plan
- [x] CI green on dev (analyze + tests)
- [ ] Smoke test on device: track change feels instant, mini bar doesn't flicker
- [ ] Toggle airplane mode mid-like / mid-add-to-playlist; verify drift state persists and replays on reconnect
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Highlights
Player track-change feel
setQueueFromTracksnow sets the audio source before broadcasting queue/mediaItem, so AudioService stops emitting the previous track's metadata mid-swap (fb95a46).flutter_cache_managerand the palette extractor;_scheduleSwaptakes a fast sync path when the warm cache hits.CacheFiller (
60085b1)cached_artists/cached_albumsfor missing relations and fills them via/api/artists/:id+/api/albums/:id. 10s initial delay, 5-minute interval, 200ms throttle between requests. Pre-warms covers for newly discovered albums.Offline mutation queue (
335940c+ wiring)cached_mutationsdrift table +MutationQueue.enqueue+MutationReplayer(3s initial drain, 1min periodic, 5-attempt drop). Likes / quarantine / add-to-playlist / Lidarr request+cancel now write their optimistic local state to drift first, attempt the REST call, and queue on failure — so the user's intent persists across network loss instead of getting rolled back.cacheFirst hang fix (
5511f87)coldFetchAttemptedflag + yield-after-fetch so populates that write to the watched table but produce no rows for the filter (Liked tab on a fresh install) don't spin forever waiting for a re-fetch that would never reveal new data.Test fixes
CacheFiller/MutationReplayerdispose (d27dd69).connectivityProviderlistener inMutationReplayer.start(); the 3s initial + 1min ticker + post-enqueue nudge cover reconnect (f6ee837).cacheFirststream Future before feeding controller in tests (67bacac).Test plan
🤖 Generated with Claude Code