Recover model-usage limits from a boot-time probe failure

The shell starts before DHCP finishes, so Claude's first probe of the
OAuth usage endpoint came back as a transport failure and pinned "Claude
limits unavailable" for a full refresh interval. Opening the panel could
not clear it either: the open path refreshed unforced and hit the same
throttle it was trying to escape.

A transport failure now arms a short retry that goes straight to the
probe, since a retry answering to the throttle never gets off the
ground. Any real answer disarms it — a server that replied, 429
included, is one to stop pestering. Probes are single-flight, a fresh
token skips the throttle its predecessor set, and opening the panel asks
for the wire without re-walking every transcript on disk.

The module also earns its place in the bar now instead of sitting there
dimmed with nothing to say: it collapses out entirely until a provider
has actually recorded usage, here or on a synced machine. That made both
presence probes redundant, so they are gone. Selection follows the
provider rather than its slot, so one appearing while the panel is open
no longer swaps out what you were reading.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
David Heinemeier Hansson
2026-07-28 11:00:43 -07:00
co-authored by Claude Opus 5
parent 9b693cca63
commit 24dc914d28
5 changed files with 112 additions and 57 deletions
+30 -5
View File
@@ -27,18 +27,33 @@ Item {
property var providers: [claudeProvider, codexProvider]
// A subscription earns a place in the panel by being both switched on in
// settings and actually present on this machine — nobody wants a Codex tab
// full of zeroes on a box that has never run Codex.
// A subscription earns a place in the bar and the panel by being switched on
// in settings and having actually produced numbers — locally or on a synced
// device. Presence on disk is not enough: a box that installed Codex and
// never ran it would get a tab full of zeroes. With nothing to show, the
// whole module collapses out of the bar rather than sitting there dimmed.
property var enabledProviders: {
var rev = syncRevision
var running = syncRunning
var result = []
if (claudeProvider.enabled && claudeProvider.installed) result.push(displayProvider(claudeProvider))
if (codexProvider.enabled && codexProvider.installed) result.push(displayProvider(codexProvider))
if (claudeProvider.enabled) {
var claude = displayProvider(claudeProvider)
if (providerHasData(claude)) result.push(claude)
}
if (codexProvider.enabled) {
var codex = displayProvider(codexProvider)
if (providerHasData(codex)) result.push(codex)
}
return result
}
// All-time, not today: a quiet day is not the same as an absent provider.
function providerHasData(p) {
return numberValue(p.totalPrompts) > 0 || numberValue(p.totalSessions) > 0
|| numberValue(p.activeDays) > 0 || Number(p.rateLimitPercent) >= 0
|| Number(p.secondaryRateLimitPercent) >= 0
}
property bool refreshing: claudeProvider.refreshing || codexProvider.refreshing || syncRunning
property double aggregateUpdatedAtMs: aggregateData && aggregateData.updatedAtMs ? Number(aggregateData.updatedAtMs) : 0
property double lastRefreshedAtMs: Math.max(aggregateUpdatedAtMs, claudeProvider.lastRefreshedAtMs || 0, codexProvider.lastRefreshedAtMs || 0)
@@ -523,6 +538,16 @@ Item {
scheduleSync()
}
// Opening the panel wants the numbers that go stale on the wire, not another
// walk over every transcript on disk. Forcing a whole refresh would do both,
// and re-opening the panel would then rescan the lot each time.
function refreshLimits() {
for (var i = 0; i < providers.length; i++) {
var p = providers[i]
if (p.enabled && typeof p.refreshLimits === "function") p.refreshLimits()
}
}
function formatTokenCount(n) {
if (n === undefined || n === null) return "0"
if (n >= 1e9) return (n / 1e9).toFixed(1) + "B"