Returns you haven’t seen yet: forecasting returns as a chain of forecasts

Forecasting
Survival Analysis
Supply Chain
Bayesian
Forecast warehouse returns as a chain of numpyro_forecast models linked by time-to-event convolutions: sales feed return initiations, which feed receipts. Scored against four baselines, including SARIMAX, with a promotion-cancellation forecast using the same fitted model.
Published

September 29, 2026

Modified

November 8, 2026

This post is a marimo notebook with its own layout, so it lives on its own page.

One sales forecast propagated through return initiations and warehouse receipts, with a storm shaded on the receipts panel

Read the post →

Warehouse receipts depend on the returns customers start this week, which depend on what sold last month and what sells this month. The post treats that as a chain of forecasts and builds it on numpyro_forecast: sales is an ordinary numpyro_forecast model written with Horizon and predict, and each return stage is a time-to-event model that speaks the same protocol. One forecast call then carries sales uncertainty through the fitted return stages, draw by draw, under explicit weather assumptions.

The chain is scored on four held-out weeks against four baselines: a weekday average, a settled and a naive return rate times lagged sales, and a SARIMAX with lagged sales and return initiations. It lands within 2% of the month, and its daily error is 44% lower than the best baseline’s.

What if July’s promotion is canceled? The post keeps the fitted model and weather assumptions fixed, changes the promotion calendar, and forecasts again. It shows the lost sales, the change in warehouse workload over time, and a distribution for how many fewer receipts to expect over the next four weeks.

The figures run in your browser, with no Python server: inspect the model’s stages and source, move the history slider, follow a sale day’s returns through both clocks, choose a baseline to compare, or inspect the promotion scenario and its effect on receipts. All forecasts are computed ahead of time; the controls only change the view.

ttenet is the small demo package that wires the stages together: a reference implementation of the idea, meant to be read, run and adapted rather than a maintained library. The notebook behind the page is examples/retail_returns_blog.py. Running it refits the model and recomputes every figure:

git clone https://github.com/kylejcaron/ttenet && cd ttenet
git checkout 3d0a7b0e3ff3f40cf889bfd028fd5d43146b223d
uv sync --python 3.13 --all-extras   # JAX has no Python 3.15 wheels yet
uv run marimo run examples/retail_returns_blog.py