The session-field half of _cleanup_chat_start_launch_failure mutated and
saved the passed-in session object without holding the per-session lock and
without re-resolving the canonical session. A concurrent successor turn
(same session_id, new stream_id) or a delete could be clobbered: pending
fields wiped or a deleted session resurrected via save().
Mirror the established #1533 pattern (routes.py:3077) and anchor-scene
write guard (routes.py:5140): hold _get_session_agent_lock, re-resolve with
get_session(), early-return on KeyError (session deleted) or when the
canonical no longer points at the failed stream, then reset pending fields
on the canonical object only.
Add deterministic race coverage: successor admitted during the
check-then-clear window keeps its pending fields and is not saved away, and
a deleted session is not resurrected by save(). Both tests fail against the
previous implementation.