Root Cause Analysis
_detect_resume (src/copilot_usage/parser.py) iterates events after the last shutdown and handles four types differently:
| Event type |
Effect |
ASSISTANT_MESSAGE |
session_resumed = True + accumulate output tokens |
USER_MESSAGE |
session_resumed = True + count post-shutdown user messages |
SESSION_RESUME |
session_resumed = True + capture timestamp |
ASSISTANT_TURN_START |
post_shutdown_turn_starts += 1 only — does not set session_resumed = True |
| All others |
Ignored |
The design intention is clear: a turn start alone (with no assistant message produced) does not constitute a resumed session — the session's shutdown is still its final state. However, this invariant is nowhere explicitly tested.
TestDetectResumeNonIndicatorEvents (line 6079 of test_parser.py) documents non-indicator events by testing TOOL_EXECUTION_COMPLETE + SESSION_ERROR, but ASSISTANT_TURN_START is structurally different: it is a partially handled event (it has a counter) that intentionally does not trigger session_resumed. Any developer reading the elif chain without the test context could reasonably consider adding session_resumed = True there — and no test would catch the regression.
Existing coverage (for context)
test_counts_user_messages_and_turn_starts — combines USER_MESSAGE and ASSISTANT_TURN_START after shutdown; session_resumed becomes True via the user messages, not turn starts.
TestDetectResumeRangeIndex.test_correctness_with_large_event_list — mixes all event types including turn starts; session_resumed=True comes from user/assistant messages.
There is no test where ASSISTANT_TURN_START events are the only post-shutdown events and the expectation is session_resumed=False.
Tests to add
In TestDetectResumeNonIndicatorEvents (or a new sibling class)
test_turn_start_alone_does_not_set_session_resumed
- Build a session:
session.start → user.message → session.shutdown → assistant.turn_start × N
- Assert
result.session_resumed is False
- Assert
result.post_shutdown_turn_starts == N
- Assert
result.post_shutdown_user_messages == 0
- Assert
result.post_shutdown_output_tokens == 0
- Assert
result.last_resume_time is None
test_full_build_session_summary_turn_start_only_is_completed
- Same event sequence, run through
build_session_summary
- Assert
summary.is_active is False
- Assert
summary.end_time is not None (shutdown time preserved)
- Assert
summary.active_model_calls == N (turn starts still counted)
- Assert
summary.active_user_messages == 0
Regression scenarios to cover
- A refactor adds
session_resumed = True to the ASSISTANT_TURN_START branch → the first test above would catch it.
- A refactor promotes
ASSISTANT_TURN_START into the "session_resumed indicators" set → the second test above would catch the incorrect is_active=True.
Generated by Test Suite Analysis · ● 20M · ◷
Root Cause Analysis
_detect_resume(src/copilot_usage/parser.py) iterates events after the last shutdown and handles four types differently:ASSISTANT_MESSAGEsession_resumed = True+ accumulate output tokensUSER_MESSAGEsession_resumed = True+ count post-shutdown user messagesSESSION_RESUMEsession_resumed = True+ capture timestampASSISTANT_TURN_STARTpost_shutdown_turn_starts += 1only — does not setsession_resumed = TrueThe design intention is clear: a turn start alone (with no assistant message produced) does not constitute a resumed session — the session's shutdown is still its final state. However, this invariant is nowhere explicitly tested.
TestDetectResumeNonIndicatorEvents(line 6079 oftest_parser.py) documents non-indicator events by testingTOOL_EXECUTION_COMPLETE + SESSION_ERROR, butASSISTANT_TURN_STARTis structurally different: it is a partially handled event (it has a counter) that intentionally does not triggersession_resumed. Any developer reading theelifchain without the test context could reasonably consider addingsession_resumed = Truethere — and no test would catch the regression.Existing coverage (for context)
test_counts_user_messages_and_turn_starts— combinesUSER_MESSAGEandASSISTANT_TURN_STARTafter shutdown;session_resumedbecomesTruevia the user messages, not turn starts.TestDetectResumeRangeIndex.test_correctness_with_large_event_list— mixes all event types including turn starts;session_resumed=Truecomes from user/assistant messages.There is no test where
ASSISTANT_TURN_STARTevents are the only post-shutdown events and the expectation issession_resumed=False.Tests to add
In
TestDetectResumeNonIndicatorEvents(or a new sibling class)test_turn_start_alone_does_not_set_session_resumedsession.start → user.message → session.shutdown → assistant.turn_start × Nresult.session_resumed is Falseresult.post_shutdown_turn_starts == Nresult.post_shutdown_user_messages == 0result.post_shutdown_output_tokens == 0result.last_resume_time is Nonetest_full_build_session_summary_turn_start_only_is_completedbuild_session_summarysummary.is_active is Falsesummary.end_time is not None(shutdown time preserved)summary.active_model_calls == N(turn starts still counted)summary.active_user_messages == 0Regression scenarios to cover
session_resumed = Trueto theASSISTANT_TURN_STARTbranch → the first test above would catch it.ASSISTANT_TURN_STARTinto the "session_resumed indicators" set → the second test above would catch the incorrectis_active=True.