* fix(browser): retry a screencast frame a viewer's socket refused
An idle page sends no next frame, so a refused last frame left the viewer on a stale picture. The
desktop's relay leg to a server uses legacy E2EE, which drops on a full socket where a direct v2 phone
queues; retrying the newest pending frame restores parity. Retries never count toward ghost eviction.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(e2ee): queue legacy binary replies with text instead of dropping them
Legacy E2EE (every direct phone, the desktop's server link) sent binary straight to the socket and
silently dropped it once the outbound budget was full, so terminals lost output and binary could
overtake queued text. Binary now shares the ordered text queue and closes on overflow like v2; the
lossy screencast opts into dropWhenBacklogged and its retry delivers the newest frame after a drain.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(e2ee): keep a backlogged screencast viewer instead of evicting it as a ghost
A lossy frame skipped on a busy socket returned false like a dead socket, so a long backlog evicted a
live viewer. Skips now return 'backlogged', which retries without counting toward eviction; legacy
judges idleness on the sealed size before encrypting, so skipped frames cost no encryption.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* test(browser): expect the ready gate to forward screencast send options
The pre-ready gate now passes the per-frame send options through to the
socket sender, so the replayed startup frame arrives with an options slot.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* test(browser): share the streamed-guest double across screencast tests
Main's renderer throttle lease now calls setBackgroundThrottling on the guest,
so the bare { isDestroyed } guest in two branch tests threw. One shared double
keeps all three screencast suites on the shape the lease needs.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb