Skip to content

fix(ai): antigravity quota publishes integer-quantized percents — 99.9% used reads as 100% / 0% remaining, 0.1% used reads as 0% #1941

Closed

Description

@dezren39

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) publishes usedPercent: 0, remainingPercent: 100 — a pool with real usage reads as completely untouched;
  • a bucket 99.9% used (remainingFraction: 0.001) publishes usedPercent: 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) publishes 50 / 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, then usedPercent = clamp(100 - remainingPercent).
  • transformModels fallback (per-model quotaInfo), 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)
  • transformModels fallback with quotaInfo.remainingFraction: 0.001 → window {"5h": {usedPercent: 100, remainingPercent: 0, ...}}; with 0.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

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/aiPackage: ai (pkgs/ or apps/ in this repo)
    on Nov 7, 2026
  2. dezren39 commented on Nov 7, 2026

    @dezren39
    Author

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-opencode)
    • Session / ID: cron job new-issue-creator-opencode, run 2026-11-07T10:45:35Z
    • Found via: filed this run
    • Task: Filed this issue: the antigravity quota provider rounds remainingFraction to an integer percent at both conversion sites (antigravity.ts:278-279 parseBucket, :393-394 transformModels fallback), so 99.9% used publishes as 100% / 0% remaining and 0.1% used as 0% / 100%. Labels applied per the taxonomy; a repo-task/v1 triage packet is enqueued on repo-health-opencode-pilot.
    • Expectation: effort s — triage decides the disposition (publish the float percent, sibling-consistent with fix(cli): quota renders unrounded percents — 33.33333333333333% used for a one-third-full window #1797's renderer-rounding split, vs. recording integer percents as the deliberate port shape); if fixing, both sites change together and sub-percent cases are pinned for both paths.
    • Links: body evidence file creator-2026-11-07-0435/issue-antigravity-percent-rounding.md (goal hidden_files); probe probe-antigravity-rounding.ts in laptop worktree ~/git/fleet/probe-2026-11-07-creator-0435
  3. dezren39 commented on Nov 7, 2026

    @dezren39
    Author

    🤖 Agent note · adopted as design phase 3 by repo design architect (opencode pass 2026-11-07)

  4. added a commit that references this issue on Nov 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/aiPackage: ai (pkgs/ or apps/ in this repo)kind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobstatus/needs-triageNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this item

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions