Skip to content

De-duplicate logical session IDs before aggregating cost and tokens #2

Description

@VirtualPaul

Summary

all_session_sources() can return more than one Claude Desktop source with the same session ID. cross_session() counts every returned source, while find_session() and deletion select the first match. This can double-count tokens/cost and makes ID-based operations ambiguous.

Tested against main at fb265549480ff0d3ad8b14b28007370539b70cf3.

Reproduction

  1. Have a normal Claude trace and a Claude Desktop local-agent trace whose cli_session_id is the same but whose paths differ.

  2. Run:

    import meter
    from collections import Counter
    
    sources = meter.all_session_sources()
    print([item for item, count in Counter(s["id"] for s in sources).items() if count > 1])
  3. Call cross_session() and compare the aggregate with the newer/preferred source alone.

  4. Call find_session(the_duplicate_id, sources) and reverse sources; the selected path changes.

In a 100-source corpus, two IDs were duplicated. One duplicated pair contained the same 18 turns, 759,845 tokens, and $3.425828 twice, so the aggregate attributed $6.851656 instead of $3.425828.

Root cause

  • meter.py:676-731 de-duplicates by path (known_paths), not by logical session identity.
  • meter.py:4638-4651 aggregates every discovered source.
  • meter.py:767-773 returns the first ID match.
  • meter.py:776-808 uses that ambiguous lookup for deletion.

Expected behavior

Each logical session contributes once to global totals, and ID-based fetch/delete operations resolve deterministically to one canonical source or reject ambiguity.

Suggested fix

  1. Define a canonical identity key, preferably (provider, id), with a documented fallback for missing IDs.
  2. Merge duplicate metadata and choose a canonical trace deterministically (for example: exact desktop metadata match, then newest mtime, then stable path tie-breaker).
  3. De-duplicate before aggregation.
  4. Make find_session() reject ambiguous identifiers unless the caller provides a path-qualified/internal source key.
  5. Never delete a log selected only by an ambiguous public ID.

Regression tests

  • Add two different paths with the same Claude session ID and assert cross_session() counts the logical session once.
  • Reverse discovery order and assert the canonical source is unchanged.
  • Assert ambiguous deletion cannot move the wrong path to Trash.
  • Assert genuinely distinct provider/session pairs remain distinct.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions