Repository navigation
fix(stats): count forked sessions' copied messages once - #312
Merged
Merged
Conversation
When a session is forked, OpenCode copies the parent's finished messages into the fork session with new ids but identical times, model, tokens, and cost. The all-history and multi-session readers counted each copy again, so forking a $10 session showed $20 in token/cost totals. Drop finished assistant rows whose fingerprint (created/completed time, provider, model, tokens, cost) matches an earlier row. Rows are sorted by time then id and copies get newer ids, so the original is kept. Unfinished rows are never merged, and a fork's own single-session read still shows its copied history. Refs #306
Review found that dropForkCopies never checked sessions, so two separate finished assistant rows in the same session with identical times, model, usage, and cost (for example two concurrent zero-usage requests) were merged. That undercounted message-based quotas and made aggregate reads disagree with the single-session read. A fork copy always lives in a different session from its original, so remember the session of the first row per fingerprint and drop a later row only when it is in a different session. Same-session duplicates keep their count, and a parent's two identical rows still drop both fork copies. Refs #306
Review found that keeping only the first session per fingerprint undercounts partial forks: a parent with two identical finished messages, an earlier fork that copied one, and a later fork that copied both returned one row when the parent was not read (or was deleted). Count each finished fingerprint as many times as the session that has it most often. Same-session identical rows are all kept, a parent and fork with the same copies still count once, and unfinished rows are never merged. Refs #306
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/tokens_*), Cursor usage and local-estimate quotas.dropForkCopiesinsrc/lib/opencode-storage.tsnow counts each finished fingerprint (created/completed time, provider, model, tokens, cost) as many times as the session that has it most often, and drops the extra copies. Identical rows inside one session are kept; unfinished rows are never merged./tokens_sessionon a fork) is unchanged and still shows its copied history.Linked Issue
Refs #306 (reported on 4.x; the 4.x backport is a separate PR into
release/4.x).OpenCode Validation
session.forkedprojector copies the parent's finishedsession_messagerows into the fork; the local package build was run in an isolated OpenCode 2.0.20 and a session was forked.Before-and-after evidence
Before: not captured live. By the issue's steps, the fork's copied messages are counted again (here: 6 messages, about 22.9K tokens).
After (
/tokens_today, same window, before and after forking "Quick check-in" with Full session and sending nothing in the fork):Surface checks:
/tokens_todaycommand dialog (TUI): checked live, totals unchanged after the fork.Quality Checklist
pnpm verify