Skip to content

🤖 ci: upgrade Bun from 1.3.12 to 1.4.3 - #6319

Merged
ThomasK33 merged 5 commits into
mainfrom
ci/bun-1.4.3-experiment
Oct 13, 2026
Merged

ThomasK33 merged 5 commits into
mainfrom
ci/bun-1.4.3-experiment

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Summary

Upgrade the pinned Bun from 1.3.12 to 1.4.3. With 6 small fixes (3 in tests, 1 in dev dependencies, 2 in production code), the full PR CI run is green on Bun 1.4.3, and CI time does not change measurably. The main gain: the Bun 1.3.12 coverage bug that hides lines after a using declaration is gone, so the CRAP gate scores those functions correctly again. resumeStream (workspaceService.ts) goes from 5% to 99% line coverage and executeBash from 9% to 96.5% on the same tree.

Background

Bun 1.3.12 loses line coverage when a method is followed directly by an async or generator method that no test calls. With a using declaration in the method, every line after the using reads as never run. The CRAP gate scores functions from Bun coverage, so these methods read about 0%.

#4958 (AbortSignal.timeout never fires after its last listener is removed, Bun 1.3.13 and 1.3.14) blocked every bump past 1.3.12. Its repro passes on Bun 1.4.2 and 1.4.3 on this host (abort event aborted= true).

Implementation

Pins changed to 1.4.3: .tool-versions, package.json, packages/chat-components/package.json, vscode/package.json (packageManager), .github/actions/setup-xum/action.yml, .github/workflows/{auto-cleanup-fixup,auto-cleanup,pr,update-models}.yml, Dockerfile, benchmarks/terminal_bench/mux_setup.sh.j2, docs/guides/github-actions.mdx, docs/AGENTS.md (host requirement) and the regenerated builtInSkillContent.generated.ts. Three test comments that name the pinned runtime now name 1.4.3. flake.nix takes Bun from nixpkgs, so it has no pin.

Not changed: tests/bugbash/sandbox/Dockerfile (oven/bun:1.3.12-slim) and its published image in image.json, and .github/workflows/perf-profiles.yml (pins Bun 1.3.5, not 1.3.12. I did not check why).

