Skip to content

[aw][code health] Active sessions without a shutdown show zero activity in interactive mode and cost view #154

@microsasa

Description

@microsasa

Root Cause

build_session_summary in src/copilot_usage/parser.py only populates active_model_calls, active_user_messages, and active_output_tokens for resumed sessions (those with a prior shutdown followed by more events). For pure active sessions — sessions that have never received a session.shutdown event — these three fields are never assigned and fall back to the Pydantic default of 0.

Both rendering paths that show active session detail read those fields:

  • _render_active_section (report.py:793–805) displays s.active_model_calls, s.active_user_messages, and s.active_output_tokens for every session where s.is_active=True.
  • render_cost_view (report.py:903–912) appends a ↳ Since last shutdown row using the same three fields for every active session.

Result: a session that is actively running (has user messages, assistant turns, and output tokens) but has not yet shut down will display 0 model calls / 0 user messages / 0 output tokens in the interactive home view and the cost view.

The empty-session e2e fixture (only session.start, no other events) happens to have genuinely zero activity, so the bug does not surface in the existing test suite.


Spec

src/copilot_usage/parser.pybuild_session_summary

In the active (no shutdown) code path (currently lines 323–337), populate the active_* fields with the same totals used for model_calls / user_messages and the token accumulator:

return SessionSummary(
    ...
    model_calls=total_turn_starts,
    user_messages=user_message_count,
    is_active=True,
    # Add these three:
    active_model_calls=total_turn_starts,
    active_user_messages=user_message_count,
    active_output_tokens=total_output_tokens,
)

For resumed sessions the semantics remain post-shutdown-only (already correct). For pure active sessions there is no prior shutdown, so "since last shutdown" equals "all activity" — these values are the same.


Testing Requirements

  1. Unit test in tests/copilot_usage/test_parser.py — add a case to the active-session test class:

    • Build a pure active session with several user.message, assistant.turn_start, and assistant.message (with outputTokens) events.
    • Assert summary.active_model_calls == (expected count).
    • Assert summary.active_user_messages == (expected count).
    • Assert summary.active_output_tokens == (expected total).
  2. Unit test in tests/copilot_usage/test_report.py — add a case to TestRenderFullSummary:

    • Create a SessionSummary with is_active=True, non-zero model_calls, user_messages, and token counts in model_metrics, but active_* fields populated by the fixed parser.
    • Assert the captured output from render_full_summary contains the non-zero counts in the Active section.
  3. E2E test — add a fixture with a pure active session that has at least one user.message and assistant.message event (no session.shutdown), and assert the interactive summary output reflects the real activity counts.

Generated by Code Health Analysis ·

Metadata

Metadata

Assignees

No one assigned

    Labels

    awCreated by agentic workflowaw-dispatchedIssue has been dispatched to implementercode-healthCode cleanup and maintenance

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions