A fuel distributor ran deliveries across several regional branches. Every branch took its orders the same way: a customer sent a WhatsApp message, someone read it, worked out what was being asked for, and decided by hand where it fitted into a truck already out on the road.
That process worked. It was also the constraint on the whole operation, because the quality of a day’s deliveries depended on how busy the person reading the messages happened to be at the moment each one arrived.
A note for readers in the United States, where WhatsApp is a personal messaging app and rarely a serious business channel. Across much of Latin America, South Asia, Africa and southern Europe it is the opposite. It is the default way customers reach a business, often the only way, and companies build their customer operations around it because that is where their customers already are. In this case the distributor’s own website did not offer an order form. It detected the visitor’s location and handed them to the WhatsApp number for their nearest branch. The messaging app was the front door.
That is worth sitting with if you operate internationally, because it inverts a common assumption. The channel is not a consumer convenience bolted onto a real ordering system. It is the ordering system, and everything downstream depends on a person reading it correctly.
We built a working demonstration of the alternative in a matter of weeks. The interesting part was not the routing engine. It was deciding which constraints were real.
What the problem actually was
Not route optimisation. Optimisation was the visible half; intake was the expensive half.
Customers write the way people write. Lowercase, no accents, no address format, no volume unless you ask. A message saying the restaurant is out of gas and needs some before lunch service contains a customer, a neighbourhood, a service type, an implied volume and a hard deadline, none of them labelled. Someone had to read that, infer the missing pieces, and decide whether the order could be served today.
Meanwhile the truck was already out. Any new order had to fit into a route in progress, without reshuffling the stops the driver had already passed.
Unstructured input arriving continuously, against a plan already in motion, under constraints that could not be broken. The hard part was not computing a better route. It was knowing which constraints were real and which were preferences.
Which constraints turned out to be real?
Four, and none of them were in the original brief.
The truck cannot be filled. A tanker with a nominal capacity has a lower working capacity, because the product expands and the vessel needs vapour space. Every load calculation runs against the lower number. A system that plans against nominal capacity produces routes that cannot legally be driven.
Delivery windows are not preferences. Some stops close at a fixed time. One was a nursery school. Ignoring windows produced a route that was measurably shorter and visibly tidier on the map, and it arrived at the nursery ninety minutes after it closed. The tidier map was the non-compliant one.
The shortest route is not always the permitted one. Hazardous materials carriers are required to choose routes on safety grounds and avoid population centres where a bypass exists. An engine that minimises time will route straight through one. That is not an inefficiency, it is a compliance failure, and no amount of optimisation quality compensates for it.
Delivery addresses are personal data. Which meant the demonstration had to run entirely on synthetic records, and the eventual system needed somewhere to put an order that was not a chat thread. The messaging app is an intake channel, not a record.
Learning those four things took longer than building the routing engine. That is the usual ratio, and it is the part that does not appear in a demo.
What we built
Three pieces, with a person at the end of them.
Interpretation. A message arrives as free text. The system extracts the customer, the location, the service type, the estimated volume and the urgency, and separately lists what a dispatcher would still need to ask before confirming. That last output matters more than the first. A system that knows what it is missing can ask; a system that guesses produces a confident wrong answer.
Sequencing. The order is inserted into the route already in progress, with completed stops locked. Load is checked against working capacity, arrival times against delivery windows, and the whole thing against the length of the shift. A full solve runs in roughly forty milliseconds, a re-solve in under five.
A reply that commits to something. The customer receives a confirmation with an actual delivery time, derived from the route, rather than an acknowledgement.
Why does it price a bad order instead of refusing it?
Because refusing removes a decision that belongs to a person.
This was the design question that mattered most. Consider an order that fits the truck comfortably but sits well off the day’s route. In our worked example it added under a kilometre of driving if it fell on the corridor the truck was already covering, and nearly seventeen kilometres, thirty-three minutes of shift and sixty times the fuel cost if it did not. Both orders fit. One is cheap and one is expensive, and nothing about the tank tells you which.
The system does not decline the expensive one. It tells the dispatcher what the detour costs and asks whether to send it today or first thing tomorrow.
The system does not promise what the operation cannot deliver, and it does not decide what a person should decide. It prices the choice and hands it back, before anyone calls the customer.
There is a second kind of refusal that is genuinely a refusal. When the load would exceed working capacity, the answer is no, because no amount of willingness changes what fits in the tank. Keeping those two cases distinct — one is geography, one is physics — is the difference between a system an operations team trusts and one they learn to override.
Why did we show the number that made us look worst?
Because a sharp operations person would have found it themselves, and finding it themselves would have cost us the room.
Our first baseline sequenced deliveries in the order they were received. Against that, the optimiser saved thirty-six percent. We threw the number out, because nobody dispatches that way and the comparison was a strawman.
So we built harder baselines: deliveries grouped by zone and sequenced hurriedly, and the same grouped by zone and sequenced carefully. The results were uncomfortable.
| Approach | Distance | Shift ends | Windows missed |
|---|---|---|---|
| Order received | 219.9 km | 19:32 | 1 |
| By zone, hurried | 175.7 km | 17:43 | 2 |
| By zone, careful | 133.0 km | 15:59 | 1 |
| Optimised | 132.2 km | 16:04 | 0 |
Against a hurried manual route, the engine saves nearly twenty-five percent. Against a careful one, it saves 0.6 percent. We built the interface to show that as a range rather than the flattering end of it.
The durable claim is the last column. Every manual approach misses at least one delivery window. The optimised route misses none. A percentage does not survive meeting a good dispatcher. Catching the window they miss, at eleven in the morning when a new order lands and they are doing three other things, does.
This is the same argument we make about what to automate first in a logistics operation: the honest version of a claim outlasts the impressive one.
What it could not do
We shipped a panel listing its own gaps, and walked through them unprompted.
The demonstration handled intake and sequencing. It did not handle compliance: route risk screening against population centres, validating that a delivery falls inside the routes a permit actually authorises, checking that an assigned vehicle is registered, inspected and insured, pre-trip inspection as a gate on dispatch, and incident reporting against a regulatory clock.
Naming those before being asked is not modesty. A buyer who discovers a gap themselves stops believing the parts that work. It is the same reasoning that puts human review and audit trails into a system at design time rather than after it is running.
We were equally explicit about what was real and what was staged. The interpretation and the routing ran live on every request. The delivery data was synthetic, the truck’s position was fixed, and distances were modelled rather than measured turn by turn. Saying so in the first three minutes reads as engineering judgment. Being found out later reads as a bluff.
What we asked for next
One week of real dispatch data from one branch, under a short data agreement, so the demonstration could be re-run against actual routes and produce a real number instead of a modelled one.
That is the whole method. Build enough to make the problem concrete, be exact about which parts are real, and ask for the one thing that turns a modelled number into a measured one.
Weeks, not months, in an industry we had not worked in before. The engineering was the fast part. Learning which constraints could not be broken was the work.
We can walk through the working system on a call. It is driven live rather than linked, because the part worth seeing is what it does with a message nobody prepared for it — including one you make up while watching.
If you have a process where unstructured messages turn into operational decisions, that is the same problem in different clothing. Tell us what it is.