Repository navigation
Keep the tokens-saved counter moving in long sessions - #747
anirudhkumar-nanonets wants to merge 1 commit into
Conversation
🌱 graft blast radiusNothing outside this diff depends on it. 1 area changed; no indexed dependents at depth 2. Who knows this code — 1 person across 1 area
Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no Test signal per changed area — 1 ✓Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.
3 test suites also reference this code3 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.
Open the interactive graph → — click an area to see its dependent symbols at file:line. |
86e2c2c to
2f0a88c
Compare
The issue: in a long session the statusline's tokens saved and dollars saved stop moving, sometimes for days, while trail keeps handing the agent learnings.
Why: the counter only adds the savings lines it finds in a trail call's output. Learnings that arrive through the prompt hook and the file-touch hook carry the same
[trail] learnings saved ≈ Nline, and that copy was never counted. After the first hour a session mostly edits, tests and runstrail check, so its savings arrive by hook and the number froze.The fix: when the prompt hook or the file-touch hook shows a learning, its savings line goes on the session's counter (
addHookSavingsinsrc/claude/session-metrics.ts). Each learning reaches a session once, so it is counted once.Moves: share of trail's Claude Code sessions whose
session_summaryreports any saving (saved_tokens_bucketnot0; PostHog events in Metabase db 11,posthog_event_full_view,cli_name = 'trail',agent_host = 'claude-code',ci = 'false', last 7 days). 21.3% (4,077 of 19,106) on 2026-11-02.How it was found
The three usual suspects (a cap on how much transcript is read, a cache keyed on something that stops changing, a total computed once) are all ruled out. I replayed the 24 local transcripts over 3 MB from the last two weeks that had a stored counter. In 21 the stored
savedTokensequals the sum of savings lines in tool results exactly, so the counter was right about what it counted, and in 8 of those it never showed a saving at all while the hooks handed over 1.8 to 5.8 million tokens of learnings. One of the other three ran trail in subagents, whose transcripts are separate files. The last two each lost one trail call's savings; I didn't find why, and this PR doesn't touch it.One 7-hour session sat at 474,532 tokens from its first minute to its end. Counting the learnings its hooks handed over, it would have ended at 5,417,031 and last moved 20 minutes before the end.
Merge order
This PR, #731 and #738 all change the
if (text) writeSession(dir, id, s);line inlearningsOnTouch(src/claude/hooks.ts), and #731 and #738 already conflict with each other there. Merge this one first. Each of the other two then keepsaddHookSavings(s, text);as the first line insideif (text) { … }when it resolves that block.src/claude/format.tsis untouched, so this merges cleanly with #727, #729 and #739 (checked withgit merge-tree).Tests
test/hook-savings.test.ts(new): a learning shown on a file read, and one shown by the prompt hook, each add their saving to the session once. Both fail without the fix.node_modulesmissingweb-tree-sitter-depth(parser tests), plus one session-start test intest/hosts-trail.test.tsthat fails the same way without this change. CI is the clean run.trail check: no conflicts.Watch out
trail askanswer is counted twice, the same as two asks that return the same learning already are.session_summary.saved_tokens_bucketnow includes learnings the hooks hand over, which is what the Moves line measures.🤖 Generated with Claude Code