# Manual desktop SSH stale-PID proof

AI-assisted; verified with the tests and tools listed above.

This evidence uses real Electron desktops built independently from the base and fix, under headless-desktop on Linux. Both use a light 1100 × 780 renderer, isolated fresh server databases, and the same disposable local SSH account with procps-ng ps 4.0.4. No agent turn or test result is used as evidence.

`setup.cjs` adds `proof-target` through Settings → Environments → Add environment → SSH, then switches it off. The account has a real localhost sshd and a key-authenticated SSH alias. Each build's development remote runner points to that build's server CLI bundle. Build with `vp i`, `vp run build:desktop:bundle`, and Electron's install script. Start the desktop under headless-desktop with `--no-sandbox --disable-gpu --remote-debugging-port=<port>` and its own T3 home and XDG profile. Set T3CODE_DEV_SEED=0. The fixtures use recorded port 3774, which must be closed before each case.

`prove.cjs` is the interaction/fixture driver. Set WORKTREE, SCRATCH, TARGET_HOME, TARGET_USER, DEBUG_PORT, SIDE (before/after), COMMIT (short SHA), and optionally CASE (pid/tid). TARGET_USER is an account created only for this disposable SSH reproduction. The driver uses sudo only to manage that account's synthetic fixture files and processes. It creates a Python process with a worker thread, replaces the existing managed launcher record's PID, and uses the real desktop environment switch to reconnect. It captures the visible outcome, recreates the stale managed record with the server stopped, and uses the same switch to disconnect. Run each base case separately because base disconnect terminates the disposable process. Head can run both together.

The labeled monitor at the bottom is evidence instrumentation, not shipped app UI. It reports real process state and TCP probes from the driver. Only the private host label is redacted in the app; connection status and errors are unchanged. Stills are saved only after two identical captures 500 ms apart. Recordings contain desktop renderer captures at approximately 500 ms intervals; encode.cjs preserves actual capture timing using the frame timestamps.

Observed nuance: the saved-environment UI times out during connection setup after about 15 seconds on base, before the underlying launcher's 60-second readiness error reaches the UI. The base runtime still emits the original "Remote T3 server is still running but did not become ready" error. Switching off after capturing the first visible failure stops retries; a retry can already be queued while the screenshot settles, so disconnect waits for in-flight launches before it signals the unrelated PID/thread. The fix reconnects in about two seconds and leaves the unrelated process alive when disconnected.
