---
name: orphan-conhost-cwd-pins-worktree
description: "the \"worktree that will not delete\" is whatever process holds the crate root as its CWD — usually a surviving descendant, but a --headless ConPTY conhost can be the sole holder (measured 2026-08-02), so check the cwd not the image name; write-inside works, rename/delete blocked; find the holder with the PEB cwd reader, then read its identity before killing"
metadata: 
  node_type: memory
  type: reference
  originSessionId: 0241438f-ee37-4144-979e-b5499de58a8e
  modified: 2026-08-02T13:16:04.974Z
---

**Mechanism (corrected 2026-08-02 by measurement — the earlier conhost attribution in this file was
WRONG and is deleted, not annotated).** A `git worktree remove` / `rmdir` that fails on
`<worktree>\crates\<pkg>` is a **live process whose CURRENT DIRECTORY is that dir**. Cargo runs test
binaries with cwd = the package root, so every child a test spawns inherits `<wt>\crates\<pkg>\` — and
so does every **grandchild**. Any of them that outlives the run pins the dir. The crate in the path is
whatever crate the test ran under; nothing is special about spt-daemon.

**A conhost is USUALLY not the pin — but "never" is false.** `CREATE_NO_WINDOW` mints exactly one
`conhost.exe` per console child, and *those* conhosts take an **OS-assigned** cwd: box-wide census =
43 readable, all `C:\WINDOWS\` or `C:\WINDOWS\system32\`, zero under any worktree; force-killing such a
child leaves its orphan conhost still reading `C:\WINDOWS\`, and on a scratch-dir positive control
killing the conhost left the dir BLOCKED while killing the real holder — an orphaned **grandchild**
(`PING.exe`, cwd inherited through `cmd`) — deleted it first try. So for the CREATE_NO_WINDOW class,
killing conhosts is not the cure and "no conhosts" is not the all-clear.

**Falsified 2026-08-02 (todlando, BAROMETER W4 teardown): a `--headless` ConPTY conhost carries an
INHERITED cwd and pins that dir BY ITSELF.** Wild specimen: `.worktrees/barometer-w4` refused removal
at `crates\spt`; the PEB sweep row was `46556 conhost …\barometer-w4\crates\spt\` (positive control:
my own shells read the repo root). Killing a stray `du.exe` first left it blocked; killing the conhost
freed it.

*Retracted from my own first argument:* I claimed the chain was tight because the conhost had **zero
children**. hertz was right that this proves nothing — **a ConPTY client is a child of whoever called
`CreatePseudoConsole`, not of the conhost**, so killing the conhost tears down the pty and can take a
living client with it. Never argue holder-identity from a conhost's child list.

What replaces it — two controlled rigs (`pin-experiment.ps1`):
1. **Inheritance:** launch `conhost.exe --headless` from a probe dir ≠ system32 → its PEB reads the
   probe dir. Not OS-assigned. (That rig launched the binary directly with a working directory.) The
   `CreatePseudoConsole` path — the one the wild specimen took — was then covered separately by hertz:
   mint a pseudoconsole from a process whose cwd is a chosen dir and the new
   `conhost.exe --headless …` reads THAT dir, with the pin's own control beside it — write-inside
   **OK**, delete **BLOCKED** while it lives, **DELETED** after `ClosePseudoConsole`. Reading a path
   and blocking a delete are different claims; both are now held.
2. **Sole-holder, by KILL ORDER:** conhost cwd = probe dir, client deliberately `cd`'d to `C:\`.
   Both alive → blocked; **kill the CLIENT only → still blocked**; kill the conhost → deletes. Step 2
   is causal, so pty-teardown-killed-a-client cannot explain it.

**A census that looked like confirmation and had zero power:** all 8 live `--headless` conhosts read
`C:\WINDOWS\system32\` — but their creator (`spt.exe`) sits there too, and that value is exactly what
OS-assignment predicts. Uniform rows, both hypotheses fit ([[uniform-table-blindness-sweep]]).

**Elevation is NOT the discriminator, and neither is access mask:** `elevated=False` and my reader
still opened 49/54 conhosts (all 8 headless). hertz's "unelevated opens NONE" turned out to be a
**parse bug in his caller**, not an access denial — his finder reads 46/50 unelevated, same mask as
mine (`PROCESS_QUERY_INFORMATION|PROCESS_VM_READ`). No elevation caveat went into the doc. I had
guessed *requested access rights*; that guess was also wrong. The durable lesson is only that the
premise was worth checking rather than accepting — [[ruling-rests-on-a-premise]].

**Landed:** hertz's amend is H2 tip `2ab3e92` (population-scoped strike-and-amend), and he closed my
method caveat by minting a `--headless` conhost through `CreatePseudoConsole` from a chosen cwd: its
PEB reads that cwd, and the pin has its own control (write-inside OK, delete BLOCKED while the
pseudoconsole lives, deleted after `ClosePseudoConsole`). Both launch paths are in the entry.

Scope: the CREATE_NO_WINDOW half of the census stands, surviving descendants stay the common case.
Only the word **"never"** dies, for the `--headless` population. Check the cwd, never the image name.

**Signature, no tool needed:** a cwd pin allows writes INSIDE the dir but blocks rename/delete (content
locks do the opposite), and persists (a scanner does not).

**Finder** (`.github/ci/find-cwd-holders.ps1`): landed in hertz's `d058d34` — **on `golden/barometer`,
NOT on main** (verified 2026-08-02; `git ls-files` on main finds nothing, which is why I rebuilt the
PEB reader from scratch rather than reusing it). Read-only PEB read,
`-Match worktrees`. It reports its readable/not-openable **denominator** — an empty result is "no pin I
could see", never "no pin". **It answers WHO pins, never whether it is SAFE TO KILL** — see
[[worktree-pin-holder-triage]]: orphan (parent dead, headless) → kill; a live agent's own shell → `cd`
out (pwsh and Bash hold SEPARATE cwds, so clearing one leaves the other).

**Two fixes refused on evidence:** flipping the rigs' `no_window()` to `DETACHED_PROCESS` removes the
conhost (1 → 0) but not the pin, and under that flag **powershell does not execute at all** while
`cmd`'s **piped stdout is lost** — which would make `job_escape_e2e::conhost_children_of`
(`unwrap_or(0)`) turn the `REQ-HAZARD-WMI-DAEMON-WINDOW` guard **vacuously green**. Nor can the helper
hand children a neutral cwd: `bind_cwd_project_e2e` / `resume_template_e2e` assert on the **inherited**
cwd. Prevention is rig **teardown completeness** (the #99 class, extended to grandchildren). Written up
as KNOWN-HAZARDS **5.18** `[REQ-HAZARD-TREE-CWD-PIN]` + a 5.17 amendment.

See [[stale-breadcrumb-tree-kill-class]], [[worktree-target-junction]],
[[reap-subtree-not-session-dir]], [[live-agents-lock-target-debug-spt-exe]],
[[stacked-defects-mask-each-other]].
