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
-
Have a normal Claude trace and a Claude Desktop local-agent trace whose cli_session_id is the same but whose paths differ.
-
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])
-
Call cross_session() and compare the aggregate with the newer/preferred source alone.
-
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
- Define a canonical identity key, preferably
(provider, id), with a documented fallback for missing IDs.
- Merge duplicate metadata and choose a canonical trace deterministically (for example: exact desktop metadata match, then newest mtime, then stable path tie-breaker).
- De-duplicate before aggregation.
- Make
find_session() reject ambiguous identifiers unless the caller provides a path-qualified/internal source key.
- 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.
Summary
all_session_sources()can return more than one Claude Desktop source with the same session ID.cross_session()counts every returned source, whilefind_session()and deletion select the first match. This can double-count tokens/cost and makes ID-based operations ambiguous.Tested against
mainatfb265549480ff0d3ad8b14b28007370539b70cf3.Reproduction
Have a normal Claude trace and a Claude Desktop local-agent trace whose
cli_session_idis the same but whose paths differ.Run:
Call
cross_session()and compare the aggregate with the newer/preferred source alone.Call
find_session(the_duplicate_id, sources)and reversesources; 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-731de-duplicates by path (known_paths), not by logical session identity.meter.py:4638-4651aggregates every discovered source.meter.py:767-773returns the first ID match.meter.py:776-808uses 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
(provider, id), with a documented fallback for missing IDs.find_session()reject ambiguous identifiers unless the caller provides a path-qualified/internal source key.Regression tests
cross_session()counts the logical session once.