usage limits are read live, and a cached reading belongs to one account

`limitsCache` was keyed on nothing. Switching account changes which credential
`readOauthLogin` returns, and the cached entry was served anyway — so the panel
showed the previous account's percentages under the new account's name for a
minute, and on a failed probe for as long as the probe kept failing. Reported
maxed out on one account, switched, and the numbers did not move.

So the limits have no TTL now: every request probes. They are per-account and they
are the number somebody opens the panel to read, so a stale one is worse than a
slow one.

The store stays, for the failure path only, and keyed on the account it was
measured for. A flaky request degrades to that account's own last reading rather
than to a blank panel or — much worse — to somebody else's numbers. A reading that
cannot be attributed gets no fallback at all rather than a shared one.

The client's five-minute stale window went with it: that query is only the instant
first paint, and holding it meant painting the old account's stored row until the
refresh landed.

The transcript scan keeps its cache. It reads ~90MB and its answer is the same
whichever account is signed in — it counts what this machine wrote, not what an
account is allowed — so a switch does not invalidate it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 01:54:05 +00:00
co-authored by Claude Opus 5
parent 854f957058
commit aa35428dde
2 changed files with 38 additions and 16 deletions
@@ -51,9 +51,11 @@ export function useClaudeUsage(enabled: boolean) {
queryKey: KEY,
queryFn: () => client.get<UsageResponse>('/chat/usage'),
enabled,
// The stored rows only change when a turn ends, and a turn ending does not happen while you are reading
// this panel. The refresh below is what keeps it honest, not a stale timer.
staleTime: 5 * 60_000,
// No stale window. This query is only the instant first paint — the refresh below is the real answer
// — and a five-minute one meant that after switching account the panel painted the OLD account's
// stored row and held it until the refresh landed, which is exactly the moment somebody decides the
// numbers are wrong.
staleTime: 0,
refetchOnWindowFocus: false,
retry: false,
});