Skip to content

fix(query): route handle_query misses through modern execute() trait path - #253

Merged
zzylol merged 1 commit into
mainfrom
route-handle-query-through-execute
May 15, 2026
Merged

zzylol merged 1 commit into
mainfrom
route-handle-query-through-execute

Conversation

@zzylol

@zzylol zzylol commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes the gap pinned in #252. The legacy ASAPQueryEngine::handle_query path can't read sketch-backed sids (query_precomputes_by_agg only matches AggKind::ExactAgg), but the modern execute(&str) trait path (engine.rs:3430) DOES — it dispatches via find_matching_policiesidx.sids_for_policy(fp)SketchReducer::evaluate and handles sketches natively.

process_via_simple_engine (HTTP handler for SketchStore-routed queries) now falls back to execute(&str) when handle_query returns None. Trait dispatch loses KeyByLabelNames; we surface KeyByLabelNames::default() (mirroring process_via_router's identical handling) — the Prometheus adapter renders the empty metric: {} shape, valid PromQL response.

Setup-side bug that this also catches

Diagnostic also surfaced a missing .with_sketch_index(idx) call in the test harness. Without it, the engine's sketch_index is None and every fast path (execute_store_query, execute(&str), query_range, …) is silently skipped — all guard with let Some(idx) = self.sketch_index.as_ref() else { return … };. Production data_plane/main.rs gets this right; start_test_server callers were missing it.

Both test harness helpers now thread with_sketch_index(sketch_index.clone()) so the engine sees the same store OTLP ingest writes to.

Test 3 strict assertion now active

controller_plan_to_query_full_roundtrip_ddsketch was soft-checking status field exists. After this PR: status == "success" — the FULL e2e path (controller plan → POST /api/v1/streaming-config → OTLP DDSketch DPs → window close → GET /api/v1/query) works end-to-end.

This is the first green-bar e2e test for the gateway-less data path.

Test plan

  • cargo test --test e2e_controller_plans_and_backend_serves: 3 passed; 0 failed (was 2/3 with Test 3 soft-checked)
  • Full sweep: lib 690 + bins 27 + integration tests all green

Out of scope

The legacy query_precomputes_by_agg filter still doesn't include AggKind::Sketch (per #252's diagnostic comment). Closing that fully would let us delete this fallback. Not blocking; the fallback is a stable bridge.

🤖 Generated with Claude Code

…path

Closes the gap pinned in #252: the legacy ASAPQueryEngine::handle_query
path can't read sketch-backed sids (`query_precomputes_by_agg` only
matches `AggKind::ExactAgg`), but the modern `execute(&str)` trait
path (engine.rs:3430) DOES — it dispatches via
`find_matching_policies` → `idx.sids_for_policy(fp)` →
`SketchReducer::evaluate` and handles sketches natively.

`process_via_simple_engine` (the HTTP handler for SketchStore-routed
queries) now falls back to `execute(&str)` when `handle_query`
returns None. Trait dispatch loses `KeyByLabelNames`; we surface
`KeyByLabelNames::default()` (mirroring `process_via_router`'s
identical handling on line 1171) — the Prometheus adapter renders
the empty `metric: {}` shape, valid PromQL response.

## Setup-side fix (the actual bug Test 3 surfaced)

The diagnostic also caught a missing `.with_sketch_index(idx)` call in
the test harness — without it, the engine's `sketch_index` is `None`
and EVERY fast path (`execute_store_query`, `execute(&str)`,
`query_range`, …) is silently skipped because they all guard with
`let Some(idx) = self.sketch_index.as_ref() else { return … };`.
This is a load-bearing wiring step that production `data_plane/main.rs`
gets right but `start_test_server` callers were missing.

Both `start_backend_http_server` and `start_full_stack` now thread
`with_sketch_index(sketch_index.clone())` so the engine's reads see
the same store the OTLP receiver / precompute engine writes to.

## Test 3 strict assertion now active

`controller_plan_to_query_full_roundtrip_ddsketch` previously
soft-checked the response had a `status` field. After this PR it
asserts `status == "success"` — the FULL e2e path
(controller plan → POST /api/v1/streaming-config → OTLP DDSketch DPs
→ window close → GET /api/v1/query) now works end-to-end.

This is the first time we have a green-bar e2e test for the
gateway-less data path.

## Tests

- `cargo test --test e2e_controller_plans_and_backend_serves`:
  3 passed, 0 failed (was 2/3 with Test 3 soft-checked).
- Full sweep: lib 690 + bins 27 + integration tests across the
  workspace all green.

## Out of scope

The legacy `query_precomputes_by_agg` filter still doesn't include
`AggKind::Sketch` (per #252's diagnostic comment). Closing that fully
— so `handle_query` itself works for sketches — would let us delete
this fallback. Not blocking; the fallback is a stable bridge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zzylol
zzylol merged commit d38856a into main May 15, 2026
zzylol added a commit that referenced this pull request May 15, 2026
…ith-gap (#254)

Extends the e2e test suite to cover the second and third sketch
families (DDSketch is already strict-success-asserted in Test 3).

## Test 4 — controller_plan_to_query_full_roundtrip_kll (passes)

Mirrors Test 3 with `sketch_type_override: Some(SketchType::KLL)`.
Builds a `KllState` via `asap_sketchlib::proto::sketchlib::KllState`,
wraps in `KllSketchDataPoint`, OTLP-POSTs, watermark-advances,
queries `quantile_over_time(0.5, request_size_bytes[10s])`, asserts
`status == "success"`. Also asserts the controller emits
`aggregationType: DatasketchesKLL` for the override.

This validates the second of the five sketch families on the
gateway-less data path. The `execute(&str)` trait dispatcher (#253's
fallback) handles KLL identically to DDSketch — both route through
`SketchReducer::evaluate` with quantile readout dispatch.

## Test 5 — controller_plan_to_query_full_roundtrip_hll (#[ignore]'d)

Workload pins HLL with `AggType::Cardinality`. The streaming-config
registration succeeds (`aggregationType: HLL` confirmed) and the
sketch state lands in `SketchStore` — but the PromQL query path for
HLL needs a query shape the analyzer recognises as
`Capability::CardinalityApprox`. `count(metric)` doesn't map today:
`resolve_sketch_metric_alias` only rewrites `count(metric)` →
`count(metric_hll)` when the bare metric is ABSENT (a deploy-time
aliasing tactic). With bare registered, alias is a no-op and the
analyzer doesn't bind `count(...)` to the cardinality capability.

`#[ignore]`'d with a precise note pointing at the gap. The OTLP
ingest path for HLL works (no `#[ignore]` on ingest); the readout
side needs follow-up analyzer / alias work.

## Helper changes

- Splits `build_workload` into `build_workload` (no override) and
  `build_workload_with_override` (with `sketch_type_override`).
- Adds `build_kll_state` / `build_kll_export` / `build_hll_state` /
  `build_hll_export` mirrors of the existing DDSketch helpers.

## Tests

- `cargo test --test e2e_controller_plans_and_backend_serves`:
  **4 passed; 0 failed; 1 ignored** (HLL).

## What's left for full 5-sketch coverage

CountSketch (topk) and CountMinSketch (frequency / count) need their
own tests + likely similar analyzer routing work as HLL. Two paths to
ship those:

1. Wait for the analyzer-side fix on HLL — same fix likely unblocks
   all three.
2. Use the demo-contract metric names (`top_endpoint_qps`,
   `endpoint_request_freq`) which `classify_demo_metric` routes
   directly, bypassing the analyzer's bare-name handling.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zzylol added a commit that referenced this pull request May 16, 2026
Closes the range-query gap I documented in PR #260's session
follow-up. Per-user direction (2026-05-16): count_over_time is
warm-tier-answerable by sampling; topk_over_time isn't standard
PromQL anyway and falls through to the cold tier (Thanos parse-
error is acceptable).

Sibling of PR #253's instant-query trait-dispatch fallback. New
`ASAPQueryEngine::execute_range_promql_modern(query, start_ms,
end_ms, step_ms)` mirrors the analyzer + reducer dispatch from
the `QueryEngine::execute(&str)` trait surface but returns
Matrix per the `/api/v1/query_range` wire-format spec.

Wire-up: `process_range_query_request` in `http.rs` tries
`handle_range_query_promql` first (legacy path, unchanged), and
on `None` calls the new modern method. If the modern path also
errors, it falls through to `format_unsupported_query_response`
(which the EngineRouter can route to a cold-tier fallback).

Prometheus semantics note: the spec says evaluate at each
`t = start, start+step, …, end`. The warm tier returns samples
at native window-close granularity instead — finer than the
user's step when window_size < step (more data, not less).
Step-precise evaluation is a future refinement; clients that
need exact step timestamps can downsample, or route step-
precise queries to the cold tier.

Test 10 (`controller_plan_to_range_query_count_over_time_cms`)
ingests heap-less CMS DPs via the same setup as Test 7, then
queries `count_over_time(endpoint_request_freq[10s])` via
`/api/v1/query_range`. Asserts `status=success`,
`resultType=matrix`, non-empty series.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zzylol
zzylol deleted the route-handle-query-through-execute branch July 17, 2026 20:06
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