Behnam Analytics

Writing Analytics engineering

Anomaly detection for data feeds

Catching a broken daily feed before the dashboard does, with day-of-week baselines, robust z-scores, STL residuals, a slow-drift check, freshness and schema checks, and thresholds that don't bury you in alerts.

Behnam Ebrahimi 10 min read

A broken feed rarely fails loudly. The load job succeeds, the row count looks plausible, and a dip appears on a dashboard that someone then explains in a meeting. Most breaks can be caught the morning after, before anyone sees them, if each day is compared with the right baseline and the checks know about bank holidays. A few problems never show up in a row count at all, and those need different checks.

This article tests six checks on a synthetic daily feed with problems planted in it, and counts what each one caught and how often it cried wolf.

The feed and what’s planted

The feed is the number of outpatient appointment records that arrive in a warehouse for each appointment date, from July 2024 to July 2026. It’s generated by feed_anomalies.py with a fixed seed. A normal weekday brings about 2,330 records and a Sunday about 40. There are a few Saturday clinics, bank holidays run at Sunday level, Christmas week and August are quieter, and volume grows 3% a year.

Planted in it:

Date Problem Effect on the day’s rows
Tue 19 Nov 2024 Partial load, one site’s file missing 58%
Tue 11 Feb 2025 Failed load 0%
Mon 17 Mar 2025 Day loaded twice 200%
Thu 5 Jun 2025 Partial load, late file 72%
Mon 8 Sep 2025 Partial re-send 115%
Sat 15 Nov 2025 Saturday loaded twice 200%
Wed 21 Jan 2026 Partial load, one clinic missing 80%
From 2 Mar 2026 Slow drift: a new clinic code isn’t in the mapping table, so its growing share of records is dropped falls to 88% by 10 May

The load log has two more: a load that finished at 11:20 instead of before 07:00, and a column renamed at source for two days.

Every check below runs as it would in production: each morning, using only data that existed then. I scored the 669 days from October 2024, once every check had enough history.

Volume against a day-of-week baseline

A Monday should be compared with other Mondays. The simplest check compares each day’s rows with the median of the same weekday over the previous eight weeks, and flags anything more than 25% out. The median matters: one doubled Monday in the history doesn’t move it.

With a calendar of bank holidays and Christmas week applied (more on that below), this check caught five of the seven one-day incidents. It missed the 15% re-send and the one-clinic partial load, which lost 20%. Both sat inside the ±25% band.

It also raised 14 false alerts, and every one was on a Sunday. A Sunday brings about 40 records, and ordinary random variation on a count that small is easily 25%. A fixed percentage band is too tight for small counts and too loose for big ones.

Robust z-scores with the MAD

A z-score measures how unusual a day is in units of the history’s own spread. The ordinary version uses the mean and standard deviation, which is a problem here: a single failed load in the history inflates the standard deviation and hides the next one. The robust version swaps in the median and the median absolute deviation (MAD):

def robust_z(value: float, reference: np.ndarray) -> float:
    """(x - median) / (1.4826 * MAD): a z-score that outliers in the history can't inflate."""
    med = np.median(reference)
    mad = 1.4826 * np.median(np.abs(reference - med))
    return float((value - med) / mad) if mad > 0 else 0.0

The 1.4826 rescales the MAD so that, for normally distributed data, it estimates the standard deviation. This is the same idea as the modified z-score that the NIST handbook describes, where Iglewicz and Hoaglin recommend treating an absolute value above 3.5 as a potential outlier. I used 3.5 too.

Scoring each day against the same weekday over the previous 12 weeks caught six of the seven, including the one-clinic partial load (z = −3.9). It raised 13 false alerts: only two on Sundays now, because each weekday is judged against its own spread, but some in August, when the seasonal dip arrives faster than a 12-week baseline can follow.

STL residuals

STL (seasonal and trend decomposition using LOESS) splits a series into a trend, a repeating seasonal pattern and a remainder. statsmodels implements it as statsmodels.tsa.seasonal.STL, and robust=True uses a weighted fit that is less swayed by outliers.

For monitoring, I fitted STL to the previous 84 days, projected today from the last trend value plus the seasonal value for the same weekday, and scored today’s miss against the misses of the previous 84 days:

seen = np.sqrt(history(feed, calendar))
miss = np.full(len(seen), np.nan)
for t in range(STL_DAYS, len(seen)):
    if not np.isnan(seen[t]):
        fit = STL(fill_by_weekday(seen[t - STL_DAYS : t]), period=7, robust=True).fit()
        miss[t] = seen[t] - (fit.trend[-1] + fit.seasonal[-7])

Two details matter. The square root puts a Sunday of 40 and a Monday of 2,400 on similar noise scales, so one threshold works for both. And today is kept out of the fit: if you decompose a window that ends with today and read today’s remainder, the trend and seasonal components can bend towards today’s value, because the end of a series is where LOESS has data on only one side.

This check caught the same six incidents with two false alerts in 22 months. It wins here for two reasons: its noise estimate uses 84 daily misses rather than 12 values per weekday, and its trend follows the August dip instead of flagging it.

