Repository navigation
feat(types): one AccuracyTarget with an optional, derived metric; any metric accepted when unset - #718
Conversation
… metric accepted when unset
Merge RequestedAccuracy into AccuracyTarget, a plain struct whose metric
is optional. A target that sets no metric accepts a guarantee in any
metric (absolute at any scale, relative, rank) that meets its epsilon,
delta and scope; a target that sets one keeps today's rule. A quantile
without a metric is no longer an input error: KLL and DDSketch compete on
cost.
- AccuracyTarget serializes as {"metric"?, "error", "failure_probability"?,
"scope"?}; the old "Exact"/{"Epsilon"}/{"EpsilonDelta"} forms are gone.
- AccuracySpec<E, P> stays the guarantee's outer shape.
- RequestedAccuracy, AccuracyRequestError, for_root and
SelectionError::AccuracyRequest are removed; default_metric_for_root
keeps the per-intent default table for display.
- Stage 3 reports, per valid candidate and query, the accepted metric
(Selection::accepted, AcceptedAccuracy); stage_pipeline writes it and
the target JSON, and the dag-viewer shows both.
- Sizing a share without a metric fails closed (no split) with a debug
assertion.
|
Usage: let target = AccuracyTarget::epsilon_delta(0.01, 0.01); // metric not set this should give an example of how accuracyTarget binds to a query? |
|
Updated the PR body's Usage: it now shows the target bound to a query through its workload entry ( |
|
impl AccuracyTarget { this should be simplifed, and each interface should be human understandable without comments. |
|
is the entire pub enum SelectionError { |
|
Agreed. Planned public API, where each method is named after the field it sets: AccuracyTarget::exact()
AccuracyTarget::max_error(0.01)
.failure_probability(0.01) // optional
.metric(ErrorMetric::Rank) // optional; unset = any metric is accepted
.scope(AccuracyScope::PerValue) // optional; default WholeResult
target.is_exact()
|
|
No, |
|
Revised plan for the same follow-up PR: AccuracyTarget::exact()
AccuracyTarget::max_error(0.01)
.failure_probability(0.01)
.accuracy_metric(AccuracyMetric::Rank)
.accuracy_scope(AccuracyScope::PerValue)
target.is_exact()The fields follow the method names ( |
Why
The user asked for one accuracy-target type whose metric is optional (#690 revisions, 2026-10-15). Before this PR a workload stated a
RequestedAccuracy, the planner resolved it per query root to anAccuracyTargetwith a concrete metric from a per-intent default table, and Stage 3 accepted only guarantees in that metric. A quantile without a metric was an input error, though the user may not care whether its error is a rank error (KLL) or a relative one (DDSketch).What
RequestedAccuracyandAccuracyTargetare merged into one plain struct,AccuracyTarget, whosemetricis optional.AccuracyRequestError::MissingQuantileMetricandSelectionError::AccuracyRequestare removed.metric not set; accepted rank (Kll).stage_pipelinewrites this to its document and the dag-viewer shows it.default_metric_for_root). It no longer rejects candidates.AccuracyTargetreads and writes as{"metric"?, "error", "failure_probability"?, "scope"?}. The old forms"Exact",{"Epsilon": ε}and{"EpsilonDelta": {...}}are no longer accepted. This PR has no compatibility shim.How
types.rs:AccuracyTargetis now a struct with serde defaults:metric: None,failure_probability: Noneandscope: whole_result. It has no wire or untagged helper types.AccuracySpec<E, P>is unchanged and remains the guarantee's outer shape.root_metricbecamedefault_metric_for_root, which returnsNonefor a quantile instead of an error.DefaultAccuracyModel::satisfies:target.metric.is_none_or(|m| metric_meets(g.metric, m)). The ε, δ and scope checks are unchanged.accuracy_violationbecameaccuracy_check. It returns, per query, theAcceptedAccuracyof the guarantee that met the target: the theoretical guarantee or the deployment's evidence, plus the sketches the root reads.select_plankeeps these inSelection::accepted.run_stage2_and_stage3passes the workload targets through unchanged, andresolve_targetsis gone.debug_assert!, and Stage 3 still checks the composed output.RequestedAccuracy→AccuracyTargetacross about 90 files, includingtools/verify_metricsql_external_consumer.sh.requirements.accuracyis now the target's own JSON.requirements.default_metric, for display only.stage3_plan_selection.acceptedholds{target_metric, accepted_metric, sketches, summary}for each shown valid candidate and query.ε=…, δ=… (metric | metric not set; default …)for each query, and the accepted metric for each valid candidate and for the plan in lane 2.Key code interfaces added / modified
crates/types/src/types.rscrates/asap-aware-mapping/src/accuracy/mod.rscrates/asap-aware-mapping/src/stage3_plan_selection.rscrates/types/src/workload.rsJSON formats. These are the
AccuracyTargetwire form and thestage_pipelinedocument (asap-stage-pipeline/v1), seecrates/devtools/src/bin/stage_pipeline.rsandtools/dag-viewer/README.md:Usage: an
AccuracyTargetis bound to one query through that query's workload entry. Each query inquery_batchorrepeating_queriescarries its ownrequirements.accuracy; the planner passes one target per query root to Stage 3 (stage1_to_stage3.rs:entry.requirements.accuracy.requested()), so two queries in one workload can ask for different ε, δ and metrics.The same entries in the workload JSON:
{"query": "quantile_over_time(0.99, latency_ms[5m])", "requirements": {"accuracy": {"explicit": {"error": 0.01, "failure_probability": 0.01, "scope": "whole_result"}}, "response_latency": "unspecified"}} {"query": "...", "requirements": {"accuracy": {"explicit": {"metric": "rank", "error": 0.01, "failure_probability": 0.01, "scope": "whole_result"}}, "response_latency": "unspecified"}} {"query": "...", "requirements": {"accuracy": "implicit_exact", "response_latency": "unspecified"}}After planning,
selection.acceptedsays which metric each query was accepted under. Continuing the example (checked atf0b07992with a scratch test):The
AccuracyRequirement::Explicit/ImplicitExactwrapper shown here is what this PR merged with. #717 removes it: thereQueryRequirementsis{ accuracy: AccuracyTarget, max_latency_ms: Option<f64> }, with exact as the default, so Q1 becomesaccuracy: AccuracyTarget::epsilon_delta(0.01, 0.01).Before this PR
RequestedAccuracy(input, metric optional) andAccuracyTarget(resolved, metric required).quantile_over_timetarget without--metricfailed Stage 3 with "must name its metric"."Exact",{"Epsilon"}and{"EpsilonDelta"}.After this PR
AccuracyTarget. Leaving its metric unset lets every candidate whose guarantee meets ε, δ and scope compete on cost, and the output says which metric each candidate was accepted in.stage_pipeline --promql 'quantile_over_time(0.99, m[1m])' --epsilon 0.01now selects a plan. The KLL candidates reportmetric not set; accepted rank (Kll)and the DDSketch candidatesmetric not set; accepted relative (DDSketch). With--metric rank, the valid candidates are KLL (metric rank; accepted rank (Kll)) and exact ones (metric rank; accepted exact).#509 examples. Selection is unchanged for all committed examples. Examples 3a and 3b set
rank, and Examples 1 and 2 have no quantile. Example 1 still selects the same plan and Example 2 still selects P1 at 6.08 with 12 valid plans. Only the document's accuracy andacceptedfields change.I also ran Examples 3a and 3b with the metric unset. These are local runs, not committed.
Verification
accuracy::tests::a_target_without_a_metric_accepts_any_metricdid not compile against main's concrete metric.a_quantile_target_without_a_metric_accepts_rank_or_relativefailed before the reporting was added.cargo nextest runon asap-types, asap-aware-mapping, asap-physical-operators, asap-frontend-promql, asap-frontend-metricsql, asap-frontend-sql, asap-planner, asap-devtools and asap-integration-tests: 1788 of 1789 passed. The one failure was the committed Example 1 fixture check. I regenerated the fixture, and a rerun ofasap-devtoolspassed 28 of 28.cargo test --docpasses on asap-types, asap-aware-mapping, the frontends, asap-planner and asap-devtools.cargo fmt --all -- --checkandcargo clippy --workspace --all-targets --all-features --locked -- -D warningsare clean.tools/verify_metricsql_external_consumer.shpasses.python3 -m unittest test_viewer test_serverintools/dag-viewer: 50 tests pass. This includes a fix to the stale"9 candidates"assertion, which already failed on main because the fixture has had 27 candidates since feat(planner): tumbling-pane window composition as a Pass 2 rule (Example 3) #713.nextest; this follows the review-only gate.Limitations and follow-ups
Debug, e.g.AccuracyTarget { metric: None, … }.library-api.md,accuracy-models.md,end-to-end-accuracy-guarantees.md,planner-layering.md) are left for Update the docs after the G1–G11 consolidation groups land #677. This PR updates onlystage-viewer.md(the viewer's accuracy and accepted-metric display) and the dag-viewer README.