flaky(runtime-host): lifecycle tests intermittently fail process-exit and settlement checks
- Dominant language
- TypeScript
- Stars
- 5.4k
- Forks
- 502
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 715
Description
## Summary
Four Runtime Host lifecycle tests fail intermittently on a clean `main` checkout, including during serial focused repetitions.
The failures concern Host process exit after launcher termination, clean settlement of a successor Candidate, and process exit after managed activation reaches true idle.
The same revision can pass a focused run and fail a later run without source changes.
## Environment
- Commit: `8b3655a1710a4c52b09759249d8c2dbb57284a7a` (`main` at the start of testing)
- OS: macOS 26.5.2, arm64
- Node.js: `v24.19.0`
- Installation and build: npm `11.19.0`
- Test commands were launched through the local npm `11.17.0` or directly through Node, as shown below
- Fresh detached worktree; Git status remained clean after testing
- A Node preload redirected `os.userInfo().homedir` to a disposable account directory
- Normal local network conditions
- `npm ci`: passed
- Complete `npm run build`: passed
## Reproduction
After installation and build, run the complete Runtime Host suite:
```bash
npm --workspace @maka/runtime-host run test:dist
```
Repeat the lifecycle tests serially, from the repository root:
```bash
node --test \
--test-concurrency=1 \
--test-name-pattern='^(?:owned Host exits promptly after its first connection closes|an authority-supervised Candidate exits if its launch owner is killed|an invocation-owned detached Host retires after launcher natural exit|an invocation-owned detached Host retires after launcher crash|a launcher-owned detached Host exits when its launcher is killed|an exited owned Candidate permits one real successor in the same election)$' \
packages/runtime-host/dist/__tests__/host-kernel.test.js \
packages/runtime-host/dist/__tests__/owned-candidate.test.js
```
The six-test selection above was repeated five times, with no skipped tests. In the recorded runs, the working directory was `packages/runtime-host`, with the equivalent `dist/__tests__/...` file arguments.
After observing a managed-activation failure in the complete suite, repeat that test separately:
```bash
node --test \
--test-concurrency=1 \
--test-name-pattern='^two real managed activations converge on one Host and exit at true idle$' \
packages/runtime-host/dist/__tests__/managed-activation.test.js
```
This single-test selection was also repeated five times.
Account-isolation preload used for the recorded runs
The following preload was passed through `NODE_OPTIONS=--import=/absolute/path/to/isolate.mjs`. The disposable account directory was created before testing. `HOME` was not changed. Replace the example path below with an existing disposable directory when reproducing.
```javascript
import os from 'node:os';
import { syncBuiltinESMExports } from 'node:module';
const userInfo = os.userInfo;
os.userInfo = (...args) => ({
...userInfo(...args),
homedir: '/absolute/path/to/disposable-account',
});
syncBuiltinESMExports();
```
## Results
| Test | Focused results |
| --- | --- |
| `a launcher-owned detached Host exits when its launcher is killed` | 4 passed / 1 failed |
| `an invocation-owned detached Host retires after launcher crash` | 4 passed / 1 failed |
| `an exited owned Candidate permits one real successor in the same election` | 3 passed / 2 failed |
| `two real managed activations converge on one Host and exit at true idle` | 4 passed / 1 failed |
The other three tests in the six-test selection passed all five rounds.
For the six-test selection, rounds 1, 4, and 5 passed completely. Round 2 failed the invocation-crash and successor-settlement cases. Round 3 failed the launcher-killed and successor-settlement cases. In the separate managed-activation repetitions, round 4 failed and the other four rounds passed.
The complete Runtime Host suite reported **1,808 passed, 1 failed, and 12 skipped**. Its failure was the managed-activation test, which subsequently also failed in a focused run.
### Launcher-related failures
The client connection had already closed, but `waitForProcessExit` still observed the Host PID after its five-second timeout:
```text
Error: process did not exit
```
### Successor settlement failure
The connection and two-launch assertions passed. The following assertion then failed because settlement returned `false`:
```typescript
assert.equal(await attempts[1]?.settle(5_000), true);
```
```text
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
false !== true
```
### Managed-activation failure
The local and remote client connections had closed. The test then failed while waiting for the Host process to exit:
```typescript
await waitUntil(() => !processExists(first.pid), 5_000);
```
```text
Error: condition did not become true
```
The same assertion failed in both the complete suite and the focused repetition. Both stacks point to `dist/__tests__/managed-activation.test.js:145` through `waitUntil`.
## Impact
These intermittent failures reduce the reliability of Runtime Host regression checks.
Because focused serial repetitions also fail, the observations are not limited to full-suite concurrent execution.
The results do not establish permanent process leaks or a shared root cause across all four tests.
## Suggested investigation
- Distinguish client connection closure, Host shutdown completion, and actual process exit.
- Determine what remains active when the process-exit budget expires.
- Identify why successor settlement returns `false`.
- Check whether the tests need explicit lifecycle synchronization.
- Preserve the ownership and process-exit assertions, and verify changes through repeated runs rather than relying only on retries or longer timeouts.
## Expected outcome
The tests reliably observe the required process exit and clean settlement, without intermittent lifecycle-timing failures.
Contributor guide
Assessment
This issue has not been assessed yet.