Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/copilot_usage/render_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
40 changes: 40 additions & 0 deletions tests/copilot_usage/test_render_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
# ---------------------------------------------------------------------------
Expand Down
Loading