Daily appointment records loaded, and the days each check flaggedCalendar applied; zoom in to see individual days
Data table
Weekday ratio ±25%
Appointment dateRecords loadedFlaggedPlanted one-day problem
2024-10-012,475
2024-10-022,422
2024-10-032,364
2024-10-041,900
2024-10-05179
2024-10-0644
2024-10-072,324
2024-10-082,394
2024-10-092,388
2024-10-102,391
2024-10-112,079
2024-10-12168
2024-10-132525
2024-10-142,396
2024-10-152,243
2024-10-162,304
2024-10-172,163
2024-10-182,009
2024-10-19150
2024-10-205050
2024-10-212,466
2024-10-222,231
2024-10-232,261
2024-10-242,204
2024-10-251,986
2024-10-26170
2024-10-2736
2024-10-282,463
2024-10-292,583
2024-10-302,290
2024-10-312,232
2024-11-011,780
2024-11-02175
2024-11-0344
2024-11-042,474
2024-11-052,504
2024-11-062,470
2024-11-072,351
2024-11-082,034
2024-11-09171
2024-11-1040
2024-11-112,440
2024-11-122,344
2024-11-132,247
2024-11-142,255
2024-11-151,925
2024-11-16156
2024-11-1741
2024-11-182,478
2024-11-191,2811,2811,281
2024-11-202,370
2024-11-212,251
2024-11-222,027
2024-11-23193
2024-11-2449
2024-11-252,519
2024-11-262,459
2024-11-272,229
2024-11-282,207
2024-11-291,804
2024-11-30162
2024-12-0146
2024-12-022,406
2024-12-032,383
2024-12-042,417
2024-12-052,289
2024-12-061,940
2024-12-07194
2024-12-0834
2024-12-092,477
2024-12-102,375
2024-12-112,223
2024-12-122,315
2024-12-131,923
2024-12-14188
2024-12-1535
2024-12-162,366
2024-12-172,338
2024-12-182,271
2024-12-192,210
2024-12-201,900
2024-12-21170
2024-12-2239
2024-12-232,533
2024-12-241,298
2024-12-2531
2024-12-2646
2024-12-271,063
2024-12-2890
2024-12-2923
2024-12-301,400
2024-12-311,330
2025-01-0139
2025-01-021,247
2025-01-031,930
2025-01-04210
2025-01-0544
2025-01-062,531
2025-01-072,383
2025-01-082,348
2025-01-092,370
2025-01-101,969
2025-01-11187
2025-01-1244
2025-01-132,577
2025-01-142,432
2025-01-152,243
2025-01-162,187
2025-01-171,928
2025-01-18177
2025-01-1950
2025-01-202,232
2025-01-212,353
2025-01-222,247
2025-01-232,243
2025-01-242,091
2025-01-25152
2025-01-2641
2025-01-272,355
2025-01-282,369
2025-01-292,296
2025-01-302,326
2025-01-311,934
2025-02-01179
2025-02-022626
2025-02-032,360
2025-02-042,425
2025-02-052,342
2025-02-062,395
2025-02-071,943
2025-02-08161
2025-02-093030
2025-02-102,403
2025-02-11000
2025-02-122,411
2025-02-132,311
2025-02-141,976
2025-02-15171
2025-02-1636
2025-02-172,567
2025-02-182,516
2025-02-192,366
2025-02-202,240
2025-02-212,024
2025-02-22207
2025-02-232424
2025-02-242,429
2025-02-252,362
2025-02-262,415
2025-02-272,303
2025-02-281,888
2025-03-01149
2025-03-0239
2025-03-032,450
2025-03-042,438
2025-03-052,408
2025-03-062,367
2025-03-071,912
2025-03-08202
2025-03-094949
2025-03-102,486
2025-03-112,587
2025-03-122,247
2025-03-132,297
2025-03-141,889
2025-03-15182
2025-03-165252
2025-03-175,0325,0325,032
2025-03-182,466
2025-03-192,261
2025-03-202,199
2025-03-212,011
2025-03-22199
2025-03-2338
2025-03-242,600
2025-03-252,294
2025-03-262,252
2025-03-272,252
2025-03-281,930
2025-03-29169
2025-03-3041
2025-03-312,478
2025-04-012,411
2025-04-022,336
2025-04-032,236
2025-04-042,009
2025-04-05194
2025-04-0637
2025-04-072,462
2025-04-082,240
2025-04-092,345
2025-04-102,202
2025-04-111,987
2025-04-12169
2025-04-1343
2025-04-142,465
2025-04-152,548
2025-04-162,299
2025-04-172,285
2025-04-1840
2025-04-19149
2025-04-202929
2025-04-2144
2025-04-222,392
2025-04-232,254
2025-04-242,198
2025-04-251,867
2025-04-26172
2025-04-2736
2025-04-282,382
2025-04-292,548
2025-04-302,525
2025-05-012,345
2025-05-021,920
2025-05-03187
2025-05-0437
2025-05-0538
2025-05-062,509
2025-05-072,436
2025-05-082,420
2025-05-091,846
2025-05-10209
2025-05-1138
2025-05-122,532
2025-05-132,420
2025-05-142,287
2025-05-152,353
2025-05-162,035
2025-05-17183
2025-05-1838
2025-05-192,584
2025-05-202,378
2025-05-212,404
2025-05-222,313
2025-05-231,899
2025-05-24176
2025-05-2540
2025-05-2652
2025-05-272,538
2025-05-282,224
2025-05-292,293
2025-05-301,929
2025-05-31169
2025-06-0146
2025-06-022,317
2025-06-032,513
2025-06-042,376
2025-06-051,6431,6431,643
2025-06-061,926
2025-06-07197
2025-06-085353
2025-06-092,415
2025-06-102,238
2025-06-112,356
2025-06-122,400
2025-06-132,051
2025-06-14189
2025-06-1546
2025-06-162,474
2025-06-172,375
2025-06-182,450
2025-06-192,385
2025-06-201,798
2025-06-21178
2025-06-2237
2025-06-232,430
2025-06-242,566
2025-06-252,341
2025-06-262,254
2025-06-271,989
2025-06-28184
2025-06-2947
2025-06-302,429
2025-07-012,271
2025-07-022,519
2025-07-032,290
2025-07-041,948
2025-07-05186
2025-07-0647
2025-07-072,435
2025-07-082,344
2025-07-092,389
2025-07-102,204
2025-07-111,908
2025-07-12171
2025-07-1339
2025-07-142,567
2025-07-152,381
2025-07-162,394
2025-07-172,319
2025-07-182,024
2025-07-19219
2025-07-2039
2025-07-212,481
2025-07-222,486
2025-07-232,283
2025-07-242,507
2025-07-252,115
2025-07-26203
2025-07-2743
2025-07-282,541
2025-07-292,348
2025-07-302,385
2025-07-312,316
2025-08-011,900
2025-08-02170
2025-08-0344
2025-08-042,139
2025-08-052,314
2025-08-062,052
2025-08-072,127
2025-08-081,826
2025-08-09169
2025-08-103030
2025-08-112,328
2025-08-122,092
2025-08-132,046
2025-08-142,022
2025-08-151,855
2025-08-16157
2025-08-1732
2025-08-182,262
2025-08-192,162
2025-08-202,135
2025-08-212,030
2025-08-221,826
2025-08-23178
2025-08-2440
2025-08-2528
2025-08-262,245
2025-08-272,189
2025-08-282,042
2025-08-291,737
2025-08-30174
2025-08-312727
2025-09-012,586
2025-09-022,535
2025-09-032,528
2025-09-042,391
2025-09-051,849
2025-09-06182
2025-09-075050
2025-09-082,8242,824
2025-09-092,353
2025-09-102,484
2025-09-112,323
2025-09-122,166
2025-09-13198
2025-09-1438
2025-09-152,522
2025-09-162,472
2025-09-172,298
2025-09-182,381
2025-09-191,892
2025-09-20205
2025-09-2130
2025-09-222,413
2025-09-232,366
2025-09-242,370
2025-09-252,295
2025-09-261,974
2025-09-27176
2025-09-2843
2025-09-292,378
2025-09-302,392
2025-10-012,466
2025-10-022,311
2025-10-031,984
2025-10-04184
2025-10-0540
2025-10-062,508
2025-10-072,519
2025-10-082,403
2025-10-092,395
2025-10-101,976
2025-10-11186
2025-10-1239
2025-10-132,376
2025-10-142,473
2025-10-152,333
2025-10-162,292
2025-10-172,083
2025-10-18177
2025-10-1943
2025-10-202,536
2025-10-212,555
2025-10-222,303
2025-10-232,355
2025-10-242,029
2025-10-25193
2025-10-2648
2025-10-272,459
2025-10-282,382
2025-10-292,287
2025-10-302,353
2025-10-311,965
2025-11-01175
2025-11-0240
2025-11-032,495
2025-11-042,556
2025-11-052,304
2025-11-062,433
2025-11-071,937
2025-11-08173
2025-11-0937
2025-11-102,561
2025-11-112,475
2025-11-122,319
2025-11-132,306
2025-11-141,953
2025-11-15350350350
2025-11-1646
2025-11-172,478
2025-11-182,405
2025-11-192,348
2025-11-202,580
2025-11-212,029
2025-11-22198
2025-11-2333
2025-11-242,538
2025-11-252,478
2025-11-262,289
2025-11-272,427
2025-11-282,031
2025-11-29183
2025-11-3046
2025-12-012,468
2025-12-022,622
2025-12-032,252
2025-12-042,371
2025-12-052,067
2025-12-06186
2025-12-0746
2025-12-082,475
2025-12-092,390
2025-12-102,460
2025-12-112,419
2025-12-122,014
2025-12-13213
2025-12-1443
2025-12-152,425
2025-12-162,592
2025-12-172,488
2025-12-182,299
2025-12-191,886
2025-12-20178
2025-12-2146
2025-12-222,496
2025-12-232,418
2025-12-241,323
2025-12-2534
2025-12-2638
2025-12-2798
2025-12-2822
2025-12-291,265
2025-12-301,365
2025-12-311,302
2026-01-0132
2026-01-021,112
2026-01-03178
2026-01-0440
2026-01-052,498
2026-01-062,401
2026-01-072,442
2026-01-082,411
2026-01-091,961
2026-01-10185
2026-01-1151
2026-01-122,542
2026-01-132,430
2026-01-142,477
2026-01-152,234
2026-01-162,037
2026-01-17164
2026-01-183333
2026-01-192,447
2026-01-202,446
2026-01-211,9591,959
2026-01-222,433
2026-01-231,970
2026-01-24180
2026-01-2545
2026-01-262,573
2026-01-272,446
2026-01-282,347
2026-01-292,380
2026-01-302,024
2026-01-31164
2026-02-0142
2026-02-022,566
2026-02-032,470
2026-02-042,455
2026-02-052,353
2026-02-061,983
2026-02-07175
2026-02-083030
2026-02-092,676
2026-02-102,499
2026-02-112,345
2026-02-122,300
2026-02-131,950
2026-02-14195
2026-02-1550
2026-02-162,544
2026-02-172,536
2026-02-182,520
2026-02-192,258
2026-02-201,979
2026-02-21179
2026-02-2237
2026-02-232,479
2026-02-242,562
2026-02-252,317
2026-02-262,140
2026-02-272,047
2026-02-28186
2026-03-0140
2026-03-022,430
2026-03-032,456
2026-03-042,378
2026-03-052,384
2026-03-062,030
2026-03-07179
2026-03-0847
2026-03-092,568
2026-03-102,360
2026-03-112,400
2026-03-122,342
2026-03-132,012
2026-03-14179
2026-03-1544
2026-03-162,494
2026-03-172,450
2026-03-182,283
2026-03-192,447
2026-03-202,070
2026-03-21185
2026-03-2240
2026-03-232,388
2026-03-242,396
2026-03-252,416
2026-03-262,149
2026-03-271,916
2026-03-28191
2026-03-2937
2026-03-302,477
2026-03-312,335
2026-04-012,325
2026-04-022,216
2026-04-0331
2026-04-04167
2026-04-0540
2026-04-0645
2026-04-072,210
2026-04-082,271
2026-04-092,214
2026-04-101,718
2026-04-11164
2026-04-1238
2026-04-132,189
2026-04-142,225
2026-04-152,287
2026-04-162,167
2026-04-171,936
2026-04-18186
2026-04-1934
2026-04-202,344
2026-04-212,242
2026-04-222,197
2026-04-232,224
2026-04-241,805
2026-04-25159
2026-04-2648
2026-04-272,235
2026-04-282,137
2026-04-292,133
2026-04-302,024
2026-05-011,757
2026-05-02155
2026-05-032929
2026-05-0432
2026-05-052,097
2026-05-062,217
2026-05-072,117
2026-05-081,772
2026-05-09178
2026-05-1036
2026-05-112,110
2026-05-122,143
2026-05-132,157
2026-05-142,166
2026-05-151,785
2026-05-16165
2026-05-1735
2026-05-182,182
2026-05-192,117
2026-05-202,151
2026-05-212,167
2026-05-221,720
2026-05-23180
2026-05-2436
2026-05-2548
2026-05-262,336
2026-05-272,167
2026-05-282,044
2026-05-291,726
2026-05-30184
2026-05-3143
2026-06-012,178
2026-06-022,118
2026-06-032,289
2026-06-042,094
2026-06-051,768
2026-06-06179
2026-06-072525
2026-06-082,243
2026-06-092,111
2026-06-102,095
2026-06-112,158
2026-06-121,882
2026-06-13146
2026-06-144747
2026-06-152,328
2026-06-162,077
2026-06-172,130
2026-06-182,103
2026-06-191,730
2026-06-20154
2026-06-2140
2026-06-222,258
2026-06-232,152
2026-06-241,962
2026-06-252,047
2026-06-261,801
2026-06-27162
2026-06-2833
2026-06-292,243
2026-06-302,183
2026-07-012,068
2026-07-022,208
2026-07-031,734
2026-07-04181
2026-07-0535
2026-07-062,292
2026-07-072,195
2026-07-082,101
2026-07-092,158
2026-07-101,722
2026-07-11158
2026-07-124545
2026-07-132,186
2026-07-142,036
2026-07-152,043
2026-07-162,056
2026-07-171,836
2026-07-18144
2026-07-1941
2026-07-202,161
2026-07-212,303
2026-07-222,231
2026-07-232,167
2026-07-241,717
2026-07-25155
2026-07-262626
2026-07-272,299
2026-07-282,004
2026-07-292,033
2026-07-302,030
2026-07-311,830
Weekday robust z
Appointment dateRecords loadedFlaggedPlanted one-day problem
2024-10-012,475
2024-10-022,422
2024-10-032,364
2024-10-041,900
2024-10-05179
2024-10-0644
2024-10-072,324
2024-10-082,394
2024-10-092,388
2024-10-102,391
2024-10-112,079
2024-10-12168
2024-10-1325
2024-10-142,396
2024-10-152,243
2024-10-162,304
2024-10-172,163
2024-10-182,009
2024-10-19150
2024-10-2050
2024-10-212,466
2024-10-222,231
2024-10-232,261
2024-10-242,204
2024-10-251,986
2024-10-26170
2024-10-2736
2024-10-282,463
2024-10-292,583
2024-10-302,290
2024-10-312,232
2024-11-011,780
2024-11-02175
2024-11-0344
2024-11-042,474
2024-11-052,504
2024-11-062,470
2024-11-072,351
2024-11-082,034
2024-11-09171
2024-11-1040
2024-11-112,440
2024-11-122,344
2024-11-132,247
2024-11-142,255
2024-11-151,925
2024-11-16156
2024-11-1741
2024-11-182,478
2024-11-191,2811,2811,281
2024-11-202,370
2024-11-212,251
2024-11-222,027
2024-11-23193
2024-11-2449
2024-11-252,519
2024-11-262,459
2024-11-272,229
2024-11-282,207
2024-11-291,804
2024-11-30162
2024-12-0146
2024-12-022,406
2024-12-032,383
2024-12-042,417
2024-12-052,289
2024-12-061,940
2024-12-07194
2024-12-0834
2024-12-092,477
2024-12-102,375
2024-12-112,223
2024-12-122,315
2024-12-131,923
2024-12-14188
2024-12-1535
2024-12-162,366
2024-12-172,338
2024-12-182,271
2024-12-192,210
2024-12-201,900
2024-12-21170
2024-12-2239
2024-12-232,533
2024-12-241,298
2024-12-2531
2024-12-2646
2024-12-271,063
2024-12-2890
2024-12-2923
2024-12-301,400
2024-12-311,330
2025-01-0139
2025-01-021,247
2025-01-031,930
2025-01-04210
2025-01-0544
2025-01-062,531
2025-01-072,383
2025-01-082,348
2025-01-092,370
2025-01-101,969
2025-01-11187
2025-01-1244
2025-01-132,577
2025-01-142,432
2025-01-152,243
2025-01-162,187
2025-01-171,928
2025-01-18177
2025-01-1950
2025-01-202,2322,232
2025-01-212,353
2025-01-222,247
2025-01-232,243
2025-01-242,0912,091
2025-01-25152
2025-01-2641
2025-01-272,355
2025-01-282,369
2025-01-292,296
2025-01-302,326
2025-01-311,934
2025-02-01179
2025-02-0226
2025-02-032,360
2025-02-042,425
2025-02-052,342
2025-02-062,395
2025-02-071,943
2025-02-08161
2025-02-0930
2025-02-102,403
2025-02-11000
2025-02-122,411
2025-02-132,311
2025-02-141,976
2025-02-15171
2025-02-1636
2025-02-172,567
2025-02-182,516
2025-02-192,366
2025-02-202,240
2025-02-212,0242,024
2025-02-22207
2025-02-2324
2025-02-242,429
2025-02-252,362
2025-02-262,415
2025-02-272,303
2025-02-281,888
2025-03-01149
2025-03-0239
2025-03-032,450
2025-03-042,438
2025-03-052,408
2025-03-062,367
2025-03-071,912
2025-03-08202
2025-03-0949
2025-03-102,486
2025-03-112,587
2025-03-122,247
2025-03-132,297
2025-03-141,889
2025-03-15182
2025-03-1652
2025-03-175,0325,0325,032
2025-03-182,466
2025-03-192,261
2025-03-202,199
2025-03-212,011
2025-03-22199
2025-03-2338
2025-03-242,600
2025-03-252,294
2025-03-262,252
2025-03-272,252
2025-03-281,930
2025-03-29169
2025-03-3041
2025-03-312,478
2025-04-012,411
2025-04-022,336
2025-04-032,236
2025-04-042,009
2025-04-05194
2025-04-0637
2025-04-072,462
2025-04-082,240
2025-04-092,345
2025-04-102,202
2025-04-111,987
2025-04-12169
2025-04-1343
2025-04-142,465
2025-04-152,548
2025-04-162,299
2025-04-172,285
2025-04-1840
2025-04-19149
2025-04-2029
2025-04-2144
2025-04-222,392
2025-04-232,254
2025-04-242,198
2025-04-251,867
2025-04-26172
2025-04-2736
2025-04-282,382
2025-04-292,548
2025-04-302,525
2025-05-012,345
2025-05-021,920
2025-05-03187
2025-05-0437
2025-05-0538
2025-05-062,509
2025-05-072,436
2025-05-082,420
2025-05-091,846
2025-05-10209
2025-05-1138
2025-05-122,532
2025-05-132,420
2025-05-142,287
2025-05-152,353
2025-05-162,035
2025-05-17183
2025-05-1838
2025-05-192,584
2025-05-202,378
2025-05-212,404
2025-05-222,313
2025-05-231,899
2025-05-24176
2025-05-2540
2025-05-2652
2025-05-272,538
2025-05-282,224
2025-05-292,293
2025-05-301,929
2025-05-31169
2025-06-0146
2025-06-022,317
2025-06-032,513
2025-06-042,376
2025-06-051,6431,6431,643
2025-06-061,926
2025-06-07197
2025-06-085353
2025-06-092,415
2025-06-102,238
2025-06-112,356
2025-06-122,400
2025-06-132,051
2025-06-14189
2025-06-1546
2025-06-162,474
2025-06-172,375
2025-06-182,450
2025-06-192,385
2025-06-201,798
2025-06-21178
2025-06-2237
2025-06-232,430
2025-06-242,566
2025-06-252,341
2025-06-262,254
2025-06-271,989
2025-06-28184
2025-06-2947
2025-06-302,429
2025-07-012,271
2025-07-022,519
2025-07-032,290
2025-07-041,948
2025-07-05186
2025-07-0647
2025-07-072,435
2025-07-082,344
2025-07-092,389
2025-07-102,204
2025-07-111,908
2025-07-12171
2025-07-1339
2025-07-142,567
2025-07-152,381
2025-07-162,394
2025-07-172,319
2025-07-182,024
2025-07-19219219
2025-07-2039
2025-07-212,481
2025-07-222,486
2025-07-232,283
2025-07-242,507
2025-07-252,115
2025-07-26203
2025-07-2743
2025-07-282,541
2025-07-292,348
2025-07-302,385
2025-07-312,316
2025-08-011,900
2025-08-02170
2025-08-0344
2025-08-042,1392,139
2025-08-052,314
2025-08-062,0522,052
2025-08-072,127
2025-08-081,826
2025-08-09169
2025-08-1030
2025-08-112,328
2025-08-122,092
2025-08-132,0462,046
2025-08-142,022
2025-08-151,855
2025-08-16157
2025-08-1732
2025-08-182,262
2025-08-192,162
2025-08-202,135
2025-08-212,030
2025-08-221,826
2025-08-23178
2025-08-2440
2025-08-2528
2025-08-262,245
2025-08-272,189
2025-08-282,042
2025-08-291,737
2025-08-30174
2025-08-3127
2025-09-012,586
2025-09-022,535
2025-09-032,528
2025-09-042,391
2025-09-051,849
2025-09-06182
2025-09-0750
2025-09-082,8242,824
2025-09-092,353
2025-09-102,484
2025-09-112,323
2025-09-122,166
2025-09-13198
2025-09-1438
2025-09-152,522
2025-09-162,472
2025-09-172,298
2025-09-182,381
2025-09-191,892
2025-09-20205
2025-09-2130
2025-09-222,413
2025-09-232,366
2025-09-242,370
2025-09-252,295
2025-09-261,974
2025-09-27176
2025-09-2843
2025-09-292,378
2025-09-302,392
2025-10-012,466
2025-10-022,311
2025-10-031,984
2025-10-04184
2025-10-0540
2025-10-062,508
2025-10-072,519
2025-10-082,403
2025-10-092,395
2025-10-101,976
2025-10-11186
2025-10-1239
2025-10-132,376
2025-10-142,473
2025-10-152,333
2025-10-162,292
2025-10-172,083
2025-10-18177
2025-10-1943
2025-10-202,536
2025-10-212,555
2025-10-222,303
2025-10-232,355
2025-10-242,029
2025-10-25193
2025-10-2648
2025-10-272,459
2025-10-282,382
2025-10-292,287
2025-10-302,353
2025-10-311,965
2025-11-01175
2025-11-0240
2025-11-032,495
2025-11-042,556
2025-11-052,304
2025-11-062,433
2025-11-071,937
2025-11-08173
2025-11-0937
2025-11-102,561
2025-11-112,475
2025-11-122,319
2025-11-132,306
2025-11-141,953
2025-11-15350350350
2025-11-1646
2025-11-172,478
2025-11-182,405
2025-11-192,348
2025-11-202,5802,580
2025-11-212,029
2025-11-22198
2025-11-2333
2025-11-242,538
2025-11-252,478
2025-11-262,289
2025-11-272,427
2025-11-282,031
2025-11-29183
2025-11-3046
2025-12-012,468
2025-12-022,622
2025-12-032,252
2025-12-042,371
2025-12-052,067
2025-12-06186
2025-12-0746
2025-12-082,475
2025-12-092,390
2025-12-102,4602,460
2025-12-112,419
2025-12-122,014
2025-12-13213
2025-12-1443
2025-12-152,425
2025-12-162,592
2025-12-172,488
2025-12-182,299
2025-12-191,886
2025-12-20178
2025-12-2146
2025-12-222,496
2025-12-232,418
2025-12-241,323
2025-12-2534
2025-12-2638
2025-12-2798
2025-12-2822
2025-12-291,265
2025-12-301,365
2025-12-311,302
2026-01-0132
2026-01-021,112
2026-01-03178
2026-01-0440
2026-01-052,498
2026-01-062,401
2026-01-072,4422,442
2026-01-082,411
2026-01-091,961
2026-01-10185
2026-01-1151
2026-01-122,542
2026-01-132,430
2026-01-142,4772,477
2026-01-152,234
2026-01-162,037
2026-01-17164
2026-01-1833
2026-01-192,447
2026-01-202,446
2026-01-211,9591,9591,959
2026-01-222,433
2026-01-231,970
2026-01-24180
2026-01-2545
2026-01-262,573
2026-01-272,446
2026-01-282,347
2026-01-292,380
2026-01-302,024
2026-01-31164
2026-02-0142
2026-02-022,566
2026-02-032,470
2026-02-042,455
2026-02-052,353
2026-02-061,983
2026-02-07175
2026-02-083030
2026-02-092,676
2026-02-102,499
2026-02-112,345
2026-02-122,300
2026-02-131,950
2026-02-14195
2026-02-1550
2026-02-162,544
2026-02-172,536
2026-02-182,520
2026-02-192,258
2026-02-201,979
2026-02-21179
2026-02-2237
2026-02-232,479
2026-02-242,562
2026-02-252,317
2026-02-262,140
2026-02-272,047
2026-02-28186
2026-03-0140
2026-03-022,430
2026-03-032,456
2026-03-042,378
2026-03-052,384
2026-03-062,030
2026-03-07179
2026-03-0847
2026-03-092,568
2026-03-102,360
2026-03-112,400
2026-03-122,342
2026-03-132,012
2026-03-14179
2026-03-1544
2026-03-162,494
2026-03-172,450
2026-03-182,283
2026-03-192,447
2026-03-202,070
2026-03-21185
2026-03-2240
2026-03-232,388
2026-03-242,396
2026-03-252,416
2026-03-262,149
2026-03-271,916
2026-03-28191
2026-03-2937
2026-03-302,477
2026-03-312,335
2026-04-012,325
2026-04-022,216
2026-04-0331
2026-04-04167
2026-04-0540
2026-04-0645
2026-04-072,2102,210
2026-04-082,271
2026-04-092,214
2026-04-101,7181,718
2026-04-11164
2026-04-1238
2026-04-132,189
2026-04-142,225
2026-04-152,287
2026-04-162,167
2026-04-171,936
2026-04-18186
2026-04-1934
2026-04-202,344
2026-04-212,242
2026-04-222,197
2026-04-232,224
2026-04-241,805
2026-04-25159
2026-04-2648
2026-04-272,235
2026-04-282,137
2026-04-292,133
2026-04-302,024
2026-05-011,757
2026-05-02155
2026-05-0329
2026-05-0432
2026-05-052,097
2026-05-062,217
2026-05-072,117
2026-05-081,772
2026-05-09178
2026-05-1036
2026-05-112,110
2026-05-122,143
2026-05-132,157
2026-05-142,166
2026-05-151,785
2026-05-16165
2026-05-1735
2026-05-182,182
2026-05-192,117
2026-05-202,151
2026-05-212,167
2026-05-221,720
2026-05-23180
2026-05-2436
2026-05-2548
2026-05-262,336
2026-05-272,167
2026-05-282,044
2026-05-291,726
2026-05-30184
2026-05-3143
2026-06-012,178
2026-06-022,118
2026-06-032,289
2026-06-042,094
2026-06-051,768
2026-06-06179
2026-06-0725
2026-06-082,243
2026-06-092,111
2026-06-102,095
2026-06-112,158
2026-06-121,882
2026-06-13146
2026-06-1447
2026-06-152,328
2026-06-162,077
2026-06-172,130
2026-06-182,103
2026-06-191,730
2026-06-20154
2026-06-2140
2026-06-222,258
2026-06-232,152
2026-06-241,962
2026-06-252,047
2026-06-261,801
2026-06-27162
2026-06-2833
2026-06-292,243
2026-06-302,183
2026-07-012,068
2026-07-022,208
2026-07-031,734
2026-07-04181
2026-07-0535
2026-07-062,292
2026-07-072,195
2026-07-082,101
2026-07-092,158
2026-07-101,722
2026-07-11158
2026-07-1245
2026-07-132,186
2026-07-142,036
2026-07-152,043
2026-07-162,056
2026-07-171,836
2026-07-18144
2026-07-1941
2026-07-202,161
2026-07-212,3032,303
2026-07-222,231
2026-07-232,167
2026-07-241,717
2026-07-25155
2026-07-2626
2026-07-272,299
2026-07-282,004
2026-07-292,033
2026-07-302,030
2026-07-311,830
STL robust z
Appointment dateRecords loadedFlaggedPlanted one-day problem
2024-10-012,475
2024-10-022,422
2024-10-032,364
2024-10-041,900
2024-10-05179
2024-10-0644
2024-10-072,324
2024-10-082,394
2024-10-092,388
2024-10-102,391
2024-10-112,079
2024-10-12168
2024-10-1325
2024-10-142,396
2024-10-152,243
2024-10-162,304
2024-10-172,163
2024-10-182,009
2024-10-19150
2024-10-2050
2024-10-212,466
2024-10-222,231
2024-10-232,261
2024-10-242,204
2024-10-251,986
2024-10-26170
2024-10-2736
2024-10-282,463
2024-10-292,5832,583
2024-10-302,290
2024-10-312,232
2024-11-011,780
2024-11-02175
2024-11-0344
2024-11-042,474
2024-11-052,5042,504
2024-11-062,470
2024-11-072,351
2024-11-082,034
2024-11-09171
2024-11-1040
2024-11-112,440
2024-11-122,344
2024-11-132,247
2024-11-142,255
2024-11-151,925
2024-11-16156
2024-11-1741
2024-11-182,478
2024-11-191,2811,2811,281
2024-11-202,370
2024-11-212,251
2024-11-222,027
2024-11-23193
2024-11-2449
2024-11-252,519
2024-11-262,459
2024-11-272,229
2024-11-282,207
2024-11-291,804
2024-11-30162
2024-12-0146
2024-12-022,406
2024-12-032,383
2024-12-042,417
2024-12-052,289
2024-12-061,940
2024-12-07194
2024-12-0834
2024-12-092,477
2024-12-102,375
2024-12-112,223
2024-12-122,315
2024-12-131,923
2024-12-14188
2024-12-1535
2024-12-162,366
2024-12-172,338
2024-12-182,271
2024-12-192,210
2024-12-201,900
2024-12-21170
2024-12-2239
2024-12-232,533
2024-12-241,298
2024-12-2531
2024-12-2646
2024-12-271,063
2024-12-2890
2024-12-2923
2024-12-301,400
2024-12-311,330
2025-01-0139
2025-01-021,247
2025-01-031,930
2025-01-04210
2025-01-0544
2025-01-062,531
2025-01-072,383
2025-01-082,348
2025-01-092,370
2025-01-101,969
2025-01-11187
2025-01-1244
2025-01-132,577
2025-01-142,432
2025-01-152,243
2025-01-162,187
2025-01-171,928
2025-01-18177
2025-01-1950
2025-01-202,232
2025-01-212,353
2025-01-222,247
2025-01-232,243
2025-01-242,091
2025-01-25152
2025-01-2641
2025-01-272,355
2025-01-282,369
2025-01-292,296
2025-01-302,326
2025-01-311,934
2025-02-01179
2025-02-0226
2025-02-032,360
2025-02-042,425
2025-02-052,342
2025-02-062,395
2025-02-071,943
2025-02-08161
2025-02-0930
2025-02-102,403
2025-02-11000
2025-02-122,411
2025-02-132,311
2025-02-141,976
2025-02-15171
2025-02-1636
2025-02-172,567
2025-02-182,516
2025-02-192,366
2025-02-202,240
2025-02-212,024
2025-02-22207
2025-02-2324
2025-02-242,429
2025-02-252,362
2025-02-262,415
2025-02-272,303
2025-02-281,888
2025-03-01149
2025-03-0239
2025-03-032,450
2025-03-042,438
2025-03-052,408
2025-03-062,367
2025-03-071,912
2025-03-08202
2025-03-0949
2025-03-102,486
2025-03-112,587
2025-03-122,247
2025-03-132,297
2025-03-141,889
2025-03-15182
2025-03-1652
2025-03-175,0325,0325,032
2025-03-182,466
2025-03-192,261
2025-03-202,199
2025-03-212,011
2025-03-22199
2025-03-2338
2025-03-242,600
2025-03-252,294
2025-03-262,252
2025-03-272,252
2025-03-281,930
2025-03-29169
2025-03-3041
2025-03-312,478
2025-04-012,411
2025-04-022,336
2025-04-032,236
2025-04-042,009
2025-04-05194
2025-04-0637
2025-04-072,462
2025-04-082,240
2025-04-092,345
2025-04-102,202
2025-04-111,987
2025-04-12169
2025-04-1343
2025-04-142,465
2025-04-152,548
2025-04-162,299
2025-04-172,285
2025-04-1840
2025-04-19149
2025-04-2029
2025-04-2144
2025-04-222,392
2025-04-232,254
2025-04-242,198
2025-04-251,867
2025-04-26172
2025-04-2736
2025-04-282,382
2025-04-292,548
2025-04-302,525
2025-05-012,345
2025-05-021,920
2025-05-03187
2025-05-0437
2025-05-0538
2025-05-062,509
2025-05-072,436
2025-05-082,420
2025-05-091,846
2025-05-10209
2025-05-1138
2025-05-122,532
2025-05-132,420
2025-05-142,287
2025-05-152,353
2025-05-162,035
2025-05-17183
2025-05-1838
2025-05-192,584
2025-05-202,378
2025-05-212,404
2025-05-222,313
2025-05-231,899
2025-05-24176
2025-05-2540
2025-05-2652
2025-05-272,538
2025-05-282,224
2025-05-292,293
2025-05-301,929
2025-05-31169
2025-06-0146
2025-06-022,317
2025-06-032,513
2025-06-042,376
2025-06-051,6431,6431,643
2025-06-061,926
2025-06-07197
2025-06-0853
2025-06-092,415
2025-06-102,238
2025-06-112,356
2025-06-122,400
2025-06-132,051
2025-06-14189
2025-06-1546
2025-06-162,474
2025-06-172,375
2025-06-182,450
2025-06-192,385
2025-06-201,798
2025-06-21178
2025-06-2237
2025-06-232,430
2025-06-242,566
2025-06-252,341
2025-06-262,254
2025-06-271,989
2025-06-28184
2025-06-2947
2025-06-302,429
2025-07-012,271
2025-07-022,519
2025-07-032,290
2025-07-041,948
2025-07-05186
2025-07-0647
2025-07-072,435
2025-07-082,344
2025-07-092,389
2025-07-102,204
2025-07-111,908
2025-07-12171
2025-07-1339
2025-07-142,567
2025-07-152,381
2025-07-162,394
2025-07-172,319
2025-07-182,024
2025-07-19219
2025-07-2039
2025-07-212,481
2025-07-222,486
2025-07-232,283
2025-07-242,507
2025-07-252,115
2025-07-26203
2025-07-2743
2025-07-282,541
2025-07-292,348
2025-07-302,385
2025-07-312,316
2025-08-011,900
2025-08-02170
2025-08-0344
2025-08-042,139
2025-08-052,314
2025-08-062,052
2025-08-072,127
2025-08-081,826
2025-08-09169
2025-08-1030
2025-08-112,328
2025-08-122,092
2025-08-132,046
2025-08-142,022
2025-08-151,855
2025-08-16157
2025-08-1732
2025-08-182,262
2025-08-192,162
2025-08-202,135
2025-08-212,030
2025-08-221,826
2025-08-23178
2025-08-2440
2025-08-2528
2025-08-262,245
2025-08-272,189
2025-08-282,042
2025-08-291,737
2025-08-30174
2025-08-3127
2025-09-012,586
2025-09-022,535
2025-09-032,528
2025-09-042,391
2025-09-051,849
2025-09-06182
2025-09-0750
2025-09-082,8242,824
2025-09-092,353
2025-09-102,484
2025-09-112,323
2025-09-122,166
2025-09-13198
2025-09-1438
2025-09-152,522
2025-09-162,472
2025-09-172,298
2025-09-182,381
2025-09-191,892
2025-09-20205
2025-09-2130
2025-09-222,413
2025-09-232,366
2025-09-242,370
2025-09-252,295
2025-09-261,974
2025-09-27176
2025-09-2843
2025-09-292,378
2025-09-302,392
2025-10-012,466
2025-10-022,311
2025-10-031,984
2025-10-04184
2025-10-0540
2025-10-062,508
2025-10-072,519
2025-10-082,403
2025-10-092,395
2025-10-101,976
2025-10-11186
2025-10-1239
2025-10-132,376
2025-10-142,473
2025-10-152,333
2025-10-162,292
2025-10-172,083
2025-10-18177
2025-10-1943
2025-10-202,536
2025-10-212,555
2025-10-222,303
2025-10-232,355
2025-10-242,029
2025-10-25193
2025-10-2648
2025-10-272,459
2025-10-282,382
2025-10-292,287
2025-10-302,353
2025-10-311,965
2025-11-01175
2025-11-0240
2025-11-032,495
2025-11-042,556
2025-11-052,304
2025-11-062,433
2025-11-071,937
2025-11-08173
2025-11-0937
2025-11-102,561
2025-11-112,475
2025-11-122,319
2025-11-132,306
2025-11-141,953
2025-11-15350350350
2025-11-1646
2025-11-172,478
2025-11-182,405
2025-11-192,348
2025-11-202,580
2025-11-212,029
2025-11-22198
2025-11-2333
2025-11-242,538
2025-11-252,478
2025-11-262,289
2025-11-272,427
2025-11-282,031
2025-11-29183
2025-11-3046
2025-12-012,468
2025-12-022,622
2025-12-032,252
2025-12-042,371
2025-12-052,067
2025-12-06186
2025-12-0746
2025-12-082,475
2025-12-092,390
2025-12-102,460
2025-12-112,419
2025-12-122,014
2025-12-13213
2025-12-1443
2025-12-152,425
2025-12-162,592
2025-12-172,488
2025-12-182,299
2025-12-191,886
2025-12-20178
2025-12-2146
2025-12-222,496
2025-12-232,418
2025-12-241,323
2025-12-2534
2025-12-2638
2025-12-2798
2025-12-2822
2025-12-291,265
2025-12-301,365
2025-12-311,302
2026-01-0132
2026-01-021,112
2026-01-03178
2026-01-0440
2026-01-052,498
2026-01-062,401
2026-01-072,442
2026-01-082,411
2026-01-091,961
2026-01-10185
2026-01-1151
2026-01-122,542
2026-01-132,430
2026-01-142,477
2026-01-152,234
2026-01-162,037
2026-01-17164
2026-01-1833
2026-01-192,447
2026-01-202,446
2026-01-211,9591,9591,959
2026-01-222,433
2026-01-231,970
2026-01-24180
2026-01-2545
2026-01-262,573
2026-01-272,446
2026-01-282,347
2026-01-292,380
2026-01-302,024
2026-01-31164
2026-02-0142
2026-02-022,566
2026-02-032,470
2026-02-042,455
2026-02-052,353
2026-02-061,983
2026-02-07175
2026-02-0830
2026-02-092,676
2026-02-102,499
2026-02-112,345
2026-02-122,300
2026-02-131,950
2026-02-14195
2026-02-1550
2026-02-162,544
2026-02-172,536
2026-02-182,520
2026-02-192,258
2026-02-201,979
2026-02-21179
2026-02-2237
2026-02-232,479
2026-02-242,562
2026-02-252,317
2026-02-262,140
2026-02-272,047
2026-02-28186
2026-03-0140
2026-03-022,430
2026-03-032,456
2026-03-042,378
2026-03-052,384
2026-03-062,030
2026-03-07179
2026-03-0847
2026-03-092,568
2026-03-102,360
2026-03-112,400
2026-03-122,342
2026-03-132,012
2026-03-14179
2026-03-1544
2026-03-162,494
2026-03-172,450
2026-03-182,283
2026-03-192,447
2026-03-202,070
2026-03-21185
2026-03-2240
2026-03-232,388
2026-03-242,396
2026-03-252,416
2026-03-262,149
2026-03-271,916
2026-03-28191
2026-03-2937
2026-03-302,477
2026-03-312,335
2026-04-012,325
2026-04-022,216
2026-04-0331
2026-04-04167
2026-04-0540
2026-04-0645
2026-04-072,210
2026-04-082,271
2026-04-092,214
2026-04-101,718
2026-04-11164
2026-04-1238
2026-04-132,189
2026-04-142,225
2026-04-152,287
2026-04-162,167
2026-04-171,936
2026-04-18186
2026-04-1934
2026-04-202,344
2026-04-212,242
2026-04-222,197
2026-04-232,224
2026-04-241,805
2026-04-25159
2026-04-2648
2026-04-272,235
2026-04-282,137
2026-04-292,133
2026-04-302,024
2026-05-011,757
2026-05-02155
2026-05-0329
2026-05-0432
2026-05-052,097
2026-05-062,217
2026-05-072,117
2026-05-081,772
2026-05-09178
2026-05-1036
2026-05-112,110
2026-05-122,143
2026-05-132,157
2026-05-142,166
2026-05-151,785
2026-05-16165
2026-05-1735
2026-05-182,182
2026-05-192,117
2026-05-202,151
2026-05-212,167
2026-05-221,720
2026-05-23180
2026-05-2436
2026-05-2548
2026-05-262,336
2026-05-272,167
2026-05-282,044
2026-05-291,726
2026-05-30184
2026-05-3143
2026-06-012,178
2026-06-022,118
2026-06-032,289
2026-06-042,094
2026-06-051,768
2026-06-06179
2026-06-0725
2026-06-082,243
2026-06-092,111
2026-06-102,095
2026-06-112,158
2026-06-121,882
2026-06-13146
2026-06-1447
2026-06-152,328
2026-06-162,077
2026-06-172,130
2026-06-182,103
2026-06-191,730
2026-06-20154
2026-06-2140
2026-06-222,258
2026-06-232,152
2026-06-241,962
2026-06-252,047
2026-06-261,801
2026-06-27162
2026-06-2833
2026-06-292,243
2026-06-302,183
2026-07-012,068
2026-07-022,208
2026-07-031,734
2026-07-04181
2026-07-0535
2026-07-062,292
2026-07-072,195
2026-07-082,101
2026-07-092,158
2026-07-101,722
2026-07-11158
2026-07-1245
2026-07-132,186
2026-07-142,036
2026-07-152,043
2026-07-162,056
2026-07-171,836
2026-07-18144
2026-07-1941
2026-07-202,161
2026-07-212,303
2026-07-222,231
2026-07-232,167
2026-07-241,717
2026-07-25155
2026-07-2626
2026-07-272,299
2026-07-282,0042,004
2026-07-292,033
2026-07-302,030
2026-07-311,830
28-day year-on-year
Appointment dateRecords loadedFlaggedPlanted one-day problem
2024-10-012,475
2024-10-022,422
2024-10-032,364
2024-10-041,900
2024-10-05179
2024-10-0644
2024-10-072,324
2024-10-082,394
2024-10-092,388
2024-10-102,391
2024-10-112,079
2024-10-12168
2024-10-1325
2024-10-142,396
2024-10-152,243
2024-10-162,304
2024-10-172,163
2024-10-182,009
2024-10-19150
2024-10-2050
2024-10-212,466
2024-10-222,231
2024-10-232,261
2024-10-242,204
2024-10-251,986
2024-10-26170
2024-10-2736
2024-10-282,463
2024-10-292,583
2024-10-302,290
2024-10-312,232
2024-11-011,780
2024-11-02175
2024-11-0344
2024-11-042,474
2024-11-052,504
2024-11-062,470
2024-11-072,351
2024-11-082,034
2024-11-09171
2024-11-1040
2024-11-112,440
2024-11-122,344
2024-11-132,247
2024-11-142,255
2024-11-151,925
2024-11-16156
2024-11-1741
2024-11-182,478
2024-11-191,2811,281
2024-11-202,370
2024-11-212,251
2024-11-222,027
2024-11-23193
2024-11-2449
2024-11-252,519
2024-11-262,459
2024-11-272,229
2024-11-282,207
2024-11-291,804
2024-11-30162
2024-12-0146
2024-12-022,406
2024-12-032,383
2024-12-042,417
2024-12-052,289
2024-12-061,940
2024-12-07194
2024-12-0834
2024-12-092,477
2024-12-102,375
2024-12-112,223
2024-12-122,315
2024-12-131,923
2024-12-14188
2024-12-1535
2024-12-162,366
2024-12-172,338
2024-12-182,271
2024-12-192,210
2024-12-201,900
2024-12-21170
2024-12-2239
2024-12-232,533
2024-12-241,298
2024-12-2531
2024-12-2646
2024-12-271,063
2024-12-2890
2024-12-2923
2024-12-301,400
2024-12-311,330
2025-01-0139
2025-01-021,247
2025-01-031,930
2025-01-04210
2025-01-0544
2025-01-062,531
2025-01-072,383
2025-01-082,348
2025-01-092,370
2025-01-101,969
2025-01-11187
2025-01-1244
2025-01-132,577
2025-01-142,432
2025-01-152,243
2025-01-162,187
2025-01-171,928
2025-01-18177
2025-01-1950
2025-01-202,232
2025-01-212,353
2025-01-222,247
2025-01-232,243
2025-01-242,091
2025-01-25152
2025-01-2641
2025-01-272,355
2025-01-282,369
2025-01-292,296
2025-01-302,326
2025-01-311,934
2025-02-01179
2025-02-0226
2025-02-032,360
2025-02-042,425
2025-02-052,342
2025-02-062,395
2025-02-071,943
2025-02-08161
2025-02-0930
2025-02-102,403
2025-02-1100
2025-02-122,411
2025-02-132,311
2025-02-141,976
2025-02-15171
2025-02-1636
2025-02-172,567
2025-02-182,516
2025-02-192,366
2025-02-202,240
2025-02-212,024
2025-02-22207
2025-02-2324
2025-02-242,429
2025-02-252,362
2025-02-262,415
2025-02-272,303
2025-02-281,888
2025-03-01149
2025-03-0239
2025-03-032,450
2025-03-042,438
2025-03-052,408
2025-03-062,367
2025-03-071,912
2025-03-08202
2025-03-0949
2025-03-102,486
2025-03-112,587
2025-03-122,247
2025-03-132,297
2025-03-141,889
2025-03-15182
2025-03-1652
2025-03-175,0325,032
2025-03-182,466
2025-03-192,261
2025-03-202,199
2025-03-212,011
2025-03-22199
2025-03-2338
2025-03-242,600
2025-03-252,294
2025-03-262,252
2025-03-272,252
2025-03-281,930
2025-03-29169
2025-03-3041
2025-03-312,478
2025-04-012,411
2025-04-022,336
2025-04-032,236
2025-04-042,009
2025-04-05194
2025-04-0637
2025-04-072,462
2025-04-082,240
2025-04-092,345
2025-04-102,202
2025-04-111,987
2025-04-12169
2025-04-1343
2025-04-142,465
2025-04-152,548
2025-04-162,299
2025-04-172,285
2025-04-1840
2025-04-19149
2025-04-2029
2025-04-2144
2025-04-222,392
2025-04-232,254
2025-04-242,198
2025-04-251,867
2025-04-26172
2025-04-2736
2025-04-282,382
2025-04-292,548
2025-04-302,525
2025-05-012,345
2025-05-021,920
2025-05-03187
2025-05-0437
2025-05-0538
2025-05-062,509
2025-05-072,436
2025-05-082,420
2025-05-091,846
2025-05-10209
2025-05-1138
2025-05-122,532
2025-05-132,420
2025-05-142,287
2025-05-152,353
2025-05-162,035
2025-05-17183
2025-05-1838
2025-05-192,584
2025-05-202,378
2025-05-212,404
2025-05-222,313
2025-05-231,899
2025-05-24176
2025-05-2540
2025-05-2652
2025-05-272,538
2025-05-282,224
2025-05-292,293
2025-05-301,929
2025-05-31169
2025-06-0146
2025-06-022,317
2025-06-032,513
2025-06-042,376
2025-06-051,6431,643
2025-06-061,926
2025-06-07197
2025-06-0853
2025-06-092,415
2025-06-102,238
2025-06-112,356
2025-06-122,400
2025-06-132,051
2025-06-14189
2025-06-1546
2025-06-162,474
2025-06-172,375
2025-06-182,450
2025-06-192,385
2025-06-201,798
2025-06-21178
2025-06-2237
2025-06-232,430
2025-06-242,566
2025-06-252,341
2025-06-262,254
2025-06-271,989
2025-06-28184
2025-06-2947
2025-06-302,429
2025-07-012,271
2025-07-022,519
2025-07-032,290
2025-07-041,948
2025-07-05186
2025-07-0647
2025-07-072,435
2025-07-082,344
2025-07-092,389
2025-07-102,204
2025-07-111,908
2025-07-12171
2025-07-1339
2025-07-142,567
2025-07-152,381
2025-07-162,394
2025-07-172,319
2025-07-182,024
2025-07-19219
2025-07-2039
2025-07-212,481
2025-07-222,486
2025-07-232,283
2025-07-242,507
2025-07-252,115
2025-07-26203
2025-07-2743
2025-07-282,541
2025-07-292,348
2025-07-302,385
2025-07-312,316
2025-08-011,900
2025-08-02170
2025-08-0344
2025-08-042,139
2025-08-052,314
2025-08-062,052
2025-08-072,127
2025-08-081,826
2025-08-09169
2025-08-1030
2025-08-112,328
2025-08-122,092
2025-08-132,046
2025-08-142,022
2025-08-151,855
2025-08-16157
2025-08-1732
2025-08-182,262
2025-08-192,162
2025-08-202,135
2025-08-212,030
2025-08-221,826
2025-08-23178
2025-08-2440
2025-08-2528
2025-08-262,245
2025-08-272,189
2025-08-282,042
2025-08-291,737
2025-08-30174
2025-08-3127
2025-09-012,586
2025-09-022,535
2025-09-032,528
2025-09-042,391
2025-09-051,849
2025-09-06182
2025-09-0750
2025-09-082,8242,824
2025-09-092,353
2025-09-102,484
2025-09-112,323
2025-09-122,166
2025-09-13198
2025-09-1438
2025-09-152,522
2025-09-162,472
2025-09-172,298
2025-09-182,381
2025-09-191,892
2025-09-20205
2025-09-2130
2025-09-222,413
2025-09-232,366
2025-09-242,370
2025-09-252,295
2025-09-261,974
2025-09-27176
2025-09-2843
2025-09-292,378
2025-09-302,392
2025-10-012,466
2025-10-022,311
2025-10-031,984
2025-10-04184
2025-10-0540
2025-10-062,508
2025-10-072,519
2025-10-082,403
2025-10-092,395
2025-10-101,976
2025-10-11186
2025-10-1239
2025-10-132,376
2025-10-142,473
2025-10-152,333
2025-10-162,292
2025-10-172,083
2025-10-18177
2025-10-1943
2025-10-202,536
2025-10-212,555
2025-10-222,303
2025-10-232,355
2025-10-242,029
2025-10-25193
2025-10-2648
2025-10-272,459
2025-10-282,382
2025-10-292,287
2025-10-302,353
2025-10-311,965
2025-11-01175
2025-11-0240
2025-11-032,495
2025-11-042,556
2025-11-052,304
2025-11-062,433
2025-11-071,937
2025-11-08173
2025-11-0937
2025-11-102,561
2025-11-112,475
2025-11-122,319
2025-11-132,306
2025-11-141,953
2025-11-15350350
2025-11-1646
2025-11-172,478
2025-11-182,405
2025-11-192,348
2025-11-202,580
2025-11-212,029
2025-11-22198
2025-11-2333
2025-11-242,538
2025-11-252,478
2025-11-262,289
2025-11-272,427
2025-11-282,031
2025-11-29183
2025-11-3046
2025-12-012,468
2025-12-022,622
2025-12-032,252
2025-12-042,371
2025-12-052,067
2025-12-06186
2025-12-0746
2025-12-082,475
2025-12-092,390
2025-12-102,460
2025-12-112,419
2025-12-122,014
2025-12-13213
2025-12-1443
2025-12-152,425
2025-12-162,592
2025-12-172,488
2025-12-182,299
2025-12-191,886
2025-12-20178
2025-12-2146
2025-12-222,496
2025-12-232,418
2025-12-241,323
2025-12-2534
2025-12-2638
2025-12-2798
2025-12-2822
2025-12-291,265
2025-12-301,365
2025-12-311,302
2026-01-0132
2026-01-021,112
2026-01-03178
2026-01-0440
2026-01-052,498
2026-01-062,401
2026-01-072,442
2026-01-082,411
2026-01-091,961
2026-01-10185
2026-01-1151
2026-01-122,542
2026-01-132,430
2026-01-142,477
2026-01-152,234
2026-01-162,037
2026-01-17164
2026-01-1833
2026-01-192,447
2026-01-202,446
2026-01-211,9591,959
2026-01-222,4332,433
2026-01-231,9701,970
2026-01-24180180
2026-01-254545
2026-01-262,5732,573
2026-01-272,446
2026-01-282,347
2026-01-292,380
2026-01-302,024
2026-01-31164
2026-02-0142
2026-02-022,566
2026-02-032,470
2026-02-042,455
2026-02-052,353
2026-02-061,983
2026-02-07175
2026-02-0830
2026-02-092,676
2026-02-102,499
2026-02-112,345
2026-02-122,300
2026-02-131,950
2026-02-14195
2026-02-1550
2026-02-162,544
2026-02-172,536
2026-02-182,520
2026-02-192,258
2026-02-201,979
2026-02-21179
2026-02-2237
2026-02-232,479
2026-02-242,562
2026-02-252,317
2026-02-262,140
2026-02-272,047
2026-02-28186
2026-03-0140
2026-03-022,430
2026-03-032,456
2026-03-042,378
2026-03-052,384
2026-03-062,030
2026-03-07179
2026-03-0847
2026-03-092,568
2026-03-102,360
2026-03-112,400
2026-03-122,342
2026-03-132,012
2026-03-14179
2026-03-1544
2026-03-162,494
2026-03-172,450
2026-03-182,283
2026-03-192,447
2026-03-202,070
2026-03-21185
2026-03-2240
2026-03-232,388
2026-03-242,396
2026-03-252,416
2026-03-262,149
2026-03-271,916
2026-03-28191
2026-03-2937
2026-03-302,477
2026-03-312,335
2026-04-012,325
2026-04-022,216
2026-04-0331
2026-04-04167
2026-04-0540
2026-04-0645
2026-04-072,210
2026-04-082,271
2026-04-092,214
2026-04-101,718
2026-04-11164
2026-04-1238
2026-04-132,189
2026-04-142,225
2026-04-152,287
2026-04-162,167
2026-04-171,936
2026-04-18186
2026-04-1934
2026-04-202,344
2026-04-212,242
2026-04-222,197
2026-04-232,224
2026-04-241,805
2026-04-25159
2026-04-2648
2026-04-272,235
2026-04-282,137
2026-04-292,133
2026-04-302,024
2026-05-011,757
2026-05-02155
2026-05-0329
2026-05-0432
2026-05-052,097
2026-05-062,217
2026-05-072,1172,117
2026-05-081,7721,772
2026-05-09178178
2026-05-103636
2026-05-112,1102,110
2026-05-122,1432,143
2026-05-132,1572,157
2026-05-142,1662,166
2026-05-151,7851,785
2026-05-16165165
2026-05-173535
2026-05-182,1822,182
2026-05-192,1172,117
2026-05-202,1512,151
2026-05-212,1672,167
2026-05-221,7201,720
2026-05-23180180
2026-05-243636
2026-05-254848
2026-05-262,3362,336
2026-05-272,1672,167
2026-05-282,0442,044
2026-05-291,7261,726
2026-05-30184184
2026-05-314343
2026-06-012,1782,178
2026-06-022,1182,118
2026-06-032,2892,289
2026-06-042,094
2026-06-051,768
2026-06-06179
2026-06-0725
2026-06-082,243
2026-06-092,111
2026-06-102,0952,095
2026-06-112,1582,158
2026-06-121,8821,882
2026-06-13146146
2026-06-144747
2026-06-152,3282,328
2026-06-162,0772,077
2026-06-172,1302,130
2026-06-182,1032,103
2026-06-191,7301,730
2026-06-20154154
2026-06-214040
2026-06-222,2582,258
2026-06-232,1522,152
2026-06-241,9621,962
2026-06-252,0472,047
2026-06-261,8011,801
2026-06-27162162
2026-06-283333
2026-06-292,2432,243
2026-06-302,1832,183
2026-07-012,0682,068
2026-07-022,2082,208
2026-07-031,7341,734
2026-07-04181181
2026-07-053535
2026-07-062,2922,292
2026-07-072,1952,195
2026-07-082,1012,101
2026-07-092,1582,158
2026-07-101,7221,722
2026-07-11158158
2026-07-124545
2026-07-132,1862,186
2026-07-142,0362,036
2026-07-152,0432,043
2026-07-162,0562,056
2026-07-171,8361,836
2026-07-18144144
2026-07-194141
2026-07-202,1612,161
2026-07-212,3032,303
2026-07-222,2312,231
2026-07-232,1672,167
2026-07-241,7171,717
2026-07-25155155
2026-07-262626
2026-07-272,2992,299
2026-07-282,0042,004
2026-07-292,0332,033
2026-07-302,0302,030
2026-07-311,8301,830

