Repository navigation
feat(planner): run the planning stages as the planner pipeline; retire MajorPass - #674
Merged
Merged
Conversation
…e MajorPass plan_stages runs logical ASAP-aware optimization (Pass 1 and composition of every combination, capped), physical ASAP-aware optimization and plan selection over the frontends' roots, and returns every stage's output. StagePipeline runs it behind OptimizationPass and is the facade default; the stage_pipeline devtool uses it (its fixture is unchanged). The combination count saturates instead of overflowing. summary_sharing: sharing tests are ignored until Pass 2 (#580); the UnivMon legacy-search test is deleted; scalar and combined-quantile tests run on plan_stages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
… cost model From #582: only plan selection prices plans, so the Pass 1 / composition and physical ASAP-aware optimization modules may not import cost_model, recurrence, analytical_cost, physical_operator_statistics or plan_selection (paths or re-exported names) outside tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
…s identity
The per-series sum keeps the input's labels, so with
$promql_series_identity after the sample value its last column is the
identity, and composition rejected the only exact option ("non-Float64
per-series avg"). The planner pipeline then had no candidate for
avg_over_time. Read the summed value by its role instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
From #629/#633: executor tests take the plan plan_stages selects (selected_dag) or its composed logical candidates (logical_candidates) instead of the legacy search and global selection. - deployment_computation, precompute_candidates, the candidates.rs fixture: ported. - planspace_series_identity_heap: keeps the selection check; the four tests of the legacy whole-root proposals are deleted. - weighted_topk_binding: ported to Pass 1 heap candidates (Count Sketch only over rates: no sign proof). The tests of legacy-only candidate generation are deleted. Ignored, with reasons: the grouped weighted binding (whole-expression heap, #589) and the two rate-heap executions (top-k output schema, #672). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
…eline From #629/#633, on support helpers over plan_stages (plan_stages, selected_dag, logical_candidates, logical_plan): - count_planning: exact counts select a Count accumulator; count updates are read from the composed Count-Min / Count Sketch candidates. The Hydra test is ported and ignored: Pass 1 offers no Hydra for a grouped count yet (#605). - univmon_candidates: the synthetic accuracy model is gone; UnivMon candidates come from Pass 1 (the shared count at an approximate target), the uncalibrated ones carry no guarantee and plan selection does not select them. - promql_corpus, metrics_observability: totality over Pass 1 and composition (logical_plan) instead of the legacy strategies; the metrics corpus reports composition errors under METRICS_OBSERVABILITY_REPORT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
From #633: the plan plan_stages selects replaces retain_exact. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
…query Under the planner pipeline each query's SUM is replaced by its exact accumulator state; sharing identical producers is Pass 2 (#580). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
… every candidate User decisions (2026-10-13): - stage modules stage2_physical_asap_optimization and stage3_plan_selection; tests stage1_logical_asap_optimization.rs and stage2_physical_asap_optimization_sql.rs; stage_pipeline keys stage0_query_language_frontends, stage1_logical_asap_optimization, stage2_physical_asap_optimization, stage3_plan_selection (fixture regenerated: only the keys change); - enumeration and selection are never capped: plan_stages enumerates every combination; the devtool's --max-displayed (was --max-candidates) caps only the listing; - code docs say "query-language frontends". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
From #629/#633, on asap_integration_tests::planning (plan_stages, selected_dag, logical_candidates): - sql_to_physical, operator_sharing, materialization_e2e, precompute_raw_samples, summary_coverage_e2e, promql_numeric_regressions: ported. - cse.rs: deleted; it pinned the legacy search's memo groups (sharing identical sub-DAGs is Pass 2, #580). - Ignored, with reasons: the UNION ALL summary test (plan selection picks the exact plan until materialization, #604), arithmetic over one selector (#580), the unit-weight heap over raw samples (#589). - precompute_raw_samples no longer requires a Count Sketch heap over raw samples (#589); materialization_e2e takes the quantile's sketch candidate, since plan selection picks the exact plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
From #633: per lowered query, the summary candidates Pass 1 offers, instead of the legacy explain_replacements. The CSE-shareable metric is dropped (sharing is Pass 2). Over every corpus at epsilon 0.01 and a 1 s ingestion interval: 145/2183 lowered queries get a summary candidate, and Pass 1 rejects none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
…ose (ignored, #672) Both corpus queries that do not compose aggregate over a topk output, which the frontend declares as [keys.., topk_k] with a Utf8 placeholder and no value column; the outer sum's accumulator has no value to read. They compose once the top-k output carries the ranked value (#672). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
One pipeline implementation: the devtool's run_planning_stages (#577) validates the frontends' roots and every composed candidate, and otherwise is plan_stages with the built-in models. Its candidate types are the library's. The Example 1 fixture is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
This was referenced Oct 13, 2026
zzylol
commented
Oct 13, 2026
zzylol
commented
Oct 13, 2026
zzylol
commented
Oct 13, 2026
zzylol
commented
Oct 13, 2026
zzylol
commented
Oct 13, 2026
3 tasks
zzylol
added a commit
that referenced
this pull request
Oct 13, 2026
…ts fields by stage (#675) Follow-up to the review on #674. Pure rename plus docs; behavior unchanged. - pass/stage_pipeline.rs -> pass/stage1_to_stage3.rs; plan_stages -> run_stage1_to_stage3; StagePipelineRun -> Stage1ToStage3Run; StagePipeline -> Stage1ToStage3Pass, registered as "stage1-to-stage3". - Run fields named by stage: stage1_pass1_per_computation, stage1_logical_asap_optimization, stage2_physical_asap_optimization, stage2_pruned, stage3_plan_selection; combinations documented as Stage 1. - Candidate label -> display_name (Logical/Physical/PrunedCandidate and the stage_pipeline JSON key); target_owners -> query_of_target. Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
#576 added Stage 2 (physical ASAP-aware optimization) and Stage 3 (plan selection), but the planner facade still ran
MajorPass, the legacy search. Many tests and devtools also still calledglobal_selection,search_workloadorassemble_selected_dag. This is G1 of the upper-stack consolidation plan: it makes the planning stages the planner pipeline.What
run_stage1_to_stage3(asap_aware_mapping::pass, re-exported from the crate root and fromasap_planner; namedplan_stagesin this PR, renamed in refactor(planner): name the planner pipeline Stage 1 to Stage 3 and its fields by stage #675) runs the stages in order on the roots from Stage 0 (query-language frontends), which the facade lowers first:optimize_physical_asap;select_plan.It returns a
Stage1ToStage3Runwith fields named by stage:stage1_pass1_per_computation(the per-computation candidates),combinations,stage1_logical_asap_optimization(the logical candidates, with per-candidate composition errors),stage2_physical_asap_optimizationandstage2_pruned, andstage3_plan_selection. Each candidate carries adisplay_name. There is no cap on enumeration. Early search-space pruning is Prune the candidate search space early without discarding a possibly-best valid plan #673.Stage1ToStage3Pass, anOptimizationPassregistered as"stage1-to-stage3", replacesMajorPassas the facade default (let default_pass = Stage1ToStage3Pass). It:PlanOutput.selectionreports the choice.OptimizeErrorgainsPerComputationCandidatesandSelection, and dropsRealizationandSearch.One pipeline implementation: test: planner-layering Examples 1–4 acceptance specs on the planning stages #577's devtool
run_planning_stagesnow callsrun_stage1_to_stage3.Legacy callers ported to the pipeline: executor, frontend-promql, frontend-sql, planner and integration tests, and the
sketch_coveragedevtool (now Pass 1 summary candidates). Callers that G2 deletes are left alone.Composition fix: a per-series avg composes over rows that carry the series identity. The regression test was written first.
Cost independence: Pass 1, composition and physical ASAP-aware optimization import no cost model (
tests/cost_independence.rs, from refactor(planner): Stage 1 no longer depends on the cost model #582).Stage identifiers carry number and name:
stage2_physical_asap_optimization,stage3_plan_selection;stage1_logical_asap_optimization.rs,stage2_physical_asap_optimization_sql.rs;stage_pipelineJSON keys:stage0_query_language_frontends,stage1_logical_asap_optimization,stage2_physical_asap_optimization,stage3_plan_selection.Code docs say "query-language frontends". The function names
optimize_physical_asap,select_planandgenerate_per_computation_candidatesare kept.How
run_stage1_to_stage3enumerates combinations in a fixed order (last target fastest), composes each one, implements each one physically, prices all of them, and selects one. SharedNotMaterializednodes are charged once per consuming query (#576).Before this PR
e2e_planand the facade ranMajorPass(legacy search withDefaultCostModel). Only the devtool showed what plan selection would choose.After this PR
The facade returns plan selection's choice over every candidate. The Example 1 fixture is unchanged apart from the stage-key renames. MajorPass merged structurally identical producers (
share_common_sub_dags) and identical scalar references; the pipeline does neither until Pass 2 sharing (#580), so two identical queries deploy separate states andscalar(rate(x[5m])) - scalar(rate(x[5m]))yields two scalar plans. The facade fails withOptimizeError::Selectionif no candidate is selectable, which only happens when physical ASAP-aware optimization prunes the exact candidate.Evidence
enumerates_every_combination_and_selects_one(crates/planner/tests/plan_stages.rs); andkubernetes_mixin_aggregates_over_topk_compose, ignored and waiting for Top-k results drop the item columns (port/job); heavy-hitter candidates resolve columns by name #672.topkoutput. The frontend declares that output as[keys.., topk_k: Utf8]with no value column, so the outersumhas nothing numeric to read. The fix is Top-k results drop the item columns (port/job); heavy-hitter candidates resolve columns by name #672's top-k output schema.Verification
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -- -D warningscargo nextest run --workspace: 1632 passed, 0 failed, 50 skipped (including test: planner-layering Examples 1–4 acceptance specs on the planning stages #577's ignored acceptance tests)test_render.py: OKtools/verify_metricsql_external_consumer.sh: OKArchitectural decisions
Later changes: #675 renamed the pipeline without changing behavior:
plan_stages→run_stage1_to_stage3,StagePipelineRun→Stage1ToStage3Run,StagePipeline→Stage1ToStage3Pass(registered as"stage1-to-stage3"), the run's fields tostage1_pass1_per_computationetc., and the candidatelabel(also in thestage_pipelineJSON) →display_name.Limitations and follow-up
quantile(...)has no native runtime implementation.Absorbs: #581 (except the tree DP and the top-k schema commits), #579 (superseded by #672 and #577), #588's pipeline (
plan_stages) part, #582's cost-independence test, #629, #633. Those PRs will be closed and will link here.Stack: tracker #528 · main → G1 → G2 (legacy removal) → G3 (crates by planning stage) → …
Human review — do not complete with an agent
🤖 Generated with Claude Code
https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW