inspector/clients
Repository files (latest commit first)
Filename Latest commit message Latest commit date
cliffhall 78f82475c4 fix: stop the drain and release both tee branches on timeout (#2319 round 24)
Losing the race rejected the caller but did not stop the read. Because
clone() tees the body, a drain still running kept pulling bytes AND
kept buffering them for the unread original branch — unbounded memory
on exactly the signal-ignoring body the race exists to contain.

The clone is now drained through an explicit reader rather than
clone().arrayBuffer(), precisely so the losing side has something it
can cancel: arrayBuffer() locks the stream to an internal reader
nothing else can reach. On any throw both branches are torn down, which
is safe because that path never hands the response to a caller.

The cancels are deliberately not awaited: cancelling one branch of a
tee can itself wait on the other, which would hold the timeout open for
as long as the stall it is meant to end. Each carries its own catch, so
a stream already cancelled, errored or locked elsewhere does not mask
the timeout the caller actually needs — covered by a test whose stream
throws from cancel().

Verified by mutation: removing the teardown makes the new test fail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFnM6RqB4nXqNysgUYmjmq
Signed-off-by: cliffhall <cliff@futurescale.com>
2026-09-11 08:19:57 -04:00
..
cli feat: bound every OAuth-path request with a deadline 2026-09-11 00:45:04 -04:00
launcher feat: seed the MCP org example server as a remote first-run card (#2201) 2026-09-06 22:57:53 -04:00
tui fix: address Copilot review round 17 on #2248 2026-09-07 23:12:28 -04:00
web fix: stop the drain and release both tee branches on timeout (#2319 round 24) 2026-09-11 08:19:57 -04:00