Repository navigation
Conversation
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.
Last PR of the #1207 stack (on #1238, PR 8). Draft: the user reviews and merges the #1207 unit by hand; not for merge on its own.
Why
PRs 0–8 replaced the planner's interfaces (memo groups as expressions, candidates $(e_v, p^{\log}v)$ with $r^{\log}{c,i}$, physical candidates and edges with$\alpha$ , contexts, constraint (K)). The tools still stopped at $\alpha$ and its rejection reason, every stage's pruned candidates) and for every plan and cost change to be listed.
todo!("#1207 PR 9 …"):asap_planner --format textand--format json(the viewer document) could not print a memo, Stage 2's candidates or Stage 3's selection;planner_fuzzfed witnesses holding ASAP operators into Pass 1, which refuses them; the snapshots were still the plans of main before #1207. #1207's Order row 9 and #1205 ask for the tools to print every notation (memo groups with properties, every edge withWhat
asap_planner --format text(planning_stages_text): each memo candidate with its operator over its input groups, θ, ω, fused groups and per-input parameter floors, markednewat the step that added it; Stage 2's physical candidates, each with every producer of each input,✓or✗with why (asap-stage-pipeline/v2(producerasap_planner.rsand consumertools/dag-viewerchanged together, DAG viewer / stage_pipeline: print memo candidates with properties, every producer–consumer edge with its feasibility and rejection reason, and every stage’s pruned candidates #1205): memo candidates withlogical_propertiesandinput_requirements;stage2_physical_asap_optimization.physical_candidateswithpropertiesand per input every edge (satisfies_logical_requirement,satisfies_physical_requirement,rejection,selected); Stage 2pruned_candidateswithproperties; Stage 3pruned_candidateswithdominated_by;memo.selected_candidates. The viewer shows them (group panel, candidate panel with ✓/✗ edges, pruned lists per stage). v1 documents are refused; every old-format reader is deleted.planner_fuzz: witnesses are costed withasap_cost::plan_costinstead of being planned again.planner-layering.mdmemo components, the worked example (numbers fromasap_planner --format text), and the stage tables over today's memo; terminology sweep (consumer, materialized, cost) across crates, docs and the viewer.How
operator_label, generic overOperator<C>); a candidate is one operator, so no node table is built (memo.nodes,MemoNodes,group_of_nodeare deleted). Edges come fromPhysicalASAPMemoCandidates::edges()(every edge, admissible or not); the reason is derived byedge_rejectionfrom the edge's two booleans and the two candidates' properties, mirroringlogical_edges_with_capped_floors(floor first, else the metric rule).Planner::planrecords each realized node's assignment (timing, lifetime, θ, coverage) read back from the realized DAG (flatten order = export order) keyed by node address (the cached plans hold the nodes, so no address is reused).Planner::costexports the witness roots withphysical_asap_dag_with_assignments(planned nodes keep their assignment; derived nodes at query time, not materialized; for a witness, a not-materialized query-time node the derived root shares with another root is costed asOneEvaluation(Memory)), thenplan_costwith the same arguments asselect_plan.W's reference cost equals the search's (the_selected_plan_costs_what_the_search_selected_it_for).Representation, rules, enumeration
PruneReason, Stage 3'sUsageNotCostable/DominatedBy).selected_candidates) andselectededges) are shown over the memo.Notation → code (what the tools print)
--format text)--format json)G<n>: <operator> <- G…,[i] <origin> <operator> <- G…memo.steps[].groups[]{operator, children},candidates[]{operator, children}θ=Kll(k=269) ω=tumbling 60000mslogical_properties{parameters, window_layout}floors=[…],requires θ ⪰ …input_requirements[],inputs[].requirementC<n> = G<g>[<i>] (timing, lifetime)physical_candidates[]{group, index_in_group, properties}✓/✗ α^… = 0: …inputs[].edges[]{producer, satisfies_logical_requirement, satisfies_physical_requirement, rejection}node<n>: C<k> … <- node…stage3_plan_selection.selected_dag,edges[].selected,memo.selected_candidatespruned by Stage 2 (n),pruned by Stage 3 (n)stage2…pruned_candidates[],stage3…pruned_candidates[]{dominated_by}Concepts not in the formulation:
origin(approved 2026-11-05); the rejection reason text.Key code interfaces added / modified
crates/devtools/src/candidate_labels.rscrates/devtools/src/planning_stages_text.rscrates/devtools/src/planner_fuzz/mod.rsViewer document: format
asap-stage-pipeline/v2(was v1), fields as in What; removed:memo.nodes, groups' and candidates'node,group_of_node,implements,accuracy_budget_parts,selected_choice,stage1…pruned_candidates,stage2…pruned.Other:
asap_cost::UnitPrice→UnitCost(pub inmeasured.rs, not re-exported);RejectionCause::failed_a_checkremoved (dead once the viewer's cause lists went).Usage (the running example, checked at the head commit):
KLL
k< 269 builds have no edge into G4 (Stage 2 pruned them:ReachesNoQueryOutput);k547 is selected over 269 because sizes above the floor tie in the objective (#1238 spec question 5).--format jsongives the same data to the viewer.Major algorithm changes
Fuzz witness costing. Problem: a witness (W's selected plan plus q' derived over it) holds ASAP operators; after PR 3 Pass 1 refuses them, so 13 witness checks were inconclusive. Before:
priceran Stages 0–3 over the witness roots (run_search_over). After:costexports the roots with each planned node's realized assignment and runsplan_cost(steps in How). Correctness: W's own plan costs exactly what the search selected it for (test above); a witness differs from W only by derived nodes and the shared nodes it reads. Limits: the witness's accuracy is not checked (q' is derived at q's target or a looser one; another statistic from q's θ, unions and key filters are not re-checked); aLongerWindowwitness's rewritten chain nodes are new nodes with no assignment (a sketch chain then has no θ and the check is inconclusive). Complexity: oneplan_costper witness instead of a full planning run.Before this PR
asap_plannerpanicked at thetodo!()s for any run past Stage 0 (text) or with candidates (JSON); the viewer read v1 fields no producer writes; fuzz witnesses were inconclusive; snapshots were main's plans before #1207.After this PR
Every stage's output is printed and documented; the viewer shows the memo, the physical edges with$\alpha$ and the reasons, and the pruned candidates of Stage 2 and Stage 3. No
todo!("#1207 PR 9 …")remains.Snapshot plan and cost changes
Re-baseline (mechanical, redo after the pending lower-PR decisions):
UPDATE_SNAPSHOTS=1 cargo test --release -p asap-devtools --test corpus_snapshots -- --ignored, then diff each changed snapshot'sselected.cost.cost_per_second, node count andaccepted[].sketches(orerror) against the base. "Before" is the snapshot at the base (main's plan before #1207: PRs 0–8 did not re-baseline). Cost model 1 as each corpus/manifest declares.o11y_bench/q02o11y_bench/q05o11y_bench/q06o11y_bench/q11o11y_bench/q12o11y_bench/q18o11y_bench/q19o11y_bench/q20o11y_bench/q21o11y_bench/q22o11y_bench/q23o11y_bench/q25o11y_bench/q26o11y_bench/q27sketch_plan_snapshots/fuzz-issue903-raw-retainedsketch_plan_snapshots/nested-windows-15m-1h-mvpsketch_plan_snapshots/quantile-grouped-mvpsketch_plan_snapshots/quantile-single-mvpsketch_plan_snapshots/random-mixed-seed-862-long-w01-q3-mvpsketch_plan_snapshots/random-mixed-seed-862-w01-q3-q8-mvpsketch_plan_snapshots/random-mixed-seed-862-w02-q2-q7-mvpsketch_plan_snapshots/ratio-of-quantiles-1h-mvpsketch_plan_snapshots/shared-quantiles-1h-mvpsketch_plan_snapshots/topk-rate-guarantees-ignored-mvpCauses: o11y_bench (all
fixed_interval60 s with no phase, 1 h range evaluation):delivers_onrefuses a tumbling-window chain to a fixed interval without a phase, so the ingestion-time chains main selected are gone and each step recomputes its window (pending decision: fixed-interval phase, PR 4/6); q11, q20, q27: an exactAggregateinstead of exact accumulators (cheaper by cost). fuzz-issue903-raw-retained: KLL → exact plan: whole-result δ 0.001 over 10,000 series is below every listed size's per-value 0.01 (#1238 spec question 1). The nine-mvpsketch workloads (raw data not retained): no plan, Stage 3 infeasible because an input has no producer that can be costed (pending: PR 5, Stage 2 with raw data not retained).Verification
cargo fmt --all;cargo clippy --workspace --all-features --all-targets -- -D warningsclean;crate_graphpasses (6/6).stage2_lists_every_edge_with_its_alpha_and_rejection,memo_section_lists_each_step_and_the_selected_candidates,the_selected_plan_costs_what_the_search_selected_it_for,pass2_holds_tumbling_windows_at_the_gcd_of_ranges_and_steps(was every divisor: the gcd decision of 2026-11-06),a_topk_heap_over_one_row_per_item_is_not_offered; viewermemo.test.mjs(14/14: θ/ω/floors, edges ✓/✗ with rejection, Stage 3 pruned with the dominating candidate),viewer_contract2/2.remaining→in_outputin Limit, leftover*_in_kept,usage_prices,UnitPrice,Pricedtest enum, "retained" where it meant materialized); a PR number in a design doc; deadRejectionCause::failed_a_check; the text section notes that#ncost rows are realized-node ids. Not taken: LongerWindow assignment carry-over and witness accuracy checks (limits above); anedges_intoindex inasap-types(the two printers regroupedges()themselves); a structured rejection instead of text and a smaller document (every edge is listed: DAG viewer / stage_pipeline: print memo candidates with properties, every producer–consumer edge with its feasibility and rejection reason, and every stage’s pruned candidates #1205 asks for it).Test table (
cargo test -p <crate> --all-features --no-fail-fast, at d61175c; the head commit after it only changes viewer wording and one comment; PR 8: 1350/97/9):Viewer:
memo.test.mjs14/0;stages.test.mjsfails at load andtest_viewer.py/test_server.py92 run, 4 failures + 21 errors, all ontest-fixtures/tumbling-windows-workload.jsonwith raw data not retained, which does not plan (PR 5).Remaining failures and causes (none stops at a
todo!()):plan_cost, once by the objective: integrationidentical_exact_queries::{identical_exact_percentiles_share_work, different_exact_percentiles_share_the_input_window},sharing_issue_regressions::{duplicate_exact_topk_shares_work, slower_repeat_reuses_faster_sum, sql_sum_shares_nested_windows_and_slower_readers, nested_exact_sum_reuses_newest_tumbling_windows}; plannersummary_sharing::{identical_ungrouped_queries_share_their_producers, identical_sql_percentiles_share_one_producer}; devtoolsasap_planner::milp_search_objective_equals_plan_cost_on_example1_and_rangeheavy, fuzzexact_duplicate_of_a_shared_query_holds,finds_issue_902_…(the planner reuses the grouped result, but its scan isNoneand charged per query),finds_issue_903_…(violation found; W ∪ {q'} now 0.288/s, the test pins 0.166).columnar_batches::a_tumbling_window_is_built_…,runtime_install::{the_plan_carries_stage3s_predicted_usage, the_plan_file_carries_theta_and_coverage_and_reads_back, tumbling_windows_of_an_hour_share_one_definition_with_distinct_times};installable::tests::view_refreshes_compile_only_the_nodes_below_them(whole-result δ 0.3: (K) infeasible); integrationsharing_issue_regressions::grouped_filtered_quantile_plans,rollup_controlled::production_distinct_rollup_finds_shared_kmv.a_counter_function_over_a_declared_gauge_plans_with_a_warning(a windowless query-time scan cannot be costed withoutrows_held), fuzzexact_rollup_…,sketch_rollup_…,longer_window_rollup_…(W ∪ {q'} infeasible for the same scan),longer_window_witness_costs_over_a_lengthened_chain(no chain selected).deployment_capabilities_flag_sets_the_capabilities_and_shows_them(no-raw part),the_nine_query_workload_{selects_a_valid_plan, lowers_and_installs}; integrationjoint_search_equivalence::different_windows_and_raw_retention_policies_produce_valid_plans; plannerruntime_install::ignoring_accuracy_guarantees_plans_the_undeclared_p99_query; the viewer tests above.runtime_install::check_compiles_reports_the_executors_error("aggregate intent has no native implementation"); devtoolsworkload_examples_select_valid_plans_with_linked_materialized_views(example1's exact top-kAggregatehasoutput_names: [], the executor needs one per measure: Pass 1 copies the frontend's group expression).stage1_logical_asap_optimization::{sql_avg_counts_its_own_input, sql_avg_from_sum_and_count_executes_as_avg, sql_avg_of_an_int64_column_keeps_the_exact_columns},sql_to_post_asap::map_projection_export_keeps_the_map_over_an_avg_of_exact_states,per_computation_candidates_sql::a_sql_fold_over_estimates_leaves_its_row_count_unbound.joint_search_equivalence::rootless_request_overhead_respects_capacity_and_latency.logical_candidates/explicit_*_candidatereturn the selected plan (L1) or a realized first-producer plan, and these tests pin a candidate the cost-optimal, (K)-checked selection no longer picks or Stage 2 no longer offers at query time:promql_to_post_asap::{promql_binary_arithmetic_keeps_an_unsupported_arm_exact, instant_topk_and_unsupported_child_remain_local_residuals, promql_quantile_of_rate_binds_kll_over_rate_accumulator, planner_heap_topk_reference_execution_matches_ground_truth},sql_to_post_asap::{clickhouse_outer_sum_recursively_binds_inner_temporal_aggregate, sql_join_recursively_binds_both_temporal_aggregate_children, sql_full_query_retains_project_and_binds_inner_aggregate},exact_composition::physical_export_carries_explicit_timing_for_a_composed_plan,promql_numeric_regressions::{sum_rate_and_increase_have_real_exact_accumulator_nodes, checked_ratio_must_not_certify_cross_zero_interpolation},filtered_aggregates::{global_kll_quantile_over_no_row_is_null, kll_quantile_of_all_null_group_is_null, hand_filtered_kll_compiles_and_executes},sketch_rollup::{distinct_counts_rolled_up_equal_the_direct_build, invalid_rollups_are_rejected}.Compared with PR 8: +46 passing. Fixed here: every devtools
todo!()(37), 6 fuzz witnesses, the CLI JSON tests,kll_tumbling_window_execution×3 (θ on the hand-built builds),sql_to_post_asap×2 (unqualified columns, PR 2b), viewer contract.Deleted
node_label,MemoNodes,group_node,memo.nodesand the node-table fieldsupgradeTumblingWindowNames,upgradeMemoSteps,memoNodeDag,memoCandidateOwnNodes,memoPrunedText,selected_choicehandling, reference-pricing/search_rejectedselection rows, joint-search panel, stage2prunedenumeration.js,enumeration.test.mjs,memo-enumeration-small.jsonmemo.enumeration/memo.nodes, written by no producer since #1190stage1_logical_asap_optimization.pruned_candidates(document)Planner::price'slast_root_is_key_filter,run_search_overwitness pathRejectionCause::failed_a_checkmaterialized_views::materialized_views_equal_the_stored_outputs_main_listed+stored_outputs_on_main.jsontumbling_windows_reject_parameters_…'s relabelled-kbatch assertionviewer_knows_every_view_refresh_and_rejection_cause's cause halfNew abstractions not in #1207 or the doc (pending approval)
parameters_label,edge_rejection,same_candidate(devtools, pub because theasap_plannerbinary uses them).Planner::cost(…, last_root_is_derived)and theOneEvaluation(Memory)promotion of nodes a witness shares.rejectionas text, see spec question 1).Spec questions
EdgeRejection(DAG viewer / stage_pipeline: print memo candidates with properties, every producer–consumer edge with its feasibility and rejection reason, and every stage’s pruned candidates #1205) namesPhysicalRequirement, which no longer exists (asap-types?price_source/NodePriceSource(serialized in the plan cost andPredictedNodeUsage; a wire rename for its own PR?); "Materialization" as section titles in design docs (planner-layering.mdstill has the section); SQL textprice; the Fargate pricing URL.Lower-PR items (not changed)
Aggregatecandidate carriesoutput_names: []; the executor refuses it (installable_plan_of→materialized_views_error).planner-layering.mdbeyond the memo section and stage tables still describes pre-Tracking: implement the optimization formulation (memo candidates, properties, edges y_{u,c,i}, MILP) as named code per stage #1207 Stage 2/3 in places (e.g.physical-planning-and-deployment.md's "Stage 2 Materialization" naming).