Nico Roig NR-02

Purchasing

Put a ready-to-send order in front of the chef instead of a dashboard, in production for the restaurant it was built for.

HospitalityRan in production1,060 words

What I built

A purchasing system for a restaurant: it predicts what the kitchen will sell, turns that into what has to be bought from each supplier before each delivery cut-off, and puts a ready-to-send order in front of the chef instead of a dashboard. It ran in production for the restaurant it was built for.

The forecast was not the hard part. The hard parts were that the cost of a wrong number is asymmetric and different for every ingredient, that the data a kitchen actually produces is worse than these systems assume, and that units are where a system like this produces a ten-fold error rather than a five-percent one.

At a glance

Result
Ran in production for the restaurant it was built for
Output
An order per supplier and delivery day; the chef reviews and sends
Forecast
Two routes chosen per ingredient: through covers, menu mix and recipes, or a direct consumption rate
Objective
The cost of being wrong for each ingredient, not an accuracy score
Guard
An order line far above normal is stopped for a person, whatever the forecast says
Known limits
Accuracy is capped by how well physical counts are done; waste and stockouts are under-recorded

Architecture

Till / sales history Purchases received Physical counts Normalise — one ingredient across supplier names, packs and units Covers, then menu mix, then recipes Direct consumption rate for what hangs off no dish Ingredient demand, as a range rather than a single number Stock position — last count + receipts − use ± measured drift Quantity — asymmetric cost, shelf life, pack rounding, anomaly block Order per supplier and delivery day — the chef reviews and sends

Scroll sideways to see the whole diagram.

Sales, purchases and counts arrive in three different vocabularies and are reduced to one ingredient list first, because everything after that is arithmetic on quantities, and arithmetic on mismatched units is how this kind of system produces a catastrophe. Demand then reaches an ingredient by one of two routes, depending on what kind of ingredient it is. Stock is an estimate that gets corrected, not a fact that gets read. The output is an order for a specific supplier and a specific delivery day.

Engineering decisions

1. Two routes to the same number, chosen per ingredient

Problem
A single dish sells a handful of units a week, so its own history is sparse and a menu change invalidates it. But plenty of what a kitchen buys does not hang off any one dish at all.
Options
Forecast every ingredient directly from its own consumption — dense and simple, blind to menu changes, unable to explain a number. Or forecast dishes and explode them through recipes — explainable and menu-aware, hopeless where the series is thin.
Chose
Both, assigned per ingredient. Dish-driven ingredients go through how many people eat and what they order, and then through the recipes: covers is a dense series driven by day of week and calendar, menu mix is a set of slowly-moving shares, and the product of the two survives a menu change and explains itself — this much onion because we expect this many covers and this share of them takes the burger. Everything consumed regardless of what is ordered is forecast directly from its own rate, where there is no explanatory chain worth building.
Cost
Two paths to keep honest instead of one, and a judgement per ingredient about which path it belongs on — a judgement that has to be revisited when the menu changes. On the dish route errors also compound: an error in covers moves every ingredient at once and in the same direction, which is why the ordering step needs guards that do not depend on the forecast being right.

2. The objective is the cost of being wrong, not accuracy

Problem
Over-ordering fresh fish is a total loss within days. Under-ordering it takes a dish off the menu at nine in the evening. Over-ordering rice costs shelf space. A single accuracy metric averages all of that into a number nobody can act on.
Options
Minimise a symmetric error and add a flat safety margin on top, or choose the order quantity directly against a per-ingredient asymmetric cost.
Chose
The second. Demand is carried as a range rather than a point, and the quantity is the place in that range where the expected cost of running out meets the expected cost of throwing away — bounded by how much of an over-order would survive to be used at all, given shelf life and turnover. A kitchen cannot give you those two costs in euros, so it is never asked for them: an ingredient is classified once by how it fails, and the classification carries the trade-off.
Cost
The system stops being summarisable by one error number, and the thing being optimised is not directly observable — you see waste and stockouts, and both are under-recorded. Judging whether it is working takes more care than reading an accuracy score, and that is an ongoing cost rather than a one-off one.

3. Theoretical stock drifts; a count is a measurement

Problem
Depletion computed from sales assumes every gram ends up in a dish. Waste, over-portioning, staff meals and breakage mean the number on the screen walks away from the number on the shelf, and it does it quietly.
Options
Trust the running figure and count occasionally to reset it, or treat each count as evidence about the running figure itself.
Chose
The count does two jobs. It resets the level, and the gap between what should have been consumed and what actually was becomes an estimate of that ingredient's drift, which then corrects expected consumption going forward. The discrepancy is the signal, not the error to be thrown away.
Cost
Accuracy ends up capped by an operational habit that no software controls. Counts get entered by tired people at closing time, so one mistyped number would otherwise become a permanent drift rate for that ingredient — which is exactly why a count implying impossible consumption cannot be absorbed silently.

4. Units, and a guard that sits outside the forecast

Problem
Recipes in grams, purchases by the case, suppliers quoting kilos at variable pack weights, and the word "unit" meaning one thing to the chef and another to the supplier. The characteristic failure here is not five percent out, it is ten times out — and an order for ten times the fish is worse than having no system at all.
Options
One global unit table with conversions filled in wherever they are missing, or conversions bound to the exact thing they describe.
Chose
A conversion belongs to a specific ingredient, from a specific supplier, in a specific pack, and is established when that supplier is set up rather than inferred at order time. On top of that, an order line far above what that ingredient normally moves is stopped for a person to look at, whatever the forecast produced. That check is arithmetic and lives outside the model on purpose, so that improving the forecast can never quietly remove it.
Cost
More friction setting up a supplier, and a rule that will occasionally stop a genuinely large order before a big service. Blocking a legitimate order now and then is a far smaller problem than sending one absurd one, and that asymmetry is the entire reason the guard exists.