Skip to content

usage: the in-memory ring adds figures across billing units #1188

Description

@huang195

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

Activity

  1. huang195 commented on Oct 2, 2026

    @huang195
    MemberAuthor

    Already fixed on main by 8776e32 ("Report billing units from the usage ring, and per agent"), merged in #1195 on 2026-09-30. That PR closed only #1182, so this one stayed open.

    The fix is the one this issue sketched:

    • Each ring bucket keeps a per-unit series. It is bucket.byCurrency in core/cost/usage/usage.go, keyed by the record's unit using the ledger's rule (pricing.UnitOf).
    • Aggregator.Snapshot fills in Currencies from the units behind every priced or saved figure, as ledger.CurrenciesIn does.
    • The ring serves group=currency. The downgrade to group: "none" is gone.

    As a result, a ring-served window (agentop cost --window 1h, or any window on a deployment with no cost ledger) no longer adds figures across units. docs/pricing.md now scopes "figures in different units are never added" to both the ledger and the ring.

    These tests in core/cost/usage/currency_test.go cover it: TestSnapshot_TheRingBreaksTotalsDownByUnit, TestSnapshot_TheRingNamesItsUnitsUngrouped and TestSnapshot_TheRingReportsDollarsLikeTheLedger.

    Assisted-By: Claude (Anthropic AI) noreply@anthropic.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions