Repository navigation
refactor(stage1): summary readouts and inputs as one operator over groups; Memo::add_candidate; one node equality in Pass 1 (#1203 2a-2) - #1218
Closed
zzylol wants to merge 4 commits into
Conversation
This was referenced Nov 5, 2026
zzylol
force-pushed
the
refactor/1203-2a-2-summary-results-inputs
branch
from
November 5, 2026 15:44
b3c7b5a to
ef701a7
Compare
zzylol
added a commit
that referenced
this pull request
Nov 5, 2026
…s candidates when found `exact_input_group` replaced the candidates of the group `find_or_add_group` returned, also when it found an existing group. Now the exact candidates replace the own candidate only of a group it added; a found group keeps its candidates and gets the new ones through `push_candidate_if_new`. Top-k and finer-aggregate reads follow #1218's interface changes (`MemoGroupId` owner, `find_or_add_producer` without budget parts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
zzylol
force-pushed
the
refactor/1203-2a-intern-pass1
branch
from
November 5, 2026 16:59
9133835 to
8182edf
Compare
zzylol
force-pushed
the
refactor/1203-2a-2-summary-results-inputs
branch
from
November 5, 2026 17:08
ef701a7 to
f27b38f
Compare
zzylol
added a commit
that referenced
this pull request
Nov 5, 2026
…s candidates when found `exact_input_group` replaced the candidates of the group `find_or_add_group` returned, also when it found an existing group. Now the exact candidates replace the own candidate only of a group it added; a found group keeps its candidates and gets the new ones through `push_candidate_if_new`. Top-k and finer-aggregate reads follow #1218's interface changes (`MemoGroupId` owner, `find_or_add_producer` without budget parts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
Contributor
Author
|
CI note: run 42071683865 failed This is a flaky test, not this PR:
I re-ran the failed job. Making the test deterministic (a seeded coin, or a looser per-job check) is CI/test work outside this PR. |
zzylol
force-pushed
the
refactor/1203-2a-2-summary-results-inputs
branch
from
November 5, 2026 20:15
e0a775f to
b8402c7
Compare
zzylol
added a commit
that referenced
this pull request
Nov 5, 2026
…s candidates when found `exact_input_group` replaced the candidates of the group `find_or_add_group` returned, also when it found an existing group. Now the exact candidates replace the own candidate only of a group it added; a found group keeps its candidates and gets the new ones through `push_candidate_if_new`. Top-k and finer-aggregate reads follow #1218's interface changes (`MemoGroupId` owner, `find_or_add_producer` without budget parts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
zzylol
force-pushed
the
refactor/1203-2a-2-summary-results-inputs
branch
from
November 5, 2026 21:13
b8402c7 to
45c8d37
Compare
zzylol
added a commit
that referenced
this pull request
Nov 5, 2026
…s candidates when found `exact_input_group` replaced the candidates of the group `find_or_add_group` returned, also when it found an existing group. Now the exact candidates replace the own candidate only of a group it added; a found group keeps its candidates and gets the new ones through `push_candidate_if_new`. Top-k and finer-aggregate reads follow #1218's interface changes (`MemoGroupId` owner, `find_or_add_producer` without budget parts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
… over groups Rules 3 (summary inputs) and 8 (summary results) add their candidates as one operator over groups (`add_candidate_over_groups`, through the shared `operator_over_groups` Pass 1 now uses too), so every node beneath them is a memo group. Summary inputs find or add their canonical inputs through `find_or_add_producer` (Stage 0's equality), which replaces the TimeRange rebinding. Equal candidates are found by `push_candidate_if_new` (hash-consing equality), which rule 9 now uses too, in place of its own graph-signature check. `boundary_groups` looks groups up with `Memo::group_whose_node_is`. Second review fixes, folded in on the rebase onto #1215's fixes: one `same_output_contract` in reuse.rs (scan widening, rule 9 and `check_output_contract` use it); `add_candidate_over_groups` takes a `MemoGroupId` owner; `find_or_add_producer` drops its always-1 budget-parts argument; `push_candidate_if_new` is a crate-private Stage 1 function, not a `Memo` method. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
…he test can rely on quantiles_rolled_up_keep_the_sketch_bound checks eight randomized KLL answers against their rank bound. Composed alone, the KLL is sized for the calibrated failure probability 0.01 (k = 52), so an answer may miss the bound (CI: rank 0.9395 for p99, error 0.0505 > 0.05). The test now sizes each candidate for its target's failure probability as Pass 1 does, with the target at 1e-6 (k = 100).
…h_candidate_if_new The concepts doc (section 3) defines Memo::add_candidate, Memo::candidate and CandidateForMemoGroupId in candidates.rs. add_candidate takes push_candidate_if_new's place: it returns the id of the candidate, the equal one already in the group when there is one. CandidateForMemoGroupId moves from the physical boundary types to candidates.rs; the planner's memo-choice check reads a candidate through Memo::candidate. hash_consing::equal_nodes is now private to the types crate.
NodeToStructuralIdCache, Pass 1's own structural identity next to Stage 0's equality, is deleted. Pass 1 adds its candidates through Memo::add_candidate, and recognizes the exact composition of a group's own node with hash_consing::equal_nodes after the composed node takes the group's schema and loses its exact guarantee. PerComputationCandidates::walked compares groups with equal_nodes. Snapshots unchanged.
zzylol
force-pushed
the
refactor/1203-2a-2-summary-results-inputs
branch
from
November 5, 2026 21:24
45c8d37 to
80bec5a
Compare
zzylol
added a commit
that referenced
this pull request
Nov 5, 2026
…s candidates when found `exact_input_group` replaced the candidates of the group `find_or_add_group` returned, also when it found an existing group. Now the exact candidates replace the own candidate only of a group it added; a found group keeps its candidates and gets the new ones through `push_candidate_if_new`. Top-k and finer-aggregate reads follow #1218's interface changes (`MemoGroupId` owner, `find_or_add_producer` without budget parts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
Contributor
Author
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.
Stacked on #1215; part of #1203, tracked in #1207 (PR 2a-2).
Merge unit. This PR merges into main only together with the rest of #1207's merge unit (steps 1a–6, #1207 "Order"): interim items below are deleted by a later PR in the unit.
Why
#1203 decided one operator per candidate, every intermediate result its own memo group. #1215 did this for Pass 1; the Pass 2 rules still add private operator chains. This PR switches the first two rules, summary inputs (rule 3) and summary results (rule 8), and adds the shared function the other rules will switch to.
What
over_child_groups, the walk refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215 added).summary_results): a candidate with two or more private builds and a readout of one of them gets a copy whose readouts, builds and inputs are all groups (originSummaryResult). It no longer builds a dedicated readout producer per readout and a consumer over them.summary_inputs): the privateProject/Filterinputs below a build are found or added as groups (originSummaryInput, sized for the whole budget), and the consumer copy over them is one operator over groups.operator_over_groups(moved out of Pass 1): remove exact guarantees below the root, find or add the child groups, raise the parts of the added groups read through.Memo::add_candidate(section 3 of the concepts doc) adds a candidate unless an equal one is there (same input groups, fused groups, budget parts, and Stage 0's node equality, children by pointer first), and returns itsCandidateForMemoGroupIdeither way. Rule 9 uses it too, in place of its own graph-signature check (SummaryStates::known).Memo::candidate(id)reads a candidate by id;CandidateForMemoGroupIdmoves tocandidates.rs, where the doc puts it.sketch_rollup::quantiles_rolled_up_keep_the_sketch_boundfailed once in CI (run 42071683865, attempt 1:web: rank 0.9395, error 0.0505 > 0.05). Not this PR's code: the test composes its candidates outside the memo, and the executor's KLL seeds its coin per run. Composed alone the KLL is sized for the calibrated failure probability 0.01 (k = 52), and the test checks eight answers. It now sizes each candidate for its target's failure probability as Pass 1 does, with the target at 1e-6 (k = 100).reuse::same_output_contract(result kind, fields, time index, unique keys, closed label set).check_output_contract, scan widening and rule 9 call it; scan widening's copy and rule 9's inline check are deleted.boundary_groupslooks groups up withMemo::group_whose_node_isand a predicate, not a pointer map each caller builds (review item E4 of refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215).corpus_snapshots/sketch_plan_snapshotsfile changes; Stage 2 candidate counts identical on every snapshot input.New abstractions not in #1207 or the doc: decisions (2026-11-05)
Per #1207's interface policy, these names are not defined by #1207, #1203 or section 3 of
memo-groups-properties-requirements.md. #1207's steps 1a–6 merge into main as one merge unit (#1207, Order), so an interim abstraction may stay in this PR only when a later PR of the unit deletes it; none reaches main. Rows marked Pending approval are not deleted by any PR in the unit and need the user's decision.operator_over_groups(crate fn)CandidateExpression)without_exact_guarantees(one function since #1222)reuse::add_candidate_over_groups,reuse::find_or_add_producerpush_candidate_if_newMemo::add_candidateNodeToStructuralIdCacheMemo::add_candidateandhash_consing::equal_nodeshash_consing::equal_nodesMemo::add_candidateand Pass 1hash_consing, the one node equality)reuse::same_output_contract(one copy, moved from scan widening)How
operator_over_groups(memo, root, queries, origin, parts):without_exact_guarantees_below(root)→over_child_groups(memo, ...)→size_own_candidate_foron every added group read through (groups_read_through_added_groups). Pass 1'starget_candidatesnow calls it instead of the three steps inline.reuse::add_candidate_over_groups(memo, owner, original, node, origin): the output-contract check shared withappend_reader(check_output_contract), thenoperator_over_groupswith the owner's queries andoriginal's parts, thenMemo::add_candidate(added when the returned index is a new one). A rewrite whose groups include the owner itself is not added.reuse::find_or_add_producer(memo, node, queries, origin): exact guarantees removed (root included), thenfind_or_add_groupwith 1 part (every caller passed 1, which had no effect). Rule 3's canonical inputs use it; equalTimeRangeinputs are already one group by Stage 0's equality, so the rule'ssame_range_inputrebinding is deleted.Representation / rules / enumeration
root_nodethat is one operator whose children are theirinput_groups' nodes (by child position), like Pass 1's. Rules 1, 2, 4–7, 9 and step 10 still add chains.find_or_add_group(viaoperator_over_groups/find_or_add_producer). Their matching still reads private chains (nodes_within,direct_input_builds), which only the unconverted rules still make.enumeration.rs, Stage 2, Stage 3 untouched).Key code interfaces added / modified
crates/types/src/stages/hash_consing.rscrates/types/src/stages/candidates.rscrates/logical-asap-optimization/src/operator_over_groups.rs(new, crate-internal)crates/logical-asap-optimization/src/pass2/memo/rules/reuse.rs(crate-internal)crates/logical-asap-optimization/src/pass2/memo/state_groups.rs(crate-internal)Usage. Neither rule fires on the KLL example or on the scan-widening example: after #1215 no Pass 1 or Pass 2 candidate there has a private
Project/Filterbelow a build or two private builds.asap_planner --workload kll.json --run-until stage1_pass2 --format text(and the scan-widening workload) print byte-identical output before and after this PR, so there is no memo excerpt to compare. The rules fire on the chains the unit tests inject into rule 1's tumbling-window candidates (state_groups::tests::check_private_inputs): forquantile_over_time(0.95, latency[5m])andquantile_over_time(0.99, latency[5m])with a private identityProject(orFilter true) under each privateSummaryTumblingWindowChain:Major algorithm changes
None. The rules match the same candidates; only the shape of what they add changes.
Before this PR
Rules 3 and 8 added dedicated producer groups (
append_producer, reused only by origin and parts) and a consumer chain over them (append_reader, deduplicated by a deep==).After this PR
Rules 3 and 8 add one operator over groups, with groups found by Stage 0's equality; Pass 1 and both rules share
operator_over_groups.Deleted
summary_results.rs: its per-readout producer groups (append_producer), the replacement map andreplaceof the consumer.summary_inputs.rs: theTimeRangerebinding throughstate_groups::same_range_input(Stage 0's equality finds the group), andcanonical_preprocessing'sResult(nothing fails any more).pass1/add_pass1_candidates.rs: the inline strip / child groups / parts raise, nowoperator_over_groups;without_exact_guarantees_belowmoved out.boundary_groupscaller built (reuse.rs×2,scan_labels.rs,state_groups.rs×2).scan_labels::same_output_contractand rule 9's inline output check (nowreuse::same_output_contract); rule 9'sSummaryStates::knownmap (nowMemo::add_candidate;graph_signaturestays for one test);find_or_add_producer's budget-parts argument.b8402c7):push_candidate_if_new(now the doc'sMemo::add_candidate); the hand-indexedmemo.candidates[group][index]in the planner's memo-choice check (nowMemo::candidate);CandidateForMemoGroupIdinstages/physical/memo_candidates.rs(moved tocandidates.rs).Kept because unconverted rules still use them:
append_reader(rollup),append_producer(top-k, rollup),nodes_within/boundary_ptrs/direct_input_builds(top-k, rules 3 and 8's matching, step 10),same_range_input(rule 9),reuse::same_node/restore_inputs(rollup).Plan cost, Stage 2 candidates and planning time
UPDATE_SNAPSHOTS=1left everycorpus_snapshotsandsketch_plan_snapshotsfile unchanged. Stage 2 physical candidates (Cn:lines of--run-until stage2) and--run-until stage3wall time per snapshot input, #1215 (b080c96) vs this PR, release builds on one host:Second review fixes
Folded into the rebased commit (
f27b38f):reuse::same_output_contractreplaces three copies:scan_labels::same_output_contract, rule 9's inline check (shared_configuration_readers.rs, which also skipped the result kind), and the body ofcheck_output_contract, which now only wraps it.push_candidate_if_new, keeping the guard against a rewrite that reads its own group. Its ownknownmap of graph signatures is deleted.find_or_add_producerdropsaccuracy_budget_parts. Every caller passed 1, so the argument changed nothing. A producer group is found or added with 1 part, and thesummary_inputscomment now says so.add_candidate_over_groups(memo, owner: MemoGroupId, ...): one id type, wasusize.push_candidate_if_newis a crate-private Stage 1 function (operator_over_groups.rs), not aMemomethod.b3c7b5a(below).Notation (formulation → code)
MemoGroup, idMemoGroupId(also theownerof an added candidate)Memo::add_candidate(doc), throughadd_candidate_over_groupsCandidateForMemoGroupId(doc), read withMemo::candidate(doc)operator_over_groups(returns the operator over the groups' nodes andhash_consing::equal_nodes(Stage 0's equality)same_output_contractConcepts not in the formulation
Interim names with no formulation term, for the user to name or drop:
find_or_add_producer): a group a rule factors out of its consumers, e.g. a summary input or a top-k ranking. In the formulation it is just a memo group.same_output_contract,check_output_contract): a rewritten candidate must produce its group's output.SummaryResult,SummaryInput): rules 3 and 8. Both go once no rule makes private chains.Memo::add_candidate's dedup): same input groups, fused groups, budget parts and an equal node.Second review verification (
f27b38f)cargo test -p asap-types --lib: 146 passed.cargo test -p asap-logical-asap-optimization --lib: 198 passed.cargo test -p asap-integration-tests --test integration -- memo_enumeration reuse_rules operator_sharing sharing_issue_regressions finer_aggregate_reuse planner_layering_example having_shared_aggregate stage1_logical_asap_optimization joint_search_equivalence sketch_rollup rollup_controlled production_rollup_workloads: 154 passed, 23 ignored (pre-existing).cargo test -p asap-devtools --lib: 18 passed.--test devtools -- asap_planner:: asap_planner_acceptance:: memo_pricing::: 56 passed, 1 ignored.UPDATE_SNAPSHOTS=1 cargo test --release -p asap-devtools --test corpus_snapshots -- --include-ignored: 9 passed, no file changed.--run-until stage1_pass2 --format text: byte-identical tob3c7b5a. Rule 9 runs on both, so its new deduplication adds the same candidates.asap_planner --run-until stage1_pass2 --format text: byte-identical to the pre-review headb3c7b5aon 35 workloads besides the two examples: the reviewer's 20 workloads, six rollup / scan-widening /avgworkloads, five earlier finer-aggregate, rollup, top-k and scan-KLL examples, andrandom-mixed-seed-862workloads 01–04.cargo fmt --all;cargo clippy --workspace --all-targets -- -D warnings: clean.One node equality in Pass 1 (2026-11-05)
NodeToStructuralIdCache, Pass 1's own structural identity beside Stage 0's equality, is deleted. Pass 1 adds its candidates throughMemo::add_candidate; the exact composition of a group's own node is recognized withhash_consing::equal_nodesonce the composed node takes the group's schema and drops its exact guarantee;PerComputationCandidates::walkedcompares groups withequal_nodes. One behaviour change: two literals that are both NaN are no longer one candidate (equal_nodescompares floats by value); no snapshot has one. Verification:UPDATE_SNAPSHOTS=1 cargo test --release -p asap-devtools --test corpus_snapshots -- --include-ignored: 9 passed, no file changed;cargo test -p asap-logical-asap-optimization --lib: 197 passed (the deletedstructural_keys_preserve_nonfinite_and_signed_zero_literalstested the deleted cache);cargo test -p asap-devtools --lib: 18 passed;cargo test -p asap-integration-tests --test integration(12 filters as above): 154 passed, 23 ignored.Interface alignment and CI fix verification (
b8402c7)sketch_rollup::quantiles_rolled_up_keep_the_sketch_bound: the composed KLL now hask = 100, failure_probability: Some(1e-6)(wask = 52, None), printed from the test. 300 local runs of the new test: 0 failures (the old test also passed 300 local runs; its CI failure is a rare draw).cargo test -p asap-types -p asap-logical-asap-optimization -p asap-planner -p asap-physical-asap-optimization --lib: 146, 198, 11, 29 passed.cargo test -p asap-integration-tests --test integration -- memo_enumeration reuse_rules operator_sharing sharing_issue_regressions finer_aggregate_reuse planner_layering_example having_shared_aggregate stage1_logical_asap_optimization joint_search_equivalence sketch_rollup rollup_controlled production_rollup_workloads: 154 passed, 23 ignored (pre-existing), the same count as before.cargo fmt --all -- --check;cargo clippy --workspace --all-targets -- -D warnings: clean.Memo::add_candidatekeepspush_candidate_if_new's equality, so the rules add the same candidates; snapshots were not rerun for this commit.Viewer
Viewer tests are not updated for the group shape (#1203 decision 6);
viewer_contractpasses.Verification
cargo test -p asap-logical-asap-optimization --lib: 198 passed.state_groups::tests::check_private_inputsnow looks for a build group both queries reach over aSummaryInputgroup among all groups (the build is now a group of the rule, not aSharedBuildgroup of step 10).cargo test -p asap-physical-asap-optimization: 29 passed.cargo test -p asap-plan-selection --lib: 142 passed.cargo test -p asap-devtools --lib: 18 passed.cargo test -p asap-integration-tests --test integration -- memo_enumeration reuse_rules operator_sharing sharing_issue_regressions finer_aggregate_reuse planner_layering_example having_shared_aggregate: 117 passed, 23 ignored (pre-existing).cargo test -p asap-devtools --test devtools -- asap_planner:: asap_planner_acceptance:: memo_pricing:: viewer_contract::: 58 passed, 1 ignored (pre-existing).UPDATE_SNAPSHOTS=1 cargo test --release -p asap-devtools --test corpus_snapshots -- --include-ignored: 9 passed, no file changed.cargo fmt --all;cargo clippy --workspace --all-targets -- -D warnings: clean.--run-until stage1_pass2 --format text: byte-identical to refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215's head.Left for 2a-3..k
SummaryResult,SummaryInputanddirect_input_builds.