Bakery Anomaly Detection

A local bakery taught me that the useful model is often the one nobody has to babysit

2 months in production · Paper in preparation for SOMI @ ECML-PKDD 2026

Overview

I built this with an artisanal bakery in northern Italy (about 50 employees and 200 products). Every morning, the owner exports a CSV with that day's planned quantities. The app points out entries that look like typing mistakes before those numbers reach purchasing and the kitchen, then gets out of the way.

That last part matters: the person using it is the bakery owner, not a data scientist.

Why I did not train a model

My first instinct was to compare Isolation Forest, LOF, and other familiar anomaly detectors. The data quickly made that feel dishonest. Each product behaves differently on each weekday, history is short, and the distribution keeps moving. A model can look sophisticated here while learning almost nothing useful.

Five properties make trained ML models unsuitable:

  1. Day-of-week independence — Monday orders differ systematically from Saturday for every product. A DOW-aware model would need ~600 instances, each trained on 4 data points.
  2. No inter-product correlation — a mistyped quantity carries zero signal in any other product.
  3. Extreme data scarcity — a 4-week rolling window means 4 training observations per model.
  4. Continuous distribution shift — seasonal volumes, new products, discontinued items.
  5. Zero-maintenance requirement — no IT budget for retraining pipelines.

The version that stuck

A rolling statistical estimator with a conjunction rule: for each (product, day-of-week) pair, compute mean and standard deviation over the last W same-weekday observations (default W = 4). Flag an anomaly only when all three conditions hold simultaneously:

  • Z-score > 7.0
  • Percentage deviation > 30%
  • Absolute deviation > volume-tier threshold

A fourth component — a year-over-year seasonality shield — suppresses false positives on seasonal products (Easter specialties, holiday items) by comparing against the same date one year prior.

There is no training job, model artefact, or drift monitor to maintain. The baseline moves with the recent data, and a new product can be handled from its second observation.

Architecture

CSV upload (daily)
       │
  Streamlit frontend
       │
  Detection engine (Python)
  ├── Rolling Z-score per (product, DOW)
  ├── Conjunction rule
  ├── Volume-tier thresholds
  └── YoY seasonality shield
       │
  Supabase PostgreSQL
  ├── Historical orders
  ├── Precomputed baselines
  ├── Audit log (append-only)
  └── Auth (role-based)

Two user roles: an administrator view (full table with Z-score, deviation, time-series charts) and a simplified operator view (one review card per flag, business-language summaries: "You ordered 500 kg; the usual Monday order is 48 ± 6 kg").

Deployed on free tiers only: Streamlit Cloud, Supabase, Cloudflare DNS.
Total recurring infrastructure cost: €0/month.

Benchmark Results

496-anomaly labelled test set, constructed with the bakery's cooperation. Competing methods receive oracle threshold selection (best possible F1 on test set) — the deployed Z-score gets no oracle.

Method Window W Precision Recall F1
Z-score (deployed) ← no oracle 4 89.0% 90.9% 85.7%
Z-score (oracle) 4 83.0% 91.1% 86.9%
MAD (oracle) 4 82.3% 83.2% 82.8%
Holt-Winters (oracle) 4 0% (inapplicable)
Z-score (oracle) 24 86.5% 91.6% 89.0%
MAD (oracle) 24 83.7% 92.8% 88.0%
Holt-Winters (oracle) 24 66.5% 75.7% 70.8%

The deployed settings land within 1.2 percentage points of the oracle-tuned Z-score at the same four-week window, without choosing a threshold on the test set. Longer windows score a little higher offline, but they adapt too slowly for the bakery's changing catalogue. Holt-Winters cannot fit the four-observation case at all and is far slower at W = 24.

What changed after people used it

  • Too many warnings make every warning invisible. Once false positives get near 20%, the owner stops trusting the list.
  • Easter broke the first version. Legitimate seasonal spikes looked alarming, so I added the year-over-year check.
  • Maintenance has to be close to zero. A scheduled retraining pipeline would not survive in this setting.
  • The explanation is part of the result. “500 kg versus a usual Monday of 48 ± 6 kg” is something the operator can act on.

Academic Output

"When Simpler Is Necessary: Anomaly Detection for Production Orders in an Artisanal Bakery"
Lucio Baiocchi — MSc Data Science and Engineering, Politecnico di Torino
Submitted to SOMI Workshop @ ECML-PKDD 2026 (Springer LNCS)

Main contribution: a problem characterisation framework — a decision tree that predicts, from the structural properties of a monitoring problem, whether a rolling statistical estimator or a trained ML model is the appropriate tool.

Stack: Python · Streamlit · Supabase (PostgreSQL) · Streamlit Cloud · Cloudflare