Synthetic data. Source: projects/article-examples/round-two/feed_anomalies.py.

Switch between the checks to see where each one fired. Zoom into a few weeks to see the Sunday false alerts of the ratio check.

The calendar matters more than the method

Take the calendar away and every daily check gets worse:

One-day incidents caught and false alerts, by check669 days scored, October 2024 to July 2026; 7 planted one-day incidents
Data table
Bank holidays and Christmas week known
CheckOne-day incidents caught (of 7)False alerts
Weekday ratio ±25%514
Weekday robust z613
STL robust z62
28-day year-on-year05
No calendar
CheckOne-day incidents caught (of 7)False alerts
Weekday ratio ±25%538
Weekday robust z532
STL robust z647
28-day year-on-year05

Synthetic data. Source: projects/article-examples/round-two/feed_anomalies.py.

Without the calendar, the three daily checks raised 38, 32 and 47 false alerts. Between 21 and 25 of each fell on bank holidays or in Christmas week, days that are low for reasons everyone already knows. STL, the best check with the calendar, was the worst without it: holidays inside its 84-day window bent the fitted pattern, and most of its other false alerts came in the first two weeks of January.

A bank holiday table is quick to build (gov.uk publishes the dates as JSON), and together with Christmas week it removed most of the noise. It’s the first thing I’d add to any volume check.

