Skip to content

docs(concepts): memo groups, properties, requirements, per-stage interfaces and rules - #1224

Open
zzylol wants to merge 67 commits into
mainfrom
docs/memo-group-model
Open

zzylol wants to merge 67 commits into
mainfrom
docs/memo-group-model

Conversation

@zzylol

@zzylol zzylol commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Review guide

  • Position: base main, rebased onto main 69fc34a90 (2026-11-10; feat(stage0, types): memo hash-consing, group properties (column_sign, depends_on_evaluation_time, aggregate_coverage), @ end()/@ start() above their subtree (#1207 PR 2) #1230 merged; the 65 doc commits replayed unchanged, so the diff is only this PR's three doc files; previous heads c298e1068 and 22eef766b, backups backup/1224-memo-group-model-c298e1068 and backup/1224-memo-group-model-22eef766b). The doc of the Tracking: implement the optimization formulation (memo candidates, properties, edges y_{u,c,i}, MILP) as named code per stage #1207 stack; the code PRs follow its names and stages. Head 7eeff73ba. The doc matches main 69fc34a90.
  • Reading order: §1 (model, summary terminology, running example, notation) → §2 (properties, requirements, decision tree, where each quantity lives) → §3 (per-stage interfaces and rules: Stage 0, Pass 1, Pass 2, Stage 2, Stage 3 and plan output) → §4 (accuracy and safe pruning) → §5 (execution contexts) → Appendix A (enumerating DAGs for debugging).
  • Mechanical: the concepts index link; the summary-terminology table in asap-primitive-schema.md (family / algorithm / summary type / θ; SketchKind and GroupingStrategy replaced by FieldDataType::Sketch(SketchAlgorithm), Hydra as an algorithm).
  • Careful: §2 decision tree and prune rules; §3 Pass 2 rules (rollup from the finest common group, dead-candidate elimination, chain groups, logical edges) and Stage 3 (baseline MILP, cycles, plan output); §4 error propagation and the (K) encoding; §5 execution contexts, cost and retention; accuracy-models.md's HLL distinct-count rule.

Behavior: before → after

Documentation only; the "user" is a reviewer or paper author looking up a definition.

Before After
Where are memo groups, candidates, properties and requirements defined? spread over the bodies of #1200, #1203, #1207 one concepts page, in the formulation's notation
Order of decisions ($e_v$, θ, τ, ℓ) and their prune rules not written down §2 decision tree; why the order changes enumeration efficiency but not $\mathcal C$
What each stage takes and returns not summarized §3: per stage, data structures, interfaces, rules, and what each deletes
Memo interfaces in §3 (Stage 0, OperatorInput, Pass 1 Memo methods) pre-#1230 names (column_sign, SummaryCoverage, reads_only_time_series, values_per_evaluation, set_input_requirements) and old paths copies of the definitions at #1230's 73785fa07, with their file paths
quantile_over_time(0.9, latency[1h]) / quantile_over_time(0.5, latency[1h]), latency non-negative: value sign not covered by the sign table (arithmetic Unknown) NonNegative (arithmetic row)
HLL distinct count within relative 0.05 at δ = 0.01 precision sized in Stage 1, δ left symbolic and bound in Stage 3 the memo holds source facts; with max_distinct_per_evaluation 9,636 precision 18 meets it; with 1,000,000 (outside the contract) or no bound, no HLL precision does (BelowRequiredAccuracy)

Interfaces

None in code. The doc describes target interfaces as Rust sketches (not compilable); each names today's path or the issue that changes it. The code PRs of the stack implement them.

Algorithm changes

None in code. The doc specifies the algorithms the stack implements: Pass 2's reuse rules, dead-candidate elimination, Stage 2's physical expansion, the Stage 3 baseline MILP (with $t$ only on strongly connected components), error propagation and constraint (K), execution contexts, and Appendix A's enumeration of every logical DAG a memo group represents (one producer per consumer input, sharing and cycle checks; inspection tool, not a planning stage).

Decisions and open questions

Needs reviewer decision: None.

Decided:

  • 2026-11-10: synced with main 69fc34a90 (feat(stage0, types): memo hash-consing, group properties (column_sign, depends_on_evaluation_time, aggregate_coverage), @ end()/@ start() above their subtree (#1207 PR 2) #1230 merged), commit 7eeff73ba:
    • Coverage in the IR: AggregateCoverage<R> / AggregateDefinition<R> (field input, was input_group) and CoverageError, derived by Operator::aggregate_coverage in ir/properties/aggregate_coverage.rs, generic over OperatorInput::Reference (reference()); the memo uses MemoGroupId; map_references. The sentence "exists only in the memo … no type parameter" is replaced.
    • The plan's content id: ViewCoverage on PhysicalASAPDAGNode::view_coverage (plan/physical_asap_dag.rs), built by stages::view_coverage(memo, group), which expands the memo's coverage; the plan does not re-derive it.
    • Value sign: ValueSign is the IEEE sign bit (-0.0 is NonPositive); the arithmetic row states the XOR rationale; the literal row the sign bit; point_counts_may_flip_sign for the Count Sketch / UnivMon readout row.
    • Memo::root_groups / queries_rooted_at methods; Operator::scanned_sources in the OperatorInput and rules blocks.
  • 2026-11-10: aligned with feat(stage0, types): memo hash-consing, group properties (column_sign, depends_on_evaluation_time, aggregate_coverage), @ end()/@ start() above their subtree (#1207 PR 2) #1230 (head 73785fa07), commits 2e0ad6735, 26ff01626 (the SketchParams / parameter_list path) 0b8a365d5 (lineage sentence without PR numbers) and 22eef766b (no PR or issue numbers left in the concepts docs: the Extension label, the θ row, the lifetime row, Pass 1's intermediate-result sentence, the §4 and §5 headings):
    • Names: column_sign → column_signs; SummaryCoverage → AggregateCoverage (with AggregateDefinition, CoverageError::NoCoverage); reads_only_time_series → scanned_sources + Source::is_time_series; node-rule check → validate_expression_over_input_groups; values_per_evaluation → number_of_values_per_query_evaluation; set_input_requirements → set_candidate_input_requirements; CandidateError::Schema → NotValidOverInputGroups.
    • Memo::new(data) stores the data workload's source facts at construction ("collects the facts of the sources the queries scan" deleted).
    • Two-scope identity: the memo compares AggregateDefinition with ==; the plan's ViewCoverage::definition_id is the content id of the expanded definition (no group or node ids). The "executor reads only definition_id" sentence and the plan node's summary_coverage field are replaced accordingly.
    • Value sign: NonNegative = every non-NaN value ≥ 0; new rows for arithmetic (scalar and vector, one rule), vector(s), quantile only for 0 ≤ q ≤ 1, Count Sketch / UnivMon point-count and top-k readouts Unknown (Count-Min keeps its sign); every row checked against column_properties.rs at 73785fa07 (added: absent_over_time, join / set-op / relabel / window rows, constant-weight states, readouts that drop the state layout).
    • Code blocks (MemoGroup, GroupProperties, AggregateDefinition, AggregateCoverage, Memo, MemoQuery, OperatorInput, MemoGroupAsInput, Pass 1's Memo methods, CandidateError) copy the 73785fa07 definitions; file paths follow the scope layout and stage crates. Memo::max_distinct_per_evaluation and GroupProperties::column_lineage are marked not yet in the code.
    • Column lineage section unchanged except one sentence: its key is not decided yet (the SourceColumn type it named was removed).
  • 2026-11-05: ErrorPropagation and error_propagation(consumer, metric) (§4) as the source of the propagation factors β and the per-input validity caps. Current form: ErrorPropagation { factor_per_input: Vec<f64>, validity_cap_per_input: Vec<Option<f64>> }; None when the consumer has no error contract for the metric (no factor guessed). Example: error_propagation(Divide, Relative) = Some { factor_per_input: [1.111, 1.111], validity_cap_per_input: [None, Some(0.1)] }; absolute and rank return None.
  • 2026-11-07 to 2026-11-10: the stack's decisions (restack plan rounds; A1–A7, D1 among them) are applied to the doc in the commits on this branch: θ is structure only and not part of the summary type; ℓ ≠ None is "materialized"; accuracy is checked at the query root through (K), not per edge; merges carry θ (A1); the metric rule cuts edges (A2); held memory per node (A3); a query-time Scan execution reads the most its context's consumers read, with no read variable (A5); @ T without a horizon gives no materialized candidate (A7); HLL distinct count from the memo's source facts (A6); Pass 2 δ levels continue in powers of ten below the per-value δ (D1); raw rows a TimeShift materializes at ingestion time are retained like a Scan's (D3).

Verification

Scope Passed / failed / ignored Newly failing vs base Notes
docs n/a n/a Docs only. Mermaid syntax checked by eye; links checked. Every crates/… path in the doc checked to exist at 73785fa07 (except ReaderConstraint's former path, marked former). git diff --stat origin/main lists only concepts/README.md, concepts/accuracy-models.md and the new concepts doc.

Tests, screenshots and measurements: not applicable.

Follow-ups

@zzylol zzylol added documentation Improvements or additions to documentation optimizer Workload optimization and plan selection extensibility labels Nov 5, 2026
@zzylol zzylol changed the title docs(concepts): memo groups, properties, requirements and the property decision tree docs(concepts): memo groups, properties, requirements, per-stage interfaces and rules Nov 5, 2026
@milindsrivastava1997

milindsrivastava1997 commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Comparing this doc with PR 1213 (memo representation proposal). Four places where the models differ.

1. Accuracy

  • PR 1213: each consumer carries its own ε. The budget is split up front; a shared producer is built for the min.
  • This PR: no ε on inputs. Row (K) checks the composed error at the query root; error_cap only drops producers that can never fit.
B = p99 / p50, target ε .01
PR 1213:  each operand gets .005
This PR:  any split with λ·ε_p99 + λ·ε_p50 ≤ .01, e.g. .002 + .008

2. Sketch family

  • PR 1213: one summary group; Kll vs. DD is a property of its candidate.
  • This PR: family is part of the expression, so one state group per family. A consumer picks a family by which group it reads.
PR 1213:  S  SummaryState(quantile, data, 300s)
               [SummaryAgg <-G1 | sketch ∈ {Kll, DD}]
          G2 [Est <-S]

This PR:  K  SummaryAgg[KLL](G1)
          D  SummaryAgg[DD](G1)
          G2 [Est <-K] [Est <-D]

Also: the §2 decision tree shows SummaryAgg[KLL] and SummaryAgg[DDSketch] as candidates of one group G, which contradicts the Example and the Pass 1 table.

3. One operator per candidate

  • PR 1213: S is a group, but multi-operator candidates remain (its open question 4).
  • This PR: every operator is its own group.
Today:    G2 [Est ← SummaryAgg Kll <-G1]
PR 1213:  S  [Merge ← TWChain <-G0]        still two operators
This PR:  G2 [Est <-K]    K [SummaryAgg θ <-G1]

4. Producer variants: stored vs. derived

  • PR 1213: no variants stored. A producer's θ is computed from the strictest requirement of the consumers that share it (built_for).
  • This PR: each θ is a stored candidate. Each consumer picks one that meets its requirement; sharing = two consumers pick the same one.
q50 ε .01, q99 ε .001 over data[5m]

This PR:  K candidates: k(.01), k(.001)
          q50 reads either; q99 reads only k(.001)
          shared plan: both read k(.001)

PR 1213:  S has one candidate
          enumeration decides q50, q99 share → built for ε .001 → k(.001)

@milindsrivastava1997

milindsrivastava1997 commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator
  • Should candidates be a field on Memo or MemoGroup? Latter makes more sense imo
  • What is operator: Operator<MemoGroupId> and how is it different from OperatorNode? Instead of expression: CandidateExpression, in CandidateForMemoGroup, can't we just reuse logical_node: Rc<OperatorNode> from MemoGroup?
  • Should LogicalEdge.input be renamed to LogicalEdge.input_index_of_consumer?
  • What is PhysicalCandidateKey? Do you mean PhysicalCandidateId?
  • Didn't understand the MILP data structs (e.g. Context) but can come back to this later.
  • Didn't understand Periodic vs TumblingWindowGrid for the schedule property

@zzylol

zzylol commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author
  • Should candidates be a field on Memo or MemoGroup? Latter makes more sense imo

Yeah it should be under MemoGroup.
candidates field is a vector of vector of Candidate data structure, in Memo, so conceptually, it is under a group.

@zzylol

zzylol commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Comparing this doc with PR 1213 (memo representation proposal). Four places where the models differ.

1. Accuracy

  • PR 1213: each consumer carries its own ε. The budget is split up front; a shared producer is built for the min.
  • This PR: no ε on inputs. Row (K) checks the composed error at the query root; error_cap only drops producers that can never fit.
B = p99 / p50, target ε .01
PR 1213:  each operand gets .005
This PR:  any split with λ·ε_p99 + λ·ε_p50 ≤ .01, e.g. .002 + .008

For this, it has the possibility to not be each operand gets .005.

2. Sketch family

  • PR 1213: one summary group; Kll vs. DD is a property of its candidate.
  • This PR: family is part of the expression, so one state group per family. A consumer picks a family by which group it reads.
PR 1213:  S  SummaryState(quantile, data, 300s)
               [SummaryAgg <-G1 | sketch ∈ {Kll, DD}]
          G2 [Est <-S]

This PR:  K  SummaryAgg[KLL](G1)
          D  SummaryAgg[DD](G1)
          G2 [Est <-K] [Est <-D]

Also: the §2 decision tree shows SummaryAgg[KLL] and SummaryAgg[DDSketch] as candidates of one group G, which contradicts the Example and the Pass 1 table.

Yeah, agree, the sketch algorithm should be the candidate dimension. But it is like this PR's way because later if we want to model each operator as one group to avoid duplicated nodes in the plans, and being more flexible about choices, it may be easier to build one group for a sketch algorithm.

3. One operator per candidate

  • PR 1213: S is a group, but multi-operator candidates remain (its open question 4).
  • This PR: every operator is its own group.
Today:    G2 [Est ← SummaryAgg Kll <-G1]
PR 1213:  S  [Merge ← TWChain <-G0]        still two operators
This PR:  G2 [Est <-K]    K [SummaryAgg θ <-G1]

I thought per operator is its own group will give us more flexibility. Didn't quite get the example; it seems not to be comparing the same aggregation?

4. Producer variants: stored vs. derived

  • PR 1213: no variants stored. A producer's θ is computed from the strictest requirement of the consumers that share it (built_for).
  • This PR: each θ is a stored candidate. Each consumer picks one that meets its requirement; sharing = two consumers pick the same one.
q50 ε .01, q99 ε .001 over data[5m]

This PR:  K candidates: k(.01), k(.001)
          q50 reads either; q99 reads only k(.001)
          shared plan: both read k(.001)

PR 1213:  S has one candidate
          enumeration decides q50, q99 share → built for ε .001 → k(.001)

I don't see there is a difference. The difference in representation only comes from storing the producer vs storing the consumer in MemoGroup.

@zzylol

zzylol commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author
  • Should LogicalEdge.input be renamed to LogicalEdge.input_index_of_consumer?

Sure.

  • What is PhysicalCandidateKey? Do you mean PhysicalCandidateId?

It's not 'PhysicalCandidateId', it's The name of a physical candidate that Stage 2 pruned. It names the pruned candidate by its content instead:

/// A pruned physical candidate, named by what it would have been.
pub struct PhysicalCandidateKey { pub logical: CandidateForMemoGroupId, pub properties: PhysicalProperties }

They exist for DAG viewer tool to display.

  • Didn't understand the MILP data structs (e.g. Context) but can come back to this later.

Context comes from these:

How often a candidate runs, and so what it costs, depends on its lifetime ℓ:

  • Materialized candidate (ℓ ≠ None). Its result is kept, so it runs once per its own schedule σ and every consumer reads that one result. One variable is enough: did we pick it or not (x_v).
  • Unmaterialized candidate (ℓ = None). Nothing is kept, so it runs inside whatever execution needs it. Each query evaluation that reads it runs it again. Its cost depends on how many places run it, so the MILP needs one variable per (place, candidate). That place is a context κ.

Row functions: one per constraint family, as see in the overleaf table. We should just call them constraints.

@zzylol

zzylol commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

What is operator: Operator<MemoGroupId> and how is it different from OperatorNode? Instead of expression: CandidateExpression, in CandidateForMemoGroup, can't we just reuse logical_node: Rc<OperatorNode> from MemoGroup?

Both use the same operator enum Operator<C>, with the same variants and arguments (Scan, Filter, SummaryAgg { family, … }, …). They differ in C, the type of the children:

OperatorNode (operator: Operator<Rc<OperatorNode>>) Operator<MemoGroupId>
Children other OperatorNodes: the root of a whole sub-DAG down to the scans memo group ids: one operator over its input groups
Other fields result_kind, schema, guarantee (from θ), and on main timing, materialization none
Meaning a fixed plan fragment: every input's producer is already chosen, all the way down $e_v = \operatorname{op}v(G{v,1}, \dots, G_{v,n})$: which candidate of $G_{v,i}$ feeds input $i$ is left to the edges ($y$)
Conversion node.operator.map_children(|child| group_of(child)) (exists today)

Example: G3 = p95 of the KLL state. As an OperatorNode it is SummaryEstimate(q=0.95) → SummaryAgg[KLL](k=345) → Scan, so k = 345 is baked in. As Operator<MemoGroupId> it is SummaryEstimate(q=0.95)(G2), and each consumer's edge picks k = 200 or k = 345 from G2.

Why a candidate cannot reuse the group's logical_node:

  1. One group has several candidates with different operators. G3 can be SummaryEstimate(G2), an exact quantile over G1, or a rollup reading a finer group. The group has one logical_node (the frontend's form), so each candidate needs its own operator.
  2. An Rc<OperatorNode> pins every input's producer. That is today's root_node / private-node problem: two consumers cannot pick different sizes of one state, and rules have to copy consumers. Children that are group ids leave the choice to the edges.
  3. An OperatorNode carries properties (guarantee from θ; on main also the physical fields). A candidate keeps those in logical_properties (θ, ω), and Stage 2 adds (τ, ℓ, σ).

Two simplifications this question points to, proposed (not yet decided):

  • Drop the one-field CandidateExpression wrapper and write expression: Operator<MemoGroupId> directly.
  • Store the group the same way: MemoGroup { expression: Operator<MemoGroupId>, schema, parents, queries } instead of logical_node: Rc<OperatorNode> + child_groups, which hold the same input information twice. Hash-consing already keys on Operator<MemoGroupId> (find_or_add_group).

@milindsrivastava1997

milindsrivastava1997 commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator
  • Rename CandidateForMemoGroupId.index to be more descriptive
  • Rename Memo.candidate() to be Memo.get_candidate()
  • Is InvalidLogicalProperties an error type? If yes, pls add the Error suffix
  • Rename LogicalRequirement to LogicalRequirements
  • Rename LogicalRequirement.parameter_floor to parameter_floor_for_required_accuracy
  • Rename satisfies_logical to does_producer_satisfy_logical_requirements. Similar for does_producer_satisfy_physical_requirements
  • Rename Medium to StorageMedium
  • What does Schedule mean? How does it relate to the window_layout logical property?
  • Rename PhysicalCandidate.logical to logical_candidate_id
  • Rename PhysicalASAPMemoCandidates.logical to logical_candidates. Similarly many names in PhysicalCandidate, PhysicalEdge, and PhysicalASAPMemoCandidates. PhysicalCandidateKey.
  • Do we need some function like combine_requirements_into_stricter_requirement? This is used in docs(proposals): memo representation — compressing the space of logical DAGs #1213 with Requirement and RequirementField framing, and seems helpful. I imagine that in this design, this logical is implicitly embedded in different places. Is it helpful (and easy) to make it explicit?
  • Need to rename Context to be more descriptive.

@zzylol

zzylol commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author
  • Rename CandidateForMemoGroupId.index to be more descriptive

Done: index_in_group (its position in the group's candidates list).

  • Rename Memo.candidate() to be Memo.get_candidate()

Kept as candidate(). Rust accessors don't take a get_ prefix (API guidelines, C-GETTER), and the codebase follows that (groups(), timing(), lifetime()).

  • Is InvalidLogicalProperties an error type? If yes, pls add the Error suffix

Yes. Renamed to LogicalPropertiesError, and likewise PhysicalPropertiesError.

  • Rename LogicalRequirement to LogicalRequirements

Agreed. It matches LogicalProperties.

  • Rename LogicalRequirement.parameter_floor to parameter_floor_for_required_accuracy

Agreed. The floor comes from the accuracy needed at that input; for a top-k reader, heap_size ≥ k is part of the same requirement.

  • Rename satisfies_logical to does_producer_satisfy_logical_requirements. Similar for does_producer_satisfy_physical_requirements

Agreed on the meaning, without does_ (Rust predicates don't use it): producer_satisfies_logical_requirements and producer_satisfies_physical_requirements.

  • Rename Medium to StorageMedium

Agreed.

  • What does Schedule mean? How does it relate to the window_layout logical property?

Schedule (σ) has been removed; physical properties are now just (timing, lifetime).

  • A OneEvaluation result belongs to one execution context: the queries with the same evaluation schedule share it.
  • Window grids are anchored at phase 0. Phase differences between queries are absorbed by the window width (the logical window_layout), whose candidates come from the gcd of the queries' ranges, steps and phases.
  • A consumer in context κ can read a materialized window chain iff the width w divides κ's interval and phase.
  • Rename PhysicalCandidate.logical to logical_candidate_id
  • Rename PhysicalASAPMemoCandidates.logical to logical_candidates. Similarly many names in PhysicalCandidate, PhysicalEdge, and PhysicalASAPMemoCandidates. PhysicalCandidateKey.

Agreed:

Struct Now New
PhysicalCandidate logical, properties logical_candidate_id, physical_properties
PhysicalCandidateKey logical, properties logical_candidate_id, physical_properties
PhysicalEdge, LogicalEdge producer, consumer producer_candidate_id, consumer_candidate_id
PhysicalASAPMemoCandidates logical, candidates logical_candidates, physical_candidates

Easy (the strictest of several floors of one family is their componentwise maximum), but not added now, because nothing would call it:

  • correctness is checked per edge: a producer shared by several consumers satisfies each consumer's requirements separately;
  • candidates come from the predefined θ list, not from "the weakest producer covering this set of consumers";
  • the two implicit combines are the gcd closure of window widths and max(k) for heap sizes, and the lists already contain those values.

It becomes useful with requirement-driven (top-down) enumeration as in #1213; we add LogicalRequirements::strictest(a, b) -> Option<Self> then.

  • Need to rename Context to be more descriptive.

Agreed: ExecutionContext and ExecutionContextId, the formulation's term.

zzylol and others added 9 commits November 10, 2026 21:15
…y decision tree

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
…idates over existing IR

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… definitions with the code and #1200

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
 formulation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…earlier modeling section

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…les per pass and stage

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pruning caps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zzylol and others added 27 commits November 10, 2026 21:15
…ary coverage

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
…mination, TimeBound coverage

Logical properties are parameters only; tumbling windows are range-free
chain groups read through TimeRange/TimeShift and merged by SummaryMerge.
Pass 2 order: rollup from the finest common group, top-k reuse, reach and
floors (set_input_requirements), dead-candidate elimination with root-cause
traces, chain groups, logical edges. SelectionBox keeps only columns, with
TimeBound intervals on the timestamp column; aggregate_coverage covers exact
Aggregate groups too. evaluation_grid_ms is None without a phase.
error_propagation takes a metric (b = 0.1, constant contracts for key-only
Filters and abs/clamp/negation); floor_for_cap lives in asap-accuracy.
Chain retention need is max(offset + range). Worked examples throughout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
… filtered builds, Stage 2 interface

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
…in instant queries; unified chain schema; UnivMon list product

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
…ntexts, edge costs, one consumer per None producer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
…strongly connected components

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
Summary terminology (family, algorithm, summary type, parameters as
structure only); value sign as a group property; readout required
accuracy replacing parameter floors, with requirement levels for
composed queries and per-metric error bounds in (K); where node, input
and edge quantities live; edge costs in the Stage 3 baseline; Stage 3
builds PlanOutput { plan: PhysicalASAPDAG } with a Selection report;
executor time-indexed store; Stage 2 prune reasons and ingestion /
across-evaluation offers; @ end()/@ start() lifted above the anchored
subtree. asap-primitive-schema terminology table follows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
…ries grid, DDSketch sign either way

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
… trait, MemoQuery

theoretical_guarantee and AccuracyEvidence::measured_guarantee take the
required failure probability and return the error bound at it (None when
θ cannot fail that rarely); AccuracyEvidence is a trait with
NoMeasuredGuarantees; a bound is compared through target_limit. The memo
holds its queries as one Vec<MemoQuery> { root, accuracy_target,
values_per_evaluation }, added by add_query(query).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
…dates, evaluation grids of groups

Count Sketch lists depths 47, 81, 117 and 155 per width (the median-of-rows
δ levels 1e-2 … 1e-5); CMS keeps 5, 7, 10, 12. delivers_on takes
&PhysicalASAPMemoCandidates, so Materialized(v) reads v. A stored result
that is not a chain delivers by GroupProperties::depends_on_evaluation_time
and LogicalASAPMemoCandidates::evaluation_grid_of_group, with the
sum_over_time(m[5m]) read every 60 s and 120 s example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6bq8xVaGKyinf4ohK6q
…r counts, rates, comparisons and readouts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…rt() and merges; lineage and sign share one column layout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…n in its refresh window's pipeline; delivers_on in Materialized(v); constraints per execution

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…cross evaluations

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…e producers it may read; ingestion time reads one batch of raw data

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…er node, scan read window, @ T without horizon, reads_only_time_series

- A candidate passing states on (SummaryMerge, Filter/TimeRange/TimeShift
  over states) carries the θ of the states it reads, one per θ, and reads
  only producers with that θ; elimination runs again after chain groups.
- The metric rule is applied per edge from the metrics each group's output
  accepts; a readout whose metric its output does not accept reads no
  state; a candidate cut off from an input is eliminated too.
- ValuesPerEvaluationUnknown: a whole-result δ with n_q unknown prunes the
  readouts it reaches.
- Stage 2 offers no (IngestionTime, None) summary build and no
  materialized alternative under @ T without a horizon end;
  QueryTimeResultsNotRetained rejects only (QueryTime, AcrossEvaluations).
- Query-time memory is held only while the node computes; query latency
  is left for later. A query-time Scan reads the largest offset + range of
  its selected consumers.
- GroupProperties::reads_only_time_series.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…L distinct count from the memo's source facts (max_distinct_per_evaluation)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…t's consumers read (no read variable)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WviZ6FUmrMfBTvVbBauNM6
…er-value δ; raw rows a TimeShift materializes at ingestion time are retained like a Scan's
Names and interfaces as the memo code defines them: column_signs,
AggregateCoverage / AggregateDefinition / CoverageError::NoCoverage,
scanned_sources with Source::is_time_series,
validate_expression_over_input_groups,
number_of_values_per_query_evaluation, set_candidate_input_requirements;
Memo::new(data) stores the data workload's source facts. Two-scope
identity: the memo compares definitions with ==, the plan's
ViewCoverage::definition_id is the content id of the expanded definition.
Value sign: the NonNegative definition and the arithmetic, vector(s),
quantile-range and Count Sketch / UnivMon readout rows. Code blocks copy
the current definitions; file paths follow the scope layout and stage
crates.
…n, sign-bit value signs

Sync with the code on main: AggregateCoverage<R> / AggregateDefinition<R>
(input) and their derivation in ir/properties/aggregate_coverage.rs,
generic over OperatorInput::Reference, with map_references; ViewCoverage
on PhysicalASAPDAGNode::view_coverage, built by stages::view_coverage;
ValueSign as the IEEE sign bit; Memo::root_groups / queries_rooted_at;
Operator::scanned_sources; point_counts_may_flip_sign.
…t a grid; no AcrossEvaluations anywhere below an absolute @ T; Stage 2 function name

The decision-tree row and the list of values not offered required a
known grid for AcrossEvaluations, while the alignment table reads a
time-independent result stored across evaluations at any time. The rule
now follows the table. The @ T rule covers every group below the anchor
(through any operator other than another @), not only the anchor's
direct child, with an example. Stage 2's levels 3 and 4 are
offered_physical_properties.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation extensibility optimizer Workload optimization and plan selection

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants