0ea0c53e89
The early-EOF reaper made _finish_reader return without publishing when wait() raises, so the session stays tracked for later reconciliation. That is right for the pipe path (_reconcile_local_exit can still reap via session.process), but PTY sessions have no session.process: when ptyprocess.wait raises (waitpid ECHILD after isalive() already reaped the child) the exitstatus is known, yet poll() reported "running" forever. Only leave the session tracked when exit_code() is still None; otherwise record the known status and finish as before. Review finding: PTY session whose pty.wait raises stays in _running forever (fail-open regression vs main)