usage panel: verified for one account, not for two

the owner confirmed it live the same day. what that leaves untested is the
half the cache exists for — a second login, the tabs, a stored row surviving
a switch — so the docs now say which half is proven instead of claiming
neither is.

also records the bug the first deploy found, since the doc had asserted the
degradation that turned out to be broken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 05:12:47 +00:00
co-authored by Claude Opus 5
parent 3cc9df27d7
commit 0f93262a8c
2 changed files with 24 additions and 21 deletions
+12 -18
View File
@@ -447,27 +447,21 @@ outside the example's new README:
## Waiting on the owner to run it ## Waiting on the owner to run it
- [ ] **The AI usage panel has never run.** Landed 2026-08-18. Click the harness pill in the chat composer - [ ] **The AI usage panel works for one account; the multi-account half is unproven.** Landed and verified
and it shows Claude Code's own usage display — limits with countdowns, tokens by day and by model — live 2026-08-18 — click the harness pill in the chat composer and it shows Claude Code's own usage
with one tab per Anthropic account, so a login you have switched away from still answers. display, limits with countdowns, tokens by day and by model.
**Two things must happen before it does anything**: `bun db:push` (it adds `ai_provider_usage`) and What is NOT proven is the reason it was built: a second Anthropic login, the account tabs, and a
`pm2 restart officer officer-claude-code`. Neither has been run. Without the push the panel opens and stored row surviving a switch. **Group C of `docs/ai-usage-panel.md`** is that, and test 10 is the one
shows the signed-in account with no tabs, which is the designed degradation rather than a failure. most likely to be wrong — a refresh must not overwrite an account it could not measure, and that
failure is silent.
**`docs/ai-usage-panel.md` is the checklist** — sixteen ordered tests in five groups. Group C is the Deliberately deferred rather than forgotten: the owner switches accounts when the work needs it, and
feature: sign in as the second account and confirm the first one keeps its numbers and its countdown. the worst case is one wrong tab. Run Group C the first time a second login lands on this machine.
Test 10 is the one most likely to be wrong — a refresh must not overwrite an account it could not
measure, and that failure is silent.
Safe to leave untested. Everything is read-only except one fire-and-forget upsert at turn end, and the Also unexercised: the model dropdown no longer renders the literal string `claude-code` for a chat
pill was already an inert label before this. The one thing worth watching is `pm2 logs officer` during that named no tier. Needs `officer-claude-code` restarted, not just `officer` — the parser in the
a turn: the snapshot is `void`ed and swallows its own errors, so a persistent failure shows up only sidecar is what emits it.
there and as a row that never updates.
Shipped alongside it and also unexercised: the model dropdown no longer renders the literal string
`claude-code` for a chat that named no tier. That half needs `officer-claude-code` restarted, not just
`officer` — the parser in the sidecar is what emits it.
- [ ] **Plan mode is live and has never been exercised.** Landed `1b811dfa` on 2026-08-17; all three - [ ] **Plan mode is live and has never been exercised.** Landed `1b811dfa` on 2026-08-17; all three
processes were restarted the same evening, so the code IS running. Not one part of it has been used: processes were restarted the same evening, so the code IS running. Not one part of it has been used:
+12 -3
View File
@@ -1,8 +1,12 @@
# The AI usage panel # The AI usage panel
**Built 2026-08-18. Never run against a live server.** The parts with unit tests are noted below; nothing **Built and running 2026-08-18. Verified for ONE account, never for two.** The owner confirmed the panel
here has been exercised through HTTP, through a real turn, or with two accounts. The test plan at the end is live the same day: limits, countdowns, tokens by day and by model all render against the signed-in account.
what "tested" would mean.
What that leaves untested is the half the cache exists for — a second Anthropic login, the account tabs, and
a stored row surviving a switch. Group C of the test plan below is that, and it is the only part still worth
running. It will be run when it is needed rather than pre-emptively, since the failure it would catch costs
nothing but a wrong tab.
Click the harness pill in the chat composer — the label reading **Claude Code**, left of the background-job Click the harness pill in the chat composer — the label reading **Claude Code**, left of the background-job
button — and it opens what Claude Code's own usage display shows: limits with reset countdowns, tokens by button — and it opens what Claude Code's own usage display shows: limits with reset countdowns, tokens by
@@ -18,6 +22,11 @@ pm2 restart officer officer-claude-code
`db:push` first. Without the table the panel still opens and still shows the signed-in account — the stored `db:push` first. Without the table the panel still opens and still shows the signed-in account — the stored
read catches and returns an empty list — but there are no tabs and nothing survives an account switch. read catches and returns an empty list — but there are no tabs and nothing survives an account switch.
That degradation was not free: it was broken on the first deploy and fixed the same day. `snapshotClaudeUsage`
had the read and the write in ONE `try`, so a missing table threw on the upsert and discarded a perfectly good
reading — the panel said "Not signed in" over an account that was signed in fine. The write has its own `try`
now, and `usage-store-degradation.test.ts` holds the line.
Both processes are needed for the _other_ change that shipped alongside this (`model:resolved`, see Both processes are needed for the _other_ change that shipped alongside this (`model:resolved`, see
"Related" below). The usage panel itself only needs `officer`. "Related" below). The usage panel itself only needs `officer`.