Slow drift: the daily checks don’t see it

From March 2026 a growing share of records went missing, reaching 12% by May. Each daily check compares today with the last few weeks, and the last few weeks were drifting too. Between them, the three daily checks flagged 9 of the 152 drift days, scattered from April to July. Nobody would read those as a trend.

Drift needs a baseline that isn’t drifting. I compared the median weekday count over the last 28 days with the same 28 days a year earlier (364 days back, so the weekdays line up). Before the drift the ratio sat at a median of 1.032, the planted 3% growth. With a ±8% band, the check fired on 7 May 2026, nine weeks after the drift began, when 11.5% of records were being lost. It also fired on five days in late January 2026, when both windows held only about three weeks of ordinary working days after Christmas, so the medians rested on fewer days.

Band First flag in the drift Records lost that day Flags before the drift
±4% 2026-04-30 10.3% 71
±6% 2026-05-05 11.1% 8
±8% 2026-05-07 11.5% 5
±10% 2026-05-11 12.0% 0

Tightening the band barely helps: halving it buys a week and costs 71 false flags. A year-on-year comparison can only see a loss that stands out from a year’s worth of real change and noise.

The better answer is to test the cause. This drift came from a clinic code missing from a mapping table, and a test that every code in the extract maps to something fails on the first day that code appears. So would a reconciliation of source rows against loaded rows. Data tests that catch real problems covers both. Keep the year-on-year check as a backstop for causes you didn’t think to test.

