672f2b1f26
* feat(stats): add avg turn duration and messages per turn to averages card Adds two new metrics to the workspace stats Averages card: mean turn duration and mean message count per turn. Both exclude outliers — turns shorter than 1s (no-op/aborted), longer than 1h (zombie turns where completed_at was backfilled across an agent restart), and turns with no messages — so the displayed means reflect typical work rather than tail skew. On a ~4k-turn sample the filter drops avg duration from ~1062s to ~289s. * fix(stats): exclude exact 1h turns and use Tooltip for averages help text Address PR feedback: the BETWEEN bound was inclusive so turns exactly at the 1h ceiling were retained, contradicting the documented half-open range. Also swap the title attribute on the new Averages rows for the shared Tooltip component so the help text is reachable via keyboard and screen readers. * fix(stats): align turn-row zero state with em-dash convention Address PR feedback: avg_messages_per_turn rendered "0.0" while avg_turn_duration_ms rendered "—" under the same empty-data condition. Also corrects the GetGlobalStats docstring to acknowledge that clean_turn_agg adds one correlated per-turn lookup on top of the four single-scan CTEs. * test(stats): cover exact 1h turn boundary in clean-turn exclusion test Add a turn of exactly 3,600,000ms (cleanTurnMaxDurationMs) to TestGetGlobalStats_CleanTurnExcludesOutliers so the exclusive upper bound is exercised directly, not just via the 2h zombie turn that sits well above the boundary. --------- Co-authored-by: Kandev Agent <agent@kandev.dev>