Every update also carries a **queue window** that nothing reads. `NowPlaying` (Rust) and `NowPlayingArgs` (Kotlin) hold a `queue` of at most twenty-one entries — the current item and ten either side, each with its id, title, artist, album, duration and art key — plus `queueIndex`, where the current one sits *within that window* rather than within the whole queue. `src/mobile/media.svelte.js` fills both from `player.queue` and `player.qi`; `MediaService` ignores them completely, so the card is byte for byte the card it was. The reason is media3: `SimpleBasePlayer.getState()` wants a playlist and an index into it, and the data that migration needs should have been running on the phone for a while before anything depends on it. Ten either side because one covers the card's own prev and next and nothing else, while a queue *list* — which is what Auto asks for — wants a screenful plus a scroll in both directions; and it is a cap, not a length, so a two-thousand-track queue crosses the bridge as twenty-one entries exactly like a twenty-one-track one does. Measured at two kilobytes of JSON for twenty-one short titles and six with long ones and real Android cover paths, against the thirty to eighty kilobytes of base64 cover that already ride the same call once per record — and an update is a track change, a transport change or the thirty-second top-up, never a position tick. Because it is on no screen, the walk reads it out of `logcat`: `MediaSessionPlugin.update` logs one `media window n=… i=… art=… at=…` line per update under the tag `SoulStream`, and the phone walk's `queue-window` check holds that against `__ss.card` — the mirror `media.svelte.js` keeps of what it last sent, beside xfernote's — field for field, through a next and a previous. Field for field is deliberate: a key spelled snake_case where the bridge wants camelCase arrives as nothing at all on both hops, with no error anywhere, which is why the art-key count is compared and not just the size and the index. Three things in that check are load-bearing and easy to undo by accident. It arms at queue index **one** rather than wherever the walk left off, which buys a row on either side (`prev()` seeks to zero at the top of a queue and `next()` stops at the end), a track that has just started (`prev()` is a seek again past five seconds), and the fact that while the queue index is at most ten nothing is clamped off the front of the window — so the window's index IS the queue index, which is what lets the logged index be compared against the queue's directly. It requires each reading to be a FRESH one at both ends, the push counter up and a new line in the log, because a `prev()` that lands back on the row it started from reads exactly like a stale line otherwise. And it FAILS rather than skips when it cannot be armed — a queue under three rows, or repeat-one, under which `next()` seeks instead of stepping — with the reason in the message.