Split out of #1153, from its peer review.
The in-memory ring (core/cost/usage) keeps no unit per figure: bucket has no currency series, and Aggregator.Snapshot never sets Snapshot.Currencies. So a window it serves — a duration such as abctl cost --window 1h, or any window when no cost ledger is configured, which is the Kubernetes deployment — adds every unit's figures into one Totals.CostMicros. abctl cost prints that under $, because an absent currencies list reads as the default.
#1153 makes the ring say what it cannot do rather than track units: group=currency is answered with group: "none", which abctl reports as a downgrade, and docs/pricing.md scopes "figures in different units are never added" to ledger windows. The ledger path separates units end to end.
Shape of a fix
The ledger writer takes its unit from pricing.Resolver.CurrencyFor(host, model). Giving the aggregator the same resolver would let it key a currency series per bucket and compute Currencies the way ledger.CurrenciesIn does — at which point the ring can serve group=currency too, and the downgrade at the top of Aggregator.Snapshot goes.
Reachable set
A configured non-USD unit: and a ring-served window. A deployment with no unit: configured is unaffected: every figure it has is USD.
Assisted-By: Claude (Anthropic AI) noreply@anthropic.com
Split out of #1153, from its peer review.
The in-memory ring (
core/cost/usage) keeps no unit per figure:buckethas no currency series, andAggregator.Snapshotnever setsSnapshot.Currencies. So a window it serves — a duration such asabctl cost --window 1h, or any window when no cost ledger is configured, which is the Kubernetes deployment — adds every unit's figures into oneTotals.CostMicros.abctl costprints that under$, because an absentcurrencieslist reads as the default.#1153 makes the ring say what it cannot do rather than track units:
group=currencyis answered withgroup: "none", which abctl reports as a downgrade, anddocs/pricing.mdscopes "figures in different units are never added" to ledger windows. The ledger path separates units end to end.Shape of a fix
The ledger writer takes its unit from
pricing.Resolver.CurrencyFor(host, model). Giving the aggregator the same resolver would let it key a currency series per bucket and computeCurrenciesthe wayledger.CurrenciesIndoes — at which point the ring can servegroup=currencytoo, and the downgrade at the top ofAggregator.Snapshotgoes.Reachable set
A configured non-USD
unit:and a ring-served window. A deployment with nounit:configured is unaffected: every figure it has is USD.Assisted-By: Claude (Anthropic AI) noreply@anthropic.com