A ticketing website counts sign-in attempts every minute. A sudden burst can mean a bot is guessing passwords. A sudden drop can mean the sign-in page is broken.
The count drifts up and down through the day, so one fixed fence would ring at every busy hour and sleep through a quiet one, the problem from Anomalies in Time Series. Instead, each minute is judged against the minutes just before it:
window counts just before it: readings[i - window] up to and including readings[i - 1]. Minute is not part of its own baseline.window), is the yardstick.threshold. Surprises count in both directions.The first window minutes have no full baseline, so they are never scored or flagged.
Task: write rolling_z_alerts(readings, window, threshold) returning a list of (i, z) tuples, one per flagged minute, in time order, with z rounded to 4 decimal places. You may assume no baseline has a standard deviation of 0.