My old churn model measured how surprising a user’s silence was against their own history. That’s a real question with a real answer, but it isn’t churn risk: it flagged regulars who took a week off and ignored light users who’d quietly stopped. It passed every backtest for two years; a confused user in a focus group is what caught it. The replacement is the table banks use for late accounts – bin users by how long they’ve been gone and how much they normally use the product, count who came back – with the same empirical Bayes shrinkage as before, pointed at the right quantity this time.
Wen et al. show two forecasters with identical marginal predictions can make arbitrarily different decisions. A disjoint contextual bandit (one model per arm) is exactly their independence forecaster. In conjugate linear models the joint is exact and free, and partial pooling through a shared component gets it back.
Our most-hit endpoint took 200 milliseconds per shift, so someone capped it at one page of results. The cap ran for years and quietly made product decisions nobody agreed to: an eleven-item shelf, a two-second page, and features that never became ideas. Then a blocked MySQL upgrade forced us to finally read the function.
If you’re running a Bayesian model in a non-stationary environment, you need to forget old data. The obvious approach – scale the precision matrix by a constant – has a failure mode called covariance windup. This post works through three forgetting rules, ending with one borrowed from adaptive control that dominates the others.
My wife has a blog that I self-host. WordPress-based, so it’s MySQL, PHP-FPM, nginx. I’d like to think about its deployment/infrastructure approximately never.
I probably overuse the normal-inverse-gamma posterior. Every time I build a bandit system, every time I need uncertainty quantification for sequential decisions, I end up back at conjugate linear regression.
For a new project at work, we didn’t want to do passwords. The two candidates were magic links and WebAuthn, and we ended up going with magic links—but I got curious about WebAuthn anyway, so I built a demo app to understand it.
Suppose you’re choosing a continuous value x and observing a noisy reward y. The reward depends on x through some unknown function f(x), and you’re making decisions repeatedly—learning as you go. This post explores how to build scalable Bayesian models for this problem using principled approximations.
In my previous post, I covered running portable services—version-controlled config, atomic updates, zero-downtime restarts, all without a container runtime. This is only half of the container story, though. You also need to build the service images.
I run bowl.science, an online Science Bowl tournament platform. It’s a side project, but it’s real production: the DOE Office of Science uses it for their Science Bowl competitions. When a tournament is happening, the app needs to work. There’s no “we’ll fix it in the next sprint.”