From c35f3a73eb68cdd7c4179cded3d1ead63ec5a033 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 16 Sep 2026 17:47:00 +0200 Subject: playlists: refuse a body no frame can carry, and say which one A DataChannel send() throws above the max-message-size the node advertises (aiortc: 65536), so the 1 MB body cap was unreachable and each body push swallowed the difference in a bare catch. Cap at 62 KB after sealing, name the playlist in the sync result, keep syncing the rest. Measured: 1000 tracks seal to 53 276 bytes, so the ceiling is ~1200. Co-Authored-By: Claude Opus 5 --- docs/playlists.md | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'docs/playlists.md') diff --git a/docs/playlists.md b/docs/playlists.md index 488a2de..45e36fe 100644 --- a/docs/playlists.md +++ b/docs/playlists.md @@ -1229,17 +1229,26 @@ reads §15.1 as more than it is. `UPLOAD_CHUNK_SIZE` is 48 KB going up while `CHUNK_SIZE` is 1 MB coming down, which is the same constraint seen from both ends. - So `USER_BLOB_BODY_MAX = 1 MB` is a cap the client can never reach. The real - limit is about fifteen 4 KB pages — near **225 tracks in one playlist**, at the - ~270 bytes a track measures once compressed. Past that the push fails: - visibly, since the sync result is reported now, but in the browser's own - words. Reading is unaffected — a node answers with a whole body, and 256 KB is - measured coming back. - - Three ways out, none taken: cap the client with a sentence a reader can act on - (small, safe, keeps the limit); split a long body over several blob kinds (no - protocol change, but the kind namespace must then carry part numbers); or raise - what the node advertises (aiortc moved 256 KB both ways here despite + So `USER_BLOB_BODY_MAX = 1 MB` is a cap the client can never reach. Measured + rather than derived: a thousand tracks with varied metadata seal to **53 276 + bytes**, and each further track costs about 50, so one playlist tops out near + **1200 tracks**. (An earlier draft of this paragraph said 225, by reading §4's + ~270 bytes a track *raw* as the *sealed* figure. `test_playlist_store.py` + measures it now, and fails if a thousand tracks stop fitting.) Reading is + unaffected — a node answers with a whole body, and 256 KB is measured coming + back. + + **Taken:** the client caps itself at 62 KB of sealed body, checked after + sealing because compression makes a track count a poor guide to a blob length. + Over it, that one playlist is skipped and **named** in the sync result; the + rest of the sweep goes as usual and the sync is not a failure. This replaced a + bare `catch {}` around each body push that swallowed the difference between a + node that went away mid-sweep and a playlist that could never be sent — the + second being exactly the silent loss the design exists to prevent. + + Two ways further out, neither taken: split a long body over several blob kinds + (no protocol change, but the kind namespace must then carry part numbers); or + raise what the node advertises (aiortc moved 256 KB both ways here despite advertising 64 KB — one line, and a protocol change that belongs in its own work, with uploads to re-examine alongside it). - **O7 is now decided, not deferred**: there is no `/playlists` page, and the -- cgit v1.2.3