The #131740 residual: a Desktop turn wedged between the 'Turn ended' log
line and run_conversation returning. The liveness watchdog fired ~600s
later naming 'API call #8 completed' as the last activity - a stamp from
the last provider response - so the stall surface read like a hung API
call, nothing pinned the blocking frame, and the abort hit a turn whose
loop had already finished.
- finalize_turn stamps the activity clock at 'Turn ended'
(_log_turn_exit): a stall in the post-loop tail is measured from when
the loop actually ended, and the watchdog's 'last activity' names the
finalizer instead of a stale API call. Guarded: a broken
activity-clock seam never raises into the finalizer.
- TurnLivenessWatchdog._surface_stall dumps every thread's stack (turn
thread marked, 40-thread cap) at the moment it fires, so the wedged
frame lands in errors.log on the next occurrence without py-spy.
Refs #131740