Skip to content

Remove fixed delay from remote filesystem provider responses #280

Description

@wieslawsoltes

Completed — 21 September 2026

The shared scheduler/protocol implementation and WebScene PR #891 now satisfy the current installed-package proof that kept this issue open. On unchanged Code OSS 645f29cc, tested WebScene change 1412283 (merged without code changes as d3c030f), and AppScene cd0a02e, 20/20 launches retained the exact remote root, registered provider, five resolved children, five Explorer-model children, five visible rows, and 64-node DOM bound.

Resolve is 751.61 ms p50 / 762.64 ms p95 / 797.49 ms maximum. First-child paint is 1828.19 ms p50 / 1860.12 ms p95 / 1870.24 ms maximum; every launch satisfies the 2-second gate. Routed selector invalidation behavior remains covered by the focused native regressions, and the direct-subject optimization has an explicit A/B escape hatch.

The remaining workspace-file/multi-root, interaction, dependent-service, visual, and repeated lifecycle matrix stays in #252. No duplicate scheduler implementation remains scheduled.

Parent/product acceptance: #252
Release coordination: #227

Problem

An unchanged Code OSS vscode-remote workspace reaches the correct new-document root and registers the stock RemoteFileSystemProviderClient, but WebScene takes about eight seconds to complete the first direct IFileService.resolve for a five-entry local fixture. Chromium against the same Code OSS server/provider/root completes the resolve in 328 ms and paints the five Explorer rows in 715 ms.

This is below the picker/navigation/workspace-context layers already qualified by #247 and AppScene#124. It is a generic native WebScene request/response latency boundary in the remote filesystem path and blocks #252's provider/Explorer performance gate.

Retained evidence

Exact source inputs:

  • VS Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c
  • WebScene 28d1d649e927c665ff05844197af44f223edf952
  • AppScene 1420e227e52579a097e7ae52a2cadb41cf073e4d
  • Node 24.18.1
  • fixture root /private/tmp/webscene-247-fixture/beta

Clean native trace after await fileService.activateProvider('vscode-remote'):

  • selected URI equals the only IWorkspaceContextService root
  • provider registered before resolve
  • resolve: 8,139.3 ms
  • first five Explorer rows: 12,324.0 ms from observer start
  • resolved child set is exact: .hidden.txt, readme-link, README.md, subdir/, unicodé.txt
  • rendered rows: 5; Explorer DOM nodes: 64

A separate overlapping run is retained as contaminated timing and excluded from the performance conclusion; it independently measured an almost identical 8,132.1 ms resolve.

Headless Chrome 153 against the same server build, stock provider, and exact root:

  • resolve: 328.2 ms
  • first five Explorer rows: 714.9 ms
  • provider/root/resolved/model/rendered sets all exact
  • observer sampling maximum: 0.5 ms
  • 2 s resolve/paint gate passed

The browser observer revision only adds post-resolve Explorer-model polling. The activation and direct resolve path is byte-equivalent to the native trace. Earlier providerRegistered=false and empty model findings were observer-ordering false positives and are excluded.

Investigation

  1. Reduce the remote filesystem request/response path to the smallest same-origin WebSocket/channel fixture that reproduces native latency with a fast Chromium oracle.
  2. Attribute time across renderer enqueue, socket write/read, server channel handling, native event-loop wakeup, interop dispatch, and promise/microtask continuation.
  3. Check whether the fixed delay applies to the first request only, every request, reconnects, cancellation, errors, and concurrent requests.
  4. Fix the smallest generic WebScene owner contract. Keep Code OSS and its remote provider unchanged.

