[Refactor] Repo-wide naming survey: overloaded and misleading names #948
Description
Example
PhysicalCandidate (plan-selection/src/search/candidates/graph.rs:18) is one operator node in the dependency graph. Before configuration it is neither physical nor a whole candidate. CandidateEvaluation, in the same module, evaluates a whole MILP assignment. PhysicalWorkloadPlan (physical-asap-optimization/src/lib.rs:133) documents itself as "One CandidatePhysicalASAPDAG". A reader meets the word "candidate" with six meanings, and the word "physical" with five, before reaching the selection code.
Similarly, PhysicalCandidate.local_cost is documented as "Local work and state only". In practice it is overwritten with lower bounds (costing/lower_bounds.rs:237), refinement weights (refinement/objectives.rs:132, refinement/search.rs:222) and zero placeholders. It is the MILP objective coefficient, not a cost.
Concrete maintenance problem
A repo-wide naming survey found that many central names don't say what the code does. They are overloaded across crates, have several synonyms, or survive from the old whole-workload planner after #933/#934. The findings are listed below. Paths are relative to crates/ unless noted.
1. Overloaded terms (highest impact)
| Term | Meanings in use |
|---|---|
| candidate | (a) a whole Post-ASAP alternative (glossary); (b) a selectable unit of execution (proposals/joint-planning-search.md); (c) one graph node (PhysicalCandidate); (d) a whole MILP assignment (CandidateEvaluation, EvaluatedCandidate, CandidateSearchResult in refinement/search.rs; SelectedPhysicalCandidate, PhysicalCandidateError in candidates/physical.rs); (e) a rewrite-rule match (SharingCandidate, CapabilitySharingCandidate, PaneCandidate, RollupCandidate, TopKReuseCandidate in asap_aware_cse.rs); (f) a realization method (ComputationCandidate = Exact/ExactAccumulator/Summary, per_computation_candidates.rs:141); (g) the executor's precompute/query split (compile_candidate, CandidateSelection) |
| physical | PhysicalASAPDAG (a timed logical DAG; types/src/ir/physical_export.rs:98); PhysicalWorkloadPlan (a Stage 2 candidate); PhysicalCandidate (an unconfigured graph node); PhysicalOperator lowering; the types::physical module; PhysicalResources (cost types) |
| memo | the Cascades memo (LogicalMemo, MemoGroup, CandidateMemo), and also pointer caches: TimingMemo (types/.../timing.rs:196), type Memo (physical-asap-optimization/src/lib.rs:1132, per_computation_candidates.rs:1567), CompatibilityMemo (candidates/factoring.rs:26), NodeKeys.memo (memo/groups.rs:421) |
| state | summary state; ExecutionDataState / output_state / data_state (edge timing+payload; physical_export.rs:74,91); trait ColState (column-reference representation; operator_properties.rs:12) |
| population | IR MaintainPopulation (set of current series); executor $population column (one series' label map; physical_planner/precompute.rs:16); ExactAccumulator "one population's state" (one group/key); Hydra "subpopulation" |
| sample | raw data sample and summary sample (glossary); limitk/limit_ratio series subsetting (SampleKind, PromqlSeriesSample, frontend Outer::Sample); SamplingKind; SQL sample stddev |
| raw | DataPrimitive::Raw (execution_data_state.rs:36) includes approximate summary estimates. This conflicts with the glossary's "raw data sample" and with reads_raw_at_query_time / query_time_raw_windows. |
| selection | Stage 3 plan selection vs SummaryCoverage.selection (rows covered; summary_coverage.rs:36). Both appear as fields named selection in planner/src/installable.rs. |
| family / kind | SketchKind is a full config struct, but its siblings ExactKind/SamplingKind/WaveletKind are algorithm enums. family is a FieldDataType (SummaryAgg), a SketchAlgorithm (SupportedSummary), and free text (StatModelParams). The executor imports FieldDataType as SummaryFamilyType and then uses SummaryFamilyType::Plain(..) 48 times for ordinary columns. |
| grouping | GroupingStrategy (per-subpopulation vs Hydra layout) sits next to reduction (the actual GROUP BY) on SummaryAgg |
| pass | Stage 1 Pass 1/Pass 2 vs OptimizationPass / Stage1ToStage3Pass (the whole optimizer) vs CandidateOrigin::Pass1 |
| domain | PaneWidthDomain, DomainProgress (pane-width search round), DomainOperand (accuracy value ranges), OperandDomain, WeightDomain |
| configuration | CandidateConfiguration (timing, materialization) vs PaneConfiguration (pane width, horizon, sketch size). There are two modules named state_configurations. |
| catalog | SqlCatalog (schemas), HistogramCatalog (metric → sample type), sql-function-catalog (function registry), and the "catalog" of candidates |
| target | AccuracyTarget; per-computation targets (candidate_labels); planner_fuzz::Check.target (a query index) |
| source (executor) | physical_planner::Source (a bound frontier input), Kind::Source(Vec<Batch>), operators/source.rs (Constant/Union/Absent/VectorToScalar), RawSource, MemorySource, and the planner Source |
| lowering | frontend → IR (lower_promql_*, LoweringError) vs logical → PhysicalOperator (design docs) |
| canonical | canonical_metricsql (re-printed text), the canonicalize pass, AggSemantic "canonical semantic", and "canonical intent algebra" |
2. Several names for one concept
- Summary state in memory:
AggregateCore(trait), accumulator (*Accumulator,take_accumulator), kernel (summary_kernels),StateColumn,ScalarState(meaning "unkeyed"). There are also two builder types:AccumulatorUpdaterandStateColumnUpdater. - Reading a value out of a summary:
SketchStatistic,SummaryEstimate.query,EvaluatePopulation.evaluation, "readout",StatisticKind, and executorStatistic. In the executor,Kind::KeyedEvaluation(really top-k) is displayed as"SummaryEstimate", whileKind::Evaluation, which implements IRSummaryEstimate, is displayed as"SummaryEvaluation". - Which aggregate:
AggIntent(types),AggSemantic(sql-function-catalog),Outer/InnerFunc(promql), executorStatistic/Reduction. - Producer / consumer: also called supplier / reader.
SupplierCandidatesis stored in a field of typeCompatibleProducers. Counts: producer 528, supplier 182, reader 670, consumer 222. - Off-query-path computation: ingestion / precompute / maintenance.
Scope::Ingestion { window_start_ms, window_end_ms }is really one pane. - A series' label set:
labels,$population,$promql_series_identity. - The joint search: "memo" (dag-viewer DOM/JSON),
--search candidate-connections(CLI),SearchAlgorithm::CandidateConnections(Rust), "Joint search" (UI), MILP. The viewer still maps the stalememo-milp/memo-brute-forcenames. - The candidate set: catalog / inventory / archive. "Inventory" also names two different types:
CandidateInventory(the lowered dependency graph) andCandidateSearchContext.inventory: &PerComputationCandidates(the Pass 1 targets). - Query outputs: query root / output reference / output group / boundary (
BoundaryConsumer). - Identical-subexpression sharing:
share_common_sub_dags, memo hash-consing, "identical-expression rule". - Shared summary builds: summary-capability rule /
CapabilitySharingCandidate/CandidateOrigin::SharedBuild/shared_builds. Windows have the same problem: window-composition rule /CandidateOrigin::Panes/PaneCandidate/window_candidates.rs/SharedPaneChain. - The materialization cut: frontier /
materialized_outputs/ precompute "boundary" /InputContract. - The materialization choice for one candidate:
PhysicalWorkloadPlan.materialization(node → option map),.assignment(Vec<Materialization>), andMaterializationAssignment(a third, pointer-keyed form). The field namedassignmentis not of typeMaterializationAssignment.MaterializationCandidateandis_materialization_pointname the same concept. - Recurrence:
Repeated/Repeating/RepeatedDemand/RepetitionInterval/QueryRecurrence. The unit of execution is likewise called invocation / request / run / evaluation.
3. Names whose meaning no longer matches the code (legacy of #933/#934)
| Location | Name | Reality | Suggested |
|---|---|---|---|
plan-selection/src/lib.rs:1200 |
PlanSelector (select_plan, offer, finish) |
The MILP selects. This type validates, prices and archives each assignment. | AssignmentEvaluator |
plan-selection/src/search/candidates/graph.rs:22 |
local_cost |
MILP objective coefficient (lower bound / refinement weight / 0) | objective_weight |
plan-selection/src/search/pipeline.rs:32-62 |
LogicalCandidate.choice, .pass2, combinations |
Always Vec::new() / None (pipeline.rs:279-281, route.rs:907-922). The Cartesian product is no longer enumerated. |
delete |
plan-selection/src/search/pipeline.rs |
LogicalCandidate, stage1_logical_asap_optimization |
Logical roots rebuilt from an evaluated assignment after selection | EvaluatedAssignmentRoots, evaluated_logical_plans |
logical-asap-optimization/src/workload_candidates.rs:32,55 |
Pass2Candidate, Stage1Candidate |
Legacy whole-workload rewrite enumeration, now used by query_pruning.rs:325, devtools and tests |
WorkloadRewrite, or move it to a legacy module |
asap_aware_cse.rs (used from memo/rules/*) |
*Pass2Candidate wrappers |
Rewritten root sets. Pass 2 vocabulary has leaked into the memo rules. | *Rewrite |
physical-asap-optimization/src/lib.rs:133 |
PhysicalWorkloadPlan |
A Stage 2 physical ASAP candidate; the glossary reserves "physical plan" for execution/deployment | PhysicalASAPCandidate |
plan-selection/src/lib.rs:1073-1075 |
CandidateConnectionReport.logical_candidates / immediate_candidates / physical_configurations |
Counts of ImplementationCandidates, unconfigured nodes, and configured nodes |
Align with the type names |
plan-selection/src/search/candidates/graph.rs:45 |
ReaderConstraint::ActivationRequires |
Symmetry-breaking between scope copies, unrelated to readers | SelectionConstraint::ScopeCopyOrder |
logical-asap-optimization/src/memo/state_groups.rs:26 |
StateGroupExpansionError |
Error type for all memo rules | MemoRuleError |
plan-selection/src/search/pipeline.rs:113 |
milp_time_limit_ms |
Whole planning budget (generation + solve + validation) | planning_time_limit_ms |
refinement/search.rs:37 |
max_refinements |
Fed from max_evaluations |
max_evaluations |
devtools/src/bin/stage_pipeline.rs:405,382 |
--exhaustive, --max-combinations, SearchKind::Exhaustive, EXHAUSTIVE_MAX_COMBINATIONS |
Keeps all evaluated plans; caps evaluated assignments. The file's own docs deny both "exhaustive" and "Cartesian product". | --archive-evaluated, --max-evaluated-assignments |
devtools/src/bin/show_logical_dag.rs |
show_logical_dag |
Prints the Pre-ASAP IR (Stage 0). "Logical" elsewhere means Stage 1 output. | show_pre_asap_ir |
devtools/src/bin/stage_pipeline.rs:258 |
Failure::Usage |
Also used for queries that don't plan, so it prints USAGE | split into Usage / Planning |
4. Other misleading names
types / planner / physical-asap-optimization / frontend-common
types/src/ir/physical_export.rs:98PhysicalASAPDAG/ modulephysical_export: post-asap-ir.md says this DAG is logical. Suggested:TimedASAPDAG.types/src/ir/schema/sketch.rsSketchStatistic: covers every summary family, not only sketches.SummaryEstimate.querycollides with workloadQuery(its doc has to warn about this). Suggested:SummaryStatistic, with one field namestatistic.types/src/workload/parsed_workload.rs:32ParsedWorkload.exprs: holds lowered and canonicalized IR roots. Suggested:LoweredWorkload.roots.physical-asap-optimization/src/lib.rs:353MaterializationCandidate: a materialization point. Suggested:MaterializationPoint.summary_coverage.rs:162Constraint: per-column value set. It is re-exported by the planner and collides with MILP constraints. Suggested:ColumnConstraint.non_asap.rs:43,159NonASAPOp::TimeRange+TimeRangeKind::Instant: an instant selector modeled as a range. Suggested:SelectorWindow.planner/src/lib.rs:97UserInput/frontend_specific: SuggestedPlanRequest/frontend.frontend-common/src/schema_resolver.rs:39SchemaResolver: derives a leaf schema from usage and binds nothing, whileresolve.rsuses "resolve" for binding.IngestionPruneReason: also used as an eligibility result. Suggested:IngestionIneligibility.GuaranteeSource: a provenance step.AccuracySpec: vague.StatisticKind::DistinctvsSketchStatistic::Cardinality.
logical-asap-optimization / plan-selection
ComputationCandidate: a realization method. Suggested:RealizationMethod; also renamesummary_candidates()tosummary_families_for_intent.SupplierCandidates,SupplierSetInterner: SuggestedCompatibleProducers.CandidateMemo: documented as "the hash-consed workload". Suggested:GroupImplementations.NodeCost.multiplier,CandidateDemand.multiplier: Suggestedcomputations_per_execution.EdgeStatisticsdescribes a node's output. Suggested:OutputStatistics.PropagationStatsshould bePropagationEvidence.
executor (paths relative to executor/src/)
operators/mod.rs:126Kind::Window(displayed as"WindowAggregate"): also runsHistogramQuantilewithwindow: None, andcoordinateis sometimes thelebound.operators/mod.rs:69-111,VectorBinary/RangeWindow/HistogramQuantilevsSeriesBinary/SeriesWindow/SeriesHistogramQuantile: the real difference is label-map rows vs flattened series rows.SeriesLabelsdoes label matching.statistic.rs:4Statistic: exact-family readout. Only 6 of its variants are reachable. Suggested:ExactStatistic.physical_planner/candidates.rs:9CompiledPhysicalPlan: a precompute/query split of aCompiledPhysicalDAG. Suggested:PrecomputeQuerySplit.summary_kernels/exact.rs:14ScalarState(.scalar/.keyed): also used as the per-key value. Suggested:ExactRecordwithunkeyed/by_key.key_by_label_values.rs:6KeyByLabelValues.labels: holds values and is used for SQL item keys too. Suggested:ItemKey { values }.summary_kernels/increase.rs:7IncreaseAccumulator: also backs Rate. Suggested:CounterAccumulator.Measurementis a bare f64 newtype.- module
query_time: unused CMS error-bound math. Suggested:sketch_error_estimation. samples.rs:214TableRowSelector: called a "raw-data-sample window" although it handles SQL rows.Kind::Joinis displayed as"RelationalJoin".
frontends / sql-function-catalog / devtools / dag-viewer
frontend-promql/src/lib.rs:32,82andfrontend-metricsql/src/lib.rs:80,94:lower_promql_workloadvslower_promql_query_workload(andlower_metricsqlvslower_metricsql_query) differ only in whether scalar roots are allowed.frontend-promql/src/promql.rs:98-171Outer/OuterIntent/Inner/InnerFunc: named by position, not meaning. Suggested:CrossSeriesAgg/SeriesSelection/RangeFunction. Its comments also mention an "UnresolvedWindow" node that no longer exists.sql-function-catalog/src/lib.rs:262,277ClickHouseBuiltin/CLICKHOUSE_BUILTINS: the aggregate table, which includesasap_rate/asap_increase.frontend-sql/src/sql/mod.rs:1243PlanningBridge: holds relation markers, but the module docs use "bridge" forasap_ratetoo.frontend-metricsql/src/lib.rs:40canonical_metricsql: returns normalized query text.- Import aliases:
UnresolvedOp as Unresolved(promql/sql) vsas U(metricsql);UnresolvedScalar as Scalar; both frontend error types are importedas LoweringError. The lowerers are inconsistent:PromqlLowerer(a unit struct),SqlLowerer, and a bareLowerer. devtools/src/planner_fuzz/mod.rs:371Planner: collides with the product name. Suggested:FuzzPlanCache.devtools/src/planner_fuzz/relations.rs:201Witness: already stored asderivation. Suggested:Derivation.devtools/src/planner_fuzz/mod.rs:352Priced.derived_root: PrivateNodes: a node set, not a root.devtools/src/rqe_atomic_costs.rs: "RQE" is undefined. Suggested:sketch_bench_operation_costs.devtools/src/lib.rs:1,bin/variant_coverage.rs:1: docs saycargo run -p asap-lower, but the crate isasap-devtools.HistogramKind::RawDataSamples: the metric isn't a histogram. Suggested:HistogramSampleType.
5. Stale documentation
docs/design_docs/architecture/asap-aware-plan-search.mdand about 10 other docs still referenceCandidateLogicalASAPDAGs,TargetSubDAGCandidates,RankedTargetSubDAGCandidates,global_selectionandassemble_selected_dag. Apart from one mention in thelogical-asap-optimization/src/lib.rsheader, none of these exist in code.- The glossary's definition of "Candidate" conflicts with
proposals/joint-planning-search.md. executor/src/capability.rs:10refers to a nonexistentbindingmodule.FieldDataType::Sketchdoc saysSketchKindcarries the grouping layout, but grouping is the second tuple field.QueryWorkload.repeating_queriesdoc says "fixed interval", butRepeatedDemandalso allowsScheduled/EstimatedRate.
Behavior that must remain unchanged
Planner output, plan costs, executor results, CLI semantics, and dag-viewer behavior. Renames only, plus deletion of the always-empty legacy fields.
Before and after structure
Before: overlapping terms as listed above. After: each term in sections 1–2 has one meaning, recorded in docs/design_docs/concepts/glossary.md, and the code follows it. Proposed order:
- Decide glossary meanings for candidate, physical, memo, state, population, sample, raw, and producer/consumer.
- Delete the dead legacy fields (
LogicalCandidate.choice,.pass2,combinations). - Rename names that say something false:
PlanSelector,local_cost,--exhaustive/--max-combinations,show_logical_dag,SummaryFamilyType,milp_time_limit_ms. - Unify synonyms crate by crate, following the step-1 glossary.
- Fix the stale docs.
Why the proposed structure is minimally complex
No new types or layers. Renames and deletions only.
Existing unit and end-to-end protection
Existing unit and integration tests (crates/integration-tests) cover the renamed types. Renames are compile-checked. The dag-viewer and JSON output field renames need the viewer and its consumers updated together.
Compatibility or migration impact
- Public API renames in
asap-types,asap-plannerand the frontends affect downstream callers. - Devtools CLI flag renames (
--exhaustive,--max-combinations) and binary names affect scripts and docs. - Report/JSON field renames affect
tools/dag-viewerand any saved outputs.
Found by an AI-assisted naming survey (four read-only sub-surveys). Each sub-survey says it read the definition and a few uses of everything it lists. Only a few of the larger claims were re-checked against the code.
🤖 Generated with Claude Code
Activity