Skip to content

fix(rollup): preserve provider through the rollup index#4

Merged
bravo1goingdark merged 1 commit into
mainfrom
fix/rollup-preserve-provider
May 5, 2026
Merged

fix(rollup): preserve provider through the rollup index#4
bravo1goingdark merged 1 commit into
mainfrom
fix/rollup-preserve-provider

Conversation

@bravo1goingdark
Copy link
Copy Markdown
Owner

Why

`/v1/rollups` and `/v1/stats?group_by=model` were returning `provider=""` for every row, even though events were ingested with `provider="mistral"` / `"groq"` / etc. Anything downstream that grouped by provider collapsed onto a single empty bucket — Obol's BY PROVIDER chart was the visible victim.

Two-part root cause:

  1. `EngineConfig.rollup_dims` was `[USER_ID, API_KEY_ID, MODEL]`. Provider wasn't a grouping dim of the keplordb rollup index, so the in-memory aggregation merged across providers without distinguishing them.
  2. `RollupKey` in `kdb_store.rs` only had four fields (day + 3 dims) and `RollupRow.provider` was hard-coded to `String::new()` in the construction path.

Fix

  • `rollup_dims = [USER_ID, API_KEY_ID, MODEL, PROVIDER]` — provider becomes a grouping dim.
  • `RollupKey` gains a `provider` field, populated from `key.dims.get(3)`.
  • `dim_filters` widened from `[3]` to `[4]` slots to match the new index shape (the new slot is unfiltered for now; filtering by provider can be wired through `query_rollups` later as a parameter).
  • `RollupRow.provider` reads `k.provider` instead of empty.

Compatibility: the rollup index is in-memory and rebuilt from segments on open (`rollup_replay_days`, default 7). Existing event data on disk is unchanged; a restart triggers a one-time re-aggregation with provider as a grouping key. No migration step needed.

Verified live

Deployed manually to a running keplor instance ahead of merge. Before / after:

before: provider='' events=82 cost_nano=2162400 (collapsed)
        provider='' events=61 cost_nano=2311560
after:  provider='mistral' events=85 cost_nano=2167980
        provider='groq'    events=61 cost_nano=2311560

Test plan

  • cargo test -p keplor-store -p keplor-server (117 / 117 pass)
  • cargo clippy --workspace --all-targets -- -D warnings
  • Live restart on a populated keplor instance — rollups re-aggregate cleanly with provider populated

query_rollups was hard-coding provider: String::new() in the response
because:

1. EngineConfig.rollup_dims didn't include DIM_PROVIDER, so the
   keplordb rollup index aggregated by (user, api_key, model) and
   dropped provider entirely from the grouping key.
2. RollupKey in kdb_store.rs only carried four fields and read
   dim[0..3]; provider had no slot.

Both consequences cascaded: /v1/rollups returned provider="" for
every row, /v1/stats?group_by=model inherited the empty provider
from rollups, and downstream consumers (Obol's BY PROVIDER chart)
collapsed every event onto a single empty bucket.

Fix:
- rollup_dims now [USER_ID, API_KEY_ID, MODEL, PROVIDER]
- RollupKey gains a provider field, read from key.dims.get(3)
- dim_filters extended from [3] to [4] to align with the index
- RollupRow.provider is now k.provider instead of String::new()

The rollup index is in-memory and rebuilt from segments on open
(rollup_replay_days, default 7). Existing event data is unchanged;
restart triggers a one-time re-aggregation with provider as a
grouping key. Verified live: 22 mistral + 61 groq events now report
their providers correctly.

117 / 117 tests pass.
@bravo1goingdark bravo1goingdark merged commit d1f3b89 into main May 5, 2026
5 checks passed
@bravo1goingdark bravo1goingdark deleted the fix/rollup-preserve-provider branch May 5, 2026 19:22
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