Skip to content

Port upstream 0.65.0: explain Antigravity offline fallback (stacked on #610) - #672

Draft
Finesssee wants to merge 4 commits into
codex/integrate-reviewed-ports-20260923from
port/micro-0.65.0-antigravity-offline-reason
Draft

Finesssee wants to merge 4 commits into
codex/integrate-reviewed-ports-20260923from
port/micro-0.65.0-antigravity-offline-reason

Conversation

@Finesssee

@Finesssee Finesssee commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

When live Antigravity usage fails and the offline conversation-history snapshot is returned instead, the result carries one fixed-text display-detail row ("Live usage") that says why:

Live Antigravity usage is unavailable; showing offline data. <reason>

The reason is a typed LiveFailureReason chosen where the failure happens (antigravity/offline_reason.rs). No error message, response body, URL, local path or stderr is ever read for it:

Live failure Reason text
No language server and no agy found "Antigravity is not running and the signed-in agy CLI was not found." (the existing Windows not-running text)
Timeout (local request or agy run) "Antigravity quota request timed out."
Desktop language server answered HTTP 401/403 "Antigravity session expired. Restart Antigravity and retry."
Language server answered another non-success status "the usage request failed (HTTP nnn)"
Language server refused the connection "Could not connect to the server."
agy -p /usage could not start "Antigravity CLI usage report failed: agy executable not found" or "... agy failed to launch"
agy -p /usage exited non-zero "Antigravity CLI usage report failed: agy exited N", plus "; a network request failed (check network or proxy settings)", "; the eligibility check failed on a network request (check network or proxy settings)" or "; the account is not eligible for Antigravity"
Parse, port detection, anything else "check Diagnostics for per-source details"
Signed out (AuthRequired) no row: stays terminal and is never masked by offline history (unchanged Windows policy)

agy failures: cli_fallback.rs now captures stderr through the same bounded reader as stdout (1 MiB cap per stream, drained concurrently with the exit wait). stderr is only matched against upstream's fixed markers in the new cli_print_failure.rs (a port of AntigravityCLIPrintFailure). It is never logged, stored or displayed. A login prompt or sign-in marker maps to AuthRequired. As in upstream SubprocessRunner, oversized output on either stream is rejected before the exit status is considered.

A successful live fetch carries no row. The row renders through the existing displayDetails path (tray panel card, provider settings usage section and codexbar usage CLI output), so no frontend change is needed.

Upstream reference

  • CodexBar v0.65.0 release bullet: "Antigravity: explain failed live fetches when falling back to offline history, keep diagnostics free of raw process and account details, and show the active source in settings instead of misleading detection warnings" (fix(antigravity): explain offline fallback and source status steipete/CodexBar#3865, fixes Antigravity: agy profile-picture download failure hides quotas behind Offline / not detected steipete/CodexBar#3861; f28ddcaf3).
  • Tag-pinned (v0.65.0): Sources/CodexBarCore/Providers/Antigravity/AntigravityProviderDescriptor.swift (AntigravityOfflineFetchStrategy.diagnostic(forPriorFailure:), reason(for:)), AntigravityCLIPrintFailure.swift, AntigravityStatusProbe.swift (cliReportFailed, timedOut, apiError descriptions), Host/Process/SubprocessRunner.swift (output limit before exit status), ProviderFetchPlan.swift (resolveFallbackError).
  • Tests translated from Tests/CodexBarTests/AntigravityCLIUsageReportTests.swift: the four stderr cases (eligibility plus network, not eligible, signed out, network) with Windows .cmd fixtures that print upstream's stderr samples, the unrecognized-stderr case, and the "print failure does not expose stderr" case.
  • The settings-source half (show the recorded source label, no process-presence Version row) already holds on Windows: ProvidersTab.tsx::providerSidebarSubtitle shows the snapshot's source label and no provider has a Version row.

Interplay with #615 (Antigravity CLI override safety)

#615 makes an unusable ANTIGRAVITY_CLI_PATH fail closed with ProviderError::NotInstalled("ANTIGRAVITY_CLI_PATH is set but does not point to a usable agy file: <path> ..."). This PR only derives reasons from typed constructors, so that error reduces to the fixed hint "check Diagnostics for per-source details" and the local path never reaches the card. With both merged, #615's managed-branch failure = Some(error) needs failure = Some(error.into()) because the fallback failure is now a LiveFailure; the ? in try_print_usage_fallback converts on its own. That adaptation belongs on #615's branch when it is brought onto this stack.

Ported / Deferred

Ported:

  • The offline diagnostic (diagnostic(forPriorFailure:), reason(for:)) for every failure category Windows can produce: not running, timeout, HTTP 401/403 (session expired), other HTTP status, refused connection (upstream shows URLError(.cannotConnectToHost) text for transport failures), classified CLI failure, and the fixed hint for everything else.
  • AntigravityCLIPrintFailure: executable not found, launch failed, exited <code> with network, eligibility-network and not-eligible reasons, sign-in detection (upstream's login prompts and sign-in markers).
  • Fallback precedence matching resolveFallbackError: a CLI fallback that is unavailable (no agy) keeps the earlier local failure; a failed CLI run replaces it.

Deferred or not applicable:

  • Account-mismatch reason: Windows has no selected Antigravity account (no token accounts or OAuth strategy for this provider), so the mismatch cannot occur.
  • AntigravityRemoteFetchError reasons: the remote/OAuth strategy is not ported (oauth returns UnsupportedSource).
  • Signed-out CLI: upstream's CLI strategy falls through to offline with "Antigravity CLI is signed out. Run agy in a terminal to sign in, then retry."; Windows keeps its existing policy that AuthRequired is terminal and surfaces the sign-in error instead of offline data.
  • Managed agy readiness timeout: still an untyped error (generic hint). It is only reachable when the CLI fallback with the same binary also fails, and that later failure replaces it.
  • A distinct reason for an unusable ANTIGRAVITY_CLI_PATH (see Port Antigravity CLI override safety #615 above); it shows the generic hint.
  • Cancellation: a cancelled fetch drops the future, so no diagnostic is produced for it.
  • Upstream's docs/antigravity.md paragraph: Windows docs have no Antigravity provider page (docs/PROVIDERS.md has no Antigravity section), so no doc was added.
  • A Rust test for the "no failure recorded" branch through resolve_runtime_fallback_with_offline: that path runs the Windows managed-agy lookup against the real machine. The branch's output (LiveFailure::not_running()) is covered by the typed-failure table.

Validation

Toolchain 1.98.0, build gate (4 jobs, E-cores).

New tests: cli_print_failure.rs (fixed descriptions match upstream, the upstream stderr table, blank/unrecognized stderr, login prompts and sign-in markers, non-ASCII bytes around a prompt, word boundaries for network markers, spawn errors, stderr never retained); cli_fallback.rs (oversized stdout or stderr rejected before the exit status, success ignores stderr, Windows .cmd fixtures for each upstream stderr case plus signed out, missing agy.exe); offline_reason_tests.rs (row text per failure, HTTP body never echoed, HTTP failure without history keeps the original error, masked CLI failure explained, unavailable CLI keeps the local reason, real loopback timeout and refused connection classified without the URL, leak table, AuthRequired adds no row, live success adds no row). mod.rs stays at 994 lines; the offline tests moved out of tests.rs (805 lines).

Affected areas

  • Provider (Antigravity, rust/src/providers/antigravity/)
  • UI surface (existing display-detail row on the tray panel card and settings usage section; no frontend code changed)
  • Settings schema / migration
  • Tray / float bar
  • Dependencies (none added)

UI proof

browser-use proof at 3444791: #672 (comment) (A0-A6 PASS).

  • Eligibility stderr: tray panel overview and Settings > Providers > Antigravity each show exactly one "Live usage" row with the fixed eligibility text; no stderr, URL or path reaches the DOM.
  • Missing agy: the row carries the generic "check Diagnostics for per-source details" hint.
  • Signed out (negative control): "Authentication required", with no offline line and no row.
  • The proof machine runs a real Antigravity, so the app ran with a reduced PATH that keeps the language-server scan from starting; the kit exe made no outbound connection.
  • Not covered in the UI: the not-running, timeout, session-expired, HTTP-status and cannot-connect reasons (blocked by that isolation; covered by the Rust tests above) and the native tray (browser-use per maintainer).

The earlier CUA proof at 093031c (not-running reason) is superseded.

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Thermo-nuclear review

Scope: rust/src/providers/antigravity/{mod.rs,offline_reason.rs,tests.rs} against the antigravity-offline-reason spec (0.65.0 audit) and AGENTS.md.

Spec conformance: matches. Reason text comes only from the typed variant (NotInstalled -> existing fixed message, Timeout -> "the quota request timed out", everything else -> the Diagnostics hint); the error payload is never read; AuthRequired stays terminal in resolve_probe_failure; a successful live/CLI fallback returns before any detail is attached; the detail id/title/length go through ProviderDisplayDetail::new. The new module is provider-local, the tests cover each class, the leak case (email, URL, path, HTTP text), auth-required and live-success.

Findings

  1. Simplification (fixing): resolve_runtime_fallback_with_offline ends in a match failure with two arms that both call resolve_probe_failure (one with a synthesized NotInstalled). This is one call with a defaulted error: failure.unwrap_or_else(|| NotInstalled(AGY_NOT_FOUND_MESSAGE)).
  2. Watch item, no change: antigravity/mod.rs is 996 lines (985 on the base). The PR stays under 1000, but any follow-up here (for example the optional agy print-usage exit classification) must land in a sibling module, not in mod.rs.
  3. Acknowledged, no change: the AuthRequired => None arm in offline_reason::live_unavailable_detail is unreachable through resolve_probe_failure (which returns first). It is kept as a deliberate, unit-tested guard so the function is safe on its own; the guard is one line.
  4. Deferred by spec (not a defect): the managed-agy readiness timeout is a ProviderError::Other, so it shows the generic hint rather than "timed out". The spec maps only the typed Timeout to the timeout wording; reclassifying that error would change unrelated behavior. The stderr-based print-failure classification remains a later step.

No blocking structural issues. Fixing item 1 in a follow-up commit.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Thermo-nuclear review follow-up

Reviewed by Codex gpt-6-luna (xhigh); verified and validated by Claude.

Fixed: item 1 (collapsed the two resolve_probe_failure arms in resolve_runtime_fallback_with_offline into one call with failure.unwrap_or_else(|| NotInstalled(AGY_NOT_FOUND_MESSAGE))). mod.rs is now 992 lines.

Left as is: items 2 (watch item), 3 (deliberate tested guard) and 4 (deferred by spec). Codex found no other valid findings.

Commands run: cargo +1.98.0 fmt --all, cargo +1.98.0 clippy -p codexbar --all-targets -- -D warnings (clean), cargo +1.98.0 test -p codexbar antigravity (131 passed). No user-visible change.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

CUA proof (rerun)

Build commit: 093031c (PR head at capture time, verified via gh pr view). Debug build via pnpm run tauri:build:debug, not rebuilt for this run.

Proof-only patches (uncommitted, not part of the PR): root Cargo.toml [patch.crates-io] dirs shim redirecting home/config dirs to CODEXBAR_PROOF_HOME, plus the matching Cargo.lock dirs source/checksum lines. No source files patched, no seed, no mock server. Real AntigravityProvider::fetch_usage path with no agy binary and 3 empty proof conversation .db files.

Commands: bash launch.sh trayPanel; bash launch.sh popOut; negative control (conversations folder renamed) with bash launch.sh popOut; driven with cua-driver.exe serve / call list_windows / call get_window_state --screenshot-out-file.

# Assertion Result
0 No real email/account/personal data visible PASS
1 Offline usage line "Offline · 3 conversations", source "offline" PASS
2 One "Live usage" row: "Live Antigravity usage is unavailable; showing offline data. Antigravity is not running and the signed-in agy CLI was not found." PASS
3 Row has no path, URL, e-mail or raw error string PASS
4 No error banner replaces the card PASS
5 Dark theme under auto; no overflow or clipped text in tray panel PASS
6 Negative control: only plain "Provider not installed: ..." error, no "Live usage" row PASS

Screenshots (local, not committed): C:\Users\FSOS\AppData\Local\Win-CodexBar\port-audit\proof\672\shots\01-traypanel.png, C:\Users\FSOS\AppData\Local\Win-CodexBar\port-audit\proof\672\shots\02-popout.png, C:\Users\FSOS\AppData\Local\Win-CodexBar\port-audit\proof\672\shots\03-negative-control.png
Timeout and generic-hint variants are not reachable via this kit and remain covered by unit tests.

Port the rest of upstream CodexBar v0.65.0 steipete#3865: failed agy print-usage
runs are classified into fixed text (signed out, eligibility, network,
exit code, missing or unlaunchable executable) from captured stderr that
is never logged or displayed, and local language-server failures keep
their HTTP status, session-expired, timeout or connection category for
the offline "Live usage" row. Oversized output on either stream is
rejected before the exit status, like upstream SubprocessRunner.
@Finesssee

Copy link
Copy Markdown
Collaborator Author

Lane A review: fixes at 3444791

Reviewed the whole branch against its base (codex/integrate-reviewed-ports-20260923 at 15f1091) and against upstream v0.65.0 (steipete#3865, tag-pinned sources and the PR diff).

Defects found at 093031c

  • Upstream's AntigravityCLIPrintFailure was missing. A failed agy -p /usage run on Windows showed the generic hint (or "the quota request timed out" for timeouts), where upstream explains signed-out, eligibility, network and exit-code failures.
  • HTTP failures from the language server were reduced to the generic hint. Upstream shows "Antigravity session expired. Restart Antigravity and retry." for 401/403 and "the usage request failed (HTTP nnn)" for other statuses.
  • Any NotInstalled error, including "Failed to detect Antigravity process" (PowerShell failed) and "agy exited before its local quota service was ready", was explained as "Antigravity is not running and the signed-in agy CLI was not found." Only the genuine not-running case says that now; other probe failures get the fixed Diagnostics hint, as upstream portDetectionFailed does.
  • The timeout text did not match upstream: "the quota request timed out" is now "Antigravity quota request timed out." (upstream timedOut).
  • Oversized output was only checked on stdout. Upstream SubprocessRunner rejects oversized stdout or stderr before looking at the exit status.

What changed (merge of the base at 15f1091, then one commit)

  • New antigravity/cli_print_failure.rs: port of AntigravityCLIPrintFailure (fixed descriptions, upstream login prompts, sign-in, eligibility and network markers, with word boundaries). stderr is captured through the bounded reader only to classify the failure. It is never logged, stored or displayed.
  • offline_reason.rs: a typed LiveFailure (error plus LiveFailureReason) is built where each failure happens: not running, timed out, session expired, HTTP status, refused connection, CLI report, or unclassified. The reason text never reads an error message.
  • cli_fallback.rs: stdout and stderr are read concurrently with the exit wait (1 MiB cap each), and oversized output is checked before the exit status. A signed-out agy stays AuthRequired (terminal, never hidden behind offline data).
  • mod.rs threads LiveFailure through the local probe and fallback chain: 994 lines, no new logic in shared paths.
  • The offline tests moved to offline_reason_tests.rs so tests.rs stays under 1000 lines (805).
  • The PR body is updated: Ported/Deferred, the Port Antigravity CLI override safety #615 interplay (Port Antigravity CLI override safety #615 needs failure = Some(error.into()) once stacked on this), and the upstream divergence for a signed-out CLI.

Commands and results (toolchain 1.98.0, run in the lane-a worktree through the build gate)

  • cargo +1.98.0 fmt --all --check: clean
  • cargo +1.98.0 clippy --workspace --all-targets -- -D warnings: pass
  • cargo +1.98.0 test -p codexbar --lib antigravity: 153 passed, 0 failed
  • cargo +1.98.0 test -p codexbar: 2262 passed, 0 failed, 1 ignored
  • cargo +1.98.0 test -p codexbar-desktop-tauri: 477 passed, 1 failed: bootstrap_payload_exposes_every_provider_variant. This is the known catalog-size drift (Isolate bootstrap payload test from real settings #684, fixed by Make the bootstrap catalog test hermetic (#684) #711); the same failure is on the base, and this PR does not touch the provider catalog.

No frontend, locale or bridge change. No new dependencies. Pushed as a fast-forward (093031c..3444791). A browser-use UI proof at this head follows.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

UI proof (browser-use)

Head: 3444791. Built from that commit with pnpm install --frozen-lockfile and pnpm run tauri:build:debug. The only proof-only patch was the throwaway dirs shim in the root Cargo.toml (plus the Cargo.lock change it causes). It was restored right after the build and never committed. There are no source patches.

Setup

  • Isolated kit home: CODEXBAR_PROOF_HOME, USERPROFILE, HOME, APPDATA, LOCALAPPDATA and TEMP all point into the kit. CODEX_HOME, CLAUDE_CONFIG_DIR and GEMINI_HOME point at empty kit folders, and the API-key and proxy variables are unset.
  • Settings: Antigravity only, theme auto.
  • Offline history: 3 empty .db files in the kit's .gemini\antigravity-cli\conversations\. Only the file names are counted.
  • The real fetch path runs, with no seeded snapshot. The live probe fails, and the CLI fallback runs a fake agy (agy.cmd, named by ANTIGRAVITY_CLI_PATH). The fake prints 1.2.2 for --version. For the usage report it writes the scenario's stderr and exits 1.
  • Isolation from the real Antigravity on the proof machine: the app is launched with PATH reduced to C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem. The machine-wide language-server scan (powershell.exe, resolved through PATH) therefore cannot start. The managed agy runtime is skipped because the local probe did not report a clean "not running".
    • Checked on the three tray-panel launches (one per scenario): the kit exe's only child was msedgewebview2.exe, it had no powershell.exe child, and it held no outbound TCP connection. The settings launch used the same launch.sh.
    • The real language server's ports were never contacted.
  • Driven over WebView2 CDP on port 9351, which was owned by the kit exe on every launch. Proof modes: CODEXBAR_PROOF_MODE=trayPanel and settings:providers.
# Scenario Assertion Result
A0 all No email or account text in the DOM (checked before each screenshot) PASS
A1 all Theme auto resolves dark: prefers-color-scheme: dark, data-theme dark, body rgb(28, 28, 30) PASS
A2 eligibility: stderr Eligibility check failed: failed to get profile picture: Get "https://lh3.googleusercontent.com/a/proof-private": EOF The Antigravity card shows Offline · 3 conversations and exactly one row in the overview: Live usage: Live Antigravity usage is unavailable; showing offline data. Antigravity CLI usage report failed: agy exited 1; the eligibility check failed on a network request (check network or proxy settings) PASS
A3 eligibility, no-cli, signed-out No stderr, URL, path or raw error text anywhere in the DOM (proof-private, googleusercontent, lh3., http://, https://, EOF, C:\, PowerShell, stderr). Checked in the overview, the selected-provider view and settings. PASS
A4 eligibility Settings > Providers > Antigravity > Usage shows the same row under Offline · 3 conversations PASS
A5 no-cli: ANTIGRAVITY_CLI_PATH names a missing file Exactly one row in the overview: Live usage: Live Antigravity usage is unavailable; showing offline data. check Diagnostics for per-source details. This is upstream's generic text, lowercase check as in upstream. The failed scan's error text never shows. PASS
A6 signed-out: stderr You are not logged into Antigravity (negative control) The card shows Authentication required. There is no offline line and no Live usage row in the overview or the selected-provider view. PASS

Screenshots are kept locally in the proof kit (port-audit\proof\672\shots\). They show fixture data only:

  • 01-eligibility-traypanel-overview.png
  • 02-eligibility-traypanel-selected.png
  • 03-eligibility-settings-providers.png
  • 01-no-cli-traypanel-overview.png
  • 02-no-cli-traypanel-selected.png
  • 04-signed-out-traypanel-overview.png
  • 05-signed-out-traypanel-selected.png

Seen but not caused by this PR (unchanged here)

Not covered in the UI

  • The not-running, timeout, session-expired, HTTP-status and cannot-connect reasons. Reaching them needs a working language-server scan, and the isolation above blocks that on purpose while a real Antigravity runs on this machine. The Rust tests listed in the PR body cover their text and selection, including a real loopback timeout and a refused connection.
  • Native tray icon and menu: not covered (native, browser-use per maintainer).

The PR stays a draft for the maintainer.

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.

1 participant