Fixes for what 1.4.3 breaks

  1. bun install on 1.4.3 hoisted playwright-core@1.63.0 (from @e2e-dev/web) to the root. @coder/pixel-storybook then loaded 1.63, whose Chromium CI does not install (Test / Storybook failed), and tests/bugbash/sandbox/build.sh found no @e2e-dev/web/playwright-core entry (Test / Bug-bash sandbox failed). Fix: a root devDependency "playwright-core": "1.57.0" (the version playwright@1.57.0 pins), which restores the 1.3.12 tree. The new bun.lock also drops two optional peer entries that nothing installs or imports (@opentelemetry/api, esbuild-register).
  2. tests/bugbash/sandbox/runner.test.ts: process.env.TMPDIR = undefined now stores the string "undefined" (Node does the same), and os.tmpdir() returned it. The test now deletes the variable when it was unset.
  3. tests/bugbash/sandbox/inContainer.test.ts and src/node/services/browser/agentBrowserCommandClient.test.ts: a fake server that calls socket.end() without reading never sees the peer's FIN, so server.close() waits forever. Node does the same; Bun 1.3.12 closed it anyway. The fake servers now call socket.resume() first.
  4. src/node/orpc/replayOwnership.test.ts: on Bun 1.4.2 and 1.4.3, AsyncLocalStorage.disable() does not hide the store from a continuation that resumes after it. Node and Bun 1.3.12 do. The product runs on Node (#!/usr/bin/env node, the Docker ENTRYPOINT, Electron), so the test now asserts the release only when a probe shows that the runtime implements it. The rest of the test runs everywhere.
  5. computePriorHistoryFingerprint and its async twin: their sort comparator was inconsistent for a non-finite persisted historySequence (NaN || tiebreak). On 1.4.3 the reference sorted such rows differently once the DFG JIT optimized it (BUN_JSC_useDFGJIT=0 makes the test pass), so the twin test failed. Fix: a shared total-order comparator (comparePriorHistoryOrder) that puts non-finite sequences after finite ones, then orders by id. The order of finite sequences does not change. It changes the fingerprint only for histories with a malformed sequence, and a fingerprint mismatch falls back to a full replay.
  6. LocalBaseRuntime (child stdout/stderr and readFile) now uses nodeReadableToWeb (src/node/utils/nodeReadableToWeb.ts) instead of Readable.toWeb. On Bun 1.4.3, Readable.toWeb can get a data event from a child's pipe after the web stream was cancelled. Its listener then calls enqueue on the closed controller and throws TypeError: Invalid state: Controller is already closed outside any caller. The bash tool hits this when it cancels its readers on output overflow. In tests it fails the test. In the CLI (terminal-bench runs it on Bun, mux-run.sh) the uncaught exception ends the run. The adapter follows Node's adapter (pull resumes the source, byte-sized queue at the source's highWaterMark, chunks copied out of the pool, cancel destroys the source, a premature close is an AbortError), and it drops data that arrives after cancel or end. A repro harness that spawns a fast-exiting writer and cancels at 1 MB threw in 15 of 300 runs on 1.4.3 with Readable.toWeb, 0 of 600 with the adapter, and 0 of 300 on 1.3.12.

Validation

CI

Run Head Result
38372263624 (+1 rerun of failed jobs) 4efc81977a (pins only) Storybook, Bug-bash sandbox (fix 1), Unit 1/6 (fixes 2, 3), Unit 3/6 (fix 4 and a flake, below). Same failures on the rerun.
38378155990 d19fec9773 Unit 4/6 only: agentBrowserCommandClient (fix 3, second file).
38382892697 f7e1fb5fea All 30 jobs green.
38396451754 6f4b6d727a (fix 6) All 30 jobs green (attempt 1, no rerun). The run for 562063cf36 was cancelled by the newer push.
38419481375 0928afbff0 (rebased onto b01fe77f6b) All 30 jobs green (attempt 1).

Flake (fix 6): bash tool > should reject overlong line at boundary (IPC mode) failed once in run 1 with Controller is already closed. Failure counts in src/node/services/tools/bash.test.ts, each test alone 40 times and the whole file 15 times:

Test 1.4.3 before 1.4.3 after 1.3.12 after
reject overlong line at boundary (IPC mode) 4/40 0/40 0/40
truncate overflow output (overflow_policy: 'truncate') 1/40 1/40 0/40
whole file 1/15 0/15 0/15

All 6 "before" failures were Controller is already closed. The one "after" failure is a second, older race in the truncate test: the tool cancels at 1 MB while perl still writes 1.5 MB, and when the pipe closes first, perl exits 1 and the tool reports success: false. It happens with and without fix 6 (1.4.3: 1 of 150 runs before, 1 of 300 after, 1.3.12: 0 of 150), so it is not caused by the fix (follow-up below).

PR CI runs (the first three predate the rebase onto current main):

Local (make static-check, make test)

make static-check passes on 1.4.3 and on 1.3.12. make test (one bun test src process, 25,321 tests) has 12 failures on 1.4.3 and 14 on 1.3.12. Both share taskGitPatchEngine (host init.templateDir) and one BackupRepoCache timeout. The other failures are 5 s timeouts that differ between runs. Every 1.4.3-only failure passes when its file runs alone on both versions, except the 3 that fixes 3–5 address.

Coverage (CRAP gate)

Main moved during the measurement and #6307 added coverage from isolated unit files, so the CI comparison uses only each shard's shared lcov.info and counts only functions in files that are the same in both trees.

Measure Before (1.3.12) After (1.4.3)
Functions above CRAP 30, all 9 lcov files, repo-wide 876 848
Same, only files unchanged between the trees (13,518 functions) 818 809
Same, unit lcov only 912 902
Above CRAP 30 in workspaceService.ts (9 files) 14 14
resumeStream (workspaceService.ts, cc 83): coverage, CRAP (9 files) 33.3%, 2124 99.5%, 83
executeBash (cc 38): coverage, CRAP (9 files) 41.1%, 333 97.2%, 38
resumeStream, unit only 5.1% 99.0%
executeBash, unit only 9.2% 96.5%

Before: unit lcov from run 38372261688 (a browser-only PR, a Checkbox component and CSS, merged into 32364fb956, the same base), integration lcov from run 38374718068 (the closest green run that ran the backend integration tests, merged into a newer main). Main push runs upload no crap-lcov-* artifacts. After: run 38382892697, scored on its merge tree (f83f8e1182 + this branch). Integration coverage comes from Jest, so Bun does not change it.

Same-tree A/B (the 9 workspaceService*.test.ts files that call these methods, run with coverage under each Bun on one tree): resumeStream 5.1% to 99.0%, executeBash 9.2% to 96.5%, fork 2% to 77%, getFileCompletions 20% to 98%. No function lost 10 points or more.

CI time
Measure 7 green PR runs on 1.3.12 (range) This PR, run 3
Total wall time (first job start to last job end) 8.9–12.2 min 10.2 min
Slowest make test-unit-ci step 439–589 s 440 s
Sum of the 6 unit test steps 1754–1972 s 1809 s
Slowest integration test step (backend runs only) 253–304 s 264 s

Runs 1 and 2 were slower to set up (unit setup 54 s vs 30 s) because the node_modules cache key includes the Bun version. This PR runs 2 jobs more than the baselines (Nix Build, Lint Actions), because it changes bun.lock and the workflows.

Bun 1.3.12 workarounds: status on 1.4.3
Workaround Bug on 1.4.3 Action
#4958 AbortSignal.timeout Fixed (repro passes on 1.4.2 and 1.4.3) Close #4958 when this lands.
tests/bunEachTableGcWorkaround.ts, tests/bunEachTableGc.test.ts (#6020) Fixed: the fixture passes 10 of 10 runs, and the workaround only runs on 1.3.12 Left. Remove after the bump.
scripts/test-unit-ci.sh isolation of bunEachTableGc.test.ts Same as above Left.
scripts/perf/desktopColdStart.ts:8 (runs under Node) Fixed: Playwright _electron.launch from Bun hangs on 1.3.12 and works on 1.4.3 Left.
scripts/crap/crapper_report.py:163 (a loaded but never-run function lists every line at 0) Still present (same DA lines on both) Keep.
scripts/crap/crapper_report.py:201 (an uncalled arrow counts a later line as hit) Still present Keep.
tests/bugbash/sandbox/proxy.ts:280 (node:http misses a client disconnect) Not tested here (out of scope) Follow-up.

Risks

Low for the product. The product runs on Node, and the production changes are the comparator (fix 5) and the stream adapter (fix 6), which follows Node's Readable.toWeb behavior. The remaining Bun-only risk is in tests: AsyncLocalStorage.disable() semantics that differ from Node, and the truncate test's pipe race.

Follow-ups

Not done in this PR:

  1. Delete the inert test.each GC workaround: tests/bunEachTableGcWorkaround.ts, its bunfig.toml preload, tests/bunEachTableGc*.ts, and the jest.config.js and scripts/test-unit-ci.sh entries. Then close 🤖 bug: Bun 1.3.13+ AbortSignal.timeout never fires after its last listener is removed (blocks Bun > 1.3.12) #4958.
  2. Move the bug-bash sandbox image to oven/bun:1.4.3 (tests/bugbash/sandbox/Dockerfile, rebuild and publish image.json), and make the "a client that goes away" test in proxy.test.ts strict again (the proxy.ts:280 removal trigger).
  3. Give the AsyncLocalStorage.disable() gate in replayOwnership.test.ts a removal trigger.
  4. Bump playwright-core together with playwright and @playwright/test: the root pin from fix 1 must move with them.
  5. Make the truncate test independent of the pipe race (for example, a script whose exit code does not depend on the pipe).

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $16.55

@mintlify

mintlify Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
Mux 🟢 Ready View Preview Oct 13, 2026, 3:08 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

@ThomasK33
ThomasK33 force-pushed the ci/bun-1.4.3-experiment branch from 6f4b6d7 to 0928afb Compare October 13, 2026 15:08
@ThomasK33 ThomasK33 changed the title 🤖 ci: try Bun 1.4.3 (experiment) 🤖 ci: upgrade Bun from 1.3.12 to 1.4.3 Oct 13, 2026
@ThomasK33
ThomasK33 marked this pull request as ready for review October 13, 2026 15:09
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T15:12:01.991026Z 0928afb Manual request
🔒 Security Review ✅ Completed 2026-10-13T15:13:13.468349Z 0928afb Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 0928afbff0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 0928afbff0

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 13, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 13, 2026
@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 13, 2026
Merged via the queue into main with commit 20cb7c6 Oct 13, 2026
35 of 36 checks passed
@ThomasK33
ThomasK33 deleted the ci/bun-1.4.3-experiment branch October 13, 2026 16:16

This branch was successfully deployed

1 active deployment
staging - docs — 0928afbf Deployed Oct 13, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🤖 bug: Bun 1.3.13+ AbortSignal.timeout never fires after its last listener is removed (blocks Bun > 1.3.12)

1 participant