Freshness and schema

Two of the planted problems leave the row counts untouched. A check at 07:00 each morning asks whether yesterday’s load has landed, and whether its columns match the agreed contract:

Appointment date Load finished Fresh by 07:00 Missing columns
2025-02-11 no load no none
2025-09-22 2025-09-23 05:50 yes clinic_code
2025-09-23 2025-09-24 05:26 yes clinic_code
2025-12-02 2025-12-03 11:20 no none

The failed load on 11 February is caught by both kinds of check, but freshness says why: no load ran, which points at the job rather than the data. The load for 2 December landed at 11:20. Its final row count was normal, so a volume check wouldn’t notice, but a dashboard refreshed at 07:00 went out without that day. On 22 and 23 September the source renamed clinic_code to clinic_cd. The loads ran on time with normal volumes, and only the schema check saw that clinic codes had stopped arriving.

Alert fatigue and thresholds

An alert that fires every few days trains people to ignore it. Before choosing a threshold, count what it will cost. For the two z-score checks, with the calendar:

Check Threshold One-day caught False alerts False per month
Weekday robust z 2.5 6 37 1.7
Weekday robust z 3.5 6 13 0.6
Weekday robust z 5.0 5 5 0.2
STL robust z 2.5 6 15 0.7
STL robust z 3.5 6 2 0.1
STL robust z 5.0 4 0 0.0

