Repository navigation
Tracking: stage-by-stage review of ASAPPlanner — functionality, concepts, abstractions, interfaces #1010
Description
Problem, by example
One query, evaluated every minute, with max_error 0.01 and failure_probability 0.001:
avg by (job) (quantile_over_time(0.5, data[5m]) / quantile_over_time(0.5, data[5m]) + quantile_over_time(0.9, data[5m]))
What each stage produces for it in the production planner, read from the stage-pipeline document tools/dag-viewer/examples/memo-ratio-of-quantiles.json (main at d728d05c) (#1002, #1008):
Corrected 2026-10-28: production numbers from the stage-pipeline document; earlier numbers came from a test helper without the series-identity column.
| After | Memo groups | Implementation candidates | Candidate DAGs | Stage issue |
|---|---|---|---|---|
Stage 0: frontends + LogicalMemo::from_roots |
7 (G0 Scan data, G1 TimeRange 5m, G2 per-series quantile 0.5 (both occurrences), G3 G2 / G2, G4 quantile 0.9, G5 G3 + G4, G6 avg by (job)) |
– | 1 | #1011 |
Stage 1, Pass 1 (try_populate_pass1) |
7 | 19 (7 each in G2, G4) | 49 = 7 × 7, of which 16 use only budget_share 1 (#1002) |
#1012 |
| Stage 1, Pass 2: window composition + concrete summary-state groups | 354 (336 PaneChain shared-build groups) |
1738 (691 each in G2, G4: 10 Pass1, 336 Panes, 345 SharedBuild) |
over 1,000 (enumeration limit) | #1013 |
| Stage 2 (called per candidate by Stage 3) | – | allowed materializations per candidate | – | #1014 |
| Stage 3 (MILP over the memo) | – | one per needed group | 1 selected plan | #1015 |
| Deployment | – | – | InstallablePlan { dag, query_texts } |
#1016 |
Even for this one query, we cannot yet say whether each number is intended: why the memo stands for 49 Pass 1 DAGs, 33 of them with a summary sized for half the budget; why one query gets 336 pane-chain groups; whether the selected plan is the cheapest. Several stages also do work that the design doc assigns to another stage (Stage 3 runs Pass 1 and Pass 2, Pass 2 exists twice). This issue tracks a stage-by-stage review of ASAPPlanner on main: for each stage, its functionality, concepts, abstractions and interfaces as designed in docs/design_docs/proposals/planner-layering.md and as implemented, with a checklist of what to fix.
Ideal concepts
- One IR for every stage. Every stage reads and writes the same DAG IR (
OperatorNode,QueryRoot), with non-ASAP operators (the logical query) and ASAP operators (summary build, merge, estimate,PaneChain). A stage adds choices; it does not convert to a stage-private representation. - Every stage's output is defined over memo groups.
- Before the memo: each stage output a
Vecof whole-workload candidate DAGs (CandidateLogicalDAGs,CandidateLogicalASAPDAGs,CandidatePhysicalASAPDAGs). - With the memo: each stage outputs a memo (groups, each with its implementation candidates), which can be converted to that enumeration of candidate DAGs (Memo: convert memo-group candidates into the vector of all candidate DAGs #1002). Stage 3 receives a complete memo and only selects.
- Before the memo: each stage output a
- One named type per stage boundary (decided in [Refactor] One named type per stage boundary: PerComputationLogicalMemoCandidates → LogicalASAPMemoCandidates → PhysicalASAPMemoCandidates #1047, 2026-10-29).
DagOfLogicalMemoGroups→ (Pass 1)PerComputationLogicalMemoCandidates→ (Pass 2)LogicalASAPMemoCandidates→ (Stage 2)PhysicalASAPMemoCandidates→ (Stage 3)Selection.- A stage or pass reads only the previous step's output type and calls no other stage.
- The
asap-plannerfacade runs the stages, including the pane-width rounds ([Refactor] Pane-width rounds without cross-stage calls: rerun Pass 2 per round, or pass an incremental Pass 2 state #1048). - Each stage prunes only what its own knowledge rules out, as
PrunedCandidate<C>. - Each stage issue below has an "Interface decided in [Refactor] One named type per stage boundary: PerComputationLogicalMemoCandidates → LogicalASAPMemoCandidates → PhysicalASAPMemoCandidates #1047" section. Names follow [Refactor] Rename memo-named caches and the memo types by stage #1050.
- Memo group. One distinct logical sub-expression (same output result). For ASAP sharing, a group may also stand for one summary state (same summary state), e.g. one shared KLL state group with a candidate in each reader group that reads it. The definition is reviewed in Stage 1 Pass 2 review: ASAP-aware CSE rules over memo groups and summary-state groups #1013.
Milestones
Each milestone is reviewed for three goals: abstractions (one concept, one name, in the right stage), correctness (the right candidates, the right plan), efficiency (planning time and memory).
| Milestone | Abstractions | Correctness | Efficiency |
|---|---|---|---|
| Representation and stages: memo groups and DAGs | same IR across stages; memo group definition; each stage's input/output over the memo (#1011, #1013; one named type per stage boundary: #1047) | memo stands for the same candidate set as the whole-workload path (#1002) | groups and candidates per workload stay bounded (336 pane-chain groups for one query today) |
| Mapping rules (Pass 1 rewrites, Pass 2 sharing rules) | one rule abstraction over memo groups; one intent → family table (#1012, #953, #954) | each rule's candidates are equivalent and legal | rule application is linear in groups × candidates |
| Solver / optimization (MILP) | Stage 3 only selects (#1015, #958) | the selected plan is the cheapest the memo allows, or the report says it is not proven (#1004, #928) | whole evaluation workloads plan within minutes (#879, #927) |
| Constraints: cost model, accuracy model | one cost vocabulary; deployment-owned sizes (#1015) | cost matches the executor (#946, #947, #726); guarantees hold (#929, #944) | sizing once per reader set (#929) |
| Query and workload coverage | frontends share one interface (#1011) | language semantics preserved; selected plans install and run (#1016) | – |
Review checklist applied to every stage
- Functionality implemented in a stage that does not belong to it (boundary and concept placement).
- Naming and over-abstraction.
- Stale code, including code from before the memo groups and the Stage 0–3 design.
- "memo" / "cache" used for things that are not the memo; dynamic-programming code or comments that are stale.
- Functionality as rules over memo groups.
Debugging process
- Go stage by stage, in the order below, then the end-to-end
asap-plannercrate. - For each stage: check boundaries and concepts, stale code, over-abstraction and naming; then correctness and efficiency by checking the stage's (or crate's) input and output.
- End to end, per stage: run the DAG viewer (
tools/dag-viewer, fed bystage_pipeline) on different workloads (the example above, the paper workloads), look at each stage's memo and candidate DAGs, and file one issue per problem with its example.
Tooling: #1008 tracks the DAG viewer showing the memo after each step and every candidate DAG it stands for (#1002–#1007).
Stage issues (in review order)
- Stage 0 review: frontends and the logical memo (hash-consed groups) #1011
- Stage 1 Pass 1 review: per-computation candidates over memo groups #1012
- Stage 1 Pass 2 review: ASAP-aware CSE rules over memo groups and summary-state groups #1013
- Stage 2 review: physical optimization and materialization per candidate #1014
- Stage 3 review: plan selection, the MILP over the memo, cost and accuracy constraints #1015
- Deployment interface review: InstallablePlan, materialized views, DataStore and the executor #1016
- asap-planner facade review: orchestration and deployment input assembly #1017
Cross-cutting: #1008 (DAG viewer memo tooling), #948 (repo-wide naming survey), #1047 (one named type per stage boundary; sub-issue #1048, pane-width rounds), #1054 (crate organization by stage: asap-accuracy, asap-cost, enforced crate boundaries, visibility), #1050 (memo/cache and memo-type renames), #1046 (dead and test-only code).
Related
#958 (reorganize by stage; decisions of 2026-10-27), #954 (one shared-producer rule), #879 (plan whole workloads within minutes), #685 (end-to-end use cases), #671 (planning roadmap), #546 / #547 / #531 (documenting strategies and extensions), #545 / #548 / #131 (extension contract), #550 (query/readout terms).
🤖 Generated with Claude Code
Activity