Skip to content

fix(usage): parse a model-scoped weekly limit at 0% with no resets_at as real zero usage - #534

Open
emotionalboySY wants to merge 1 commit into
sirmalloc:mainfrom
emotionalboySY:fix/scoped-weekly-limit-unused-zero
Open

fix(usage): parse a model-scoped weekly limit at 0% with no resets_at as real zero usage#534
emotionalboySY wants to merge 1 commit into
sirmalloc:mainfrom
emotionalboySY:fix/scoped-weekly-limit-unused-zero

Conversation

@emotionalboySY

Copy link
Copy Markdown

Symptom

On an account with a Fable weekly quota that hadn't used Fable yet in the current window, the fable-weekly-usage widget rendered nothing — and whenever the usage API entered an error window it degraded to error text instead. That's how I noticed: my statusline showed 7d-F: [Rate limited] for a full server-side 429 backoff window (Retry-After 3600) while the core session/weekly widgets kept rendering fine from the stdin rate_limits payload.

Root cause

/api/oauth/usage reports a model-scoped weekly quota like this before the scoped model has been used in the current window:

{
  "kind": "weekly_scoped", "group": "weekly", "percent": 0, "severity": "normal",
  "resets_at": null,
  "scope": { "model": { "id": null, "display_name": "Fable" }, "surface": null },
  "is_active": false
}

isPlaceholderUsageApiLimit() treats every percent 0 + resets_at null entry as a placeholder, so this entry is discarded and fableUsage stays undefined. Two consequences:

  • the widget renders blank even though the API explicitly reports the quota at 0%;
  • the field never makes it into usage.json, so per-model widgets lean on the conclusive-absence heuristic, and on API error paths without a usable stale cache (e.g. the cached token hash no longer matches after a token refresh) they fall back to getUsageErrorMessage() text like [Rate limited] for the whole backoff window.

I verified against the live API that this state is real data rather than a placeholder — the moment the scoped model is first used in the window, resets_at fills in while percent stays 0 (same account, minutes apart):

// before first Fable use this window
{ "kind": "weekly_scoped", "percent": 0, "resets_at": null, "scope": { "model": { "display_name": "Fable" } }, "is_active": false }

// right after first Fable use
{ "kind": "weekly_scoped", "percent": 0, "resets_at": "2026-07-31T11:59:59.663688+00:00", "scope": { "model": { "display_name": "Fable" } }, "is_active": false }

It is also the same semantic state that a null legacy per-model bucket already reports as 0 via getUsageApiBucketUtilization() (the #343 convention), so today the two encodings of "quota exists, unused" are treated inconsistently.

Fix

Exempt entries whose scope names a concrete model from the placeholder guard: their percent: 0 is surfaced as a real 0% reading, while the reset field stays unset until the window actually starts (the WINDOW_RESET_FIELD_SENTINELS mapping already handles that for requirement checks).

The guard is unchanged for unscoped session / weekly_all entries, so the #343 phantom-0% protection still applies where it was aimed. Accounts without a per-model quota omit the weekly_scoped entry entirely, so this cannot resurrect a phantom window — the conclusive-absence heuristic still covers that case, and keeps a dedicated test.

Tests

  • parses an unused fable quota (0%, no resets_at) as real zero usage and serves it from cache — probe-harness test updated from the previous placeholder-fable one; now also asserts the field round-trips through usage.json.
  • treats a missing fable window as conclusive when core usage fields are present — new probe test preserving conclusive-absence coverage with a truly absent fable window.
  • treats a model-scoped weekly limit at 0% with no resets_at as real zero usage, not a placeholder — parse-level test replacing absent when fable placeholder (percent 0, no resets_at), which asserted the old behavior.
  • treats a limits[] entry with percent 0 and no resets_at as a placeholder (#343 rationale) — unchanged and passing (unscoped guard intact).

bun test on the usage suites: 114 pass; 1 pre-existing environment-dependent failure on my Windows machine (preserves root errors within a process... times out at 5000 ms on an unmodified checkout too). bun run lint (tsc + eslint) clean.

🤖 Generated with Claude Code

… as real zero usage

A weekly_scoped limits[] entry naming a concrete model reports percent 0 /
resets_at null until that model is first used in the current window
(resets_at fills in on first use while percent stays 0), so it is a real
0% reading, not a placeholder. The placeholder guard discarded it, leaving
the per-model usage field undefined: the widget rendered blank and, since
the field never entered the cache, API error windows degraded per-model
widgets to error text such as [Rate limited] instead of a real reading.

Exempt model-scoped entries from the placeholder guard. Unscoped
session/weekly_all entries keep the sirmalloc#343 phantom-0% protection, and truly
absent per-model windows are still covered by the conclusive-absence
heuristic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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