Acceptance

  • A product-neutral browser/native oracle returns identical stat/read-directory results and error classes through the same request/response protocol.
  • Cold and warm native p50/p95 are recorded against Chromium; the five-entry fixture completes resolve and first-child paint within 2 s.
  • One logical provider request produces one bounded socket write and response; queue depth, queued bytes, tasks, DOM mutations, scene publications, and wakeups have explicit ceilings.
  • Cancellation, disconnect/reconnect, denied/missing paths, malformed responses, and out-of-order concurrent responses settle once without stale delivery.
  • A repeated lifecycle gate releases sockets, callbacks, promises, tasks, provider listeners, documents, and watcher handles; RSS/V8 heap growth is bounded.
  • The unchanged Code OSS product trace preserves the exact selected URI, provider registration, five resolved/model/rendered children, and watcher readiness under the latency bounds.
  • Directly related macOS/Linux native checks and the Chromium oracle pass before Qualify remote workspace bootstrap, Explorer contents, and watcher refresh #252 is requalified.

Current disposition — 18 September 2026

The implementation chain is complete: #297 closed its theme-continuation slice and the scheduler work from #287/#293/#289 landed through PR #347 as dbd7351a. Product-shaped direct evidence now keeps the 1.07 MiB protocol flush at 0.157 ms p95 / 0.274 ms max with bounded queues and flat V8 heap.

This issue requires no separate implementation. It remains open only for the same current-package #252 exact provider/root/first-child proof used to close #287, #293, and #289. If that run passes, close all four from the shared evidence; if it fails, attribute the new earliest boundary before opening another child.

