Last summer, at Rev.io, I took a quick pass at a recommendation feature. It shipped, it worked, and it bothered me. Not because it was broken. Because it was unfinished. I had reached for the obvious approach, gotten something plausible, and walked away with the distinct sense that I had skipped the interesting part. That feeling sat there, quietly, for the better part of a year.
Recommendation has been a slow pull of mine for a long time. Long enough that when I was deciding what to do a doctorate in, one of the roads I seriously considered was computer science, with recommender systems as the thing I would spend years on. I went a different way (disaster sociology, where I still am) and I don't regret it. But a road not taken has a way of leaving a light on in the window. The Rev.io itch was that light getting brighter.
So a little over two months ago I finally sat down with it. What came out is a library called Kindling. The announcement is about what it does. This is about the part that actually mattered, which was not the shipping but the chewing.
The chewing
Two months, mostly at the edges of the day. 219 commits. 26 experiment branches. 168 benchmark runs across 13 datasets. 20 experiments written up in full, the failures filed right beside the wins. The loop was always the same: have an idea, test it, watch the numbers reject it, sit with why, come back the next day with another. Most nights it was where my mind wandered whether I planned it or not. The shower, the walk, 11pm when I should have been asleep.
That is the real story of Kindling, more than any feature in it. Not a clever insight that arrived whole, but a problem I could not put down, sanded smooth over sixty-odd days of letting it marinate until it gave something up.
Have an idea, watch the numbers reject it, sit with why, come back the next day with another. Let it marinate until it gives something up.
Two camps, both half right
Modern recommendation has two camps, and each is half right. One says capacity wins: give a deep model enough data and it will learn structure no hand-built feature can match. The other says most of the real value still lives in a handful of classical, closed-form methods that have been quietly strong for a decade. The deep camp is right when the data is rich. The classical camp is right that most real catalogs are not rich. They are sparse, cold, and full of users you have barely seen.
The frame that holds both sits one level up: stop picking a model, and start matching the model to the regime the data is actually in. That is the whole design of Kindling. It reads the shape of your interactions when it fits, and turns on only the machinery the data can support. A closed-form base for small catalogs, cooccurrence for large ones; trend, sequential, and user-collaborative channels that each switch on by a measurable property rather than a config flag you would have to guess at. Cold start is the baseline, not a bolt-on. Repeat buying is first-class, because on grocery and retail data, suppressing it throws away real accuracy.
What the chewing gave up
What surfaced surprised me, and I will own the assumption it corrected. I had quietly filed the shallow, closed-form methods under obsolete, the kind of thing you learn for context before moving on to the real models. Assembled with care and measured honestly, they go toe to toe with the approaches I had assumed buried them. Full-ranking NDCG@10 of 0.293 on MovieLens-1M, the strongest personalized model on all four headline datasets, beating implicit ALS everywhere. On grocery data where people genuinely rebuy, the gap stops being polite: Dunnhumby at 0.48 against about 0.05 for every baseline. And the same gate that turns that win on refuses the false version of it on Steam, where a re-log is a replay, not a repurchase.
None of that is a single headline number, which is the point. There is a live chart on the Kindling page that lets you watch each model's accuracy grow from cold to warm, dataset by dataset. On some discovery catalogs, plain popularity is a stubborn cold-start baseline that takes real history to beat, and I left that in plain view. A benchmark you can only read in your own favor is not a benchmark. The negative results are in the repo for the same reason. They are half the value.
A solid, unglamorous choice
So the end result is a solid engineering choice. Not novel. Not state of the art. A careful assembly of known pieces, gated well and graded without flinching. I would take that over clever any day.
I ship most things because I want them to exist in the world. This one I built because it would not let me go, and because a path I had talked myself out of, once, turned out to still want walking. It is open source, Apache 2.0, at github.com/rhoekstr/kindling. If you have a cold catalog, I would genuinely like to know what has held up on it...