Skip to content

feat(lower): counter-derivative range functions (#44) - #54

Merged
zzylol merged 2 commits into
mainfrom
feat/counter-derivative-fns
Jul 2, 2026
Merged

feat(lower): counter-derivative range functions (#44)#54
zzylol merged 2 commits into
mainfrom
feat/counter-derivative-fns

Conversation

@zzylol

@zzylol zzylol commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What & why

Closes #44. 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.

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 __GAP pin-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:

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 not sample counts; delta/idelta/deriv are gauge derivatives. Scalar params are carried in the intent — predict_linear its horizon (seconds), double_exponential_smoothing its two smoothing factors; holt_winters lowers to the same intent.

Full pipeline:

  • L3 AggIntent — new Changes/Delta/IDelta/Deriv/Resets/PredictLinear{seconds}/DoubleExpSmoothing{smoothing,trend}; requires()=TimeSeries, is_per_series()=true, output_column() named after the function (float64).
  • L2 AggFunc — mirror variants. The window rides on the L2 Window node (like *_over_time), so — unlike Rate/Increase — these don't carry it.
  • Converter agg_func_to_intent — maps each, threading scalar params.
  • PromQL front endInnerFunc variants + lower_inner_call arms (predict_linear reads arg 1; double_exponential_smoothing/holt_winters read args 1–2).

Tests

  • promql_conformance.rs section M — distinct intents per function, predict_linear horizon carried, double_exp/holt_winters alias equivalence, label preservation under an outer sum by (job).
  • awesome_prometheus_alerts.rs — the 3 __GAP tests flipped to positive (function body lowers; the full ... > N alert still needs the scalar operand, QueryExpr::BinaryOp has no scalar/literal operand — vector-op-scalar PromQL rejected #35).
  • promql_equivalence.rschanges/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; cargo clippy --all-targets clean.

Notes

Branches off latest main (includes #42). The full real-world alerts (changes(...) > 2 etc.) still gate on the scalar-threshold operand (#35) — the function bodies underneath now lower fine.

🤖 Generated with Claude Code

zz_y and others added 2 commits July 2, 2026 08:57
`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>
@zzylol
zzylol merged commit d8e418f into main Jul 2, 2026
1 check passed
@zzylol
zzylol deleted the feat/counter-derivative-fns branch July 2, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PromQL: counter-derivative range functions (changes/delta/deriv/resets/predict_linear/idelta) unsupported

1 participant