Two review findings on the CPython backend:
- Disposal could return while a same-group descendant that ignores SIGTERM
but releases the inherited pipes was still alive: the leader's close fired
and the previous fix relied on an unref'd SIGKILL timer that a short-lived
host never fires, reparenting the survivor to init. settle() now withholds
the run's finished promise on a ref'd process-group poll until the SIGKILL
has emptied the group (bounded by graceMs + margin, zero-cost when already
empty), so teardown's "await each child's exit" holds.
- A binding called from a model worker thread via asyncio.run created its
reply Future on that thread's loop, but _pump_replies completed it directly
from the main loop; asyncio.Future is not thread-safe across loops, so the
call hung to the wall clock. Replies now complete via the owning loop's
call_soon_threadsafe, and a lock serializes the id claim/write/advance.
Tests: the same-group reap case now asserts a heartbeat file stops (robust
whether the killed descendant is reaped or a zombie, so it holds where PID 1
does not wait() orphans); a cross-loop case runs a binding from a worker
thread and asserts the reply round-trips instead of timing out. Agent Note
expanded to all six fixes with rejected alternatives; zh pair re-recorded.