Repository navigation
fix(usage): parse a model-scoped weekly limit at 0% with no resets_at as real zero usage - #534
Merged
sirmalloc merged 2 commits intoSep 17, 2026
Conversation
… 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 <[email protected]>
This was referenced Sep 18, 2026
Closed
pcvelz
added a commit
to pcvelz/ccstatusline-usage
that referenced
this pull request
Sep 25, 2026
Upstream: TUI kept off the render path (sirmalloc#575), flex mode default full (sirmalloc#590), usage cache fingerprinted by refresh token (sirmalloc#536), CLAUDE_CONFIG_DIR keychain credential first (sirmalloc#573), llms.txt (sirmalloc#527), faster terminal width probing (sirmalloc#501), git/jj symbol slots (sirmalloc#574), model-scoped 0% quota as real zero (sirmalloc#534), custom-command output cache + timeout (sirmalloc#539), usage-percent widgets on a shared module (sirmalloc#545), hideable reset-timer placeholders (sirmalloc#542), git command timeouts (sirmalloc#559, sirmalloc#585) Hand edits outside conflicts: - src/widgets/shared/usage-percent-widget.ts: compat fix - pass RenderContext to getUsageProgressBarWidth (fork narrow/medium bar widths) and add fork short labels WS:/WO: that the extracted Sonnet/Opus widgets used to render; point the fable-weekly kind at the fork field weeklyFableUsage / resolveWeeklyFableUsageWindow (upstream's fableUsage / resolveFableUsageWindow do not exist in the fork and crashed the render) - .fork-keep-deleted: drop llms.txt (points agents at the upstream package and at docs the fork deletes) Conflict resolutions that deviate from upstream on purpose: - src/types/Settings.ts: keep fork default flexMode full-minus-40 (upstream sirmalloc#590 switched to full) - src/utils/terminal.ts: keep fork tmux $TMUX_PANE width probe, ported to execFileSync; upstream's CCSTATUSLINE_WIDTH override in getTerminalWidth replaces the fork copy - src/ccstatusline.ts: keep getTerminalWidth() without the per-session width cache options (fork invariant); add upstream customCommandCacheTtlSeconds - src/widgets/WeeklyFableUsage.ts (+ test): keep fork widget (Fable:/F: labels, 0% for accounts without Fable, weeklyFableUsage field) instead of upstream's shared-module FableWeeklyUsage - src/utils/__tests__/usage-fetch.test.ts: adopt upstream sirmalloc#534 real-zero semantics on the fork field weeklyFableUsage - docs/test-retirements.md: ledger entries for four tests upstream renamed or replaced (sirmalloc#542, sirmalloc#534) and one duplicate upstream test dropped - src/utils/__tests__/usage-fetch.test.ts: compat - upstream's model-scoped real-zero test expects the fork field weeklyFableUsage - src/widgets/__tests__/WeeklyFableUsage.test.ts: compat - set the shared suite's new required expectedWholePercentTime - src/tui/components/__tests__/ImportPreviewDialog.test.ts: fork deviation - default flexMode is full-minus-40, so the non-default side is full - src/utils/__tests__/usage-fetch.test.ts: drop upstream's duplicate "missing fable window" test that used the upstream-only fableUsage field
pcvelz
added a commit
to pcvelz/ccstatusline-usage
that referenced
this pull request
Sep 25, 2026
Weekly Pace can measure the Sonnet, Opus or Fable weekly bucket (`s` cycles), and the per-model usage fields derive from WEEKLY_MODEL_USAGE_BUCKETS, so a Sonnet/Opus bucket the account never reports no longer holds the usage lock open and leaves [Timeout] on screen. Changes on top of the PR: - src/utils/usage-types.ts: hasTrustworthyPaceUsage trusts any defined reading. The PR's "0% with no reset = placeholder" rule predates upstream sirmalloc#534 (model-scoped 0% is real zero); placeholder filtering stays in usage-fetch - src/widgets/__tests__/WeeklyPace.test.ts: the placeholder-zero test now asserts the real-zero verdict - README.md, package.json: dropped the PR's stale v2.4.14 entry and version bump; credited in the v2.4.19 entry - src/utils/__tests__/usage-fetch.test.ts: 20s timeout on the ~14-subprocess "preserves root errors" test, which exceeded the 5s default under machine load on every commit attempt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
On an account with a Fable weekly quota that hadn't used Fable yet in the current window, the
fable-weekly-usagewidget rendered nothing — and whenever the usage API entered an error window it degraded to error text instead. That's how I noticed: my statusline showed7d-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 stdinrate_limitspayload.Root cause
/api/oauth/usagereports 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 everypercent 0+resets_at nullentry as a placeholder, so this entry is discarded andfableUsagestaysundefined. Two consequences: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 togetUsageErrorMessage()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_atfills in whilepercentstays0(same account, minutes apart):It is also the same semantic state that a
nulllegacy per-model bucket already reports as0viagetUsageApiBucketUtilization()(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: 0is surfaced as a real 0% reading, while the reset field stays unset until the window actually starts (theWINDOW_RESET_FIELD_SENTINELSmapping already handles that for requirement checks).The guard is unchanged for unscoped
session/weekly_allentries, so the #343 phantom-0% protection still applies where it was aimed. Accounts without a per-model quota omit theweekly_scopedentry 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 throughusage.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 replacingabsent 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 teston 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