Skip to content

fix(antigravity): stamp mtime fallback at emission, tighten path classification#612

Merged
iamtoruk merged 4 commits into
getagentseal:mainfrom
Battiatus:feat/antigravity-ide-timestamps
Jul 16, 2026
Merged

fix(antigravity): stamp mtime fallback at emission, tighten path classification#612
iamtoruk merged 4 commits into
getagentseal:mainfrom
Battiatus:feat/antigravity-ide-timestamps

Conversation

@Battiatus

@Battiatus Battiatus commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

• Makes Antigravity IDE sessions visible to CodeBurn by reading conversation files under ~/.gemini/antigravity-ide (Windows included), alongside the existing CLI / base app roots.
• Tightens path classification so IDE vs CLI vs base app is decided from the .gemini root, not from a profile folder name like “Antigravity IDE”.
• Fixes untimestamped SQLite gen_metadata usage so calls are not dropped by date-range filters and do not jump forward when only the .db mtime changes:
• prefer real ChatStartMetadata.created_at when present (chatModel.#9.#4);
• otherwise a stable first-seen fallback per dedup key (assignStableTimestamps);
• withFallbackTimestamp remains an emit-time safety net on cache-hit paths (copy only).
• Documents that %APPDATA%\Antigravity IDE\User\globalStorage\state.vscdb holds trajectory metadata (titles, workspace paths, etc.), not token usage — usage still comes from the .db conversation files under .gemini.

Partially addresses: #411 (#411) — fixes zero / missing usage for IDE sessions found under .gemini/antigravity-ide, and the untimestamped / mtime-drift cases. Does not add a new token-usage read path from APPDATA state.vscdb alone.

Issue

Changes

• antigravity.ts
• Discover .gemini/antigravity-ide conversation / implicit roots (same pattern as CLI).
• Classify paths by .gemini root; drop the incorrect APPDATA-as-usage-source framing.
• Decode ChatStartMetadata.created_at when present; stable first-seen fallback for rows without it.
• Antigravity cascade CACHE_VERSION = 5.
• session-cache.ts: Antigravity parse fingerprint worktree-project-grouping-v5.
• main.ts: Install message notes that the status-line hook captures CLI (agy) only; IDE sessions are read from .db files automatically.
• docs: Clarify state.vscdb = trajectory metadata only; token usage from .db under .gemini.
• tests
• IDE path classification.
• Unit: created_at preferred over file mtime.
• Integration (generic parser + session-cache): first parse → cache hit → mtime-only rewrite keeps timestamp → date-range / today behavior.

Notes

• Untimestamped calls in one multi-day .db still share that file’s first-seen mtime when created_at is absent (best-available).
• Helpers in code: withFallbackTimestamp, assignStableTimestamps (not stampFallbackTimestamp).

Test Plan

• [x] Antigravity provider tests (incl. path classification + created_at)
• [x] Integration: tests/parser-antigravity-timestamp.test.ts (parse / cache hit / mtime rewrite / range / today)
• [x] TypeScript compilation clean (tsc)
• [x] Manual: npx tsx src/cli.ts with Antigravity IDE usage under .gemini/antigravity-ide and verify sessions without --provider
• [x] Manual: second run verifies cache hit (no reparse)

CodeBurn previously only detected Antigravity CLI usage (.pb files under
.gemini/antigravity/). Antigravity IDE on Windows stores session state in
VSCode-style storage at %APPDATA%\Antigravity IDE\User\globalStorage\state.vscdb,
which was not detected.

Add support for reading Antigravity IDE sessions from the VSCode-style storage:
- Extend CONVERSATION_ROOTS to include APPDATA Antigravity IDE path
- Refine path classification to properly identify IDE vs CLI sessions
- Handle missing per-call timestamps by stamping file mtime as fallback
- Bump CACHE_VERSION to 4 for cache invalidation

Fixes: CodeBurn reports zero usage when Antigravity IDE is actively used.
@Battiatus
Battiatus marked this pull request as draft July 3, 2026 13:45
@Battiatus
Battiatus marked this pull request as ready for review July 3, 2026 13:47

@ozymandiashh ozymandiashh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the underlying problem it targets (SQLite gen_metadata calls with no per-call timestamp being silently dropped by the date-range filters) is real and worth fixing. A few things to resolve before it can merge:

1. Scope/title is stale vs main. Antigravity IDE discovery already landed in #418 (35a8518): ~/.gemini/antigravity-ide/conversations (+ implicit) are in CONVERSATION_ROOTS on main today. This PR does not add a new storage root, so "add support for Antigravity IDE storage" / "previously only detected Antigravity CLI" no longer describe the change. Please retitle to what it actually does (timestamp fallback + path classification).

2. The new APPDATA classifier branch is unreachable. antigravityAppDataDirFromSourcePath's if (lower.includes('/antigravity ide/')) (src/providers/antigravity.ts:471) can't fire in normal operation: discoverAntigravitySessionSources only walks the ~/.gemini/... roots, so no discovered source.path is ever an APPDATA path — and your own doc note says the %APPDATA%\...\state.vscdb DB holds trajectory metadata, "not token usage". As written it is dead code. Either wire APPDATA discovery for real, or drop the branch.

3. If kept, that classifier misroutes a real case. It is a broad substring match checked after the .gemini/antigravity-{ide,cli}/ cases, so a base-app path under a folder literally named "Antigravity IDE" — e.g. C:\Users\Antigravity IDE\.gemini\antigravity\conversations\x.db — classifies as antigravity-ide, and detectServer then targets the wrong server. Guard the base path first: if (lower.includes('/.gemini/antigravity/')) return 'antigravity' before the APPDATA line. No test covers this; the added test only checks the .gemini/antigravity-cli/ precedence case.

4. mtime-as-timestamp misattributes cost across date ranges. stampFallbackTimestamp assigns the same new Date(s.mtimeMs) to every timeless call and persists it into the cache. Consequences: (a) an entire multi-turn session's cost buckets onto the day the .db was last written, so today/week/month views are wrong for older sessions; (b) any later file rewrite shifts all historical calls forward to the new mtime. Antigravity already exposes real per-entry times (RPC chatStartMetadata.createdAt, and the state.vscdb trajectory metadata you documented), so prefer those over a shared file mtime. At minimum, don't persist a synthesized mtime into the cache, so a re-write can't retro-date history.

CI is green and types are clean, so none of this is blocking on CI — but 2-4 are correctness issues. Happy to re-review once addressed.

…sification

- Apply the mtime fallback to a copy at emission instead of mutating and
  persisting it into the cache, so a later file rewrite can't retro-date a
  session's history to the new mtime. SQLite gen_metadata rows have no real
  per-call time; the RPC path still uses chatStartMetadata.createdAt.
- Drop the unreachable APPDATA classifier branch (discovery only walks the
  ~/.gemini roots; APPDATA state.vscdb holds no token usage). This also removes
  the misroute of base-antigravity paths under an "Antigravity IDE" profile dir.
- Bump CACHE_VERSION to invalidate caches that persisted a synthesized mtime.
@Battiatus Battiatus changed the title feat(antigravity): add support for Antigravity IDE storage on Windows fix(antigravity): stamp mtime fallback at emission, tighten path classification Jul 12, 2026
@Battiatus

Copy link
Copy Markdown
Contributor Author

Good catches. All three are fixed and pushed.

For 2 and 3 I just deleted the APPDATA branch outright. Discovery never walks anything outside ~/.gemini, so that path couldn't actually reach the classifier, and per the doc note the vscdb has no usage data anyway — not worth wiring up. Dropping it also removes the misrouting case, since there's no longer a broad substring match to trip on. Added a test for the base-antigravity-under-"Antigravity IDE" path.

On 4 — yeah, persisting the mtime was the actual bug. Now the fallback is only applied to a copy right before the call is yielded, and the cached entry keeps its empty timestamp, so a rewrite can't drag old calls forward. I kept the mtime as the fallback itself since the SQLite rows genuinely have no per-call time (the RPC path already uses createdAt where it has one). Bumped the cache version so anything that already stored a synthesized time gets dropped.

I also renamed the PR.

Thanks

@ozymandiashh

Copy link
Copy Markdown
Collaborator

Thanks — points 2 and 3 are fixed, but point 4 is still merge-blocking.

withFallbackTimestamp() avoids mutating the Antigravity-specific cache, but the emitted copy is persisted by the generic session-cache.json path in parser.ts. I reproduced this at head e7f5659: parsing the same SQLite DB with mtime 2026-01-02T03:04:05Z persisted that timestamp; after changing only the DB mtime to 2026-06-07T08:09:10Z, the same historical call with the same deduplication key was emitted and persisted as June 7.

On a source fingerprint change, parser.ts clears and reparses the non-durable source, so every historical row without a timestamp receives the latest file mtime again. The statement that a later file rewrite can no longer drag old calls forward is therefore not true at the system level; the change only prevents persistence in the Antigravity-specific cache.

Please add an integration test through the generic parser/cache covering:

  1. first parse;
  2. cache hit;
  3. DB mtime rewrite;
  4. today / date-range behavior.

Existing deduplication keys must retain a real or stable timestamp across rewrites. Before falling back to mtime, please decode chatModel.#9.#4 (ChatStartMetadata.created_at) when present; for rows without it, use a stable per-session/per-dedup fallback rather than the current file mtime.

The PR description is also still stale: it says this change adds APPDATA / state.vscdb discovery, while the current diff explicitly removes that path. Please update the description as well.

@iamtoruk iamtoruk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the mtime-fallback fix itself is correct. We traced it: SQLite gen_metadata calls are built with an empty timestamp (src/providers/antigravity.ts:732) and the query-time range filter in src/parser.ts drops every turn whose first call has one, which is exactly the 0 calls / 0 cost symptom. Stamping at emission fixes that, real timestamps are untouched, and the PROVIDER_PARSE_VERSIONS bump is required and present. The regression test would fail on the old code, which is what we want.

Two things before this can merge, both about the PR text rather than the code:

  1. The description does not match the diff. The title says tighten path classification and the body describes %APPDATA% scanning and refining antigravityAppDataDirFromSourcePath(), but none of that is in the diff and that function is unchanged. The body also names the helper stampFallbackTimestamp() while the code has withFallbackTimestamp, and says CACHE_VERSION goes to 4 while the code sets 5. Please rewrite the description to describe the actual change.

  2. Resolves #411 is overstated. The issue reports that IDE usage lands only under %APPDATA% and the .gemini files were not updated during IDE use. This PR adds no new read location, so for that exact scenario nothing new is discovered. It does fix the dropped-untimestamped-usage case, which is real and worth landing. Please change the closing keyword to something like partially addresses #411 so the issue stays open.

One optional nit: all untimestamped calls in a file collapse to that file's single mtime, so a multi-day db attributes them to one day. The code comment acknowledges this; fine as best-available, just worth keeping in the description too.

Extract ChatStartMetadata.created_at from proto-encoded data and decode multiple timestamp formats (ISO string, Timestamp submessage, unix varint). Implement assignStableTimestamps() to preserve first-seen timestamps across file rewrites, preventing retro-dating of sessions when .db files are modified. Make conversation roots dynamic (computed per call) to honor environment overrides in tests. Add comprehensive timestamp stability tests verifying that timestamps remain fixed across file mtime changes while respecting date-range filters.
Adds a test case to verify that the 'today' date range filter correctly excludes sessions based on their first-seen timestamp, not file modification time. This ensures that even if a database file is rewritten with a later mtime, sessions with earlier first-seen dates are properly filtered out.

Refs getagentseal#411
@Battiatus

Copy link
Copy Markdown
Contributor Author

Thanks — points 2 and 3 are fixed, but point 4 is still merge-blocking.

withFallbackTimestamp() avoids mutating the Antigravity-specific cache, but the emitted copy is persisted by the generic session-cache.json path in parser.ts. I reproduced this at head e7f5659: parsing the same SQLite DB with mtime 2026-01-02T03:04:05Z persisted that timestamp; after changing only the DB mtime to 2026-06-07T08:09:10Z, the same historical call with the same deduplication key was emitted and persisted as June 7.

On a source fingerprint change, parser.ts clears and reparses the non-durable source, so every historical row without a timestamp receives the latest file mtime again. The statement that a later file rewrite can no longer drag old calls forward is therefore not true at the system level; the change only prevents persistence in the Antigravity-specific cache.

Please add an integration test through the generic parser/cache covering:

  1. first parse;
  2. cache hit;
  3. DB mtime rewrite;
  4. today / date-range behavior.

Existing deduplication keys must retain a real or stable timestamp across rewrites. Before falling back to mtime, please decode chatModel.#9.#4 (ChatStartMetadata.created_at) when present; for rows without it, use a stable per-session/per-dedup fallback rather than the current file mtime.

The PR description is also still stale: it says this change adds APPDATA / state.vscdb discovery, while the current diff explicitly removes that path. Please update the description as well.

You’re right — the mtime fallback was still landing in session-cache on reparse. Fixed with created_at when present, a stable first-seen stamp per dedup key, and an integration test covering parse / cache hit / mtime rewrite / today+range. Description updated too.

@Battiatus

Copy link
Copy Markdown
Contributor Author

Thanks, the mtime-fallback fix itself is correct. We traced it: SQLite gen_metadata calls are built with an empty timestamp (src/providers/antigravity.ts:732) and the query-time range filter in src/parser.ts drops every turn whose first call has one, which is exactly the 0 calls / 0 cost symptom. Stamping at emission fixes that, real timestamps are untouched, and the PROVIDER_PARSE_VERSIONS bump is required and present. The regression test would fail on the old code, which is what we want.

Two things before this can merge, both about the PR text rather than the code:

  1. The description does not match the diff. The title says tighten path classification and the body describes %APPDATA% scanning and refining antigravityAppDataDirFromSourcePath(), but none of that is in the diff and that function is unchanged. The body also names the helper stampFallbackTimestamp() while the code has withFallbackTimestamp, and says CACHE_VERSION goes to 4 while the code sets 5. Please rewrite the description to describe the actual change.
  2. Resolves Detect Google Antigravity IDE usage #411 is overstated. The issue reports that IDE usage lands only under %APPDATA% and the .gemini files were not updated during IDE use. This PR adds no new read location, so for that exact scenario nothing new is discovered. It does fix the dropped-untimestamped-usage case, which is real and worth landing. Please change the closing keyword to something like partially addresses Detect Google Antigravity IDE usage #411 so the issue stays open.

One optional nit: all untimestamped calls in a file collapse to that file's single mtime, so a multi-day db attributes them to one day. The code comment acknowledges this; fine as best-available, just worth keeping in the description too.

I rewrote the description to match the real change, and switched #411 to partially addresses so the issue stays open for pure APPDATA discovery. Multi-day → single first-seen mtime is noted as best-available.

@iamtoruk iamtoruk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the update in depth: the created_at decode and the first-seen stability logic are both pinned by tests that fail when either is broken, the integration test reproduces the exact mtime-rewrite scenario from the review, full suite is green on top of current main, and the description now matches the diff with the closing keyword correctly downgraded. Nice work turning two rounds of review into a better design.

@iamtoruk
iamtoruk merged commit 68ad0be into getagentseal:main Jul 16, 2026
3 checks passed
@iamtoruk

Copy link
Copy Markdown
Member

Merged, thank you. The untimestamped SQLite usage now survives date-range filters and stays put when only the .db mtime changes, with the created_at decode picking up real times where the data has them. Appreciate you working through both review rounds, the first-seen design that came out of it is better than what either round started with. Ships in the next release.

@ozymandiashh

Copy link
Copy Markdown
Collaborator

Yep, GG buddy

@Battiatus

Copy link
Copy Markdown
Contributor Author

Thanks for re-verifying end-to-end. The session-cache mtime drift was the part that needed the second design pass; glad the tests, main, and description all line up now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants