diff --git a/src/copilot_usage/render_detail.py b/src/copilot_usage/render_detail.py index 2650b22..48c1b24 100644 --- a/src/copilot_usage/render_detail.py +++ b/src/copilot_usage/render_detail.py @@ -387,10 +387,9 @@ def render_session_detail( session_start = ( ensure_aware(summary.start_time) if summary.start_time is not None - else ( - ensure_aware(events[0].timestamp) - if events and events[0].timestamp is not None - else datetime.now(tz=UTC) + else next( + (ensure_aware(ev.timestamp) for ev in events if ev.timestamp is not None), + datetime.now(tz=UTC), ) ) _render_recent_events(events, session_start, target_console=out) diff --git a/tests/copilot_usage/test_render_detail.py b/tests/copilot_usage/test_render_detail.py index 8434d0f..ddaa608 100644 --- a/tests/copilot_usage/test_render_detail.py +++ b/tests/copilot_usage/test_render_detail.py @@ -233,6 +233,46 @@ def test_no_start_time_no_event_timestamps_does_not_raise(self) -> None: assert "Session Detail" in buf.getvalue() +# --------------------------------------------------------------------------- +# session_start fallback scans all events for first non-None timestamp (#1182) +# --------------------------------------------------------------------------- + + +class TestRenderSessionDetailFirstNoneTimestampFallback: + """When start_time is None and events[0].timestamp is None, the renderer + must scan forward to the first event with a non-None timestamp rather + than falling back to datetime.now(tz=UTC), which would clamp every + relative-time column to +0:00. + """ + + def test_relative_times_correct_when_first_event_has_no_timestamp(self) -> None: + """events[1] anchors at +0:00, events[2] shows +5:00.""" + t = datetime(2026, 3, 15, 12, 0, 0, tzinfo=UTC) + ev0 = SessionEvent( + type=EventType.SESSION_START, + timestamp=None, + data={}, + ) + ev1 = SessionEvent( + type=EventType.USER_MESSAGE, + timestamp=t, + data={"content": "first"}, + ) + ev2 = SessionEvent( + type=EventType.USER_MESSAGE, + timestamp=t + timedelta(minutes=5), + data={"content": "second"}, + ) + summary = SessionSummary(session_id="null-head-test", start_time=None) + + buf, console = _buf_console() + render_session_detail([ev0, ev1, ev2], summary, target_console=console) + output = _strip_ansi(buf.getvalue()) + + assert "+5:00" in output + assert "+0:00" in output + + # --------------------------------------------------------------------------- # Gap — render_session_detail start_time fallback from events (#954) # ---------------------------------------------------------------------------