fix: render one Antigravity lane per quota bucket on the dashboard - #2963
fix: render one Antigravity lane per quota bucket on the dashboard#2963urda wants to merge 1 commit into
Conversation
The dashboard snapshot emitted primary, secondary, and every extra window. Antigravity copies its busiest Gemini and Claude/GPT buckets into primary and secondary so the icon and menu bar have standard slots to read, so the web card repeated two buckets as extra "Gemini Models" and "Claude and GPT" rows: six rows for four windows. Render the quota-summary lanes alone when the snapshot carries them, one row per bucket. Every family stays visible, since the dashboard is a detail surface. Snapshots without summary lanes are unchanged.
|
🦞👀 Pull request received. I will update this pull request when review starts. |
|
Codex review: needs real behavior proof before merge. Reviewed August 15, 2026, 10:51 PM ET / August 16, 2026, 02:51 UTC. ClawSweeper reviewWhat this changesThe PR makes Antigravity dashboard snapshots emit only real quota-summary buckets instead of also emitting copied primary and secondary representative windows. Merge readiness⛔ Blocked until real behavior proof from a real setup is added - 6 items remain Keep open: the duplicate-row bug is source-backed, but the patch changes the documented dashboard-v1 window contract without a compatibility path and needs real after-fix behavior proof. Priority: P2 Review scores
Verification
How this fits togetherThe Antigravity probe turns provider quota buckets into a shared usage snapshot used by compact app surfaces and dashboard consumers. The dashboard builder serializes that snapshot for both flowchart LR
A[Antigravity quota summary] --> B[Status probe]
B --> C[Usage snapshot]
C --> D[Dashboard snapshot builder]
D --> E[CLI dashboard JSON]
D --> F[HTTP dashboard API]
C --> G[Menu and widget]
Decision needed
Why: The documented v1 API is shared by the one-shot CLI and HTTP consumers, so accepting a removed window kind requires an explicit compatibility decision. Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Expose the bucket-only representation through an explicitly versioned dashboard contract, preserving v1 output for existing clients and updating the built-in dashboard to consume the new shape. Do we have a high-confidence way to reproduce the issue? Yes—current main directly constructs copied primary and secondary representatives alongside named quota-summary buckets, while the existing dashboard builder serializes both. Is this the best way to solve the issue? Unclear—the deduplication is appropriate for a detail view, but changing the documented v1 API without a versioned migration is not yet the safest solution. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f6daa60e8f88. LabelsLabel changes:
Label justifications:
EvidenceWhat 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
|
…n-zero history, Antigravity dashboard lanes, Claude OAuth revoked detection steipete#2946 Codex routed models pricing — codex_routed_provider() + strip_route_prefix() in cost_pricing.rs; deepseek/, kimi/, opencode/ routes price against matching models.dev provider; unknown provider/ prefixes return None. steipete#2944 Codex auth.json read-only during refresh — codex_external_oauth_sources_allowed setting (default OFF); is_external_oauth + last_refresh fields on CodexCredentials; enforce_external_oauth_gate (8-day staleness window). steipete#2932 Codex known-zero history — known_zero field on CostSummary; set in both cache-debounce and full-scan paths (history_coverage_established && sessions_count == 0); knownZero JSON field + CLI text update. steipete#2963 Antigravity dashboard lanes — quota-bucket dedup in parse_user_status; models sharing the same (remaining_fraction, reset_time) collapse to one lane. steipete#2516 Claude revoked vs missing OAuth — ProviderError::OAuthRevoked variant; revocation detection (401/403 with revoked/invalid_grant/token_revoked); 15-min CLI result cache (LazyLock<Mutex<Option<CachedCliResult>>>); fetch_via_auto returns cached CLI result when OAuth revoked, and stale cache when all live sources fail.
…n-zero history, Antigravity dashboard lanes, Claude OAuth revoked detection steipete#2946 Codex routed models pricing — codex_routed_provider() + strip_route_prefix() in cost_pricing.rs; deepseek/, kimi/, opencode/ routes price against matching models.dev provider; unknown provider/ prefixes return None. steipete#2944 Codex auth.json read-only during refresh — codex_external_oauth_sources_allowed setting (default OFF); is_external_oauth + last_refresh fields on CodexCredentials; enforce_external_oauth_gate (8-day staleness window). steipete#2932 Codex known-zero history — known_zero field on CostSummary; set in both cache-debounce and full-scan paths (history_coverage_established && sessions_count == 0); knownZero JSON field + CLI text update. steipete#2963 Antigravity dashboard lanes — quota-bucket dedup in parse_user_status; models sharing the same (remaining_fraction, reset_time) collapse to one lane. steipete#2516 Claude revoked vs missing OAuth — ProviderError::OAuthRevoked variant; revocation detection (401/403 with revoked/invalid_grant/token_revoked); 15-min CLI result cache (LazyLock<Mutex<Option<CachedCliResult>>>); fetch_via_auto returns cached CLI result when OAuth revoked, and stale cache when all live sources fail.
* Port upstream 0.50.1: Cursor rename + Ollama cookie stripping (steipete#2951, steipete#2949) * Port upstream 0.50.1: OpenCode Go session+weekly pace in CLI (steipete#2957) * Port upstream 0.50.1: chart axis label centering (steipete#2974) * Port upstream 0.50.1: Kiro re-authenticate via kiro-cli login (steipete#2340) * Port upstream 0.50.1: serve identity follows app redaction per-request (steipete#2960) * Port upstream 0.50.1: Codex routed pricing, auth.json read-only, known-zero history, Antigravity dashboard lanes, Claude OAuth revoked detection steipete#2946 Codex routed models pricing — codex_routed_provider() + strip_route_prefix() in cost_pricing.rs; deepseek/, kimi/, opencode/ routes price against matching models.dev provider; unknown provider/ prefixes return None. steipete#2944 Codex auth.json read-only during refresh — codex_external_oauth_sources_allowed setting (default OFF); is_external_oauth + last_refresh fields on CodexCredentials; enforce_external_oauth_gate (8-day staleness window). steipete#2932 Codex known-zero history — known_zero field on CostSummary; set in both cache-debounce and full-scan paths (history_coverage_established && sessions_count == 0); knownZero JSON field + CLI text update. steipete#2963 Antigravity dashboard lanes — quota-bucket dedup in parse_user_status; models sharing the same (remaining_fraction, reset_time) collapse to one lane. steipete#2516 Claude revoked vs missing OAuth — ProviderError::OAuthRevoked variant; revocation detection (401/403 with revoked/invalid_grant/token_revoked); 15-min CLI result cache (LazyLock<Mutex<Option<CachedCliResult>>>); fetch_via_auto returns cached CLI result when OAuth revoked, and stale cache when all live sources fail. * Port upstream 0.50.1: Mistral PAYG spend, cost-summary display style, per-provider accent color Item 1 — Mistral PAYG current-month API spend (steipete#2821, steipete#2947): - Add MonthlyPlan variant to MetricPreference enum - Add currency_symbol field to CostSnapshot with with_currency_symbol builder - Set currency_symbol from Mistral billing API response - Add MonthlyPlan to bridge label/parse, tray selected_metric_percent (None = no bar) - Show formatted cost amount in provider_status_label for MonthlyPlan - Add format_cost_amount helper in bridge.rs - Add Mistral monthly spend row in MenuCardDetails - Add monthlyPlan option to MenuBarMetricSection for Mistral Item 2 — Menu cost-summary display style per provider (steipete#2976): - Add CostSummaryDisplayStyle enum (Compact/Detailed/Hidden) in types.rs - Add cost_summary_display_style field to Settings + Default + RawSettings round-trip - Add to SettingsSnapshot bridge + SettingsUpdate + apply in Tauri commands - Add bridge label/parse functions - Apply in MenuCardDetails: hidden hides cost section, compact shows used/limit only - Update describeCard to filter hasCost for hidden style - Add Select control in UsageSpendTab Item 3 — Per-provider accent color override (steipete#2972): - Add accent_color field to ProviderConfig - Add brand_color(ProviderId) function in provider.rs (mirrors frontend registry) - Add accent_color/set_accent_color/effective_accent_color accessors in Settings - Add set/get/get_effective Tauri commands + normalize_hex_accent_color validator - Add providerAccentColors map to SettingsSnapshot bridge - Add setProviderAccentColor/getProviderAccentColor/getProviderEffectiveAccentColor to tauri.ts - Create AccentColorSection component (hex input, color picker, reset button) - Inject --provider-accent CSS variable on MenuCard article and ChartsSection - Update menu-metric__bar-fill and chart colors to use --provider-accent fallback - Update chartPalette providerCostColor/providerCreditsColor fallback chain - Pass providerAccentColors through TrayPanel/PopOutPanel/ProvidersTab/ProviderDetailPane Also: - Add 11 new locale keys to all 7 .ftl files + keys.ts - Add costSummaryDisplayStyle + providerAccentColors to all test mock SettingsSnapshot - Update chartPalette tests for --provider-accent fallback * Resolve merge conflicts and fix gate checks * Thermo-nuclear: extract ollama cookies, codex pricing, simplify accent color * fix: correct serde attribute placement on currency_symbol after rebase
Summary
The dashboard snapshot builder emits
primary,secondary,tertiary, and every entry inextraRateWindows. That is correct for providers whose primary and secondary are real, distinct windows.Antigravity is not one of those providers. It reports one bucket per quota family and window, and
AntigravityStatusProbethen copies the most-used Gemini bucket intoprimaryand the most-used Claude/GPT bucket intosecondary, so the icon, the menu bar, and the notification paths have standard slots to read. Those two slots hold copies, not new data.The dashboard printed the slots and the bucket list together, so a four-window account rendered six rows. The two extra rows carried the generic
sessionLabelandweeklyLabelfrom provider metadata, which made the copies look like separate quotas.Before, with four real windows:
Rows 1 and 4 are one window. Rows 2 and 5 are one window. The identical reset times show it.
After, one row per bucket:
Every family stays visible. The dashboard is a detail surface, so it follows Preferences > Providers > Antigravity, which also shows all four lanes. Compact surfaces keep their existing behavior: the menu card and the widget still hide a family whose lanes all report zero, per #2875.
GET /dashboard/v1/snapshotandcodexbar dashboardshare this builder, so both transports change together. Antigravity snapshots without quota-summary lanes, and every other provider, take the existing path unchanged.AntigravityStatusSnapshot.isQuotaSummaryWindowIDbecomes public so CodexBarCLI can identify the summary lanes. The check already exists and is already used inside CodexBarCore.Commands run
swift buildmake check(SwiftFormat and SwiftLint strict): 0 violationsmake test: 864 selections in 72 groups, 0 failures, 0 retriesTests
Tests/CodexBarTests/DashboardAntigravityWindowTests.swiftbuilds the four-bucket shape the probe produces, withprimaryandsecondaryset to copies of two buckets, and covers:These tests use a fixture snapshot. They run no live provider probe.
Known related issue, not in this change
codexbar cardshas the opposite defect on the same provider.CLIRendererrendersprimaryandsecondary, then asks the descriptor for extra windows throughextraRateWindowSelector. Antigravity declares no selector, so the default returns an empty array, and terminal cards show only the two copies and none of the real buckets.The fix there is not symmetrical with this one: the same selector feeds
MenuDescriptor, so adding it would change the app menu as well. That belongs in its own change with its own coverage.