Skip to content

fix(rate-limits): a failed shared-quota read is an Antigravity error, not an absent reading - #17200

Open
brennanb2025 wants to merge 3 commits into
mainfrom
brennanb2025/antigravity-failed-quota-read-is-an-error
Open

brennanb2025 wants to merge 3 commits into
mainfrom
brennanb2025/antigravity-failed-quota-read-is-an-error

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​70 $\color{#cf222e}{\Huge{\mathbf{−}}}$​9 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​61
Prod 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​22 $\color{#cf222e}{\Huge{\mathbf{−}}}$​13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​9

Adjudication: the unreadable-response rule vs. the reverted Antigravity judgement

A stated rule (unreadable-usage-response.ts, on #17193) and a documented prior decision (#15876)
disagreed about the Antigravity usage mirror. This PR settles it. Outcome: the prior decision was
made under an assumption that no longer holds.
It is changed deliberately; its tests are updated
in place, not deleted; and the reasoning is written into the file the next person meets.

The previous author's reasoning (#15876, 636f428c25)

Before #15876 the mirror was {...gemini, provider: 'antigravity'}. On a Gemini failure the
Antigravity row said "Refresh failed" and quoted Gemini's raw error (Gemini project ID not found) — for a request Orca never sent, since Antigravity's token lives in the OS keyring and Orca
has no Antigravity endpoint. #15876 gave the row two Antigravity-owned reason strings and settled it
unavailable, pinned by service-antigravity-usage.test.ts — "never leaves a cached Antigravity
snapshot in the error retry lane / Why: stale-retention would otherwise show Gemini numbers as
'Refresh failed' Antigravity usage."

That reasoning is about wording and blame, and it is sound. It is preserved here in full.

The assumption that no longer holds

unavailable was picked as a label choice. It is a retention verdict: applyStalePolicy
discards on unavailable and retains on error. Driven on a1f198be0d, one Gemini failure:

AFTER GOOD  gemini= {"s":"ok","sess":42}       antigrav= {"s":"ok","sess":42}
AFTER FAIL  gemini= {"s":"error","sess":42}    antigrav= {"s":"unavailable"}   ← 42% destroyed

The same read backs both rows. #15876's own second test blesses a successful Gemini read as
Antigravity's reading — so that read cannot be Antigravity's when it succeeds and nobody's when it
fails. That is exactly the shape the rule names: a failed read reclassified as an absent one.

The asymmetry, and why it now has a stated reason

It no longer exists on a failed read — both rows retain, both settle error. It is retained,
with a reason, for the other Gemini verdict: unavailable (opt-in off) still maps to unavailable
on both, because nothing was read. Driven post-fix:

FAILREAD gemini= {"s":"error","u":42}          antig= {"s":"error","u":42}  + Antigravity wording
OPTOFF   gemini= {"s":"unavailable"}           antig= {"s":"unavailable"}   + Antigravity wording

On the second harm — the hidden status surface

Driven, and it does not apply to Antigravity, uniquely: isProviderConfigured returns false for
unavailable, but getVisibleUsageProvider re-renders the row from the settings signal
(antigravityUsageConfigured && geminiCliOAuthEnabled), which is what makes the row exist at all.
The row survived either way. Only the destroyed-snapshot half was ever real here — reported rather
than overstated.

"Refresh failed" comes back — deliberately

The label is status-derived. With a retained reading it reads "Refresh failed — showing cached
data"
over the Antigravity reason line, which names the shared quota as the thing that failed, so
no Antigravity-specific request is implied. A bespoke provider label (the usage-error-copy.ts
failureKind mechanism, which already existed in Aug 2026) was considered and declined: it
would suppress the more useful "showing cached data" suffix. Stated in the file header.

Verification

Failing-first, 1-to-1: the two new assertions were red on unmodified main before the fix; the two
prior-author status assertions went red only after it, and were then updated in place with their
new reasoning. Ablations run serially, each mutation verified applied and reverted clean, over
src/main/rate-limits + src/renderer/src/components/status-bar (89 files / 741 tests, green):

Ablation Red
A — delete the rule (status back to 'unavailable') 3
B — broaden the predicate to true (all non-ok → error) 2
C — leak gemini.error into the Antigravity reason 5

Both halves are separately load-bearing, and #15876's message protection is still strongly pinned.

Read sites grepped, including the chip: status-bar-provider-visibility.ts, usage-error-copy.ts,
usage-provider-settings-target.ts (Antigravity's CTA points at accounts-gemini, consistent),
StatusBar.tsx. No new fetch churn: deriveAntigravityRateLimits only emits error when Gemini is
error, and Gemini already forces the same non-individually-refreshable fetchAll() lane.

Gates: pnpm tc all projects exit 0 · check:code-quality:changed exit 0 (native + type-aware

  • React Doctor, 0 findings across 3 files) · focused plugin configs with --deny-warnings exit 0
    (oxlint proven non-vacuous with a control violation) · git diff --check clean · formatted with
    npx oxfmt --write <paths>. No suppressions, no max-lines disable.

Scope: nothing here touches #17193. The conclusion is that Antigravity now conforms to the
rule, so the rule file needs no exception — but #17193's note that the rule "contradicts the
reverted antigravity judgement" is now resolved and its owner may want to drop it.

… not an absent reading

Antigravity has no endpoint of its own: the Gemini read of shared Google Code
Assist quota is Antigravity's read, which is why a successful one is mirrored
verbatim. #15876 settled a *failed* one as `unavailable` to stop the row saying
"Refresh failed" for a request Orca never sent. That fixed the wording, but
`unavailable` is a retention verdict, not a label — `applyStalePolicy` discards
on `unavailable` and retains on `error` — so one failure wiped the Antigravity
row while sparing Gemini's, from the same read.

Settle a failed quota read as `error` so both rows keep the last good reading.
A Gemini `unavailable` (opt-in off) still maps to `unavailable`: nothing was
read, which is genuinely absent. #15876's real protections are untouched and
still pinned — the row never quotes Gemini's raw error and never blames a
sign-in that exists, now including while it retains a reading.

The two tests that pinned the old status are updated in place, not deleted.
@greptile-apps

greptile-apps Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

Greptile Summary

The PR distinguishes malformed Gemini credentials and failed shared-quota reads from genuinely absent credentials, allowing Gemini and Antigravity to retain their last successful quota readings consistently.

  • Classifies a failed shared-quota read as an Antigravity error while preserving Antigravity-specific error wording.
  • Treats a present but malformed Gemini OAuth credential file as a read error rather than a signed-out state.
  • Updates focused tests for stale-reading retention, missing credentials, malformed credentials, and error-copy isolation.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/main/rate-limits/antigravity-usage-mirror.ts Reclassifies failed shared-quota reads as Antigravity errors while keeping absent-sign-in handling unavailable and preserving provider-specific wording.
src/main/rate-limits/gemini-oauth-sources.ts Throws for a present but structurally invalid OAuth credential file while continuing to treat a missing file as absent.
src/main/rate-limits/service.ts Integrates the revised Antigravity mirror semantics into the existing shared refresh and stale-retention flow.
src/main/rate-limits/service-antigravity-usage.test.ts Verifies symmetric stale-reading retention and prevents Gemini’s raw failure text from leaking into Antigravity output.
src/main/rate-limits/gemini-usage-fetcher.fallback.test.ts Distinguishes malformed-present credentials from genuinely missing credentials in fallback behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Read Gemini credentials] --> B{Credentials present and valid?}
  B -->|Missing| C[Gemini unavailable]
  B -->|Malformed| D[Gemini error]
  B -->|Valid| E[Read shared Code Assist quota]
  E -->|Success| F[Gemini and Antigravity OK]
  E -->|Failure| D
  D --> G[Antigravity error with provider-specific reason]
  D --> H[Retain recent Gemini snapshot]
  G --> I[Retain recent Antigravity snapshot]
  C --> J[Gemini and Antigravity unavailable; discard stale readings]
Loading

Reviews (3): Last reviewed commit: "fix(rate-limits): a malformed Gemini oau..." | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 57f34573-02ca-4dd5-849d-e102d7e120cb

📥 Commits

Reviewing files that changed from the base of the PR and between 864600f and a79a76f.

📒 Files selected for processing (6)
  • src/main/rate-limits/antigravity-usage-mirror.test.ts
  • src/main/rate-limits/antigravity-usage-mirror.ts
  • src/main/rate-limits/gemini-oauth-sources.ts
  • src/main/rate-limits/gemini-usage-fetcher.fallback.test.ts
  • src/main/rate-limits/service-antigravity-usage.test.ts
  • src/main/rate-limits/service.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/rate-limits/antigravity-usage-mirror.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

readGeminiCredentials now reports invalid existing credential files as errors and keeps missing files as unavailable. deriveAntigravityRateLimits mirrors Gemini quota read errors as error with an Antigravity-specific reason. Tests verify retained shared-quota readings, matching error status in both rows, and filtered Gemini error text.

Merge Risk: ⚪ Minimal · up to a79a7

Failed shared-quota reads now retain cached data while surfacing an error with provider-specific messaging preserved; the localized change has no actionable merge-blocking risk remaining after normal checks.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description provides detailed context, rationale, testing evidence, linked issue references, and scope. However, it does not follow the repository template structure and omits or leaves unclear re… Update the description to include the required template headings and information. Add an explicit linked issue using Fixes #..., state N/A with a reason for Visual Proof if there is no UI change, complete the testing and checklist items…
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: failed shared-quota reads now produce an Antigravity error instead of an unavailable result.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description provides detailed context, rationale, testing evidence, linked issue references, and scope. However, it does not follow the repository template structure and omits or leaves unclear required items such as an explicit ELI5, What Changed, Why, Linked Issue using Fixes #, Visual Proof with N/A when applicable, checklist confirmations, and the Agent skill upstream boundary section.

Resolution

Update the description to include the required template headings and information. Add an explicit linked issue using Fixes #..., state N/A with a reason for Visual Proof if there is no UI change, complete the testing and checklist items, and address the AI Disclosure, Review, Agent skill upstream boundary, and Notes sections as applicable.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

brennanb2025 and others added 2 commits August 29, 2026 06:30
…lable usage

This lane now retains the last reading, so the tooltip prints the reason above a
live meter; the old wording contradicted the numbers beside it. Also corrects the
service comment that still stated the reversed rule.
…d, not absent

readGeminiCredentials() returned null both when the file was missing and when it
was present but did not match the credential contract. The caller turns null into
status 'unavailable' / "credentials not found", so a corrupt or wrong-typed
oauth_creds.json was reported to the user as signed out — the failed read became
an absent one before the shared-quota rule could see it, and absent takes the
discard path.

Throw on the present-but-invalid case so it reaches the caller's error path, and
keep ENOENT returning null so an actually missing file still reads as absent.
Both sides of that boundary are now pinned.
@nwparker

Copy link
Copy Markdown
Contributor

Migration coordination: #21654 replaces the Gemini-derived Antigravity mirror with the native, version-guarded agy --print /usage --output-format json path. It is a draft, not merged; the mirror in this PR should not be reintroduced when combining the changes.

The underlying retention requirement remains valid for Antigravity's own last successful reading. I checked the current takeover stack and reran all six service-antigravity-usage.test.ts tests: they pass, including a successful Antigravity reading of 18 followed by an agy error retaining 18, independent of Gemini's 42. Changing the configured agy executable deliberately clears the previous executable's reading (#21678).

ELI5: retain the last numbers from Antigravity when its refresh temporarily fails; do not borrow Gemini's numbers. The native migration preserves that distinction.

This is service-level evidence using mocked readings. Actual installed agy 1.2.7 has returned empty quota groups in our live verification, so populated OAuth readings and live stale retention are not yet proven. No merge or closure is requested on that basis.

This branch has not been deployed

No deployments
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.

2 participants