Files
lumbridge-code/docs/decisions/0012-usage-ledger-and-footer-provenance.md
Metal AgentandClaude Opus 5 ef52aa7ce2 Replace the footer's placeholder usage with a real observation ledger
The footer showed invented percentages. It now shows what two harnesses
actually report, or says it does not know.

lumbridge-core gains an append-only per-profile UsageLedger and a projection
that labels every derived value estimated, withholds a burn rate from a single
sample, withholds a window fraction with no reported ceiling, withholds an
exhaustion estimate that lands after the reset, and reports an expired window
as rolled over rather than freezing its last percentage. A missing fact renders
as missing, never as zero. (0012)

lumbridge-harness is the impure side: processes, clocks, and untrusted wire
text in, observations out. Three adapters:

- Codex's account/rateLimits/read over the app-server's JSON-RPC stdio. The
  client cannot express a request outside a two-variant enum and answers every
  server-to-client request with -32601, so a harness asking Lumbridge for a
  credential is refused by construction. (0013)
- Claude Code's session transcripts, as a byte-offset tail follower that
  reports nothing until the backlog is read to EOF — a partially-read backlog
  is indistinguishable from a burst of spend, and the first run against 20 MB
  reported forty-six billion tokens an hour. The parser models four counters,
  so the conversations in those files are not representable. (0014)
- Claude Code's five-hour and seven-day subscription windows, via a bridge
  installed as its statusLine command. 0014 had claimed no such surface
  existed; it does, and the record is corrected in place rather than quietly
  edited. Lumbridge does not read the OAuth credential to call the account
  usage endpoint, which is what comparable tools do — AGENTS.md forbids it,
  and 0015 says so rather than leaving the gap unexplained.

Also in here: a capability-check ordering fix in the workspace reducer, where
the applied-request replay table was consulted before the capability check and
so answered questions the caller had no right to ask; the GPUI spike wired to
the live probes with per-harness gauges and provenance chips; and a launcher
that matches its own window by PID, because GPUI sets WM_NAME but not
_NET_WM_NAME and a title match never succeeded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 21:47:11 -07:00

68 lines
3.4 KiB
Markdown

# 0012: The footer renders a derived projection, never a stored percentage
Status: accepted. Supplemented by decisions 0013 and 0014, which supply the
first two real adapters. Every rule below still holds.
Decision 0002 established that usage observations carry provenance. This
decision fixes how those observations become the five answers the footer owes
the user, and what the footer must do when it cannot answer.
## The contract
`lumbridge-core` owns an append-only `UsageLedger` of `UsageObservation`s per
`AccountProfile`. An observation is a fact: consumed units, an optional ceiling,
an optional provider window, a provenance, and the time it was observed. The
ledger never edits an observation and refuses one that predates the newest entry
for that profile, because an append-only stream cannot move backwards.
`UsageLedger::project` derives the footer view. Reported facts keep their own
provenance. Anything the projection computes is labelled `Estimated` even when
every input was provider-reported, because a derived rate is not a reported
fact.
## Rules the projection enforces
- A burn rate needs at least two observations inside the same window, the same
unit, and a minimum elapsed sample. One reading yields no rate at all rather
than a rate of zero.
- A window fraction requires a reported ceiling. A self-hosted endpoint has no
quota, so it reports consumption and explicitly says no ceiling exists.
- An exhaustion estimate is withheld when the window resets first. Telling a
user they will run out after the quota has already refilled is worse than
telling them nothing.
- An `Unavailable` observation invalidates older facts for that profile instead
of letting a stale reading keep rendering as current.
- An expired window is reported as rolled over, not as a frozen percentage from
a window that ended.
- Staleness is surfaced, not hidden: past the staleness budget the value still
renders but its confidence drops to unknown and the footer says so.
## What the UI may do
A compact surface may substitute the short provenance label. It may not drop the
label, round an estimate into a reported fact, or substitute a placeholder
number for a missing one. `FooterUsage` therefore returns explicit phrases —
`usage unavailable`, `reset time unavailable`, `burn rate unavailable`,
`no usage source` — and the GPUI shell renders unavailable values in the quiet
tone with the provenance chip coloured by source rather than by value.
A pane with no harness attached shows the detached roll-up. It never inherits
another pane's account, because attributing one agent's spend to another is the
same class of untruth as inventing the number.
## Status of the numbers
The GPUI shell's observations are still a declared spike fixture. The path is
real: the fixture records through the same ledger and reads back through the
same projection, so the honest-gap behaviour above is exercised on every frame
rather than asserted only in tests.
The first real adapter now exists in `lumbridge-harness` (decision 0013) and its
integration tests drive a synthetic Codex transcript through this ledger and
this footer, proving every rule above survives the adapter path. Pointing the
running shell at a live account spawns a process against the user's own
subscription, so it stays a separate, user-consented step.
All arithmetic is integer arithmetic and fractions are carried as permille, so a
rendered percentage cannot drift from the stored fact.