Antigravity: Support root envelope field 2 for token counts - #3266
Conversation
…d CLI cost command - Update AntigravityProtoReader to parse protobuf root envelopes starting with field 2 (turn coordination) and field 4 (step UUID). - Add support for resolving turn timestamps via the steps table (steps.metadata field 1 timestamp and field 12 step UUID) when gen_metadata turns omit embedded field 9 timestamps. - Update AntigravityLocalSQLiteSchema to discover both gen_metadata and steps tables in a single pass of sqlite_master. - Enable supportsCostCommand on Antigravity's ProviderCLIConfig in AntigravityProviderDescriptor. - Add test cases covering root field 2 decoding, steps timestamp joins, and fail-closed validation for unresolvable timestamps.
|
🦞👀 Pull request received. I will update this pull request when review starts. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be9214f72b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| stepProgress.rows += 1 | ||
| let count = Int(sqlite3_column_int64(statement, 1)) | ||
| let attemptedBytes = max(count, payload.byteCount) | ||
| guard stepProgress.rows <= stepProgress.rowLimit, | ||
| attemptedBytes <= stepProgress.byteLimit - stepProgress.bytes |
There was a problem hiding this comment.
Charge step rows against the shared scan budget
When timestamp recovery scans steps, each row and its payload are counted only in StepScanProgress; neither budget.chargeRow() nor budget.chargeBytes() is called. With multiple databases containing missing-timestamp turns, these secondary scans can therefore process far beyond the configured 50,000-row and 128 MiB job-wide limits while statistics.rows and attemptedBytes remain unchanged, defeating the bounded-work guarantees used for hostile or unexpectedly large local databases.
Useful? React with 👍 / 👎.
| while true { | ||
| try budget.check() | ||
| guard sqlite3_step(statement) == SQLITE_ROW else { return false } | ||
| guard sqlite3_step(statement) == SQLITE_ROW else { break } |
There was a problem hiding this comment.
Reject schema scans that terminate with a SQLite error
If sqlite3_step returns SQLITE_CORRUPT, SQLITE_IOERR, or another error after gen_metadata (and possibly steps) has already been observed, this guard treats it identically to SQLITE_DONE and returns the accumulated tables as supported. The reader can then publish rows with complete coverage from a database whose schema scan actually failed; distinguish SQLITE_DONE from all other non-row results and fail closed on the latter.
Useful? React with 👍 / 👎.
|
Codex review: needs changes before merge. Reviewed August 29, 2026, 7:27 AM ET / 11:27 UTC. ClawSweeper reviewWhat this changesThis branch recovers Antigravity token-history timestamps from local SQLite Merge readinessKeep open: the supplied real-session trace now proves the intended recovery path, but the new bounded Priority: P2 Review scores
Verification
How this fits togetherCodexBar reads local Antigravity session databases, decodes usage protobufs, and produces date-bucketed token totals for the app and CLI. Missing timestamps are now resolved by a second lookup in the same database snapshot. flowchart LR
A[Antigravity session database] --> B[Usage-row scan]
B --> C[Protobuf usage parser]
C --> D{Timestamp present}
D -->|Yes| E[Token event]
D -->|No| F[Steps metadata scan]
F --> E
E --> G[Cost totals and CLI output]
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Copy recommended automerge instructionTechnical reviewBest possible solution: Continue scanning within the existing job-wide safety budget until all required UUID occurrences are found or the database is exhausted, and add a regression case with the needed step beyond the former cap. Do we have a high-confidence way to reproduce the issue? Yes (source-reproducible): one pending usage row plus more than 256 preceding unrelated Is this the best way to solve the issue? No: the two-phase recovery design is appropriate, but its arbitrary scan cap must not prevent locating required metadata that remains within the existing global budget. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against ce44713574f9. LabelsLabel justifications:
EvidenceAcceptance criteria:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (1 earlier review cycle)
|
In recent versions of Antigravity, session SQLite databases structure events with outer root envelopes containing:
Unlike earlier layouts where turn timestamps were always embedded in field 9 (
timestamp), newer sessions may omit field 9 fromgen_metadataand instead record the timestamp inside thestepstable (steps. metadataprotobuf: field 1timestamp, field 12stepUUID).Two-Phase Scan Workflow:
gen_metadata):Eventimmediately.stepUUID, it is buffered intopendingTimestampRows.steps):pendingTimestampRowsis non-empty and the database contains thestepstable, the reader queriessteps.metadataonly for the requiredstepUUIDs.stepUUIDto correctly handle multi-turn step reuse across midnight boundaries.steps, the reader setscoverage = .partialand discards un-timestamped events to prevent date skew or ledger corruption.Detailed Changes
1. Protobuf Parser (
Sources/CodexBarCore/Providers/Antigravity/AntigravityProtoReader.swift)parseTurnto process root message field 2 (traversing into turn coordination payload) and field 4 (storingturn.stepUUID).parseStepMetadatato extract(stepUUID: String?, timestampMs: Int64?)fromsteps.metadataprotobuf blobs.parseTimestampFieldinto a reusable sub-parser for variable-length timestamp records.2. SQLite Schema & Query Engine (
Sources/CodexBarCore/Providers/Antigravity/)AntigravityLocalSQLiteSchema.swift: ReplacedhasGenMetadataTablewithsupportedSQLiteTables, queryingsqlite_masterin a single pass to check for bothgen_metadataandsteps.AntigravityLocalSQLite.swift:readStepTimestampshelper to streamstepsrows, extract timestamps for required UUIDs, and enforce memory/byte constraints.appendRecoveredEventshelper to join recovered timestamps with pending turns in first-in-first-out order per UUID.gen_metadatacursor before invoking thestepsscan.3. Provider Descriptor (
Sources/CodexBarCore/Providers/Antigravity/AntigravityProviderDescriptor.swift)supportsCostCommand: trueonProviderCLIConfig.Testing & Verification
Unit Tests Added (
Tests/CodexBarTests/)AntigravityLocalReaderTests.swift:field 2 root envelope with step table timestamps aggregates complete coverage: Validates end-to-end token counting, model breakdown (gemini-3.7-flash), and date attribution via step table timestamps.field 2 root envelope with embedded timestamp in field 9 aggregates complete coverage: Validates fallback to embedded field 9 timestamps when present.field 2 root envelope without timestamp in either gen_metadata or steps fails closed with partial coverage: Ensures unresolvable timestamps mark history coverage incomplete rather than misattributing.field 2 root envelope with reused step UUID consumes step timestamps in order: Validates sequential timestamp assignment when a single step UUID is referenced across midnight day boundaries.AntigravityLocalScanTests.swift:optional steps scan does not exhaust embedded timestamp usage rows: Validates that secondary step scanning respects budget boundaries without dropping legitimate usage records.AntigravityLocalFixture.swift:blobWithRootEnvelope(...)andstepMetadataBlob(...)protobuf generators.stepBlobssupport to fixture database builder.Automated Test Runs
$ sqlite3 ~/.gemini/antigravity-cli/conversations/.db ".tables"
battle_mode_infos parent_references trajectory_metadata_blob
executor_metadata steps
gen_metadata trajectory_meta
37/37 databases expose a steps table; e.g. gen_metadata=145 rows / steps=295 rows
$ codexbar cost --provider antigravity --refresh
Antigravity Cost (API-rate estimate)
Today: — · 162M tokens
Last 30 days: — · 178M tokens
Estimated from local logs · may differ from your bill
$ codexbar cost --provider antigravity --refresh --format json
historyCoverageIsEstablished: true | historyDays: 30
2026-08-27 total= 1,477,948 in= 276,587 out= 0 reasoning= 32,648 cacheRead= 1,168,713 [claude-opus-4-6-thinking]
2026-08-28 total= 14,781,961 in= 2,385,841 out= 25,745 reasoning=143,689 cacheRead= 12,226,686 [gemini-3.7-flash-tiered, claude-opus-4-6-thinking, unknown, gemini-3.7-flash]
2026-08-29 total= 161,748,040 in=10,139,100 out=131,379 reasoning=495,438 cacheRead= 150,982,123 [gemini-3.7-flash, unknown]
$ HOME= codexbar cost --provider antigravity --refresh
Antigravity Cost (API-rate estimate)
Today: —
Last 30 days: —
$ HOME= codexbar cost --provider antigravity --refresh --format json
{"provider":"antigravity","historyCoverageIsEstablished":false,"daily":[],"source":"local", ...}