Skip to content

supervisor-import-graph test probes host-lifecycle.js three times; test 3 runs two cold probes in one 30 s budget and times out under load #4408

Open

Description

@code-yeongyu

Summary

packages/coding-agent/test/supervisor-import-graph.test.ts starts five cold Node processes per file run, and three of them probe the same entry (dist/modes/rpc/host-lifecycle.js). The test "keeps the supervisor program's own graph to the supervisor plus its preamble" (:130) starts two of those probes back to back inside one 30 s test budget. On a heavily loaded host each probe takes 10-12 s, so that one test times out even though the graph it checks is correct.

Reproduction

  1. bun run build in a senpi checkout.
  2. Run the file under contention, for example on a 40-core Linux runner at a load average of about 93: cd packages/coding-agent && CI=1 bunx vitest run --reporter=verbose test/supervisor-import-graph.test.ts.

Observed on such a host (evidence held locally; trimmed):

✓ stays inside its module budget ...                              12389ms
✓ gives the bundled supervisor its own program ...                 2438ms
× keeps the supervisor program's own graph to the supervisor ... 36445ms
  → Test timed out in 30000ms.
✓ keeps the CLI argument parser and the provider catalog out ...  10431ms

On an idle machine the same commit passes 4/4 in about 2 s (test 3: 0.5-1.5 s). The PR head that showed the failure and its merge-base both pass there, so this is the cost of the probes under load, not a graph regression.

Expected (ideal state)

Each entry's import graph is probed once per file run, and every test reads the shared result. Test 3 then starts one probe of its own (host-supervisor-entry.js) plus the shared host-lifecycle.js result, not two cold processes. The 30 s budget then bounds one probe, not two in sequence. No assertion changes, and the timeout is not raised.

Actual

  • test/supervisor-import-graph.test.ts:103-105 (test 1), :131-139 (test 3, two probes) and :155 (test 4) each call probeImportGraph(repoRoot, .../host-lifecycle.js) on their own.
  • test/helpers/esm-import-graph-probe.ts:78 runs each probe as a blocking spawnSync(process.execPath, ...): a fresh Node process with a loader hook that calls appendFileSync once per resolved and loaded module.
  • packages/coding-agent/vitest.config.ts:17 sets testTimeout: 30000.

Root cause

The same deterministic graph is computed repeatedly in separate cold processes. Under CPU contention a single probe costs a third of the test budget, and test 3 pays for two.

Scope and acceptance criteria

  • host-lifecycle.js is probed at most once per file run, through a lazily computed, memoized result shared by tests 1, 3 and 4. The memo keys on the entry path, so host-supervisor-entry.js and dist/bundle/host-supervisor.js keep their own single probes.
  • Test 3 starts exactly one new probe process.
  • Every existing assertion stays byte-for-byte the same, and the test timeout is unchanged.
  • Optional: the probe runs as an async spawn awaited on the child's exit event (with the same bounded wait), so the vitest worker stays responsive while the child runs.
  • Proof: a count of probe processes per file run (for example a spy on the helper) shows 3 instead of 5, and the file passes under an artificial CPU load that made it fail before.

Related

Activity

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions