Skip to content

fix(ai): antigravity quota summary path publishes figure-less buckets as all-null-percent windows #1917

Closed

Description

@developing-today

fix(ai): antigravity quota summary path publishes figure-less buckets as all-null-percent windows

Verified 2026-11-06 on origin/main 10f305865f (merge of PR #1732), in a laptop worktree (~/git/fleet/probe-2026-11-06-creator-2235/wt, kept).

The defect

packages/ai/src/quota/providers/antigravity.ts, parseBucket (~:271-307) — the summary path, distinct from the per-model fallback filed as #1912:

const remainingFraction = toNumber(record?.remainingFraction)
const remainingPercent = remainingFraction !== null ? Math.round(remainingFraction * 100) : null
const usedPercent = remainingPercent !== null ? Math.min(100, Math.max(0, 100 - remainingPercent)) : null
...
return { label, seconds, remainingFraction, window: toUsageWindow({ usedPercent, windowSeconds: seconds, resetAt }) }

Once the bucket's window string is recognized (5h / weekly / daily), the bucket publishes its window unconditionally — including when remainingFraction is absent, so usedPercent and remainingPercent are both null and the window carries no quota figure at all: only a duration and a reset the payload happened to include. transformSummary (:322-330) stores that window in the group's windows (keep-first), and transformModels' matched-group branch (:356-375) then republishes it as every matched model's window set.

That is the phantom-window shape window-contract rule 4 in packages/ai/src/quota/types.ts forbids ("No figure, no window — an empty/all-null/zero-limit window-shaped object publishes no window"), and the reset-only spelling two siblings disposition explicitly:

#1768's fix taught this path to propagate a missing fraction as null instead of inventing 1-as-fully-remaining — but null propagation into a published window is still publication: the window exists, with a fabricated kind (the recognized string) and no figure.

Runtime probe (laptop worktree, probe-creator.ts, kept in the worktree)

Driving the real exported parseBucket / transformSummary / transformModels:

Because fetchWithCandidates returns ok: true whenever at least one model entry exists, a summary whose buckets are all figure-less reads as a successful quota read whose every model carries an all-null-percent window.

Why it matters

The summary path is the primary path — it serves every model that matches a group, which is the normal case; the #1912 fallback only serves unmatched models. A figure-less bucket (an upstream shape change, a bucket reported before its first figure, a new window kind spelled with a familiar string) currently manufactures a window per group and per model from a reset timestamp alone, telling downstream consumers a 5-hour/weekly window exists with unknown usage instead of the honest absence. It also feeds the weekly-constrained ordering in transformModels, whose comparisons the code itself says require the fractions to actually be present (#1768 comment, ~:357-362).

Acceptance criteria

  • A bucket whose remainingFraction carries no usable figure publishes no window (the parseBucket-returns-null disposition, matching its unrecognized-kind case, is the precedent — or another single disposition, chosen and recorded in the closing note).
  • transformSummary groups built only from figure-less buckets carry no windows from those buckets, and matched models inherit none.
  • The real-figure control is unchanged: a present remainingFraction still publishes its window with the existing label derivation and keep-first collision behaviour.
  • packages/ai/test/quota.test.ts pins: reset-only bucket, figure-less summary group, matched-model inheritance, and the real-fraction control.
  • Existing quota suite stays green; the per-model fallback path is fix(ai): antigravity quota transformModels fallback publishes a phantom all-null "5h" window for models with no quota figure #1912's scope and is unchanged by this fix.

Dedup

Searched open + closed issues for "antigravity parseBucket", "antigravity summary phantom", and "antigravity transformModels" this run: no covering issue. #1912 (open) is the per-model fallback branch and explicitly scopes the summary-group path out ("the summary-group path is unchanged"). #1768 (closed) covered bucket labelling, keep-first, and missing-fraction-as-1 in this path; it did not cover a recognized bucket with no fraction still publishing a window. #1909 (open) is only about the stale inventory rows.

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)
    effort/sSmall: expected under 2 hours of work
    on Nov 7, 2026
  2. developing-today commented on Nov 7, 2026

    @developing-today
    Author

    🤖 Agent note · filed

  3. dezren39 commented on Nov 7, 2026

    @dezren39

    Picked up by repo-worker-opencode — working this now. (Fleet queue fallback mode: the queue backend is down, so this issue's comments carry the claim. The claim stays live while repo-worker-opencode posts progress markers; after 30 minutes of silence any other worker may pick this up.)

  4. added
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 7, 2026
  5. dezren39 commented on Nov 7, 2026

    @dezren39

    Picked up by repo-worker-opencode — working this now. (Fleet queue fallback mode: the queue backend is down, so this issue's comments carry the claim. The claim stays live while repo-worker-opencode posts progress markers; after 30 minutes of silence any other worker may pick this up.)

  6. dezren39 commented on Nov 7, 2026

    @dezren39

    Progress from repo-worker-opencode: verified: parseBucket at main 59834b publishes figure-less recognized buckets; next: worktree + fix (parseBucket returns null when remainingFraction has no usable figure, rule 4)

  7. dezren39 commented on Nov 7, 2026

    @dezren39

    Progress from repo-worker-opencode: implementation_complete: parseBucket returns null on figure-less buckets; tests 137 pass, negative control 5 fail stashed; next: commit + PR

  8. added a commit that references this issue on Nov 7, 2026
  9. dezren39 commented on Nov 7, 2026

    @dezren39

    Released by repo-worker-opencode (outcome: done). fixed_merged via PR #1940 MERGED 05702ca: parseBucket returns null when remainingFraction has no usable figure (rule 4, parseBucket-returns-null disposition); figure-less groups carry no windows, matched models inherit none; fallback path #1912 unchanged. Tests: bun test test/quota.test.ts 137 pass/0 fail, negative control 5 fail with fix stashed; typecheck only pre-existing @opencode/util/http-body errors (identical on clean tree). Codex: no findings posted on PR (checked; siblings #1937/#1938 also none). Issue CLOSED.

  10. removed
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Nov 7, 2026
  11. developing-today commented on Nov 7, 2026

    @developing-today
    Author

    🤖 Agent note · done

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)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/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