Time-Series Transforms

observability counters and gauges store only the current value — nothing turned a counter into a per-second rate — and cost_telemetry only buckets by a fixed day. This adds Prometheus-style rate / irate / increase / delta (reset-aware) plus tumbling-bucket downsample and grid resample over (timestamp, value) sequences.

Pure standard library (bisect); imports no PySide6. No wall clock is read — windows use the series’ own timestamps — so every function is fully deterministic in CI.

Headless API

from je_auto_control import ts_rate, ts_increase, ts_downsample, ts_resample

series = [(0, 0), (10, 50), (20, 120)]      # (timestamp_s, counter_value)
ts_rate(series)                              # 6.0  (120 over 20s)
ts_rate(series, window_s=10)                 # rate over the last 10s only
ts_increase(series)                          # 120.0 (reset-aware)

ts_downsample([(0, 1), (3, 3), (5, 10)], 5, "avg")   # [(0, 2.0), (5, 10.0)]
ts_resample([(0, 0), (20, 20)], 10, fill="linear")   # [(0,0),(10,10),(20,20)]

ts_rate / ts_increase treat a value drop as a counter reset (Prometheus semantics); ts_irate is the instant rate from the last two samples; ts_delta / ts_idelta are gauge first-to-last and last-two differences. ts_downsample rolls the series into bucket_s tumbling buckets aggregated by avg / sum / min / max / first / last / count. ts_resample aligns to a fixed grid, filling with "last" (carry forward), "linear" (interpolate), or None (gaps).

Executor commands

AC_ts_rate returns {rate} for a series (optional window_s); AC_ts_downsample returns {buckets} for a series and bucket_s (optional agg). Both are exposed as MCP tools (ac_ts_rate / ac_ts_downsample) and as Script Builder commands under Data.