Three spawn-lifecycle holes in shared/wire.js where a throw on the happy path leaks the child's fds and can deadlock the blocking reap:
push():642 — the finally closes only rfd then io.reap(pid); wfd is closed IN-try at :639, so a throw in drainRecvAdvert/writeAll BEFORE it leaves git-receive-pack blocked reading commands on its still-open stdin. FILEReap is an unconditional blocking waitpid loop (dog/abc/FILE.c:303) → be put --force over ssh HANGS forever, plus fd/zombie leak in the resident loop. Reachable via verbs/put/put.js:310. JS-076 fixed only wire.fetch; JS-100 only pushSession/pushRemote — push() is the untouched sibling.curlRun():181 — no try/finally: a handler throw or the guard path leaks/zombies the curl child, and reap precedes the fd close.curlPost():198 — stages the request body OUTSIDE the try: a write failure leaks the fd and the tmp file; the tmp name is predictable.From the 2026-07-07 be/ review (BE/REVIEW), all three CONFIRMED (push() structural, curl by inspection). Method Issues.
push():642 finally { try{io.close(rfd)}catch; try{io.reap(pid)}catch } — wfd absent; the peer never sees EOF on stdin so waitpid never returns.