Script icon
UploadFiles icon
If icon
Fail icon
Log icon
Schedule icon

Detect lasting KPI shifts and name the release that caused them

Find lasting KPI level shifts with ruptures in Kestra, ignore promo spikes and weekly patterns, and name the release deployed just before each shift.

Categories
BusinessData

Threshold alerts on a business KPI fire every Saturday and every campaign, and stay silent when a release quietly cuts Android orders by 40%, because the total moves less than the noise. A changepoint is a different question: did the level of this series move and stay moved? This flow answers it per segment and adds the context people ask for first: which release went out just before?

  1. The weekly pattern is divided out per segment, so a busy Saturday is not a shift.
  2. ruptures (PELT) finds level shifts with a minimum segment length, so a two-day promotion is not a shift either.
  3. Shifts smaller than min_shift_pct are ignored.
  4. Each shift is matched to the closest release from 3 days before to 1 day after the detected date.

It needs no secrets. The demo has 90 days of daily orders for web, iOS and Android, and a release calendar.

How it works

  1. detect (io.kestra.plugin.scripts.python.Script, ruptures==1.1.10) deseasonalizes each segment, runs PELT, keeps lasting shifts, attributes releases and writes changepoints.md.
  2. publish_report (io.kestra.plugin.core.namespace.UploadFiles) keeps one report per day under kpi/.
  3. alert_gate (io.kestra.plugin.core.flow.If) fails the run when a shift started within recent_days, so the usual failure alerts reach the team. Older shifts stay in the report only.
  4. daily (io.kestra.plugin.core.trigger.Schedule).

Quick start

scenario Result
TRACKING_BREAK (default) Failed: android -38.9% from 2026-09-16 (2,465 to 1,506 orders a day, held 20 days), attributed to v2.16 Android analytics SDK upgrade on 2026-09-17. Web and iOS unchanged
PROMO_SPIKE No shift: the two-day +90% web campaign is shorter than min_segment_days
STABLE No shift
TRACKING_BREAK, recent_days: 7 No alert, the shift is in the report as older

The detected date is one day before the real change on Sep 17. Changepoint estimates are often off by a day, which is why release matching looks one day after as well.

Using it with your KPIs

  • Replace the generator with a query returning one value per day and segment.
  • Replace the release calendar with your deploy history, for example GitHub releases or the executions of your deploy flow.
  • Tune min_shift_pct and min_segment_days to how noisy the KPI is. Watch the report for a few weeks before turning on the alert.

Inputs

  • scenario (SELECT, demo only), min_shift_pct (FLOAT, default 15.0), min_segment_days (INT, default 5), recent_days (INT, default 21).

Expected outputs

  • outputs.detect.vars: shifts, alerts, detail.
  • Namespace file kpi/changepoints-<date>.md.

Links

This blueprint was created by zkasuran.

See How

New to Kestra?

Use blueprints to kickstart your first workflows.