Skip to content

feat(promql): type-driven histogram_quantile discrimination (#79) - #94

Merged
zzylol merged 1 commit into
mainfrom
feat/79-histogram-type-metadata
Jul 5, 2026
Merged

zzylol merged 1 commit into
mainfrom
feat/79-histogram-type-metadata

Conversation

@zzylol

@zzylol zzylol commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Closes #79.

Problem

histogram_quantile(φ, m) picks between exact classic-bucket interpolation (HistogramQuantile, not sketch-able) and the generic sketch-able Quantile using a purely structural heuristic (by (le) grouping / _bucket metric name / le= matcher). The true signal is the argument's sample type, which structure only proxies — so the heuristic has real failure modes:

  • false positive — a metric merely named …_bucket (or a native histogram so named) → interpolation;
  • false negative — a classic histogram exposed without _bucket and queried without le → the sketch path, which is wrong (you can't sketch pre-aggregated buckets).

Fix: drive it from declared sample type

  • histogram module: HistogramKind (ClassicBucket / Native / RawSamples — only ClassicBucket is non-sketch-able) and a HistogramCatalog (metric → kind) the client supplies.
  • histogram_arg_is_sketchable: a declared kind for any metric referenced in the argument decides it; otherwise fall back to the existing structural heuristic. So metadata overrides structure where the sample type is known, and undeclared metrics behave exactly as before.
  • New entry point lower_promql_with_histograms(query, accuracy, catalog). lower_promql stays heuristic-only.

This directly serves the design the two lowerings exist for: a client holding raw samples can declare them RawSamples and get the sketch-able Quantile even when the user wrote histogram_quantile.

On the plumbing

The discrimination is consulted in exactly one place (walk_histogram), reached from deep in the recursive, free-function walk chain. Rather than thread a catalog parameter through ~20 functions / 36 call sites, the catalog is installed as an RAII-guarded thread-local for the duration of one lowering call (lowering is synchronous, one query at a time). A test asserts it doesn't leak across calls.

Scope

The heuristic is kept as the deliberate fallback — not every metric will carry metadata, so removing it would regress undeclared queries. #79 also floated per-series tagging and an L4-deferred variant; per-metric catalog is the right granularity for the lowering-time decision and is what the client can actually declare. The mechanism is now in place for a production catalog to feed.

Tests

histogram_metadata.rs:

  • heuristic baseline unchanged without a catalog;
  • false-negative fix: declared ClassicBucket on a suffix-less metric → HistogramQuantile;
  • false-positive fix: declared RawSamples/Native on a _bucket-named metric → Quantile;
  • undeclared metric falls back to the heuristic;
  • the ambient catalog does not leak across calls.

Unit tests cover is_sketchable, catalog lookup, and guard install/restore. Full workspace suite green; clippy clean.

`histogram_quantile(φ, m)`'s classic-bucket (exact interpolation) vs
sketch-able (generic Quantile) choice was a purely structural heuristic
(`by (le)` / `_bucket` name / `le=` matcher), with false-positive
(`_bucket`-named non-histogram) and false-negative (suffix-less classic
histogram) failure modes. Drive it from the argument's declared sample type
when available.

- `histogram` module: `HistogramKind` (ClassicBucket / Native / RawSamples;
  only ClassicBucket is non-sketch-able) and a `HistogramCatalog` (metric →
  kind) the client supplies. Installed for the duration of a lowering call via
  an RAII thread-local guard — the discrimination is consulted in exactly one
  place (`walk_histogram`), so an ambient catalog avoids threading a parameter
  through the whole free-function `walk` recursion.
- `histogram_arg_is_sketchable`: a declared kind for any metric referenced in
  the argument decides it; otherwise fall back to the structural
  `is_classic_bucket_arg` heuristic (unchanged for undeclared metrics).
- New entry point `lower_promql_with_histograms(query, accuracy, catalog)`;
  `lower_promql` stays heuristic-only.

The heuristic remains as the deliberate fallback (not every metric carries
metadata); the metadata simply overrides it where the true sample type is
known.

Tests: `histogram_metadata.rs` pins the heuristic baseline, the false-negative
fix (declared ClassicBucket → HistogramQuantile), the false-positive fix
(declared Raw/Native → Quantile), heuristic fallback for undeclared metrics,
and that the ambient catalog does not leak across calls. Unit tests cover
`is_sketchable`, catalog lookup, and guard install/restore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@zzylol
zzylol merged commit 4252600 into main Jul 5, 2026
1 check passed
@zzylol
zzylol deleted the feat/79-histogram-type-metadata branch July 5, 2026 14:20
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.

PromQL: histogram_quantile classic-bucket vs sketch-able quantile is a structural heuristic — drive it from sample type/metadata

1 participant