Files
mokosh/.planning/debug/resolved/01-10-vitest-build-test-timeout.md
Mark 0854baf66c fix(01-10): vitest build-test it() timeout — bump to 30s for slower welcome-page build
The build-completes Tier-1 gate at tests/background/no-test-hooks-in-prod-bundle.test.ts:247
was racing vitest's default 5000ms it() ceiling. Plan 01-10 closure shipped the welcome
page (commits d48a715 welcome mark + 49f087f welcome HTML/CSS/JS + 8 WOFF2 fonts) which
slowed standalone `npm run build` from ~2.88s to ~5.28s. The exec-level
BUILD_TIMEOUT_MS = 60_000 child-process bound was correctly declared at line 240, but
the surrounding it() block had no timeout option, so the 5s default fired first and the
60s exec bound was never reachable.

Surgical fix: add `, 30_000` 3rd arg to the it() call. 30s is ~6× the observed build
duration and well below the 60s exec ceiling, so both bounds remain meaningfully
active. SKIP_BUILD=1 env-var escape hatch untouched.

Acceptance gates:
- `npm test` (FULL, no SKIP_BUILD=1): 150/150 GREEN, exit 0
- `npx tsc --noEmit`: exit 0
- `npm run build`: exit 0
- Tier-1 grep gate: PASS (all 12 FORBIDDEN_HOOK_STRINGS asserted against dist/)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:52:39 +02:00

4.6 KiB
Raw Permalink Blame History

slug, status, goal, trigger, phase, plan, opened, closed, orchestrator_diagnosed
slug status goal trigger phase plan opened closed orchestrator_diagnosed
01-10-vitest-build-test-timeout resolved find_and_fix npm test (full run, no SKIP_BUILD=1) fails 1/150 with timeout in tests/background/no-test-hooks-in-prod-bundle.test.ts at line 247 — Test timed out in 5000ms 01-stabilize-video-pipeline 01-10 2026-05-20 2026-05-20 true

Debug session 01-10-vitest-build-test-timeout — vitest it() default 5s ceiling races slower welcome-page build

Problem statement

After Plan 01-10 closure (commits d48a715 welcome mark + 4bba679 notif-text), npm test (full run, no SKIP_BUILD=1) failed 1/150 with a vitest timeout in tests/background/no-test-hooks-in-prod-bundle.test.ts at line 247:

FAIL  tests/background/no-test-hooks-in-prod-bundle.test.ts > production bundle has no test-hook leaks (Tier-1 gate — T-1-11-01) > npm run build completes and dist/ exists with at least one chunk
Error: Test timed out in 5000ms.

Standalone npm run build had slowed from ~2.88s (pre-Plan-01-10) to ~5.28s due to welcome page Vite processing + SVG ?url import + 8 WOFF2 fonts shipped in d48a715 / 49f087f. With the build now exceeding 5s, vitest's default 5000ms it() ceiling races and loses.

SKIP_BUILD=1 npm test was passing 150/150 GREEN, confirming this was purely a test-infrastructure timeout-tuning issue, NOT a real build/grep-gate regression.

Root cause

The it() block at tests/background/no-test-hooks-in-prod-bundle.test.ts:247 was declared without a 3rd-arg timeout option:

it('npm run build completes and dist/ exists with at least one chunk', async () => {
  if (process.env.SKIP_BUILD !== '1') {
    await runProductionBuild();
  }
  // ...
});  // <-- no timeout 3rd arg → vitest's 5000ms default applies

The test author had correctly bounded the EXEC-level child-process timeout via BUILD_TIMEOUT_MS = 60_000 at line 240 (passed to execFileAsync), but forgot to bound the surrounding it() block. Vitest's default it() timeout is 5000ms; the build now takes ~5.28s, so the it() ceiling fires before the exec bound is even close.

This is the classic "two-tier timeout where only one tier is configured" bug. The exec timeout existed but was useless because the outer it() timeout fired first.

Fix design

Surgical one-line change: add , 30_000 as the 3rd arg to the failing it() call.

30 seconds was chosen because:

  • Generously above the observed 5.28s build + npm overhead (~6× headroom)
  • Well below the 60s exec bound (BUILD_TIMEOUT_MS), so the exec timeout remains the dominant ceiling for true hangs
  • Above the 15s minimum requested by the orchestrator
  • Consistent with vitest convention for build-touching it() blocks (real-IO tests routinely declare 10s+ ceilings)

Inline comment added above the it() documenting why the 30s ceiling exists, citing the +2.4s welcome-page-asset slowdown and the relationship to BUILD_TIMEOUT_MS.

The alternative — setting a global testTimeout in vitest.config.ts — was rejected because:

  • 95% of vitest cases are pure-CPU and should keep the 5s default (catches accidental hangs fast)
  • Only this one it() touches IO at build scale
  • Per-it() timeouts are the standard vitest idiom for "this specific test does slow IO"

SKIP_BUILD=1 env-var escape hatch left untouched for CI environments.

Files modified

  • tests/background/no-test-hooks-in-prod-bundle.test.ts (line 247 it() — added , 30_000 3rd arg + 7-line explanatory comment above)

Acceptance gates — all PASS

  • npm test (FULL run, no SKIP_BUILD=1): 150/150 GREEN, exit 0, 12.89s total
  • npx tsc --noEmit: exit 0
  • npm run build: exit 0, 4.86s (within new 30s it() ceiling with ~6× margin)
  • Tier-1 grep gate: PASS (all 12 FORBIDDEN_HOOK_STRINGS asserted against dist/, including the build-completes gate that was previously timing out — now passes within the new ceiling)

Noteworthy

  • The exec-level BUILD_TIMEOUT_MS = 60_000 ceiling still bounds the child process. This fix only adjusts the SURROUNDING vitest it() ceiling so the exec bound becomes reachable. If npm run build ever truly hangs, the exec timeout fires at 60s; the it() ceiling fires at 30s. Both bounds remain active and meaningful.
  • No SKIP_BUILD logic touched. CI environments using SKIP_BUILD=1 (with a pre-existing dist/) skip the slow path entirely and are unaffected.
  • Build slowdown attribution (for future archaeology):
    • d48a715: welcome page mokosh-mark.svg via ?url import (+~0.4s Vite asset processing)
    • 49f087f: welcome HTML/CSS/JS entries + 8 WOFF2 font assets (+~2.0s emit + manifest)
    • Net: ~2.88s → ~5.28s on this hardware