Most of the real breaks scored far beyond any of these thresholds, from −48 to +22, and the misses were too small for any sensible one. Dropping the threshold to 2.5 caught nothing new and multiplied the false alerts; raising it to 5.0 started losing real incidents. Big breaks are easy, and the small ones are usually better caught by a specific test than by a lower threshold. The 15% re-send is a duplicate-key problem, and a uniqueness test on appointment_id would have failed on the day.

Some habits that keep alerts useful:

  • Track false alerts per month as a design metric. My rule of thumb is fewer than one a month per check, or people stop reading them.
  • Alert on the start of a problem, not every day of it. The year-on-year check flagged 80 drift days; one message on 7 May was enough.
  • Give each alert an owner and a severity. A missing load pages the platform team. A volume warning goes to whoever knows the source.
  • Write down what “normal” is. A baseline, a calendar and a threshold are a definition, and they deserve the same review as a metric.

What I’d set up first

  1. A freshness check on every source, with a deadline before the first dashboard refresh.
  2. A schema check against the columns and types you expect.
  3. Uniqueness and mapping tests on the keys and codes that matter.
  4. A weekday robust z-score on daily volume, with a bank holiday calendar. Graduate to the STL version if the false alerts bother you.
  5. A monthly year-on-year comparison as a backstop for drift.

The first three are cheap and deterministic. The volume checks catch what you didn’t think to test for. If you’re building metric logic alongside these checks, metric definitions as code and the outpatient analytics pipeline show where they sit in a pipeline, and SPC charts for operational metrics covers the related job of telling signal from noise in the metrics themselves.

Reproduce

The feed, the load log, every check, both charts and the tables above come from one script. It takes about 20 seconds, most of it fitting STL once per day:

uv run python projects/article-examples/round-two/feed_anomalies.py