Tell "nothing to meter" apart from "couldn't find out"

Found by looking at the bar on an echo session rather than by reading
the diff: it said "5-hour usage unknown -- this machine reports no
usage", which is the failure the rest of this file was written to avoid,
one level up.

A machine with no metered provider is never asked by the backend, so it
returns no snapshot for it. The bar read that silence as a failed
lookup, because Unavailable was the nearest word it had -- and a session
on `echo`, or on a local llama.cpp, has no paid quota at all. That is a
fact about how somebody set the machine up, not a question that went
unanswered, and reporting it as unknown nags about a deliberate choice
on every screen forever.

So the state exists now: NotMetered, drawn as nothing, because there is
nothing. Unavailable keeps its words and its reason and still covers the
three ways an answer can fail -- nobody logged in, machine unreachable,
snapshot without the window.

Verified on the emulator against the real endpoint: a setup carrying
claude-cli draws the bar at 22% of 5h, selected by kind "session"; the
no-snapshot path was the one on screen before this change, so it is
reached, and this only changes what it draws.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VETa8afmpWaYezLCqJhDB8
This commit is contained in:
irisandClaude Opus 5 committed 2026-08-29 20:16:31 -04:00
1 parent 6680fbb987
commit cf3ed68511
1 file changed
+26 -4
@@ -27,6 +27,17 @@ sealed class FiveHourUsage {
data class Known(val percent: Double, val resetsAt: String?) : FiveHourUsage()
/**
* This machine meters nothing, so there is no window to show.
*
* Separate from [Unavailable], and the distinction is the whole point: a session on `echo` or
* on a local llama.cpp has no paid quota at all, which is a fact about how it was set up and
* not a failure to find something out. The backend never asks such a machine, so it returns no
* snapshot for it -- and reading that silence as "couldn't find out" is exactly the mistake of
* answering with the nearest available word. Drawn as nothing, because there is nothing.
*/
data object NotMetered : FiveHourUsage()
/**
* The question could not be answered, and why.
*
@@ -69,11 +80,18 @@ fun SessionUsageBar(settings: ServerSettings, setup: String, modifier: Modifier
}
}
// Nothing at all for a machine that meters nothing: a row saying "unknown" there would
// report a problem about a setup somebody chose, on every screen, forever.
if (usage is FiveHourUsage.NotMetered) {
return
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 2.dp),
) {
when (val state = usage) {
FiveHourUsage.NotMetered -> Unit
// Words, not a colour and not an empty bar: "couldn't check" is a different kind of
// answer from "this much is used", and only words carry a difference in kind.
is FiveHourUsage.Unavailable ->
@@ -111,14 +129,18 @@ fun SessionUsageBar(settings: ServerSettings, setup: String, modifier: Modifier
* the label is written to be read and would stop matching the day its wording changes, silently
* leaving the bar with nothing to show.
*
* Every way of not having a number is [FiveHourUsage.Unavailable] with the reason in it: a machine
* nobody logged into, one that could not be reached, a snapshot that came back without the window.
* None of them may look like zero.
* Every way of having *failed* to get a number is [FiveHourUsage.Unavailable] with the reason in
* it: a machine nobody logged into, one that could not be reached, a snapshot that came back
* without the window. None of them may look like zero, and none of them may look like
* [FiveHourUsage.NotMetered], which is the machine having no quota rather than the question going
* unanswered.
*/
fun fiveHourFor(snapshots: List<UsageSnapshot>, setup: String): FiveHourUsage {
val mine = snapshots.firstOrNull { it.setup == setup }
// No snapshot at all means the backend never asked, which it only does for a machine with
// nothing metered on it. That is a different answer from having asked and failed.
if (mine == null) {
return FiveHourUsage.Unavailable("this machine reports no usage")
return FiveHourUsage.NotMetered
}
if (mine.state != "ok") {
return FiveHourUsage.Unavailable(mine.detail ?: mine.state)