Skip to content

feat(storage): aggregate cost-ledger spend by dimension - #40

Merged
prashar32 merged 1 commit into
mainfrom
feat/usage-summary-storage
May 31, 2026
Merged

feat(storage): aggregate cost-ledger spend by dimension#40
prashar32 merged 1 commit into
mainfrom
feat/usage-summary-storage

Conversation

@prashar32

Copy link
Copy Markdown
Owner

First PR of the v0.2.0 observability work (#37) — the storage foundation. No public surface changes; the CLI (audit summary) and API (GET /v1/usage/summary) land in follow-ups on top of this.

What

Store.SummarizeLedger(ctx, SummarizeOptions) (UsageSummary, error) — groups cost-ledger spend (calls / prompt+completion tokens / dollars) across runs by one dimension:

  • provider, model, day (UTC date), name (run name), or metadata.<key> (e.g. metadata.team)
  • optional Since / Until time bounds (inclusive / exclusive)
  • ordered by spend desc; includes a grand Total

Spend is summed from cost_ledger (the auditable source of truth), not the run rollup.

Safety

  • The grouping expression is structural, so it's chosen from a fixed whitelist — never built from raw caller input.
  • For metadata.<key>, the key is validated (identifier-like only) and the JSON path is bound as a parameter to json_extract. No SQL injection surface.

Tests

TestSummarizeLedger: by team (metadata), provider, name, and day (with a time bound), grand total, spend-desc ordering, and rejection of an unsupported dimension / unsafe metadata key. go test ./internal/storage, go vet, gofmt all clean. (json_extract confirmed working under the pure-Go modernc.org/sqlite driver.)

Part of the v0.2.0 series: storage → API → CLI → OTel tagging → tool_calls read-back (#38) → example dashboard.

Add Store.SummarizeLedger — group spend (calls/tokens/dollars) across runs by
provider, model, day, run name, or a run-metadata key (e.g. metadata.team), with
optional since/until time bounds. Sums from the cost_ledger (the auditable source),
not the run rollup.

The grouping expression is chosen from a fixed whitelist (it's structural, not a
bindable parameter); the metadata JSON path is bound as a value and its key is
validated, so nothing is built unsafely from caller input.

This is the storage foundation for the usage-rollup CLI/API (#37) — no public
surface yet.
@prashar32
prashar32 merged commit e6359cf into main May 31, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant