You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Parent: #280
Product acceptance: #252
Related completed API contract: #73
Prior socket wake fix: #284 / #285
Problem
WebScene's browser task arbitration drains every ready Worker, MessagePort, or WebSocket event before it considers any due timer. Its FileReader compatibility implementation intentionally uses a zero-delay timer both before reading a Blob and before publishing progress/load/loadend.
Code OSS's unchanged remote protocol receives binary WebSocket frames as Blob values and feeds them through a persistent FileReader. Under the remote-workspace startup stream, the WebSocket source therefore starves the FileReader timers needed to consume those same responses. The provider stays correct but waits seconds for stat/readdir promises.
This is distinct from #284: the runtime now wakes promptly for an empty-to-nonempty socket queue and rotates fairly among the three asynchronous message sources, but that arbitration tier still precedes due timers unconditionally.
Retained evidence
Exact inputs:
WebScene aa06172c92a60324b1f2e5fa2d94a00bd1e15214
AppScene 1420e227e52579a097e7ae52a2cadb41cf073e4d
VS Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c
Node 24.18.1
local query-gated observer commit 74b3b94 (not pushed)
One bounded, no-host-poll product trace retained the exact selected vscode-remote URI, registered provider, exact five resolved/model children, five Explorer rows, and 64 Explorer DOM nodes. Its protocol measurements were:
151 native WebSocket events, 13,118,749 bytes, maximum queue depth 27
native receive-to-runtime-dispatch: 25,322.5 ms aggregate across events, 3,563.26 ms maximum
WebSocket JS callbacks: 200.777 ms aggregate, 4.916 ms maximum
callback microtask checkpoints: 1.890 ms aggregate, 1.100 ms maximum
146 FileReader reads, 13,115,590 bytes
underlying Blob.arrayBuffer: 1.532 ms aggregate, 0.041 ms maximum
FileReader call-to-loadend: 658,518.7 ms aggregate across overlapping reads, 14,940.7 ms maximum
exact-root provider stat calls in the first wave: about 5,416 ms
exact-root provider readdir calls in the next wave: about 2,299 ms
scene publication samples remained bounded individually (observed maximum 64.35 ms)
The byte counts align the WebSocket/Blob/FileReader path. Copying and callbacks are small; the multi-second boundary appears while FileReader waits for its scheduled tasks. Source ordering confirms that ready async-message sources return before has_due_timer() is serviced.
Scope
Make task arbitration fair between due timers and continuously ready asynchronous message sources. Preserve FIFO ordering within each source and the browser-observable asynchronous FileReader event sequence. Do not add a Code OSS/provider special case.
Acceptance
A product-neutral native/browser fixture feeds at least 256 consecutive binary WebSocket Blob frames through one FileReader queue and verifies exact bytes and loadstart → progress → load → loadend order.
With Worker, MessagePort, and WebSocket sources continuously refilling, due zero-delay timers have p95 ≤ 25 ms and maximum ≤ 100 ms; no source waits behind an unbounded competing backlog.
Socket callbacks and promise/microtask continuations settle once and preserve FIFO message order.
Abort, cancellation, disconnect/reconnect, close, malformed input, and navigation teardown release timers, callbacks, Blobs, sockets, and task queues without stale delivery.
Queue depth/bytes, task counts, scene publications, worker wakeups, V8 heap, and RSS remain bounded over repeated cold/warm cycles.
Parent: #280
Product acceptance: #252
Related completed API contract: #73
Prior socket wake fix: #284 / #285
Problem
WebScene's browser task arbitration drains every ready Worker, MessagePort, or WebSocket event before it considers any due timer. Its
FileReadercompatibility implementation intentionally uses a zero-delay timer both before reading a Blob and before publishingprogress/load/loadend.Code OSS's unchanged remote protocol receives binary WebSocket frames as Blob values and feeds them through a persistent FileReader. Under the remote-workspace startup stream, the WebSocket source therefore starves the FileReader timers needed to consume those same responses. The provider stays correct but waits seconds for
stat/readdirpromises.This is distinct from #284: the runtime now wakes promptly for an empty-to-nonempty socket queue and rotates fairly among the three asynchronous message sources, but that arbitration tier still precedes due timers unconditionally.
Retained evidence
Exact inputs:
aa06172c92a60324b1f2e5fa2d94a00bd1e152141420e227e52579a097e7ae52a2cadb41cf073e4d645f29cc3176500b4b5762ba887cf2a7f0ffdf2c24.18.174b3b94(not pushed)/private/tmp/vscode-252-product-navigation-280-attribution.logOne bounded, no-host-poll product trace retained the exact selected
vscode-remoteURI, registered provider, exact five resolved/model children, five Explorer rows, and 64 Explorer DOM nodes. Its protocol measurements were:The byte counts align the WebSocket/Blob/FileReader path. Copying and callbacks are small; the multi-second boundary appears while FileReader waits for its scheduled tasks. Source ordering confirms that ready async-message sources return before
has_due_timer()is serviced.Scope
Make task arbitration fair between due timers and continuously ready asynchronous message sources. Preserve FIFO ordering within each source and the browser-observable asynchronous FileReader event sequence. Do not add a Code OSS/provider special case.
Acceptance
loadstart → progress → load → loadendorder.