Repository navigation
[Bug]: Usage counts most Antigravity calls three times (step, generation and retry copies are all added) #17071
Description
Activity
Note
Grok responding on behalf of Julius.
Triage (main @
b24f0fbb)Confirmed in code. The reader has no step to drop identical copies of the same call. Response ids are the only thing it merges on:
metadata()returns the entry's main usage plus one usage for every retry entry: field 9 and the field 28 list for steps, field 4 and the field 17 list for generations (L131-L137).readDatabasemakes a record for every usage of every step and then every generation (L202-L253). Ids come only from fields 11/12/7 (L227-L230). With no id, the key falls back toantigravity:${sessionId}:${source}:${index}:${usageIndex}(L244), so every copy gets its own key.readAntigravityUsagemerges candidates only when they share a key from that id list (L325-L333).UsageAggregator.adddrops only repeateddedupeKeys (usageAggregation.ts L176-L180). Copies without an id never collide.
I checked this locally against
main's reader with a made-up DB. One call with no id is stored as a step usage, a generation usage, and a generation retry entry, all with the same counters. The reader returns 3 records (step:0:0,generation:0:0,generation:0:1).Tests. Every Antigravity fixture that has both a step and a generation copy gives them a shared field-11/12 id (usageTranscriptReader.test.ts L531-L590, L615-L658, L696-L739). No fixture covers id-less copies, which is where the duplicates come from. In the one retry fixture, the retry has different counters and its own id (
retry-1), and the test expects it to stay a separate record.Origin. Not a later regression. The multi-source reading, the retry lists and the per-source fallback key have been there since the reader landed in #10409. The only later change to the file, #15101, renamed
fasttospeed.Fix direction. Dedupe within each conversation in
readDatabase, before the id merge:- Drop a retry entry whose counters match its entry's main usage, unless it carries a different id. The existing retry test, with different counters and its own id, should still pass.
- Pair id-less step and generation usages that have identical counters, nth with nth, so that two real identical calls are both kept.
- Keep the response-id merge across files as it is.
Add a fixture with id-less step, generation and retry copies.
Caveats:
- Matching on counters is a heuristic. Two genuinely separate calls in one conversation with exactly the same counters (fields 2/3/4/5/9/10) would be collapsed if their copies don't line up nth with nth. That is probably rare, but it can happen.
- It's not clear from the code whether
steps.idxandgen_metadata.idxline up one-to-one. The model fallback appears to assume they do (L238), but pairing by idx isn't verified, so pairing by counters is the safer choice. - Reading only generations would undercount, because step-only stores and step usages with no generation are handled on purpose (L741-L758).
Related.
- Open PRs fix(usage): skip unchanged Antigravity databases on repeat scans #13902 (skip unchanged Antigravity DBs on repeat scans) and fix(server): price Antigravity Gemini Flash effort variants #13809 (Gemini Flash pricing) also edit
antigravityUsageReader.ts, so a fix here will likely conflict with them. - [Bug]: Antigravity shows token usage only, not limits #16104, feat(antigravity): report subscription usage limits #15198 and feat(usage): Antigravity reports weekly limits for each model group #15299 are about limits, not token counts. [Bug]: Usage double-counts a provider transcript directory shared between Windows and a WSL environment (source fingerprint cannot unify one directory across the OS boundary) #7858 is double counting from a directory shared across Windows and WSL. They're related but separate.
Unconfirmed:
- Whether real Antigravity DBs store the same usage in all three places, and the reporter's numbers (34 files, 10,592 records vs 3,598 calls, 2.94×; 165 of 10,702 usages with ids). I can't check either without the databases. The code path above counts such copies separately if they're there.
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 8, 2026
Before submitting
Area
apps/server
Steps to reproduce
~/.gemini/antigravity/conversations(the Antigravity app) and/or T3 Code's Antigravity profile,<state dir>/providers/antigravity/<sha256 of instance id>/antigravity-acp/conversations.main's reader directly from the repo root (Node ≥ 23.6; prints aggregates only):Expected behavior
Each Antigravity model call is counted once.
Actual behavior
Most Antigravity calls are counted three times, so Antigravity's requests, tokens and API-equivalent cost on the Usage page are about 3× too high.
Antigravity writes the same usage message to up to three places in a conversation database. Counts of non-zero usage messages across 34 conversation files on one Mac:
steps.metadatagen_metadata.datagen_metadata.dataretry liststeps.metadataretry listAll 3,506 generation usages have exactly the same counters (fields 2, 3, 4, 5, 9 and 10) as a step usage in the same conversation; the other 92 step usages have no generation entry. Only 165 of the 10,702 usages carry a response id (fields 11/12/7): 55 calls whose three copies share their ids, so only those are merged today.
Where the copies get through:
metadata()returns an entry's main usage plus every retry entry (L131–L136).readDatabasemakes a record for every usage of every step and every generation (L202–L244). Without a response id, the fallbackdedupeKey(…:${source}:${index}:${usageIndex}, L244) is different for each copy.readAntigravityUsagemerges only records that share a response id (L325–L331), andUsageAggregatordrops only repeated dedupe keys (usageAggregation.ts L176–L177), so every id-less copy is counted.The script above on those 34 files (9 from the Antigravity app, 25 from T3 Code's Antigravity profile):
That's 10,592 records for 3,598 calls (2.94×), and 924M tokens for 312M.
Impact
Minor bug or occasional failure
Nothing breaks, but every Antigravity figure on the Usage page (requests, tokens, API-equivalent dollars) is about 3× too high.
Version or commit
T3 Code Nightly 0.0.46-nightly.20261008.2801; the reader is unchanged on main @ b24f0fb
Environment
macOS 27.2, desktop app (Nightly). Antigravity provider (gemini-3.8-flash-high, gemini-pro-agent) plus the Antigravity app's own history (app 2.21.1).
Workaround
None in the app.
Possible fix
Within one conversation, count each call once:
Reading only generations wouldn't be enough: 92 step usages here have no generation entry.