Skip to content

fix(mcp-conformance-fixture): set hookTimeout to match testTimeout - #2241

Closed
willgriffin wants to merge 1 commit into
mainfrom
fix/issue-2240-conformance-hook-timeout
Closed

fix(mcp-conformance-fixture): set hookTimeout to match testTimeout#2241
willgriffin wants to merge 1 commit into
mainfrom
fix/issue-2240-conformance-hook-timeout

Conversation

@willgriffin

Copy link
Copy Markdown
Contributor
{"schema":"hv-agent-run:v1","runtime":"claude","session":"8a94e288-0358-403f-a3a6-8e81a80e6c5d","issue":"2240","head_sha":"8451eac142f993640ee0e4d512596b1cd141e40d","policy_revision":"1.0.0","status":"complete"}

Summary

packages/mcp-conformance-fixture had testTimeout: 240_000 but no hookTimeout, so its
beforeAll ran against vitest's 10 s default. That is backwards for this suite — the
expensive work is entirely in the hook:

work
beforeAll generate the MCP server, spawn tsx on the generated TypeScript (stdio transport), complete a protocol handshake with listTools assertions, then spawn the HTTP adapter as a second process
each it one fetch POST to the already-running adapter

So the cheap half held the 240 s budget and the heavy half held none.

Impact

This is nondeterministic and it failed PRs that have nothing to do with MCP:

Both showed:

❯ src/generated-server-conformance.test.ts (2 tests | 2 skipped) 10067ms
Error: Hook timed out in 10000ms.
  ❯ src/generated-server-conformance.test.ts:27:1

67 ms over the line, both tests skipped — the failure carried no signal about the code
under test. Because the merge queue runs mode: full while the PR lane runs mode: affected,
a PR could sit at CLEAN and still be ejected on queue entry.

Why match testTimeout rather than pick 30 s

The repo's usual value is hookTimeout: 30000 (with 60_000 in bundle-gate), but those
hooks do not spawn two tsx processes. Matching the value this package already declares for
the same workload avoids inventing a third number, and the hook runs once per suite so there
is no cost to the headroom. It only relaxes a limit — it cannot mask a failure, since an
actually-hung spawn still fails, just later.

Validation

  • pnpm --filter @happyvertical/smrt-mcp-conformance-fixture test2 passed, 3.32 s total
    on an idle machine, confirming the hook is normally fast and the 10 s default was marginal
    only under CI contention rather than covering a real hang
  • npx turbo build --filter=@happyvertical/smrt-mcp-conformance-fixture... — 6/6 successful
  • biome check — the path is ignored by the repo's Biome config, so no diagnostics apply
  • Single-file test-config change; no runtime or source code is touched

Related: #2220 is the same class (permission tests marginal against their timeout, failing the
merge queue nondeterministically).

Closes #2240

This suite's expensive work is all in beforeAll: it generates the MCP
server, spawns tsx on the generated TypeScript for the stdio transport,
completes a protocol handshake, then spawns the HTTP adapter as a second
process. The it blocks only POST to that already-running adapter.

testTimeout was already 240s, but hookTimeout was left at vitest's 10s
default, so the cheap half had the generous budget and the heavy half had
none. On a contended runner the hook aborted at 10067ms, reported both
tests as skipped, and failed PRs unrelated to MCP: it ejected #2230 from
the merge queue and turned #2231 red.

Closes #2240
Copilot AI review requested due to automatic review settings August 5, 2026 20:41
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the @happyvertical/smrt-mcp-conformance-fixture Vitest configuration to prevent nondeterministic CI failures caused by a long-running beforeAll hook timing out under Vitest’s default hook timeout.

Changes:

  • Adds hookTimeout: 240_000 to match the already-configured testTimeout: 240_000.
  • Documents why the suite’s timeout budget needs to apply to hooks (the heavy work is in beforeAll).

// beforeAll, not in the tests: it generates the MCP server, spawns `tsx` on
// the generated TypeScript for the stdio transport, completes a protocol
// handshake, and then spawns the HTTP adapter as a second process. The `it`
// blocks only POST to that already-running adapter. Left at vitest's 10s
@willgriffin

Copy link
Copy Markdown
Contributor Author

Closing as a duplicate of #2239 — same root cause, same fix, filed ~6 minutes apart by two sessions that hit the ejection independently.

Timeline: I filed #2238 at 20:28Z and opened #2239 at 20:35Z; #2240 was filed at 20:37Z and this PR at 20:41Z. Keeping #2239 because it is a strict superset — the same hookTimeout: 240_000 with an equivalent explanatory comment, plus prevention in .claude/rules/testing.md and TESTING_STANDARD.md, which matters because this is not the first occurrence (smrt-svelte's teardown hook, #1426).

No criticism of the work here — your inline comment is good, and you actually ran the fixture suite locally (2 passed, 3.32s), which is more validation evidence than my PR carries. Nothing is lost by consolidating; the fix is identical. Reopen if you disagree.

@willgriffin willgriffin closed this Aug 5, 2026
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.

fix(mcp-conformance-fixture): beforeAll runs against the 10s default hookTimeout and fails unrelated PRs

2 participants