Repository navigation
Meter Amp, Cline, Gemini CLI, OpenCode and Qwen Code from what each one keeps - #772
Conversation
7e7e178 to
ed19ae3
Compare
78baeac to
397d473
Compare
3cee81c to
7991631
Compare
397d473 to
e978a80
Compare
e978a80 to
ee5d429
Compare
…ne keeps Five agents read "not metered" on the Dashboard beside Antigravity (#769). Each was checked in its own source, on 2026-09-18, for what it can tell a client, and each now tells it. Balances, asked of the vendor with the agent's own sign-in: - Amp: `amp usage` prints the balance in a short report Amp's server writes ("**Individual credits:** $10 remaining"); there is no JSON form, so only that line and "Signed in as" are read. Lookups share a 60-an-hour limit with Amp's own, so a reading stands for five minutes. Running it left Amp's binary and log untouched. - Cline: the same two calls Cline's CLI makes for its account screen (`/api/v1/users/me`, then the active organization's or the user's balance, in micro-dollars), with the session in `providers.json`. The token is used while valid and never refreshed: a refresh rotates the refresh token, and not writing it back would sign Cline out. Between Cline's own refreshes the last reading stands with its age. Spend, read from the agents' own records into the ledger: - Gemini CLI and Qwen Code chat logs, priced at list price. Gemini writes a message again as its counts arrive and hides rewound ones without un-spending them, so a log is read whole each time it changes, at the last record of each call; Qwen appends a record per call and resumes by offset. Both use the Gemini API's arithmetic (the prompt includes the cache, thinking and tool-use prompts are counted apart). - OpenCode's `opencode.db` and Cline's `sessions.db`, at the cost the agent recorded, a free model's zero included. Rows can now carry that `vendorCost`, the ledger prefers it to list price, and spend says `vendorMetered` or `mixed`, the provenance the protocol already had and nothing used. Cline's own `usage` is read, never `aggregateUsage`, whose subagents are rows of their own. - Another application's SQLite file is opened through `openForeignDatabase`: a WAL database whose owner is not running is opened `immutable`, because a plain read-only open creates `-shm` and `-wal` in the owner's folder (measured). Binding: agents with no knowledge-table entry (Amp's registry adapter, Qwen Code through npx) are named by the program they run, so their meters are reached, and each agent's records are found with its row's environment, so a row that moves an agent's home is read from where it moved it. On the card: a balance counts as usage reported in the line above the cards ("Cline is out of credits." where it said "No agent here reports plan usage."), a spent balance says it waits for a top-up rather than a reset, and the Accounts rail shows the balance where a percentage would go. Also a bug the new tests found in `projectRootOf`: its memo stored the first repository-less folder's answer on every ancestor, so every later folder without a repository was filed under that first one. It now remembers the repository at or above each folder walked, or that there is none. A CRLF test had passed only because of it and now counts across rows. Checked against this machine's real records (not published): Gemini CLI $2.15 over 103 calls, Cline $0.65 Cline-billed over 14 sessions, OpenCode $0 on its free model, Amp $10 left, and nothing written beside OpenCode's or Cline's databases. Co-Authored-By: Claude Opus 5 <[email protected]>
The band under "What it cost" said "what these tokens would have cost at public API rates. Not a bill." of every total. Since the previous commit, OpenCode's and Cline's rows are the cost each agent recorded (a free model's zero included, and Cline's is what it billed), so on a desk with either of them the sentence was false about part of the figure it sat under. `spendHint` reads the provenance the ledger already reports: the list-price sentence as before, "what the agents recorded these tokens cost." for `vendorMetered`, and for `mixed` that it is both and not all of it is a bill. Co-Authored-By: Claude Opus 5 <[email protected]>
The first commit said Zen's balance and Go's limits were both closed to an API key. Zen's balance is: no endpoint reads it (asked upstream in anomalyco/opencode#10448). Go's limits are not: `GET /zen/go/v1/usage` with the Go key returns the rolling 5-hour, weekly and monthly windows, shipped from anomalyco/opencode#16017, found while filing the ACP request. The desk does not read it yet, since there is no Go subscription here to measure it against; the comment and the doc now say so. Co-Authored-By: Claude Opus 5 <[email protected]>
…nts' own Two sentences still called every cost a public price. With Cline's and OpenCode's calls priced at the cost each agent recorded, both were false, on a page whose band header already says "what the agents recorded": - the page's own sentence: "what the work cost at public rates"; - the footnote under *Where it went*, whenever no row was short: "Every call in this window has a public price, so these figures are exact." Both now follow the ledger's provenance, as the band header does: public rates for list price, the agents' own records for `vendorMetered`, and both for `mixed` (`costClause`, `pricedNote`). The footnote's sentences for rows with a model that has no price are unchanged. Pinned in usage.test.ts. Co-Authored-By: Claude Opus 5 <[email protected]>
ee5d429 to
f0531fc
Compare
|
Review by Codex 0.155.0 · GPT-5.6-Sol · Low effort · via HarnessDesk I found three correctness defects.
Risks and missing coverage:
What I checked and found sound: Cline uses a valid access token without refreshing or writing another application's file; expiry preserves the last reading with its original age and account changes discard it. The billed-account selection (active organization, otherwise user), micro-dollar conversion, and I read the full 2,496-line diff and the touched implementation/tests at Verdict: request changes |
…t guessing, keep priced and unpriced rows apart, follow the Gemini home Codex GPT-5.6-Sol (low) found three real defects. - Another application's SQLite file was opened `immutable` whenever no `-shm` sat beside it. That absence says nothing: an owner in exclusive locking mode never makes one, and a leftover one (Cline's has outlived its run by weeks) says nothing either. `readForeignDatabase` now chooses from what is on disk. A WAL database with neither `-wal` nor `-shm` is opened `immutable` and the read is checked afterwards, so an owner that starts mid-read has its answer discarded. One with either file is copied, with its log, to a private folder and read there, trusted only if the source's size and time were the same before and after, and retried up to three times. Nothing of the owner's is opened, locked or recreated. - A session the agent priced and one it did not, on one day, model and folder, were summed into one row, which the ledger then called wholly the agent's: the unpriced one lost its list price and the provenance claimed more than was known. The scanner's key and the store's primary key now carry whether the agent priced a request, so the two never share a row. A ledger written before is rebuilt in place, rows kept. - A moved Gemini home (GEMINI_CLI_HOME) moved the chat logs but not the sign-in, so a card could show one account's quota beside another's spend. The meter now takes the row's environment, as Cline's already did. Each fix has a test that fails without it: the reader against an owner with commits only in its log, an exclusive-locking owner, an owner starting during an immutable read, and a commit during the copy; the mixed-session row through the whole ledger, the store's key and its migration; the Gemini meter's path and the corpus root moving together. Also stated in usage/amp.ts: a reworded Amp report reads as silence on purpose. And measured, not changed: on 166 real Gemini chat logs (104 message ids, 242 checkpoints) no later record restates lower counts than an earlier one, so the last record of each call is also its largest. Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
Round 1 of at most 3 — Codex GPT-5.6-Sol (low) requested changes on [P1]
[P1]
[P1] Risks and missing coverage
|
iamenahs
left a comment
There was a problem hiding this comment.
Review by Codex GPT-5.6-Sol · Low · via HarnessDesk
Review by Codex 0.155.0 · GPT-5.6-Sol · Low effort · via HarnessDesk
I found no remaining correctness defect on 9bc375a1.
The three round-1 P1 repairs are sound:
packages/server/src/ledger/foreign-db.ts:59:readForeignDatabaseno longer infers ownership from-shm. A quiescent WAL database is read immutably and rejected if the database/WAL stamps or side-file presence change; a database with either WAL side file is copied with its WAL, checked against the source, retried on a detected race, and read only from the private copy. Errors propagate to the scan, sopackages/server/src/ledger/index.ts:210retains the prior rows rather than replacing them with a torn or empty read. The active-WAL, exclusive-locking, owner-starting, one-commit retry, and continuously-changing refusal tests exercise the important branches.packages/server/src/ledger/scan.ts:154andpackages/server/src/ledger/store.ts:83: the vendored bit is now part of both aggregation identities. The store migration derives it fromvendorCost, and the upsert conflict target matches the new primary key, so a priced request cannot absorb an unpriced request while requests within either class still accumulate. The same-day/same-model/same-project ledger test proves the observable result: recorded cost plus list-price fallback withmixedprovenance.packages/server/src/usage/gemini.ts:121andpackages/server/src/bootstrap.ts:502:GeminiMeterandcorpusRoot('gemini', env)receive the same merged row environment. The moved-home binding test checks both credential watch path and transcript root, closing the account-splitting defect.
Risks and missing tests:
packages/server/src/ledger/foreign-db.ts:139deliberately uses size/mtime stamps rather than a SQLite backup API. That is consistent with the read-only requirement and the tests cover the application-level races this PR can induce, but an adversarial same-size/same-mtime rewrite or atomic replacement is not covered. I do not see evidence that OpenCode or Cline writes that way; proving more would require a live stress test against their actual database writers or adding inode/content/version checks.packages/server/src/ledger/store.ts:109tests migration from the pre-vendorCostschema and reopening the result, but not a separately constructed intermediate schema that already hasvendorCostand lacksvendored. The migration SQL handles that shape directly (carried === true), so this is a coverage gap rather than a supported defect.packages/server/src/ledger/foreign-db.ts:112intentionally refuses an active database whose database plus WAL exceed 1 GiB. That preserves correctness and previous rows, but a user with a very large OpenCode/Cline store will see stale spend until the database becomes quiescent or smaller; there is no boundary test at the limit.- Per the read-only instruction I did not run tests or builds. I confirmed the checkout and live PR head are
9bc375a1, the base is6b007c6d, and GitHub reports the build/test, browser integration, and native integration checks green on that head. I also inspected both main-merge resolutions; their substantive main-side changes are in menu/delegation and reduced-motion/workbench surfaces, not this PR's usage implementation.
What I checked and found sound beyond the repairs: OpenCode and Cline whole-file scans replace prior file rows only after a successful read; zero vendor cost remains a priced zero; ledger pricing and vendorMetered/mixed propagation agree with the Dashboard's band, page sentence, footnote, balance rail, and top-up wording. Cline continues to avoid refresh-token rotation, selects the active organization's balance before the user's, converts micro-dollars correctly, and reads usage rather than double-counting aggregateUsage. Gemini/Qwen token normalization, Gemini last-record deduplication, Amp's fail-closed parser and five-minute throttle, command-name binding, environment-specific corpus roots, and the project-root memoization fix are coherent with their tests and callers.
I read the complete PR diff and every touched implementation, test, and documentation file at 9bc375a1.
Verdict: approve
… two migrations, state the two accepted limits Codex GPT-5.6-Sol (low) approved round 1's three fixes with no remaining correctness defect, and named three residual risks — none an actionable defect in this PR's own reach. - The consistency check in `readForeignDatabase` compares size and modification time, not bytes, so a rewrite landing on both by chance would slip past it. Neither OpenCode's nor Cline's writer does this: every write through SQLite's WAL path changes the WAL file's size. Stated as the deliberate tradeoff it is, in `foreign-db.ts` and the docs, rather than adding a byte-level check to guard a pattern neither writer uses. - A store already carrying `vendorCost` but not the `vendored` key bit — the shape between the two migrations — had no test. Added: built with that exact intermediate schema, migrated, read back correct. It fails without the migration's `carried` detection. - The 1 GiB snapshot limit is now stated in `foreign-db.ts` as deliberate: a database that size and possibly open is refused rather than copied, so a very large store keeps its last good rows rather than paying for a whole-file copy on every scan. Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
Round 2 of at most 3 — Codex GPT-5.6-Sol (low) approved on Three residual risks, all in code this PR touches but none an actionable defect:
Both rounds are done: round 1 found and fixed three P1s, round 2 found no defect and closed the one real coverage gap it raised. Merging. |
|
Review by Codex 0.155.0 · GPT-5.6-Sol · Low effort · via HarnessDesk I found one remaining correctness defect.
Risks and missing coverage:
What I checked and found sound: the round-1 immutable/snapshot reader repair covers quiescent WAL, active WAL, exclusive locking, start-during-read, commit-during-copy, retry exhaustion, cleanup, and read-only behavior. The round-1 priced/unpriced split remains correct in both the scanner key and store primary key; zero vendor cost stays priced, and the query produces honest I read the complete 2,909-line diff and the touched implementation/tests at Verdict: request changes |
…was read from the default account, not its own Codex GPT-5.6-Sol (low) found one real defect, the last round under the project's 3-round limit. Cline moves its whole folder with `--data-dir <dir>` on the row, and has no environment variable for it (`known-agents.ts` already says so, and `identity.ts` already resolves it for the account chip). The usage binding only read `CLINE_DATA_DIR`/`CLINE_DIR`, which such a row never sets, so a second Cline account run this way showed the default account's balance and spend, or nothing at all, despite `--data-dir` naming exactly where its records are. `clineDataFolder` in `identity.ts` is now `clineDataDirOverride`, doing only the unambiguous half — resolving `--data-dir` the way Cline resolves it, relative to the row's own `cwd` — and reused from `bootstrap.ts`: a row that carries the flag has its meter and its ledger corpus both built from that folder; one that does not falls back to the environment as before. New test: a row with `--data-dir /work/second-cline` binds its meter and its ledger root under that folder, a relative `--data-dir` resolves against the row's `cwd`, and a plain row keeps the environment-based default. It fails without the fix. Per the review process's 3-round limit, this is the last round: I am not running a fourth. `node script/verify.mjs` is green on this commit; the PR reply and the report to the owner cover what happens next. Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
Round 3 of at most 3 — Codex GPT-5.6-Sol (low) requested changes on [P1]
Per the project's 3-round limit, I am not running a fourth round or merging. I've reported the full state — every round, this fix, and what's still open — to the owner directly; they'll decide how to proceed. |
iamenahs
left a comment
There was a problem hiding this comment.
Review by Codex GPT-5.6-Sol · Low · via HarnessDesk
Review by Codex 0.155.0 · GPT-5.6-Sol · Low effort · via HarnessDesk
I reviewed the full 21-file diff at 086058a6 and then read every touched file in this checkout. I did not build or run tests, per the read-only instruction. The current checks I could inspect show Build/typecheck/test, UI-system native integration, and UI-system browser integration passing; the unsigned package job had not completed when I checked.
Findings:
packages/server/src/bootstrap.ts:539drops Cline'sCLINE_DB_DATA_DIRas soon as the row also has--data-dir. The no-flag path delegates tocorpusRoot, whose Cline branch explicitly givesCLINE_DB_DATA_DIRprecedence over the data folder (packages/server/src/ledger/scan.ts:891-893), but the round-3 branch hard-codes<override>/db/sessions.db. A valid row using--data-dirfor settings/account state andCLINE_DB_DATA_DIRfor the database will therefore bind the meter to the right account but scan the wrong (usually absent or stale) database. The new local-meter test covers absolute, relative, and plain--data-dir, but not this supported combination.packages/server/src/bootstrap.ts:554-556binds every Amp row to a defaultnew AmpMeter(), even though this function has already constructed the row's merged environment.AmpMeterthen resolvesampfrom the host process PATH/home and launches it without the row environment (packages/server/src/usage/amp.ts:91-107,134-139). An Amp ACP row that runs with a row-specific PATH or home can work normally while the card either finds no Amp CLI or reports the host's default Amp account instead of that row's account. The Amp tests inject a command/runner directly, so they do not cover the actuallocalUsageForbinding with a moved environment.packages/ui/src/lib/usage.ts:527-528still hard-codes the plural exhausted headline as “agents are out of quota.” Now that prepaid balances participate inmeteredandexhausted, two spent balance-only accounts (for example Amp and Cline) produce that sentence even though neither has a quota; a mixed exhausted balance/window set is also mislabeled. The new runway test pins only the single overdrawn-balance branch, so this plural path is untested.
Risks and missing coverage: please add the --data-dir + CLINE_DB_DATA_DIR precedence case, an Amp binding test that proves command discovery and execution use the row environment, and plural exhausted-balance/mixed-state runway cases. I am also unsure whether Amp supports more account-selection inputs beyond PATH/home; a two-profile real-CLI run would be needed to establish that, but the environment mismatch above exists independently in the code.
What I found sound: the round-3 helper is shared by identity and usage binding, and its absolute and cwd-relative --data-dir resolution is internally consistent; Cline settings and the default database stay together in those covered cases. I also read and found sound the Gemini and Qwen token arithmetic/deduplication, OpenCode and Cline session scanners (including avoiding Cline aggregate/subagent double counting), vendor-cost/list-price row separation and store migration, project-root memoization repair, read-only foreign-SQLite snapshot/immutable paths and race checks, host/context root plumbing, Gemini moved-home binding, single-account balance copy/rail rendering, and provenance-specific dashboard copy. The tests cover those named paths with focused fixtures, and the documentation matches the implementation except for the override combinations above.
Verdict: request changes
…give Amp the row's environment, name a plural spent group by what it ran out of Codex GPT-5.6-Sol (low) reviewed round 3's fix and the full diff. Found three real defects, all in code this PR added or changed. - The round-3 Cline fix hard-coded `<override>/db/sessions.db` for a row carrying `--data-dir`, dropping `CLINE_DB_DATA_DIR`'s own say over the database alone — a rule `corpusRoot` already honours with no override. A row using `--data-dir` for the account and `CLINE_DB_DATA_DIR` for the database bound the meter correctly but scanned the wrong one. Fixed: the environment variable still wins for the database path even under an override; only the settings path is unconditionally the override's. - `AmpMeter` was always built bare (`new AmpMeter()`), so it asked the host process's own `PATH`/`HOME` for `amp` and ran it there, ignoring the row's merged environment `localUsageFor` had already built. A row with its own Amp account, reached through a row-specific PATH, would report the host's account instead of its own. Fixed: the meter takes the row's environment, used both to locate the binary and to run it. - The plural "N agents are out of quota." line said "quota" even when every exhausted account was a spent balance (Amp, Cline), which has none. Fixed: the plural line now says "credits" when every one is balance-only, "quota" when none is, and "credits or quota" for a mix — the same distinction the singular line already drew. Each fix has a test that fails without it: a Cline row with both flags set, proving the database follows the environment variable and the settings follow the override; an Amp row with a fixture `amp` on a row-only PATH, proving the row's environment reaches both the lookup and the run; three runway cases (all-credits, all-quota, mixed) for the plural headline. Per the review process, the owner approved exactly one round beyond the project's normal 3-round limit for this PR, given round 3's fix was small. Round 4 found real defects, so per the same "an issue stops the loop" rule this is not a clean round either: I am not running a further round on my own authority. `node script/verify.mjs` is green on this commit. Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
Round 4 (one round beyond the project's normal 3-round limit, approved by the owner given round 3's fix was small) — Codex GPT-5.6-Sol (low) requested changes on [P1]
[P1]
[P1]
|
|
Review by Codex 0.155.0 · GPT-5.6-Sol · Low effort · via HarnessDesk I found one remaining row-binding correctness defect.
Risks and missing coverage:
What I checked and found sound: all three round-4 repairs are internally complete for their covered inputs. Cline keeps Verdict: request changes |
…spoke variables, moves every local usage path Codex GPT-5.6-Sol (low) reviewed the three round-4 fixes and the full diff, and found one more real defect, in the fallback beneath all of them. `localUsageFor` merges a row's own environment over the desk's, and rounds 1, 3 and 4 each taught one path to follow a bespoke variable moved with it — `GEMINI_CLI_HOME`, `--data-dir`, a row-only `PATH`. None of them followed the plainest one: a row isolated with a bare `HOME`, ahead of any of the above. `records()`'s call to `corpusRoot` dropped its `home` argument entirely, falling back to the desk's own `homedir()`; `GeminiMeter` and Cline's `clineDataDir` each had the same fallback internally; and `--data-dir ~/...` expanded `~` against the desk's home too. A row running as a second account through nothing but `HOME` had its Gemini or Cline sign-in, its Qwen and OpenCode spend, all read from the desk's own account. `localUsageFor` now computes the row's effective home once (`env['HOME']?.trim() || homedir()`) and threads it through every one of those: `corpusRoot`'s `home` parameter, a new `home` option on `GeminiMeter`, Cline's internal fallback, and the `home` passed into `clineDataDirOverride`. New tests: one row isolated only by `HOME` proves Gemini, Cline (plain), Qwen and OpenCode all move together; a `--data-dir ~/...` row under that same `HOME` proves the `~` expansion follows it too; and `GeminiMeter` constructed directly with only `env` (the path `localUsageFor` never exercises, since it always supplies `home` explicitly) is pinned on its own. Each of the five call sites fails under its own mutation with the fix removed, and passes restored. Per the review process, the owner approved this as a second round beyond the normal 3-round limit, given round 4's three findings were fixes to the same class of gap rather than new scope. Round 5 found one more in that same class, so per the same rule this is not a clean round either: I am not running a sixth round on my own authority. `node script/verify.mjs` is green on this commit. Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
Round 5 (second round beyond the project's normal 3-round limit, approved by the owner) — Codex GPT-5.6-Sol (low) requested changes on [P1] A row isolated with a bare
|
|
Merging without a round 6, on the owner's explicit decision. Five rounds, four of them (1, 3, 4, 5) found a real defect and one (2) approved outright. Every finding was fixed on the head that follows it, each with a test proven to fail under its own mutation:
Rounds 3 through 5 all found the same class of gap — a row-specific override the binding forgot to thread through — each time in the fix the previous round produced or in a sibling path the reviewer went looking for after. Merging now on the strength of that evidence rather than a sixth round. |
Follows #769, which metered Antigravity and merged as
0502b80d. This PR is based onmain.Summary
Besides Antigravity, five agents read not metered on the Dashboard: Amp, Cline, Gemini CLI, OpenCode and Qwen Code. I checked each one's own source, on 2026-09-18, for what it can tell a client. Each card now shows what that agent actually exposes:
Before and after
The same desk and the same fixture records, captured on the real host with
HOMEpointed at the fixtures. Fake CLIs stand in forampandagy, and a local server stands in for Cline's API. No real account or transcript is in either frame. Before ismainat0502b80d, where only Antigravity is metered (#769); after is this branch.main)Screenshots
From the same fixture desk as the before and after above; no real account is in any frame.
Each agent's card
amp usageA spent balance
The Cline stand-in answering an overdrawn balance, −$0.016.
The money band
The four agents' spend is stacked by day. The sentence under the total now says what the figure is made of: part is what OpenCode and Cline recorded, and part is list price (
mixed). Before, it called every figure "what these tokens would have cost at public API rates", which is no longer true of all of it (second commit,66a277d9).Two more sentences called every cost a public price, which is no longer true when some prices are what an agent recorded. Both now say where the prices came from, the way the band's subtitle does: public rates, the agents' own records, or both, as here (fourth commit,
f0531fc2).What each agent offers, and what the card now shows
amp usageprints the credit balance in a short markdown report written by Amp's server; there is no JSON form. Account lookups share a limit of 60 per hour with Amp's own.amp-acpreceives the SDK's per-messageusageand discards it.$10.00 left; re-asked at most every 5 minutes/api/v1/users/me, then the balance of the active organization or the user (in micro-dollars), with the session stored inproviders.json. Its ACP server receives ausageevent from its engine and drops it (case "usage": return []).sessions.dbkeeps each session'susage.totalCost.GET /zen/go/v1/usagewith the Go key returns the rolling 5-hour, weekly and monthly windows (shipped from anomalyco/opencode#16017). This PR doesn't read that endpoint yet, because there's no Go subscription here to test against. OpenCode sendsusage_update(context size and session cost) and stores each session's tokens andcostinopencode.db.$0usageMetadatafor every call.Design
**<name>:** $<n> remaininglines andSigned in as. A report with neither shows nothing. Runningamp usageleft Amp's binary and log files untouched.vendorCost, and the ledger uses it in place of list price. A free model's$0stays$0; it is not reported as unpriced.vendorMetered, ormixedwhen it also includes list-priced rows. The protocol already defined both labels; nothing used them.usageis read, neveraggregateUsage: subagents are separate rows, so adding the aggregate would count them twice.-shmand-walfiles in the owner's folder (measured), and neither a leftover-shmnor a missing one says who has it open: Cline's has outlived its last run by weeks, and an owner in exclusive locking mode never makes one.readForeignDatabasechooses from what is on disk instead. A WAL database with neither-walnor-shmbeside it is openedimmutable, and the read is checked afterwards, so an owner starting mid-read has its answer discarded. One with either file is copied, with its log, to a private folder and read there; the copy is trusted only if the source's size and time were the same before and after it, and is retried up to three times. Nothing of the owner's is opened, locked or recreated.A bug the new tests found
projectRootOfmemoised the first repository-less folder's answer onto every ancestor folder. Every later folder without a repository was then filed under that first one. Asking for/work/aand then/work/breturned/work/aboth times, which merged unrelated projects in the Where it went band.It now remembers, for each folder it walks, the repository at or above it, or that there is none. One CRLF test had only passed because of the bug, since it merged the fixture's two folders into one row. It now counts across rows.
Checked against real records
The same build also ran against the development machine's own records, with nothing published from it:
The frames from that run showed real accounts and were deleted.
Upstream
Filed while working on this PR. Each report links this PR as the workaround in use until it's resolved.
usageasusage_updateandPromptResponse.usage; today it drops the event.PromptResponse.usage), counted from the usage Amp reports for each response.usage_updateandPromptResponse.usage, not only_meta.quota. The same request (google-gemini/gemini-cli#24280) was closed as completed without the change.amp usage --jsonis drafted for [email protected].Nothing is filed for Qwen Code: it has no quota to report, and its transcripts already carry usage.
Test plan
ledger-agents.test.ts:$0and the paid cost are used as recorded, and nothing is written next to the database.usageversusaggregateUsagerule.mixedprovenance, the store migration,readForeignDatabaseon idle, live-owner, exclusive-locking and racing databases, a priced and an unpriced session sharing a day, model and folder, the store's key and its migration, a moved Gemini home, each agent's path overrides, and theprojectRootOfregression.credit-meters.test.ts:local-meters.test.ts: each agent binds, including rows with no knowledge-table entry.usage.test.tsandUsage.note.test.tsx: the balance-aware header line, the top-up sentence, and the page sentence and table footnote (costClause,pricedNote).node script/verify.mjson6206125a, onmainat4762d35c: every step green.6206125a; see the reply on this PR.ampandagy, a local stand-in for Cline's API): every card shows its figure; the page sentence and the Where it went footnote read as in the frames above; switching the stand-in to −$0.016 and pressing Refresh turns the line above the cards to "Cline is out of credits.", the card to the top-up sentence and the rail to a red balance; no-shmor-walfile appears beside the fixture databases.mainand on this branch: the frames above. Before was re-shot onmainat0502b80d. The overview, the Accounts rail and the table footnote were re-shot on Meter Antigravity from agy's own /usage, and step around a spent model group #769'sed19ae3d; what reachedmainsince changes nothing these frames show (a server-side hold on agy's last answer, seating, two z-index values turned into tokens, and docs).🤖 Generated with Claude Code