---
name: live-agents-lock-target-debug-spt-exe
description: "on this host the live agents RUN target/debug/spt.exe, so any rebuild of the spt bin fails with os error 5; use a redirected CARGO_TARGET_DIR for e2e work"
metadata: 
  node_type: memory
  type: project
  originSessionId: 7755f304-48e2-4a81-8b92-79c5f42ce085
  modified: 2026-08-02T00:02:29.581Z
---

The live spt-core agents on hfenduleam (doyle, flynn, perri, liam + the daemon) execute the DEV BUILD directly: `C:\Users\decid\Documents\projects\spt-core\target\debug\spt.exe`. So `cargo test -p spt --test <any e2e>` — anything that relinks the `spt` bin — dies with:

```
error: failed to remove file `...\target\debug\spt.exe`
Caused by: Access is denied. (os error 5)
```

It is INTERMITTENT (it links fine in the gaps between agent invocations), which makes it read like a flaky build rather than a lock.

**Why:** killing the holders is not an option — they are the live agent perches, including my own. Waiting for a gap is a coin flip on a host that is always working.

**How to apply:** run `spt` e2e suites with the target dir redirected — NOT into the session scratchpad (superseded 2026-08-01: scratchpad targets ate 112 GB and killed the v0.50.0 floor, see [[scratchpad-target-trees-eat-the-box]]) but via the `.worktrees/gate-target` junction per [[worktree-target-junction]]. Then `cargo build --bin mock-shell` (e2e suites need the sibling binary; `--test x` alone does NOT build it) before `cargo test -p spt --test ...`. Follow-ons: (1) e2e suites leave `spt.exe` ORPHANS that hold the redirected exe on the next run — reap by PATH ONLY, never a bare name-match kill (that takes down the live agents); (2) `cargo clippy`/`cargo check`/lib tests need no redirect — they emit no exe; (3) **the e2e lane cannot run FROM a live endpoint at all** (todlando, 2026-08-01 W5): with `$SPT_ENDPOINT_ID` set the suites fail via `DAEMON_STOP_REFUSED`, and the failed run leaves the exe-holding orphans behind — clear the marker or run from a non-endpoint shell. Related: [[daemon-lib-tests-deadlock-on-live-host]], [[spt-verification-gates]], [[alarm-every-test-run]].

⚠ **Second holder class, named 2026-08-29/30 (doyle, banked IR-63 third face @`aa9ac15a`): orphaned
headless `conhost.exe`.** The spt.exe entry above is about a locked BINARY; this is about a locked
DIRECTORY. Battery legs leave orphaned `conhost.exe` processes whose **CWD is
`<worktree>\crates\spt-daemon`**, and a live CWD pins the whole worktree tree — so
`git worktree remove` and a target reap both refuse with a handle error that names nothing.
Measured population at the time: **31 conhosts pinning 5 dead worktrees**, plus 1 still pinning
`gate-w1-786d2381`, 12 on `gate-w1-a8f04aff`, 5 on `io-parser-w1`.

**How to find the holder when `handle.exe` is not installed:** probe each process's PEB CWD and
match it against the directory you are trying to remove — that is what named these. Kill the
pinning conhosts FIRST, then remove; otherwise the removal refuses and reads as a mysterious
Windows lock rather than as this session's own litter.

**Why it matters beyond disk:** the same battery legs that leak `spt.exe` (see above) leak these,
so a box that has run batteries all day accumulates BOTH classes — one blocks the next BUILD
(Access denied on the linker output), the other blocks the next CLEANUP.
