# 078 — Metric-comparison filters scan every metric's buckets on every query ## Summary Same underlying issue as ticket 077 (iterators should narrow the key range as far as possible, and take a range as a parameter), applied to metrics: a metric-comparison filter (e.g. `latency_ms[value]<200` in the filter bar) rebuilds its matching-sequence set from scratch on every single query by scanning *all* buckets for *all* metrics, then discarding everything that doesn't match the requested metric name — instead of seeking directly to that metric's key range. ## Where - `EngineSnapshot::bucket_values` (`src/engine/snapshot/metrics.rs:295-312`) ranges `IndexKey::MetricBucketSplit..IndexKey::End` — every bucket for every declared metric — and filters by `name == metric_name` inside the `filter_map` closure. `IndexKey::Bucket { metric_name, labels }` (`src/engine/index_key.rs:23-26`) derives `Ord` on `metric_name` first, so this is seekable: a lower bound of `IndexKey::Bucket { metric_name: metric_name.into(), labels: BTreeMap::new() }` and an upper bound one metric name past it would narrow the range to just that metric's buckets. - The compare-filter compiler, `compile_metric_comparison` (`src/engine/snapshot/filter.rs:83-104`), calls `self.bucket_values(metric, None)` and builds a fresh `HashSet` of matching sequences on every call — this runs once per filter compile, and filters are compiled fresh per query (`compile_filter_query`, called from `src/engine/snapshot/query.rs:46`), so a dashboard or search bar polling with a metric-comparison filter re-scans all bucket values every poll interval. Unlike the log sort-helper indexes (`src/engine/snapshot/sort.rs`), there is no incremental cache here keyed by `(metric, param, op, value)`. ## Scope - Narrow `bucket_values` to accept/derive a key range for the requested `metric_name` instead of ranging `MetricBucketSplit..End` and filtering by name in the closure. This alone removes the "every other metric's buckets" part of the scan regardless of caching. - Separately (bigger win, more invasive — may warrant its own follow-up ticket): consider whether metric-comparison results can be incrementally maintained similarly to `sort_helper_indexes` (`src/engine/snapshot/sort.rs`) rather than recomputed per query, if profiling shows compare-filtered dashboard polling is a hot path. Keep this ticket scoped to the range-narrowing fix; note the caching idea here so it isn't lost, but split it out if it turns out to need design work (cache invalidation on new bucket values, per unique filter expression). ## Depends on None. Same principle as ticket 077.