Repository navigation
Read the Windows rings the way the Mac does: stale, and round-ended - #271
Merged
Merged
Conversation
Three differences, all in how a ring reads rather than what it says. The age a reading goes stale at. Windows dimmed after 5 minutes, the Mac after 15 (UsageStore.staleAfter), and it polls at 1 and 5. At five minutes a reading dimmed between two polls of a provider that was answering perfectly well, so "stale" came to mean "fetched a little while ago" rather than "old enough not to trust". A provider that knows its own reading is stale still says so in its status, and that still dims at once. What dims. `.dim` sat on the whole ringwrap, so the spinning white arc and the yellow pulse faded with the percentage — but whether an agent is running right now is current whatever the age of the number beside it. The Mac adds its ActivityArc after the opacity it gives the stale stack, and TASKS.md puts it plainly: staleness dimming applies to the usage reading only. The arc moves to a layer of its own so the dim can go around it, while the track, the weekly ring and the glyph still fade. The ends of the arcs. The Mac strokes its rings with lineCap .round; ours drew them square. A fraction of exactly zero now draws nothing at all, because a zero-length dash paints a dot once the caps are round, where the Mac's trim(from: 0, to: 0) draws nothing. A reading small enough that its two caps meet still draws as a dot, as it does on the Mac: ProviderRing has no minimum sweep, and vinzdg#260 is arguing for one on the local model's arc rather than this one. If that lands, the same floor belongs here.
The ring dimmed the moment Claude answered one 429, though the reading behind it was seconds old — and on Windows the endpoint is the only source there is, so the first refused refresh of a rate limit dimmed the notch for as long as the limit lasted. The Mac keeps the status it had and lets age decide (UsageStore keeps the previous status until staleAfter), and its back-off guards the endpoint rather than the reading. So a 429 now leaves the status alone and says so in the note it already writes — "Rate limited, retrying in Ns" — and the reading goes stale on its own fifteen minutes after it was actually fetched. A fetch that fails for any other reason is treated the same way: no reading at all is still an error, a reading we could not refresh is just a reading. A snapshot restored from disk keeps the status it was saved with, for the same reason: fetched_at came back with it, so its age is already known. The tray menu decided the same question five minutes earlier than the page, though its own comment says both draw on the same rule. Fifteen there too.
abhishekthakur7
pushed a commit
to abhishekthakur7/codenotch
that referenced
this pull request
Sep 28, 2026
abhishekthakur7
pushed a commit
to abhishekthakur7/codenotch
that referenced
this pull request
Sep 28, 2026
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.
Four differences between how a Windows ring reads and how the Mac's does. None of them change what a reading says — only when it is dimmed and how it is drawn.
Stale at 15 minutes, not 5.
staleOfdimmed anything fetched more than 5 minutes ago; the Mac'sUsageStore.staleAfteris 15, and it polls at 1 and 5. At five minutes a reading dimmed between two polls of a provider that was answering perfectly well, so "stale" came to mean "fetched a little while ago" rather than "old enough not to trust".traymenu::stale_sinceasked the same question five minutes earlier than the page, though its own comment says both draw on the same rule, so it moves too.A refused refresh is not a stale reading.
usage.rssetstatus = "stale"on the first 429, though the reading behind it was seconds old — and since the endpoint is the only source Windows has, one 429 dimmed the notch for as long as the rate limit lasted. This is the case that actually bites: I hit it within a minute of testing the change above. The Mac keeps the status it had and lets age decide (UsageStoreholds the previous status untilstaleAfter), and its back-off guards the endpoint rather than the reading. So a 429 now leaves the status alone and says what is happening in the note it already writes — "Rate limited, retrying in Ns" — while the reading ages out on its own fifteen minutes after it was really fetched. A failure for any other reason is treated the same: no reading at all is still an error, a reading we could not refresh is just a reading. A snapshot restored from disk likewise keeps the status it was saved with, sincefetched_atcame back with it and its age is already known.Only the reading dims.
.dimsat on the whole.ringwrap, so the spinning white arc and the yellow attention pulse faded along with the percentage. Whether an agent is running right now is current whatever the age of the number beside it — the Mac adds itsActivityArcafter the opacity it gives the stale stack, and TASKS.md says it outright: "Staleness dimming applies to the usage reading only." The activity arc moves into an SVG layer of its own so the dim goes around it. The track, the weekly ring and the glyph still fade.Round arc ends. The Mac strokes its rings with
lineCap: .round; these were square. A fraction of exactly zero now draws nothing at all, because a zero-length dash paints a dot once the caps are round, where the Mac'strim(from: 0, to: 0)draws nothing.A reading small enough that its two caps meet still draws as a dot, exactly as it does on the Mac —
ProviderRing.sweepismin(max(usedFraction ?? 0, 0), 1), with no minimum. #260 is arguing for a floor on the local model's arc rather than this one, so that question belongs with #260 rather than here; if it lands, the same floor belongs on these rings too.Testing:
cargo test98 pass, 0 fail, 2 ignored;windows/scripts/check-ui-scripts.mjsparses all three pages. Checked by hand on Windows 11: the arcs read as round-ended, staleness forced on in a throwaway build confirms the rings fade while a running agent's arc stays at full strength, and a rate-limited Claude now keeps its reading with "Rate limited, retrying in Ns" in the card instead of greying out on the first 429.#257 also touches
notch.htmlandusage.rs. Innotch.htmlit is around the card and the pointer handlers, while this is the ring CSS andrenderRing/svgArc. Inusage.rsits nearest hunks are at ~471 and ~528 and this one sits between them, in theRateLimitedandOtherarms — close, but not the same lines.