diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-16 17:24:10 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-16 17:24:10 +0200 |
| commit | 3d4080e9a1b79e99428a80391e224ea73cf4274d (patch) | |
| tree | 5c44081ca087d9442bc694492cf8d85595ba2584 /docs/playlists.md | |
| parent | 1c6bc8d98bcb4674e4a874d37a61af7732a9402d (diff) | |
| download | meshbay-3d4080e9a1b79e99428a80391e224ea73cf4274d.tar.gz | |
playlists: drive the blob ops over a real DataChannel
The six MNP 3.1 ops were the only new ones never crossing a channel in a
test. Two cases on the existing aiortc harness: a round trip read back on
a second connection, and a 256 KB body. Found that the 1 MB body cap is
unreachable from a browser — docs/playlists.md §15.3.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'docs/playlists.md')
| -rw-r--r-- | docs/playlists.md | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/docs/playlists.md b/docs/playlists.md index d8eda18..488a2de 100644 --- a/docs/playlists.md +++ b/docs/playlists.md @@ -1184,17 +1184,26 @@ level of the named failure rather than the count. | 7 | The store: a stale node cannot lower the merged state; a deletion is not resurrected; an edit made elsewhere arrives with its body; a sync with nothing to do writes nothing; a deleted body is reclaimed; what leaves the browser is sealed | `test_playlist_store.py`, in Chrome against a stubbed node | | 8 | The menus: the toolbar's five verbs, naming a playlist in a field, Favourites offered first before it exists, adding an album from its cover, loading into the queue, the two-level tracklist, deleting after a confirm | `test_playlist_ui.py`, in Chrome | | 9 | An unreachable group is skipped **whole** — six dead tracks, one more than the bound | `test_music_queue.py` | +| 10 | The six ops across a **live DataChannel**: sealed bytes out and the same bytes back on a *second* connection, `req_id` on the reply, a listing that carries revisions and no payloads, an absence that is not an error, a delete that reclaims | `test_webrtc_transport.py` — real aiortc, real handshake, real frames | ### 15.2 Not checked, and what that costs These need things a test suite here does not have. They are listed so nobody reads §15.1 as more than it is. -1. **A round trip through a real node daemon.** The MNP handlers are driven - directly against a real `BundleStore`, and the store is checked across a - close and reopen — but not across a running daemon, a real DataChannel and a - real handshake. The likeliest thing to be wrong there is msgpack `bin` - framing for a payload of this size, which nothing here exercises. +1. ~~A round trip through a real node daemon.~~ **Closed**, and more cheaply + than this entry implied: `test_webrtc_transport.py` already stands up a real + `WebRTCTransport`, a real aiortc `RTCPeerConnection` and a real handshake for + two dozen other cases, and `test_keypair_bundle_store_and_fetch` is the same + shape as what was missing. The six `USER_BLOB_*` ops were simply the only new + ones in 3.1 that never got it. + + Measuring corrected this entry's own guess. A 256 KB blob arrives as **one** + application message of 262 213 bytes — SCTP fragments and reassembles beneath + us, so the four-byte length prefix is not doing the work credited to it here. + What the test pins is that nothing truncates or re-encodes a `bin` value of + that size. It also found the ceiling in §15.3, which is the part that + matters. 2. **Two browsers, one account, one node, converging** — and the same with the node stopped between the two edits. The merge is proved; the *plumbing* around it is proved against a stub that always behaves. Confirmed working in @@ -1211,6 +1220,28 @@ reads §15.1 as more than it is. ### 15.3 Still open +- **A body larger than about 64 KB cannot leave a browser.** aiortc advertises + `a=max-message-size:65536` in its SDP (`RTCSctpTransport.getCapabilities`, + hardcoded — checked by generating one), and a browser refuses a `send()` above + the negotiated value. The SPA builds one frame per message with no size check + (`transport.js:3016`), so a sealed body over that limit throws instead of + syncing. The codebase already lives under this ceiling, and asymmetrically: + `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 + 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 Search page needed no change beyond passing `userId` — §11's requirement is met by `MusicApp` being mounted in both places. |