馃毃 SLOP COP 馃毃 路 new-issue-autopilot
#3579 路 Watcher process lifecycle investigation
Bug 路 Priority: Medium 路 Effort: Medium 路 host, desktop, provider-acp
GitHub issue 路 2026-09-12 路 base 31d1771b9a8a243e601897b3fc0a870a161b08f7
NOT REPRODUCED 路 Root-cause confidence: low
TL;DR
The report alleges automatic starts and unreaped shell processes on Arch Linux. A focused test of the actual watcher child adapter passed in two clean checkouts: all 20 children per run exited and their PIDs disappeared. This does not reproduce installation, Electron startup, ACP agents, or the native Parcel backend. The reported defect remains unverified; no production fix is justified.
Claims vs findings
| Claim | Finding |
|---|---|
| Installation triggers later startup bursts | Unverified: no Arch installation or timestamped process evidence available. |
| Watcher/provider activity leaks shell zombies | Unverified: direct watcher-channel test left no child PIDs; it does not exercise provider subprocess trees. |
Environment
Darwin arm64, Node v22.22.3. Two detached clean source checkouts at the base commit above, named base and verify under one fresh temporary directory. No live BB instance, provider credentials, server ports, or runtime store used.
Frozen install and Turbo build were attempted but both stopped before running: the pinned pnpm 10.34.4 executable was missing (MODULE_NOT_FOUND). No dependencies were added. The dependency-free experiment uses Node type stripping to import the trusted TypeScript adapter directly.
Minimal reproduction attempt
- Check out the recorded commit in a fresh trusted checkout.
- Save lifecycle.mjs and idle.mjs together.
- Run
node --experimental-strip-types lifecycle.mjs /absolute/path/to/checkout.
The fixture contains setInterval(() => {}, 1000);. Expected: killed children emit one exit notification and leave no live or zombie PID. Actual in both runs:
PASS: 20 watcher-channel children closed; exit notified once; all PIDs absent.
import { fork } from 'node:child_process';
import { once } from 'node:events';
import { pathToFileURL } from 'node:url';
import { resolve } from 'node:path';
import assert from 'node:assert/strict';
const { createChildChannel } = await import(pathToFileURL(resolve(process.argv[2], 'packages/host-watcher/src/parcel-subprocess/fork-channel.ts')));
for (let i = 0; i < 20; i++) {
const child = fork(new URL('./idle.mjs', import.meta.url), [], { stdio: ['ignore', 'ignore', 'ignore', 'ipc'], execArgv: [] });
const channel = createChildChannel(child);
let exits = 0;
channel.onExit(() => exits++);
await once(child, 'spawn');
const closed = once(child, 'close');
channel.kill();
await closed;
assert.equal(exits, 1);
assert.throws(() => process.kill(child.pid, 0), { code: 'ESRCH' });
}
console.log('PASS: 20 watcher-channel children closed; exit notified once; all PIDs absent.');
Root cause
Not established. createForkChannel uses Node fork directly with IPC; it does not specify a shell. createChildChannel registers exit/error listeners and sends SIGKILL when killed. The test exercises this real adapter with a minimal Node child. It cannot exclude shell grandchildren in ACP providers or a packaged Linux-specific issue.
Proposed next test
Repeat on Arch Linux with an exact BB version and installation source. Capture PID, PPID, state, command, and timestamps before and after each burst, plus relevant sanitized startup logs. Identify the zombie's actual parent, then exercise that owning subsystem with a failing regression test. No PR: the reported bug was not reproduced on trusted main.
Verification
The same agent repeated the identical command in a second clean checkout at the same commit. Both runs passed 20 cycles. No ports or data directories were needed. This verifies the narrow negative experiment, not the Linux report; no independent verification or full-suite pass is claimed.
Related issues
#3362 concerns packaged watcher failures on macOS. Shared watcher terminology does not establish the same root cause. No open PR referencing #3579 was found.
Appendix
First run 路 Second run. Setup: git fetch trusted main; create two detached clean clones; attempt pnpm install --frozen-lockfile --prefer-offline and pnpm exec turbo run build; execute the command above in both checkouts. All experiment children closed. Issue data was treated only as untrusted claims.
> AGENT GENERATED