* fix(relay): sweep detached tools on immediate terminal close * test(relay): reject failed process cleanup queries
4.1 KiB
OMP relay-host immediate-close probe (#9530)
This opt-in probe uses a real installed OMP binary and native PTYs behind production
PtyHandler spawn/data/shutdown handlers. The dispatcher is an in-process test
transport; no SSH connection or rendered client is exercised. OMP source is read-only.
ORCA_BACKGROUND_LAUNCH=1 ORCA_OMP_PROBE_BINARY=/absolute/path/to/omp \
ORCA_OMP_PROBE_SHELL=/bin/bash \
node node_modules/vitest/vitest.mjs run --config config/vitest.config.ts \
tests/tools/omp-relay-close-lifecycle.test.mjs
The test defaults to zsh on macOS and bash on Linux. Windows is skipped. It needs
existing native node-pty dependencies; do not install or rebuild as part of the probe.
HOME, user profile, XDG roots and OMP/PI agent roots are disposable, profiles cleared,
and zsh inheritance fenced to the disposable root. No model request is made. The
probe runs ! /bin/sleep 120, records exact shell/OMP/tool process rows, requests
immediate close, and observes those PIDs independently of the relay inventory.
Matching PID/start-time/group identities bound leftover cleanup. Reports and capped
terminal transcripts stay in .bench-fixtures/omp-relay-close-*.
Measured on macOS with OMP 18.1.18
At source base 93c370246388, bash mode leaves sleep PID 43156, PGID 43156, alive
and reparented to PID 1 after root PID 42902 and OMP PID 42949 exit. The zsh control
exits cleanly: OMP uses a headless PTY for zsh/fish user-shell tools, while bash
uses its embedded-shell subprocess path. Thus an external command alone does not
determine the process lifetime; the configured user shell matters.
With the correction, the same bash probe leaves none of its captured PIDs present. This is detached-tool leakage, not proof of the original foreground-OMP-survives report. The local-provider/daemon correction is PR #20642; this probe and correction cover the separate direct-relay backend.
Reliability contract
- Invariant:
terminal-session.explicit-close-retirement. Explicit immediate close captures still-parented detached descendants before root termination, preserves the exact host owner through physical exit, and cannot attach/adopt that owner while the close is pending. A concurrent close joins the same operation. - Failure source/oracle: actual OMP external sleep survives the bash-mode relay close before the fix; independently queried owned PIDs are absent afterward. Unit tests also cover pending attachment/adoption/create replay, natural exit during capture, signal failure/retry, retained claims during initial promotion, and close completing while attachment awaits a source checkpoint.
- Gate: the existing experimental explicit-close gate's descendant/backend tests, relay lifecycle suites and this opt-in real-PTY probe. Live SSH transport and rendered client flows remain explicit validation gaps.
- Budget: one existing bounded process-table capture (one-second timeout, 32-MiB cap), plus one bounded identity recheck after the two-second grace when there are descendants. Same-turn captures coalesce; no recurring polling is added.
- Authority: the execution host does all process inspection/signaling. Pending-close refusal carries no proven-exited marker; it is not evidence of process death. No new RPC fields/opcodes or required capabilities. Older clients receive an ordinary failed attach while close is pending, not a successful doomed attachment.
- Scope: every immediate POSIX relay close, including still-parented intentionally detached jobs. Graceful close, disconnect grace, keep-alive and fatal-exit/dispose policies are unchanged. Windows retains its immediate force-kill path and now rejects attachment during the physical-exit wait. Folder workspaces and worktrees use the same PTY identity, without repository metadata checks.
- Gaps: macOS runtime evidence only; Linux/Windows/WSL runtime, live SSH/mobile and mixed-version clients are not exercised. Children reparented before capture and same-second identity ambiguity retain the incumbent cleanup limitations.
Mock-PTY suites isolate the sweep: their fake PIDs often equal the test runner's PID and must never reach the real host process table or descendant signals.