PTY pressure experiment¶
Question and composition¶
Can browser consumption drive pause/resume at the local PTY bridge while all sent Updates still render correctly? This follows the local ingress experiment and the validation plan. It composes a built SDK application, the bundled-ConPTY bridge, and the existing xterm mixed ingress.
This prototype uses opt-in local bridge controls for consumption credits. They operate independently of protocol Messages and Operation outcomes. Normal application examples leave them disabled.
Workload and accounting¶
producer.mjs opens one mutable Block, sends 256 full Updates with
distinct ASCII labels and 2048 repeated characters, Seals, and explicitly closes
the Context. Its synchronous SDK writer calls Node stdout; if a write returns
false, the application waits for drain before sending the next Operation.
It reports how often that path was used and, since the 2026-09-18 follow-up,
the longest synchronous write duration.
The composed follow-up selects a larger fixed workload and a
two-second browser hold using the same implementation.
The stalled-consumer check holds it indefinitely and verifies
host-side termination instead of successful completion. Since 2026-09-19, these
pressure fixtures enable a five-second consumption-progress watchdog; normal
examples still leave the optional flow-control path disabled.
The browser holds the first Update before native rendering until it
also observes a host pause. It queues incoming binary data in arrival order and
returns a cumulative consumed-byte offset only after ingress.push() completes.
That offset measures local byte processing, not success of every Operation.
The opt-in host uses FlowWindow to count sent-but-not-yet-consumed bytes. It pauses PTY reading at 16,384 bytes and resumes at or below 4096 bytes. Duplicate offsets grant no extra credit; backward, fractional, or beyond-sent offsets close the connection. Child-exit reporting waits for outstanding bytes to drain. The existing loopback binding, Origin/token check, single-child policy, and cleanup remain in place. These numbers are fixture settings, not selected product limits.
The last data callback may cross the high watermark by a whole chunk; a paused
reader also does not remove bytes already buffered elsewhere. Thus the high
watermark is not a hard memory or queue limit. Host peak counts binary bytes
until browser credit; browser peakPendingBytes counts received binary bytes
until processing finishes. peakSocketBytes samples ws.bufferedAmount after
binary sends. Metrics/control JSON, OS/ConPTY buffers, renderer allocations,
Session snapshots, and child stdout buffers are not included in those totals.
Observed result¶
On 2026-09-16, a local browser run using Windows bundled ConPTY and pinned xterm 6.0 passed: 256 Updates rendered, final native and Session content matched, the Block was sealed, Context closed, child exited zero, and outstanding bytes reached zero. The first recorded run reported:
761,325 binary bytes forwarded and consumed;
13 pause/resume pairs;
71,476 peak outstanding host bytes and peak pending browser bytes;
zero sampled WebSocket buffered bytes;
zero producer stdout drain waits.
Chunking and counts can vary between runs; the check does not require these exact numbers. The run demonstrates the browser-to-PTY-reader control path and finite completion. Producer waiting remained unresolved: there were no drain waits, and synchronous write duration had not yet been measured. Zero sampled WebSocket bytes also leaves buffering elsewhere unmeasured.
The upstream follow-up compares normal and paused ConPTY reading with independent producer progress and write-duration measurements. The composed measurement then observes producer waiting overlapping a browser hold in the larger workload. Total pipeline memory remains unmeasured.
Run and verification¶
On Windows with Node 24+, from the repository root:
pnpm install
pnpm prototype:pty-pressure
Open http://127.0.0.1:4178/ and choose Run pressure check. Expect PASS and
the accounting report; reload for a new child. The check verifies the controlled
stall, pause/resume, exact Update count, final native and logical content, normal
closure, and fully credited bytes. A mismatch or thirty-second page deadline
reports FAIL. Close the page to stop its child; Ctrl+C stops the server. Run only
one port-4178 PTY fixture at a time.
pnpm typecheck, pnpm test, and pnpm build:pty-pressure check types, Node
regressions (including byte-window transitions/invalid offsets), and browser
bundling. The browser run is separate from the Node tests; built static files
still require the development host and its injected token. The original
terminal-host checks
exercise the unchanged default, without flow credits.
The original 2026-09-16 verification passed type checking, 181 Node tests, the pressure and both example builds, this browser pressure check, and all four existing terminal-host and multi-round browser scenarios. Those four regressions do not use flow credits.
This is one finite ASCII workload in a fixed 40-by-8 browser terminal using experimental OSC 9002 and private xterm APIs. It does not validate general Unicode, eviction, clipboard/search, a stalled renderer’s recovery, malformed peer behavior over a real socket, long-running memory use, other terminals, Unix, SSH, or tmux.