Skip to content

Evaluate native HTTP/WebSockets end to end #20

Closed

Description

@Igloczek

Parent

Native Bun APIs: measure and selectively migrate runtime boundaries (#18)

What to build

A supported decision for the main environment server's HTTP/WebSocket boundary. Adopt native Bun transport only if it fixes the qualifying problem or provides the measured benefit while users retain authenticated RPC, responsive Browser streams, remote connections, and a working installed archive. Otherwise record why the existing transport remains the right choice.

Ticket-definition review completed on 2026-10-08: Claude Opus 5.5 agrees this ticket is ready for agent implementation with no remaining blockers. Separate review thread. The completed-work review below remains required after execution.

Acceptance criteria

  • Read the parent and baseline ticket. Refresh the baseline if the pin, application, dependency graph, or measured build changed. Declare this boundary's workload and claimed benefit before prototyping; the parent's attribution gate must pass first.
  • If attribution is insufficient, parity is impossible, or evidence is inconclusive, record a retained/inconclusive decision and land no production changes, including composition refactors. A retained result is successful completion.
  • For an eligible candidate, keep Bun-only imports in fork-owned modules reached from production entry composition. Inject HTTP layers at existing construction sites. Replace only existing Browser Node socket/handshake reads with a scoped capability for pending outbound bytes, immediate termination, and uncompressed upgrade/send; keep route control flow unchanged. Fork-owned Node-test and Bun-production implementations provide that capability without runtime selection. Replace only the auth client-address source read with the portable Effect request address while keeping current normalization; no new auth service is needed. Any local adapter port stays narrow and shares one Effect context.
  • Compose a server-only native layer/port while retaining the existing HTTP platform, file-response implementation, HTTP body compression, and ETag generation. Do not adopt the reference aggregate Bun layer's pathname-based file responses or new compression algorithms as a side effect. Native file-operation changes belong to Evaluate native file operations #21.
  • Prove current-build routing, authenticated RPC, OAuth/MCP endpoints, cookies/CORS, streaming bodies, failed/refused upgrades, reconnection/cancellation, and graceful shutdown. Prove session client-address metadata is preserved in persisted sessions and its displayed/CLI form using portable request metadata. Late writes to dead/closed sockets must not terminate the server. Hosted/local clients and local/remote/relay/tunnel interfaces retain their contracts at existing transport seams; no live cloud/relay account is required. Loopback callback servers and outbound HTTP clients remain outside the candidate.
  • Through the new transport, reuse existing HTTP/file tests to prove static, media, attachment, and Browser download content, invalid/nonregular paths, validated identity-change behavior, range/HEAD, cache/ETag, Content-Encoding/wire behavior, and descriptor closure on client abort. Prove retained raw Node-readable bodies keep lazy opening, no descriptor open for HEAD, client-driven backpressure, abort destruction/close, Content-Length, and 206 framing, including compressed raw bodies. A narrow raw-body-to-web-stream conversion inside transport response mapping is allowed if needed; adopting a native file platform to bypass failed parity is not. When native transport is accepted, this proof is required before Evaluate native file operations #21 begins.
  • Prove Browser viewers have bounded queued bytes and unacknowledged frames, immediate slow-viewer cleanup, and correct send/drop/backpressure/drain handling. JPEG frames stay uncompressed; extension-negotiation internals are not the contract. Browser limits do not tighten RPC socket limits.
  • Measure representative RPC wire bytes and server CPU, preserving compression benefits. Dedicated per-socket compression is allowed; a transport passing functional tests but materially worsening wire traffic does not pass.
  • Reuse Bun-run contract fixtures and the disposable source/actual-archive harness. Native-adapter evidence covers macOS arm64, Linux x64, and Linux arm64. Permitted container/emulation evidence is identified and never used for performance claims; missing parity evidence prevents acceptance. Real-client/browser verification follows AGENTS.md and applicable consent; no new browser authorization is implied by ticket creation.
  • Apply the parent's adoption/regression method: qualifying incompatibility fix or at least 5% end-to-end benefit exceeding baseline range; two independent alternating batches, at least five launches per variant/build per batch, at least 60 seconds idle, separate RSS/footprint/heap metrics, and no failing regression gate. Source and archive pass separately; neither can be averaged away. One-batch-only regression or unresolved noise prevents adoption; at most one repeat.
  • Pass the parent's baseline/candidate upstream-import rehearsal. Native implementation remains fork-owned; shared substitutions are limited to existing construction/entry sites and the specifically identified transport consumers above. The fixed input/rehearsal covers every changed shared file, including consumers: include the full recorded import ranges needed to cover their most recent upstream edits, rather than selecting only the bootstrap's last edit. Consumer substitutions must introduce no additional conflicts outside construction/entry sites; only construction/entry conflicts may need the parent's mechanical preservation-rule repair. Broader conflicts or recurring manual procedures require retaining the candidate. Record a real fixed input and conflicts/repairs; a no-op merge is not evidence.
  • On acceptance, ship one chosen production backend, remove comparison variants, and update only durable runtime/sync guidance. Honor the parent's single-user runtime-break permission, unchanged wire/auth/durable formats, safe upgrades, web/server scope, and existing CI. Put results/artifact links on this ticket, not research files in the repository.
  • Have the completed decision and any implementation/evidence verified by Claude Opus 5.5 in a fresh separate T3 thread; record its link and resolve blocking findings before completion.

Blocked by

Activity

  1. Igloczek commented on Oct 8, 2026

    @Igloczek
    Author

    Program progress: execution started (2026-10-08)

    • Prerequisite Baseline and profile native Bun opportunities #19 is complete and closed. HTTP/WebSockets is eligible on a reproduced Bun 1.4.2 incompatibility: the RPC socket's perMessageDeflate is never negotiated through the ws compatibility path (matched controls: Bun 494,592 vs Node 4,206 received bytes). See the Baseline and profile native Bun opportunities #19 results comment.
    • Owning stack layer: native-bun/http-websockets, the bottom layer, based on origin/main = d5cee2d8fa, in orchestration worktree t3-325d51f7. The layer is omitted if the decision is retained or inconclusive.
    • Execution worker: delegated task native-bun-20-exec-r1 (Codex GPT-6.1-Sol, high reasoning).
    • Carried forward from Baseline and profile native Bun opportunities #19: the unresolved dev-runner WS-upgrade timeout, and a representative JPEG/slow-viewer Browser workload required before adoption.

    Status: evaluating

  2. Igloczek commented on Oct 8, 2026

    @Igloczek
    Author

    #20 outcome: retained (no production changes; stack layer omitted, no PR)

    Decision: keep the current Effect Node HTTP / ws-compatibility transport on Bun 1.4.2.

    • Declared workload and benefit: fix the Baseline and profile native Bun opportunities #19-reproduced RPC permessage-deflate incompatibility, judged by RPC wire bytes and server CPU, with full behavioral parity and the regression gates.
    • Obstacle: pinned Bun.serve always strips a handler-supplied Content-Length on streamed bodies. Every stream form becomes chunked: Node-readable, Web, type:"direct", bytes, async-iterable, 206 ranges and raw gzip. Only bodies fully buffered before the first write keep their length. The cause is RequestContext.rs do_write_headers plus the stream sink at tag bun-v1.4.2. The ticket requires Content-Length and 206 framing for retained raw bodies, including compressed ones. Buffering whole files, reopening validated files by pathname, adopting native file responses, and upgrading the pin are all out of scope.
    • Held descriptors are no workaround either. Bun.file(fd).slice(a, b) on a held descriptor returns 206 with Content-Length set to the full file size while sending only the slice. Only pathname-opened files frame correctly. Evaluate native file operations #21 also depends on this.

    Still unresolved (stated explicitly): the #19 deflate incompatibility remains. Under Bun 1.4.2, RPC frames reach remote, relay and tunnel clients uncompressed. This retention leaves that problem with no owner, so the maintainer decides whether it gets a separate tracking item outside this program. The dev-runner WS-upgrade timeout carried from #19 also remains unresolved. The JPEG/slow-viewer workload was not run because no candidate reached adoption.

    Reopen trigger: a Bun pin whose Bun.serve preserves a handler-supplied Content-Length on streamed bodies, with valid descriptor-slice framing. The dedicated-compressor WebSocket measurement (53,245 vs 12,974 shared-compressor bytes) is unexplained, and anyone revisiting native HTTP must explain it first.

    Completed-work review: fresh Claude Opus 5.5 / Gilfoyle thread mcp:f9c1c66c-86ce-47e8-ae49-66e3db41f7a1 . The reviewer confirmed the blocker three ways:

    • the pinned source (byte-identical to tag 744846f8);
    • re-running the worker's probe;
    • its own probes of every body shape and of the held-descriptor slice.

    It also confirmed the branch has no residual changes. Verdict: AGREE — all #20 acceptance criteria satisfied for a retained decision.

    Per the parent's sequence, #21 now evaluates only read/write file paths. Native HTTP file responses are out of scope because transport was retained.


    Decision: retained — keep the current HTTP/WebSocket transport on Bun 1.4.2.

    The eligible deflate issue does not justify adopting a transport that fails another required behavior. Plain pinned Bun.serve removes supplied Content-Length on large streamed HTTP/1.1 responses, including 206 ranges and compressed raw bodies. The candidate cannot preserve the ticket's retained raw-readable framing contract through the allowed narrow conversion. Buffering whole files would sacrifice the required streaming/backpressure behavior; swapping the file platform or upgrading the pin exceeds scope. The early feasibility stopping rule applies.

    Independent raw-TCP source and compiled probes, separate Bun compatibility/native processes on native macOS arm64, reproduced:

    Response Compatibility length Native length/framing
    Node-readable/Web/direct streams, 65,536 bytes 65536 absent; chunked
    206 range stream, 65,536 bytes 65536 absent; chunked; Content-Range/status preserved
    Raw gzip stream, 65,576 bytes 65576 absent; chunked; encoding preserved
    Small gzip / buffered control 97 / 65536 preserved

    All bodies matched. This is a correctness rejection, not a speed/regression claim. The compiled fixture is not the actual main archive. Pinned RequestContext.rs explicitly strips the supplied framing headers.

    Secret evidence gist, immutable revision: https://gist.github.com/Igloczek/3d6c1a1cd2ae7918841f992f3c2aa7d6/80249e25a5d5968750277f08c029cf06c52104a4. Its seven files were checked byte-for-byte and public=false. They contain standalone synthetic tooling/replay commands, preregistration, redacted prelaunch hashes and results; no repository source, private state, local paths or diagnostic logs. The full report and raw artifacts remain local and unpublished.

    Baseline/main/pin/lock/fixture/archive hashes remained unchanged; preregistration SHA 85541c23beee263af2f897eadba79558fdd663ca8229590417a86c91b894bdf5, 2026-10-08T21:13:23.618464+00:00. The branch native-bun/http-websockets has zero new commits, HEAD d5cee2d, and a clean working tree. All prototype/composition/doc changes were removed; no pushes, stack commands, PRs, issue comments or browser launches by this worker.

    Checks: temporary Node-test composition focused suites passed 3 files/20 tests. A native main-source pairing + one catalog RPC pilot passed. Shared raw-body compatibility fixture passed; initial native HEAD cleanup was fixed, then native GET framing failed. The preliminary server-only typecheck failed on unfinished prototype code; no green typecheck is claimed. Decisive plain-runtime body/status/encoding assertions passed and recorded the required native parity failures.

    Unrun gates/gaps: no ≥5-launch/60-second-idle alternating adoption batches, CPU/RSS/footprint/heap/tail regression verdicts, native main archive, full client/auth/address/file parity, representative JPEG/slow-viewer workload, or complete upstream-import rehearsal. The avoidable auth import micro-merge was not a gate rehearsal or rejection reason. Existing preservation guidance remains unchanged. The inherited dev-runner WS timeout remains unresolved. Linux arm64 Docker pull failed because daemon storage was full; no container ran; x64 emulation was not launched. Missing Linux evidence would independently prevent acceptance.

    Cleanup: all 27 captured process starts have stops, source server PID 18019 stopped normally with scoped SIGTERM exit 130; compiler/test/sidecar PIDs were not exhaustively journaled. Our unique disposable machine was deleted, no test container exists, unrelated stopped containers were preserved, and OrbStack was stopped after verifying no active resources. No live T3 state access or kill by name/pattern.

    Model/harness: GPT-6.1-Sol, high reasoning, Codex in T3 Code.

  3. Igloczek commented on Oct 8, 2026

    @Igloczek
    Author

    Closing: retained decision; acceptance and completed-work Opus review gates passed (see the results comment above). No repository changes.

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

    ready-for-agentSpecified and ready for agent implementation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions