Skip to content

Name a failed load, dedupe favourites rows, and debounce the search box - #214

Merged
eetu merged 4 commits into
mainfrom
player-load-errors-and-search
Aug 8, 2026
Merged

Name a failed load, dedupe favourites rows, and debounce the search box#214
eetu merged 4 commits into
mainfrom
player-load-errors-and-search

Conversation

@eetu

@eetu eetu commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Three unrelated faults found while testing the de-bloat branch.

An empty response reported itself as a decoder bug

chiptune3.js's load() handed whatever came back to the decoder, because
fetch only rejects on a network failure. A 404 body or a 200 with no bytes
therefore reached the WASM as a module, and each engine reported the failure in
its own vocabulary — an empty response came out as

Couldn't play this module — SID buffer too small

which is libsidplayfp's own check for a buffer under 0x12 bytes, and reads
like a bug in the player rather than "the file never arrived".

Now the status and a minimum length are checked at the fetch. 128 bytes cannot
reject anything real — a PSID header alone is 0x7c. Verified in a browser
against the live backend: a real file plays, a 404 reports Load (HTTP 404),
an empty 200 reports Load (0 bytes).

The empty response that prompted this was transient — a scan of the HVSC share
found no .sid under 18 bytes, and the tune in question serves fine. This does
not stop that happening; it names it when it does.

Favourites rendered a track twice, under one key

Switching to favourites flattens the id stream into a single bucket. Until that
view's reshape lands the stream is still the previous view's, where a track
appears once per bucket it belongs to (multi-group / multi-album) — so the same
id rendered twice under the same key and Svelte threw each_key_duplicate.
flatRows now dedupes, which is what the favourites view already documented
itself as showing.

The search box shaped on every keystroke

Typing "parallax" was eight requests, each a full pass over the index
server-side (~0.7s across HVSC's 94k joined rows), each superseded before it
could be read. Seven of the eight were waste, and the queue is what made
searching feel like ten seconds. Query-only edits now wait 250ms for a pause;
a facet, sort or tab change is a single event and still fires at once. Measured
in a browser: eight requests down to one.

The per-request cost is untouched — /api/library/ids materialises every row
for any query — and is recorded in apps/tracker/CLAUDE.md as the next step.


just lint clean, tracker unit 54 passed, player unit 139 passed, tracker
integration (--ignored) 37 passed. Each fix was reproduced in a real browser
before and after.

eetu added 4 commits August 8, 2026 23:51
`fetch` only rejects on a network failure, so a 404 body or a 200 with no
bytes went to the decoder as a module. Each engine then reported the
failure in its own vocabulary from inside the WASM: an empty response
surfaced as "Couldn't play this module - SID buffer too small"
(libsidplayfp's own check for a buffer under 0x12 bytes), which reads
like a player bug rather than "the file never arrived".

Check the status and a minimum length at the fetch instead. Nothing under
128 bytes can be a tune - a PSID header alone is 0x7c - so the floor
cannot reject anything real. Verified in a browser against the live
backend: a real file plays, a 404 reports "Load (HTTP 404)", an empty 200
reports "Load (0 bytes)".
Switching to favourites renders the id stream flattened into one bucket.
Until that view's reshape lands the stream is still the previous view's,
where a track can appear once per bucket it belongs to (multi-group /
multi-album) - so the same id was rendered twice, under the same key,
and Svelte threw each_key_duplicate.

`flatRows` dedupes, which is what the favourites view already documented
itself as showing.
The search box shaped on every keystroke: "parallax" was eight requests,
each a full pass over the index server-side (~0.7s across HVSC's 94k
joined rows), each superseded before it could be read. Seven of the eight
were waste, and the queue is what made the search feel like ten seconds.

Debounce query-only edits by 250ms; a facet, sort or tab change is a
single event and still fires at once. Measured in a browser: eight
requests down to one.

The per-request cost is untouched - /api/library/ids materialises every
row for any query, which is a separate fix.
@eetu
eetu merged commit b59f414 into main Aug 8, 2026
8 checks passed
@eetu
eetu deleted the player-load-errors-and-search branch August 8, 2026 21:07
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