1. clients/web/.npmignore's explanatory comment still said the root "files"
allowlist restricts publishing to build/ and dist/ and that everything else
under clients/web "stays out regardless". #1934 added clients/web/static to
that allowlist, so the claim was false — in a file that exists precisely
because a packaging contract was misread once. Name static/ and say why it
ships (read from disk at runtime by sandbox-controller.ts, at a path
relative to the runner dir).
2. Replace the four unjustified `as unknown as Response` doubles in
useServers.test.tsx with real Responses over real ReadableStreams: a
null-body Response for the `!res.body` guard, a stream whose pull throws for
the reader-rejects case, and pull-driven streams for the multi-frame and
priming-comment cases (pull runs once per read, so the counting and the
blocking second read behave exactly as the hand-rolled reader doubles did).
The doubles are now structurally type-checked against the Response API.
3. scripts/smoke-web-app.mjs orphaned the MCP test server on a readiness
timeout: startMcpServer() returned the child only once the announcement
line matched, so a child that was alive but never announced left `mcpServer`
unassigned, shutdown() could not stop it, and process.exit(1) left it
holding its port. Publish the child to `mcpServer` the moment it is spawned,
so every throw path is covered by teardown.
Closes#2000
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hzwzS8UvBsr4yZm7o7sev
Signed-off-by: cliffhall <cliff@futurescale.com>