# bun 1.3.x breaks the test suite — spawnSync/http-fixture deadlock + full-suite wedge

> **Status:** todo
> **Filed:** 2026-06-02
> **Folder:** issues
> **Severity:** high (CI was red for 3 days; masked by pre-existing flakes)
> **Category:** tests / infrastructure

## Context

CI ran `oven-sh/setup-bun@v2` with `bun-version: latest`, which resolved to
**1.3.14**, while local dev is on **1.2.22**. The version skew produced two
CI-only failures that do not reproduce locally:

1. **`cli-ref-pull-bulk.test.ts` (#048) deadlocks.** The test spawns the CLI
   via `spawnSync("bun", [CLI, ...])` and points it at a `node:http` fixture
   server living **in the test process**. On 1.3.14 `spawnSync` blocks the
   parent event loop, so the fixture server never responds to the child's
   download request → every test in the file dies at the per-test timeout
   (5 of 5, reproduced locally with `mise x bun@1.3.14`). On 1.2.22 the same
   pattern works (parent loop still serves while the child waits).
2. **Full-suite wedge at `analyze-frames-language.test.ts`.** ROOT-CAUSED
   (2026-06-02, ci-debug-wedge branch): NOT bun-1.3-specific — reproduced on
   1.2.22 too, but ONLY on GitHub runners (passes on macOS and in a local
   `oven/bun:1.2.22` container with identical file order, env, and 2-cpu
   limit). Minimal repro on the runner: just
   `bun test analyze-video-logging.test.ts analyze-frames-language.test.ts`
   wedges at the second file's load with zero output (per-test timeout never
   fires → the block is at module load / outside test bodies). The trigger
   was `mock.module("…/llm.js")` in analyze-video-logging — bun's
   process-wide registry mutation + a leaked `callLLMState.fn` (and even a
   "restore the real callLLM in afterAll" variant still wedged on the
   runner). FIXED by removing `mock.module` entirely: the test now stubs
   `globalThis.fetch` with a canned chat-completions response and runs the
   real `callLLM` + openrouter connector end-to-end. Verified on the runner:
   the pair runs in 87ms, the formerly-wedging 82-file order in 36.6s.

## Interim fix (shipped)

`.github/workflows/test.yml` pins `bun-version: 1.2.22` to match local dev.
Never use `latest` there — CI must run what developers run.

## Proper fix (this issue)

- [x] Kill the `mock.module` leak: `analyze-video-logging.test.ts` rewritten
      to fetch-level stubs (2026-06-02). Rule of thumb going forward: never
      `mock.module` a shared lib module in this suite — stub `globalThis.fetch`
      (or inject) instead.
- [x] Rework `cli-ref-pull-bulk.test.ts` to be event-loop-safe: use async
      `spawn` + `await` the child instead of `spawnSync`, so the in-process
      fixture server can serve during the child's lifetime regardless of bun
      version. Same audit for any other test that pairs `spawnSync` with an
      in-process server. (2026-06-11: done via shared `tests/helpers/spawn-cli.ts`;
      also reworked `cli-ref-pull-site.test.ts` — the audit found no other
      spawnSync+in-process-server pairings; both files green on bun 1.3.14.)
- [ ] Upgrade the pin (workflow + local `bun --version` parity) once the
      spawnSync rework lands and the suite is green on 1.3.x.

## Repro

```bash
mise install bun@1.3.14
$(mise where bun@1.3.14)/bin/bun test --timeout 15000 tests/integration/cli-ref-pull-bulk.test.ts
# → all 5 tests time out; on 1.2.22 the same command passes in ~3s
```
