One model contract, so every forecast ships the same way
Forecasting work had spread across solar, wind and pricing, and the tooling grew one model at a time. We rebuilt the path from notebook to production around a model contract, MLflow packaging and a challenger-versus-champion loop.
- Role
- Platform R&D
- Stack
- Python, MLflow, Kubernetes, CI/CD
<1 day
Deploy prep, down from 4-5 days
3×
Challengers tested per week
6 weeks
Concept to rollout

How it works
- 1
Model contract
- 2
MLflow package
- 3
Challenger
registered with metadata
- 4
Side-by-side test
same data, same pipeline
- 5
Champion swap
Results
Before and after the rebuild
Deploy prep fell from 4 to 5 days to under one, and the team tested three times as many challengers a week.
- Before
- After
Deploy prep
Challengers per week
Six weeks from concept to rollout.
Past models stay reproducible, solar and wind moved into one repository, and the roadmap opened up to physics integrations, nowcasting and ensembles.
Key decisions
- 01
Put the contract inside the model
The contract says what every model takes in, what it returns and what it needs to run. It ships inside the model, so a mismatch shows up the moment a pipeline loads it.
- 02
One package format for everything
Every model is packaged the same way with MLflow. Experiments, tests and production all run the exact same package.
- 03
Make challengers earn the slot
A new model registers as a challenger and runs on the same data slices as the production champion. It replaces the champion only after winning for several weeks.
- 04
Make releases boring
Shipping a model or rolling one back became a one-line change instead of a deployment project.