Activity

  1. added
    bugSomething isn't working
    vscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration
    on Sep 17, 2026
  2. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The first generic defect is now split as native subissue #284 with focused PR #285.

    Direct evidence for that split:

    • an observer-free baseline fails to finish the socket lifecycle before a single observation at 500 ms;
    • PR Wake runtime for fair WebSocket delivery #285 completes 100 sequential cold/warm connect/echo/close cycles before that observation, while a MessagePort queue refills continuously;
    • final direct result: cold 0.118 ms, p95 0.155 ms, at most 23 competing MessagePort deliveries, cancellation/reconnect exactly once, stable 1,027,564-byte V8 heap, and 45.7 MB max RSS;
    • related worker/postMessage/idle-platform filters pass.

    The correctly rebuilt and relinked unchanged Code OSS product trace shows #284 is necessary but not sufficient for this parent issue. Functional output remains exact—registered provider, selected URI equals the only workspace root, exact five resolved/model children, 5 rendered rows, 64 Explorer DOM nodes—but resolve still takes 7,641.1 ms and first paint 11,577.4 ms. Log: /private/tmp/vscode-252-product-navigation-280-correct.log.

    Therefore #280 and #252 stay open. The remaining investigation must attribute time below the now-qualified socket wake/fairness boundary; PR #285 does not claim the product latency gate.

  3. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Post-merge control on exact WebScene aa06172c rules out the native harness's 100 ms host-evaluation polling as the remaining delay.

    The query-gated local observer stopped all host state evaluations and invalidations immediately after the first navigation handoff, then relied only on the in-page terminal console record. The unchanged Code OSS result was:

    • host workspace-state polls during resolve: 0
    • exact selected URI/workspace root: yes
    • provider registered: yes
    • exact resolved/model child set: 5
    • rendered Explorer rows / DOM nodes: 5 / 64
    • resolve: 8,055.1 ms
    • first child paint: 12,034.7 ms
    • observer sampling maximum: 51.43 ms
    • peak child-process RSS: 801,800,192 bytes

    This matches the original 8.14 s boundary, so observer polling is excluded. #284's merged socket queue/wakeup gate remains independently qualified (max 23 competing MessagePort deliveries and stable V8 heap), while the remaining delay stays under #280. Investigation-only local vscode-demo commit: a3ab610; product log: /private/tmp/vscode-252-product-navigation-280-no-host-poll.log.

  4. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The one-shot, exact-package attribution trace on merged WebScene aa06172c identifies the remaining generic scheduler boundary and splits it to native subissue #287.

    Inputs were AppScene 1420e227, unchanged Code OSS 645f29cc, Node 24.18.1, and local query-gated observer 74b3b94 atop validated no-host-poll observer a3ab610. The app/server process group was terminated immediately after the terminal workspace record. Log: /private/tmp/vscode-252-product-navigation-280-attribution.log.

    Functional evidence remained exact:

    • selected vscode-remote URI == only workspace root
    • remote provider registered
    • exact resolved/model children: .hidden.txt, readme-link, README.md, subdir/, unicodé.txt
    • five rendered Explorer rows; 64 Explorer DOM nodes

    Attribution:

    • 151 native WebSocket events / 13,118,749 bytes; maximum queue depth 27
    • receive → runtime dispatch: 25,322.5 ms aggregate, 3,563.26 ms maximum
    • JS socket callbacks: 200.777 ms aggregate, 4.916 ms maximum
    • post-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 → loadend: 658,518.7 ms aggregate across overlapping reads, 14,940.7 ms maximum
    • first exact-root stat wave: about 5,416 ms; following readdir wave: about 2,299 ms
    • sampled scene publications remained individually bounded; observed maximum 64.35 ms
    • peak child-process RSS: 856,621,056 bytes

    The byte counts align the native socket, Blob, and FileReader path. Blob copying, JS callbacks, and callback microtasks are small. The source-level boundary is task arbitration: ready Worker/MessagePort/WebSocket sources return before the runtime checks due timers, while FileReader schedules both its read start and terminal events with zero-delay timers. Continuous protocol traffic can therefore starve the timers required to consume its own responses.

    #287 owns product-neutral fairness between async message sources and due timers, with direct native/browser, ordering, cancellation/reconnect, teardown, queue, scene, heap/RSS, and unchanged-product gates. #284 remains complete and is not reopened. #280 is reopened because #284 was necessary but did not satisfy this parent's product latency acceptance.

    The instrumentation intentionally adds bounded observation and this run is attribution evidence, not a new performance qualification result. The clean no-host-poll 8,055.1 ms result remains the comparison baseline until #287 is fixed and the unchanged product is rerun.

  5. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    #287's focused direct candidate proves timer fairness against the Worker/MessagePort/WebSocket group, but the unchanged product rerun shows that source group is not the full remaining #280 owner.

    On local 0f92cf47 rebased to WebScene main aa786c0e, the 256-frame FileReader gate records p95 0.119–0.198 ms and maximum 0.272–0.716 ms, exact bytes/event order, ≤20 competing port deliveries, 514/514 timers, ≤4,482 microtasks, 2 scene builds, stable heap, and 47.6 MB RSS. Baseline fails the same gate.

    The exact AppScene 1420e227 / Code OSS 645f29cc / Node 24.18.1 product rerun remains correct but slow:

    • exact selected/root URI, provider registration, five resolved/model children, five rows, 64 DOM nodes
    • resolve 7,749.84 ms
    • first child paint 11,788.09 ms
    • sampling maximum 48.46 ms
    • peak child-process RSS 860,160,000 bytes

    Product log: /private/tmp/vscode-252-product-navigation-287-candidate.log. #287 remains local/unpushed and does not close #280. The next measurement must distinguish other runtime task sources and non-task phases before another fix.

  6. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The unchanged-product candidate timeline moves the remaining parent boundary to existing Worker/MessagePort owner #81; no duplicate defect is opened.

    From /private/tmp/vscode-252-product-navigation-287-candidate.log:

    • workspace observer start (correlated): 1789655981628.9
    • direct provider resolve start: 1789655985605.0
    • remote extension host reported unresponsive: 1789655989676
    • AgentHost:remote Connected: 1789655993265
    • exact five-child resolve completes: 1789655993354.9 — about 90 ms after connection
    • five Explorer rows paint: 1789655993417 — about 152 ms after connection

    The extension-host WebSocket opened after 1,247 ms, but the AgentHost connection milestone took roughly another 16.6 seconds. Once it connected, provider resolution and paint completed immediately. #81 already owns unchanged Code OSS's browser extension-host iframe, Worker, transferred MessagePort, handshake, responsiveness, and lifecycle acceptance, with #288/PR #245 owning the active-port lifetime overlap.

    Dependency order is now: #81 packaged handshake/latency (coordinated with #288 as needed) → rerun #280 direct provider bound → rerun #252 Explorer 2 s bound. #287 remains a valid focused generic timer/task-source fairness finding, but its local candidate is independently insufficient for this parent.

  7. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The #81 phase trace refines this issue's upstream dependency. Local iframe/Worker/transferred-MessagePort startup completes in order, while the remote extension-host protocol takes 1,177 ms from connected transport to Ready and 4,379 ms from Ready to Initialized. That distinct owner is now #289 (native subissue of #81), separate from #288.

    After the remote handshake, the separate AgentHost service connects and the exact five-child/five-row workspace result follows 99 ms later. Requalify this issue after #289: #289 → #280 → #252. Local #287 remains unpushed and is not sufficient.

  8. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Packaged receiver-boundary trace on unchanged Code OSS 645f29cc, AppScene 1420e227, exact Node 24.18.1, and the current diagnostic package now separates the 4.2 s remote Ready → Initialized interval.

    Second workspace document:

    • remote transport connected → Ready: 1,288.17 ms
    • Ready → next Promise microtask: 0.116 ms
    • _createExtHostInitData() settle: 426.90 ms
    • JSON + UTF-8 serialization: 8.61 ms for 1,071,424 bytes
    • init-data send → remote Initialized: 3,788.40 ms
    • total Ready → Initialized: 4,224.01 ms

    Resource delivery remains fast: the iframe response was 0.899 ms / 6,786 bytes and the worker module response was 2.803 ms / 1,932,148 bytes. The exact selected URI/root, provider registration, five resolved/model children, five rendered rows, and 64 maximum Explorer DOM nodes all passed functionally. Peak app process-group RSS was 837,376 KiB. The bounded run terminated its complete process group and verification found no app/server/helper descendants.

    The independent 20-cycle native product-neutral oracle is also fast (Ready p95 5.944 ms; Initialized p95 5.408 ms; socket dispatch p95 5 ms; FileReader p95 2.536 ms; Promise/microtask p95 0.0078 ms; serialization p95 0.213 ms). Chromium passes the same 43/43 contract (Ready and Initialized p95 1.7 ms). Therefore no generic WebScene implementation is justified from this evidence yet. The next trace must split the receiver side after the 1.07 MB init payload is sent: receipt/parse, init-data hydration, extension scan/activation, and Initialized response.

    Retained evidence:

    • product log: /private/tmp/vscode-252-product-handshake-289.log
    • product log SHA-256: d85db2b31883b5f5f7e3a6747de96945c1810e792b0293a03df104a5dee0b761
    • process/RSS summary: /private/tmp/vscode-252-product-handshake-289-process.txt
    • native oracle: /private/tmp/webscene-289-baseline.log
    • Chromium oracle: /private/tmp/webscene-289-chrome-baseline-verify/results.json
    • query-gated local vscode-demo observer commit (not pushed): 10fc9aa
  9. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Receiver-side instrumentation isolates the breach before Node parsing or extension initialization.

    On the retained second workspace document:

    • Node remote extension host sent Ready at 1789658968549
    • WebScene browser received Ready at 1789658969571: 1,022 ms inbound delivery
    • WebScene serialized and sent the 1,071,425-byte init message at 1789658969991
    • Node remote extension host received that exact 1,071,425-byte message at 1789658973482: 3,491 ms outbound browser → Node delivery
    • receiver UTF-8 decode: 0.133 ms
    • receiver JSON parse: 3.589 ms
    • total receiver hydrate/watchdog work before Initialized: 12.204 ms
    • Node sent Initialized at 1789658973495
    • WebScene browser received Initialized at 1789658973588: 93 ms return delivery

    ExtensionHostMain construction begins only after Initialized is sent, so extension scanning/activation cannot own the Ready → Initialized breach. The exact root/provider/five resolved children/five model children/five rendered rows/64-node result still passes functionally. The 50 s bounded observer waited for the later constructor completion marker, then terminated the complete process group; no app/server/extension-host descendants remained. Peak process-group RSS was 843,184 KiB.

    A size-matched control preserves the earlier fast baseline: the product-neutral native oracle sends a binary-compatible 1,071,424-byte payload for 20 cycles and reports Initialized p95 6.140 ms; Chromium passes 43/43 in 89 ms. The next reduced gate must add the actual Code OSS binary framing/compression and concurrent traffic/queue shape, retain enqueue → wire → server-receipt timing, and preserve this fast size-only control before any WebScene implementation.

    Retained evidence:

    • app log: /private/tmp/vscode-252-product-receiver-289.log (SHA-256 51d5b4d696b5474e2210a1f13851b39531443030927fa148f6705ffc79aed160)
    • server/receiver log: /private/tmp/vscode-252-product-receiver-289-server.log (SHA-256 372b41c577260eb7787ceeaaca6c7f6655ced1259f4a4d4e9715e6280cf2e9db)
    • process/RSS summary: /private/tmp/vscode-252-product-receiver-289-process.txt
    • matched-size native control: /private/tmp/webscene-289-one-mib.log
    • matched-size Chromium control: /private/tmp/webscene-289-chrome-one-mib-2/results.json
    • local query-gated receiver observer commit (not pushed): da9db1a
  10. 2 remaining items

  11. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Post-#281 qualification keeps #280 open. On exact main 1bd8596e, local b75d3795 fixes the reduced 1,071,425-byte multi-source timer oracle (max 3617.66 ms → 0.204 ms) while preserving Worker/ServiceWorker/MessagePort/WebSocket rotation. However, unchanged packaged Code OSS still waited 3698 ms from protocol-send request to native WebSocket.send entry. Native send then returned in 0.783 ms, its microtask ran in 0.834 ms, and the remote Initialized reply arrived 184 ms after send entry.

    This excludes WebSocket wire throughput as the remaining bottleneck and shows that timer-vs-async arbitration alone is insufficient. The next investigation is the other product runtime task tiers that can return before due timers. No candidate PR will be published while #252 misses its two-second gate; draft #292 also has a live runtime-task path collision.

    Evidence: /private/tmp/vscode-252-product-b75d3795.log, SHA-256 f58b40413fe5dd30567d0d6a3d207b668fd07bea96b594aae9c5568509a38252. All traced descendants were terminated and port 54759 released.

  12. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    #293's local candidate proves generic due-timer fairness against self-refilling window messages, but unchanged Code OSS still waits 3478 ms from protocol-send request to native WebSocket.send entry; Ready→Initialized is ~4102 ms. Native send itself is 0.815 ms and its microtask 0.857 ms. Therefore #280 remains open and the remaining owner is another pre-timer runtime tier or timer-eligibility boundary. No push/PR.

    Evidence: /private/tmp/vscode-252-product-b485f6aa.log, SHA-256 cb9b7c5c843da4badc2b8c7e35c2850b41598c70b7510afce7c94bee5b5a2a26. Full process cleanup and port release verified.

  13. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The remaining #280 startup delay is now attributed below task arbitration to the built-in light_vs.json fetch promise continuation: one drain_fetch_task took 2457.000 ms, of which 2424.455 ms was the required microtask checkpoint and 32.530 ms style-batch finish. Response construction and promise settlement were only 0.012 ms. The overdue protocol timer's histogram assigned 2457.097 ms to that one fetch task.

    Opened #297 for the product-neutral theme continuation/DOM-CSS performance reduction. #287/#293 remain valid generic scheduler findings but neither qualifies unchanged #252. No push/PR.

    Evidence: /private/tmp/vscode-252-fetch-phases-7ad62971.log, SHA-256 d1feb5b7970d56298ee80c2a49228dfc3060c4663dec3a2249b09e77c4d98b72; all traced processes terminated and port 57829 released.

  14. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The exact AppScene d4a73888 / WebScene dd39f118 / Code OSS 645f29cc workspace run now supplies the product evidence for this owner. Functional #252 output passes: exact remote root, provider registration, five resolved/model children, five visible rows, and 64 Explorer DOM nodes.

    The performance gate fails with a clear FileReader/completion split: 149 FileReader operations read 13,209,295 bytes, sum to 88,463.6 ms, and have a 2,219.39 ms maximum, while 149 Blob.arrayBuffer() calls for the same bytes sum to 1.11 ms with a 0.040 ms maximum. Initial provider stats take about 1.21-1.27 s; root readdir takes about 332 ms. This keeps #280 open and makes it the next workspace-performance implementation before #252 can close.

    Evidence: /private/tmp/vscode-demo-workspace-dd39f11-d4a7388/. vscode-demo #8 adds a bounded compact summary because the verbose 149-call record exceeded the runtime diagnostic record cap.

  15. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The latest exact installed-package rerun is functionally correct and refines the remaining performance owner back to #287 with a new concrete boundary:

    • exact root/provider/five resolved children/five model children/five rendered rows/64 Explorer nodes pass;
    • 149 FileReader operations, 13,209,295 bytes;
    • FileReader call-to-loadend: 88,463.629 ms aggregate across overlapping reads, 2,219.394 ms maximum;
    • matching Blob.arrayBuffer(): 1.111 ms aggregate, 0.040 ms maximum;
    • initial provider stats: about 1.21-1.27 s; root readdir: about 332 ms.

    PR #423 implements the product-neutral #287 follow-up: FileReader uses its own bounded browser task source instead of sharing the application timer backlog. The exact-main test-only control drains 4,096 timers before FileReader and takes 57.847 ms; the candidate completes in 0.405 ms after two competing timers. Native and Chrome pass the shared contract 48/48, and the existing 100-cycle/20-cycle protocol gates remain green with bounded work and flat settled V8 heap.

    Do not close this parent from the reduced result. After #423 merges, rebuild the exact SDK/package and rerun the same unchanged-product workspace trace. Close #280/#252 only if resolve and first-child paint meet the two-second bound with exact functional output.

  16. wieslawsoltes commented on Sep 21, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Exact current-package requalification on 21 September isolates the remaining #280 breach and starts a focused candidate.

    Exact input:

    • AppScene cd0a02ecd15f0a635bccc242cdd657888db39e25
    • WebScene 62c4c6175fc55bbebb633eb18b5a94e7de613efe
    • unchanged Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c
    • executable SHA-256 f5594cd51d43f840b84426b2f33ba3c906dcd5b1c17623c759784e6078c47095

    The unchanged-product functional oracle passes: selected URI equals the only workspace root, the provider is registered, and the exact five fixture children appear in the provider result, Explorer model, and five visible rows with 64 Explorer nodes. Resolve is now 1,219.824 ms and passes the 2-second bound. First-child paint is 2,530.115 ms, so #280/#252 remain open.

    The remaining timing signal is FileReader scheduling: 90 reads cover 11,833,296 bytes; matching Blob.arrayBuffer() work is at most 0.0393 ms, while FileReader call-to-loadend is at most 1,114.299 ms. WebScene currently schedules one dedicated file-reading task for loadstart and a second task for terminal events, closing two microtask/style batches per protocol Blob.

    Local focused candidate 302e6d18 keeps one asynchronous FileReader task open through the Blob promise checkpoint and ordered loadstart → progress → load → loadend delivery. Abort, errors, immediate chained reads, native queue bounds, and event order remain covered. Pinned Node compatibility passes 8/8. The native gate passes 100 WebSocket cycles, 20 product-shaped protocol cycles, 0.0253 ms FileReader p95, 0.314 ms completion under a 64-timer backlog, queue high-water marks of one, and flat settled V8 heap.

    An exact clean SDK/package rebuild is running. Do not close #280/#252 or publish the PR until the unchanged-product first-paint rerun passes the 2-second bound. Evidence: /private/tmp/vscode-demo-workspace-62c4c617.log; focused design: docs/validation/file-reader-single-task-20260921.md on the candidate branch.

  17. wieslawsoltes commented on Sep 21, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Exact transport attribution after WebSocket per-socket fairness (#888) narrows the remaining #280/#252 breach to same-socket binary-message processing.

    Exact input:

    • AppScene cd0a02ecd15f0a635bccc242cdd657888db39e25
    • WebScene diagnostic candidate 2f3ff02a8fef7b6dd5cfa5fd07a532e850902639 on merged main 2b29eed6
    • unchanged Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c

    The functional oracle remains exact: remote root/provider, five resolved children, five model children, five visible Explorer rows, and 64 Explorer DOM nodes. Resolve is 980.58–981.00 ms. First paint is 2,061.06–2,078.14 ms, narrowly above the 2 s gate.

    Opt-in metadata-only native tracing records socket id, event type, byte count, enqueue/dispatch times, queue delay, and remaining events; it never records payload content. Relative to the second-document observer:

    • management socket 3: 81 events / 11,869,851 bytes; native queue delay p95 652.62 ms, max 729.09 ms;
    • extension-host socket 4: 23 events / 33,087 bytes; p95 104.72 ms, max 212.85 ms;
    • the one-byte extension-host Ready frame is dispatched in about 8 ms despite the management backlog;
    • Node sends Ready immediately after its cold process startup, so the remaining pre-Ready cost includes about 940 ms of process launch;
    • the management stream is dominated by 262,144-byte binary frames. Its response frames wait behind earlier frames from the same socket.

    This proves #888 removed cross-socket head-of-line blocking. The worker loop also already avoids layout/scene publication when these protocol tasks leave the document unchanged. The next focused implementation is the binary WebSocket → Blob → FileReader path. WebScene's Blob constructor currently stringifies every input part eagerly for a nonstandard toString() cache; stringifying a 262 KiB Uint8Array creates a large comma-separated decimal string even when no caller requests text. That work repeats across the 11.87 MB startup stream and is absent from browser Blob construction.

    Next change: make Blob's compatibility string representation lazy while preserving its current observable result, add a large binary Blob/WebSocket regression and bounded construction benchmark, then rerun this exact package gate. Keep #280/#252 open until first paint is below 2 s.

    Evidence: /private/tmp/vscode-demo-workspace-2f3ff02a-trace.log, /private/tmp/vscode-demo-workspace-2f3ff02a-trace-evidence/logs/server.log, and /private/tmp/vscode-demo-workspace-2f3ff02a-graceful.log.

  18. wieslawsoltes commented on Sep 21, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Exact merged-package closure evidence — 21 September 2026

    The current installed-SDK Release now passes the shared unchanged-product gate that this issue was waiting for.

    Exact inputs:

    • AppScene cd0a02ecd15f0a635bccc242cdd657888db39e25
    • WebScene a99eaf23aef5e5525b0a58c5635fa8a431b604f1
    • unchanged Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c
    • SDK manifest SHA-256 475c5652aed411cb98867ad79074e75096534adce6f607cbe1a11f5b2b39ab9b
    • executable SHA-256 9c3404b01537cca336717492030f548b15180fc5c3d1f684185963808d430b4f
    • product log SHA-256 c78d19651bf5615b9db7595ea2aa16bc252ad1395d19b83b610088639c864fc2

    Unchanged-product result:

    • selected URI equals the only workspace root;
    • stock remote provider registered;
    • exact resolved/model/rendered child set: .hidden.txt, readme-link, README.md, subdir, unicodé.txt;
    • resolved/model/visible counts: 5/5/5;
    • maximum Explorer DOM nodes: 64;
    • provider resolve: 757.40 ms;
    • first-child paint: 1,880.02 ms, inside the 2-second product budget;
    • observer sampling maximum: 15.37 ms;
    • protocol: 79 FileReader reads / 11,801,046 bytes, 47.41 ms maximum FileReader completion, 0.067 ms maximum Blob conversion;
    • remote transport → Ready: 939 ms; Ready → Initialized: 295 ms;
    • after bounded termination, no AppScene host, bundled server, extension-host, or helper process remained.

    The closing implementation chain is merged: shared task-source/protocol fairness, dedicated FileReader scheduling, per-socket WebSocket fairness (#888), metadata-only diagnostics (#889), and lazy binary Blob compatibility-string expansion (#890, merge a99eaf23). The 12 MiB focused Blob gate measured 0.867 ms construction without requested text expansion versus 55.79 ms with explicit expansion (~64.4×), preserved the exact snapshot/string result, retained cross-socket ordering, and finished with flat settled heap.

    The wider workspace/watcher/dependent-service matrix remains tracked by #252. This issue's shared implementation and exact-product latency gate are complete.

  19. wieslawsoltes commented on Sep 21, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Reopened after repeated exact-package run — 21 September 2026

    The first exact merged-package run passed at 1,880.02 ms, but a second independent cold run on the same AppScene cd0a02e / WebScene a99eaf2 / unchanged Code OSS 645f29cc package painted at 2,179.19 ms. Provider resolve remained bounded at 1,110.87 ms, the exact root/provider/five resolved/model/rendered children remained correct, and maximum Explorer DOM nodes remained 64.

    Because this issue explicitly requires the unchanged-product first-child result within two seconds across repeated cold/warm qualification, one passing run is insufficient. The issue is reopened pending a multi-cycle p50/p95 gate and attribution of the remaining approximately 179 ms breach. The already merged direct scheduler/Blob regressions remain valid and are not reverted.

  20. wieslawsoltes commented on Sep 21, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Repeated native qualification on exact merged inputs WebScene a99eaf23, AppScene cd0a02e, unchanged Code OSS 645f29cc:

    • 20/20 launches reconstructed the exact root/provider/five-entry model and visible Explorer rows, with a 64-node maximum Explorer subtree.
    • Provider resolve: 914.43 ms p50, 1,158.98 ms p95, 1,187.14 ms max.
    • First-child paint: 2,164.26 ms p50, 2,262.03 ms p95, 2,263.77 ms max; only 9/20 met the 2,000 ms bound.
    • A five-cycle trace correlates the slow cluster with management-socket queue delay: 548 ms p95 in the passing trace versus 786–839 ms in failing traces. Blob conversion stayed below 0.1 ms and FileReader maxima stayed around 38–48 ms.

    I tested a bounded worker task-batch change from 4 ms to 8 ms. It preserved exact functionality but regressed paint to 2,219.65 ms p50 / 2,337.72 ms p95 / 2,361.70 ms max and 8/20 passes. The candidate was discarded and was not committed or published.

    The next implementation must target the actual management-channel queue or repeated cascade/layout publication boundary, while retaining the 4 ms task batch and the existing input/resize/render opportunities.

  21. wieslawsoltes commented on Sep 21, 2026

    @wieslawsoltes
    CollaboratorAuthor

    A second targeted candidate removed the intermediate Uint8Array and JavaScript slice() for WebSocket binaryType="arraybuffer" delivery.

    The focused WebSocket/FileReader suite passed: exact Blob and ArrayBuffer bytes, 100 cross-source fairness cycles, settled heap, protocol timing, and FileReader ordering. The unchanged-product 20-launch gate did not improve:

    • exact functionality: 20/20;
    • within 2,000 ms: 9/20, unchanged;
    • resolve: 914.63 ms p50 / 1,137.48 ms p95;
    • paint: 2,215.91 ms p50 / 2,273.17 ms p95 / 2,281.95 ms max, versus clean 2,164.26 / 2,262.03 / 2,263.77 ms.

    The candidate was discarded without a commit or PR. This rules out the ArrayBuffer conversion copy as the owner of the bimodal delay. Next work stays focused on protocol callback work and the layout/scene publication boundary.

  22. wieslawsoltes commented on Sep 21, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Completed by the shared merged scheduler/protocol chain plus WebScene PR #891.

    The exact unchanged-product qualification passed 20/20 launches with the requested root, provider, five resolved/model/rendered children, and first-child paint under 2 seconds. Resolve p95 is 762.64 ms and paint p95 is 1860.12 ms. Broader workspace-file, multi-root, interaction, visual, dependent-service, and lifecycle acceptance remains tracked in #252.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingvscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions