Skip to content

Re-enable the controller-plans e2e against the ASAPPlanner path - #726

Merged
zzylol merged 1 commit into
mainfrom
fix/723-e2e-payload-port
Sep 14, 2026
Merged

zzylol merged 1 commit into
mainfrom
fix/723-e2e-payload-port

Conversation

@zzylol

@zzylol zzylol commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Closes #723. The 12 tests in data_plane/tests/e2e_controller_plans_and_backend_serves.rs are un-ignored and passing.

−415 / +133.

What was wrong

#725 ported the scaffolding — the file compiled — but the tests still built their OTLP payloads for the summary families the legacy path was told to use via sketch_type_override. ASAPPlanner has no such override; it picks from the accuracy target. Three separate things had to line up.

1. Grouping is a contract between the plan and the wire

The population key the backend materializes under has to match the attributes the producer puts on each frame. The registered queries carried no grouping, so the planner derived an empty grouping_labels while the frames carried service / zone. Ingest rejected them:

summary frame for http_latency_ms declares materialization 16862332280056730734
  but active schema resolves 0
frame has no matching transmission rule

Queries are now registered as sum by (service) (...), which is what puts service into grouping_labels. Verified directly rather than assumed:

quantile_over_time(0.99, http_latency_ms[1s])                  -> grouping=[]
quantile_over_time(0.99, http_latency_ms{service="..."}[1s])   -> grouping=[]
sum by (service) (quantile_over_time(0.99, http_latency_ms[1s])) -> grouping=["service"]

2. Registration is not readout

Wrapping the query in the same aggregation was my first attempt, and it returned No result for query everywhere. A diagnostic against a populated backend showed why:

sum by (service) (quantile_over_time(0.99, http_latency_ms[1s]))
  -> {"error":"No result for query"}
quantile_over_time(0.99, http_latency_ms[1s])
  -> {"result":[{"metric":{"service":"e2e-test"},"value":[...,"1.0512202836445257"]}]}

The data was fine the whole time. The stored summaries are already per-service, so the inner form reads them and the result carries the label without the outer aggregation. Registration decides how the materialization is keyed; readout uses the original query shape. The tests now register with the grouping and read with the inner form.

3. Payload families follow the planner

Measured, not assumed:

query old sketch_type_override planner's choice
quantile_over_time(0.5, request_size_bytes[1s]) KLL DDSketch, alpha
count_over_time(unique_users_per_min[1s]) HLL CountMinSketch, w=55 d=3
topk(3, count_over_time(top_endpoint_qps[1s])) CountSketch CountMinSketch

Payloads are built from materializations[0].parameters rather than from constants, so a later planner change moves the fixture with it instead of breaking it. The topk case also needed the plain Data::Countminsketch proto envelope — it was declaring Data::Countsketch, which is why it kept missing the transmission rule after the other fixes landed.

Harness fixes

  • The first two tests used start_backend_http_server, which never attached the physical-plan handles (503: physical-plan hot-reload handles are not attached). They now use start_full_stack like the other ten.
  • The first test's window went from 60s to 1s so it agrees with the pane layout post_full_config pins, which was failing as InvalidWindowLayout { reason: "window kind disagrees with size and slide" }.
  • Test 2's grouping assertion moved off the legacy streaming-config snapshot (gone with Retire the collector-facing emission pipeline #725) onto the installed materialization's grouping_labels — the invariant it was actually checking.

Removed

build_kll_state, build_kll_export, build_hll_state, build_hll_export, build_heap_bearing_msgpack, start_backend_http_server, get_streaming_config and the KLL/HLL proto imports. Every test now installs through the same physical-plan path, so none of them has a caller. The data plane still supports those wire encodings; these are fixture builders, recoverable from history if a future test needs to cover those formats.

Testing

  • cargo +1.98.0 test -p data_plane --test e2e_controller_plans_and_backend_serves — 12 passed, 0 failed.
  • cargo +1.98.0 fmt -- --check — clean.
  • cargo +1.98.0 clippy --workspace --all-targets -- -D warnings — clean.
  • cargo +1.98.0 test --workspace -- --test-threads=1 — exit 0, zero failures.

🤖 Generated with Claude Code

The 12 tests were ignored by #725 because their payload construction
assumed the summary families the legacy path was told to use via
`sketch_type_override`. ASAPPlanner has no such override — it picks from
the accuracy target — so the tests now read back what it committed to.

Three things had to line up.

**Grouping.** The population key the backend materializes under has to
match the attributes the producer puts on the wire. The queries carried
no grouping, so the planner derived an empty `grouping_labels` while the
frames carried `service`/`zone`, and ingest rejected them with `active
schema resolves 0` or `frame has no matching transmission rule`. The
queries are now registered as `sum by (service) (...)`.

**Registration is not readout.** Wrapping the *query* in the same
aggregation returns no result: the stored summaries are already
per-service, so the inner form reads them and the result carries the
label. Registration decides how the materialization is keyed; readout
uses the original shape.

**Families follow the planner.** Measured, not assumed:

| query | old override | planner's choice |
|---|---|---|
| `quantile_over_time(0.5, request_size_bytes[1s])` | KLL | DDSketch (`alpha`) |
| `count_over_time(unique_users_per_min[1s])` | HLL | CountMinSketch (`w`, `d`) |
| `topk(3, count_over_time(top_endpoint_qps[1s]))` | CountSketch | CountMinSketch |

Payloads are built from `materializations[0].parameters`, so a future
planner change moves the fixture with it instead of breaking it.

Two harness fixes: the first two tests moved to `start_full_stack`
because `start_backend_http_server` never attached the physical-plan
handles, and the first test's window went from 60s to 1s to agree with
the pane layout the install pins.

The KLL and HLL builders, the plain `start_backend_http_server` harness
and the legacy streaming-config snapshot accessor go with them — every
test now installs through the same physical-plan path.

Closes #723.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@zzylol
zzylol merged commit fa563ae into main Sep 14, 2026
1 check 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.

Re-enable the controller-plans e2e against the ASAPPlanner path

1 participant