feat(lower): counter-derivative range functions (#44) - #54
Merged
Conversation
`changes`, `delta`, `idelta`, `deriv`, `resets`, `predict_linear`, and
`double_exponential_smoothing` (a.k.a. `holt_winters`) parsed but were
rejected (`UnsupportedFunction`). They now lower to distinct per-series
intents — the second-largest un-tracked lowering gap (108 corpus
rejections, 5.6%).
Each is a per-series, label-preserving reduction of one series' range
window to one value, riding on the enclosing `TimeRange`:
changes(v[w]) -> Aggregate{Changes, by:[]} -> TimeRange{w} -> Scan
Deliberately NOT aliased to rate/increase/count: `changes` (value-change
count) and `resets` (counter-reset count) are distinct from a sample
count; `delta`/`idelta`/`deriv` are gauge derivatives. `predict_linear`
carries its horizon (`seconds`); `double_exponential_smoothing` carries
both smoothing factors; `holt_winters` maps to the same intent.
Pipeline:
- L3 `AggIntent`: + Changes/Delta/IDelta/Deriv/Resets/PredictLinear/
DoubleExpSmoothing; requires()=TimeSeries, is_per_series()=true,
output_column() named after the function (float64).
- L2 `AggFunc`: mirror variants (window rides on the L2 Window node, like
*_over_time, so — unlike Rate/Increase — they don't carry it).
- Converter `agg_func_to_intent`: map each, threading scalar params.
- PromQL front end: `InnerFunc` variants + `lower_inner_call` arms
(`predict_linear` reads arg1; `double_exponential_smoothing`/
`holt_winters` read args 1-2).
Tests:
- promql_conformance.rs section M — distinct intents, predict_linear
horizon, double_exp/holt_winters alias equivalence, label preservation
under an outer `sum by`.
- awesome_prometheus_alerts.rs — 3 __GAP tests flipped to positive
(function body lowers; the full `... > N` alert still needs #35).
- promql_equivalence.rs — changes/resets upgraded from rejected to
pairwise-distinct vs count_over_time.
- promql_conformance.rs — dropped the 5 now-supported entries from
unsupported_functions_are_rejected.
Full workspace suite green; clippy --all-targets clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cs (#44) Pin how the new counter-derivative intents compose with the rest of the lowering — they are per-series/label-preserving, so they reuse the general nesting path with no special-casing: - outer cross-series stat over a derivative nests two levels and threads the outer group key + any scalar param (`avg by (dc)(predict_linear(...))`) - `topk(k, deriv(...))` is generic Sort+Limit, not a heavy-hitter TopK - as a binary-op operand and under `sum(rate(...) + changes(...))` - counter-derivative over a sub-query stays cleanly rejected (a #42 follow-up) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
What & why
Closes #44.
changes,delta,idelta,deriv,resets,predict_linear, anddouble_exponential_smoothing(a.k.a.holt_winters) parsed but were rejected (UnsupportedFunction). They now lower to distinct per-series intents.This was the second-largest un-tracked lowering gap — 108 corpus rejections (5.6%), high real-alert value (host/disk/restart rules). Three of them (
changes/delta/predict_linear) had orphaned__GAPpin-tests and no implementation.How
Each function is a per-series, label-preserving reduction of one series' range window to one value, riding on the enclosing
TimeRange:Deliberately not aliased to
rate/increase/count:changes(value-change count) andresets(counter-reset count) are not sample counts;delta/idelta/derivare gauge derivatives. Scalar params are carried in the intent —predict_linearits horizon (seconds),double_exponential_smoothingits two smoothing factors;holt_winterslowers to the same intent.Full pipeline:
AggIntent— newChanges/Delta/IDelta/Deriv/Resets/PredictLinear{seconds}/DoubleExpSmoothing{smoothing,trend};requires()=TimeSeries,is_per_series()=true,output_column()named after the function (float64).AggFunc— mirror variants. The window rides on the L2Windownode (like*_over_time), so — unlikeRate/Increase— these don't carry it.agg_func_to_intent— maps each, threading scalar params.InnerFuncvariants +lower_inner_callarms (predict_linearreads arg 1;double_exponential_smoothing/holt_wintersread args 1–2).Tests
promql_conformance.rssection M — distinct intents per function,predict_linearhorizon carried,double_exp/holt_wintersalias equivalence, label preservation under an outersum by (job).awesome_prometheus_alerts.rs— the 3__GAPtests flipped to positive (function body lowers; the full... > Nalert still needs the scalar operand, QueryExpr::BinaryOp has no scalar/literal operand — vector-op-scalar PromQL rejected #35).promql_equivalence.rs—changes/resetsupgraded from rejected to pairwise-distinct vscount_over_time.promql_conformance.rs— dropped the 5 now-supported entries fromunsupported_functions_are_rejected.Full workspace suite green;
cargo clippy --all-targetsclean.Notes
Branches off latest
main(includes #42). The full real-world alerts (changes(...) > 2etc.) still gate on the scalar-threshold operand (#35) — the function bodies underneath now lower fine.🤖 Generated with Claude Code