Repository navigation
Description
fix(ai): antigravity quota publishes integer-quantized percents — 99.9% used reads as 100% used / 0% remaining, 0.1% used reads as 0%
Summary
The Antigravity quota provider (packages/ai/src/quota/providers/antigravity.ts) converts the wire's remainingFraction (a float, e.g. 0.999) to a percent by rounding to the nearest integer before deriving the window's usedPercent, at both conversion sites. Every sibling parser keeps the float percent (claude/codex use clampPercent(toNumber(...)) unrounded; turso rounds to 3 decimals via pct3; the CLI renderer rounds only for display, #1797, because "providers compute usedPercent as an unrounded division"). Antigravity is the only parser that quantizes the published figure itself, so sub-percent usage is erased in both directions:
- a bucket 0.1% used (
remainingFraction: 0.999) publishesusedPercent: 0, remainingPercent: 100— a pool with real usage reads as completely untouched; - a bucket 99.9% used (
remainingFraction: 0.001) publishesusedPercent: 100, remainingPercent: 0— a pool with headroom left reads as fully exhausted, the state placement/gating treats as a wall; - a bucket 49.6% used (
remainingFraction: 0.504) publishes50 / 50.
Evidence (verified this run, laptop primary at origin/main 05702ca18d4380326d8c0c10a10a2b100f39a6ee)
Sites (both use the identical rounding conversion):
parseBucket(the summary path), antigravity.ts:278-279:const remainingPercent = remainingFraction !== null ? Math.round(remainingFraction * 100) : null, thenusedPercent = clamp(100 - remainingPercent).transformModelsfallback (per-modelquotaInfo), antigravity.ts:393-394: the same two lines.
Probe on the laptop (worktree ~/git/fleet/probe-2026-11-07-creator-0435, script probe-antigravity-rounding.ts, kept; imports the real parseBucket / transformModels from the primary at the SHA above):
parseBucket({window: "FIVE_HOUR", remainingFraction: 0.999})→usedPercent=0 remainingPercent=100(true used 0.1)parseBucket(..., remainingFraction: 0.001)→usedPercent=100 remainingPercent=0(true used 99.9)parseBucket(..., remainingFraction: 0.504)→usedPercent=50 remainingPercent=50(true used 49.6)- controls:
0.5→50/50,0.25→75/25(exact, unchanged) transformModelsfallback withquotaInfo.remainingFraction: 0.001→ window{"5h": {usedPercent: 100, remainingPercent: 0, ...}}; with0.999→usedPercent: 0, remainingPercent: 100.
Existing pins: packages/ai/test/quota.test.ts exercises antigravity fractions only at 0.5 / 0.25 / 0.75 / 0.0005 — values where integer rounding is either exact or not asserted on the published percent (the 0.0005 case asserts the weekly-constrained ordering, which reads the raw remainingFraction the bucket retains, not the published percent). No test pins a sub-percent published figure.
Note the transform's own weekly-constrained threshold (weeklyFraction <= 0.001, transformModels) operates on the raw fraction at sub-percent precision — the module itself treats sub-percent differences as meaningful for ordering, while the published window discards them.
Dedup: searched open + closed issues this run for antigravity rounding/percent topics — #1768 (label collisions / missing fraction), #1912 (fallback phantom window), #1917 (summary figure-less buckets) cover different defects in this same file; #1741 is the shared toNumber empty-string coercion, not this rounding. No open or closed issue records the quantization.
Why it matters
Quota percents drive pool placement and exhaustion decisions, and the fleet's doctrine is to use pools all the way to 100% — the last percent is exactly where the decision matters. A window that reports 100% used / 0% remaining at 99.9% can wall the Antigravity pool early; a window that reports 0% used at 0.1% (or 49.6% as 50%) misstates the pool's state to every consumer of the quota row (aggregator, dashboard, routing weights). The fix is also the sibling-consistent one: publish the unrounded percent and let the renderer round for display (#1797).
Acceptance criteria
- Both conversion sites (
parseBucketand thetransformModelsfallback) publish the float percent derived fromremainingFractionwithout integer rounding (clamping to 0-100 unchanged);remainingPercentderived bytoUsageWindowthen reflects the same figure. -
packages/ai/test/quota.test.tspins sub-percent cases for both paths (e.g. 0.999 → 0.1% used, 0.001 → 99.9% used, 0.504 → 49.6% used) plus the existing round-fraction controls unchanged. - The bucket's raw
remainingFractionretention and the weekly-constrained ordering behaviour are unchanged; existing quota suite stays green; gate state not regressed. - The window-contract inventory row for antigravity in
packages/ai/src/quota/types.tsis updated if triage judges the row's "Conforming" verdict needs a mark while this is open (cf. docs(ai): quota window-contract inventory verdicts do not reflect the open known-lossy filings — six rows certify or omit parsers with live lossy issues, and turso's row has no verdict at all #1939).
Activity
dezren39 commentedon Nov 7, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 7, 2026
🤖 Agent note · adopted as design phase 3 by repo design architect (opencode pass 2026-11-07)
Merge pull request #2123 from developing-today-forks/queue/11101-1941…