The optimiser made a plan and the desk rebuilt it by hand before eight
In short
When a dispatch desk rebuilds the same parts of an optimised plan every day, the model is missing constraints the desk holds in its head. The test is recurrence: log every manual edit for 2 weeks with a reason code, cluster by edit type and stop, and any edit repeating on more than half the days is a constraint rather than a preference.
Key takeaways
- Recurrence separates a missing constraint from a judgement call. The same edit on more than half the observed days is a constraint the model does not hold.
- Log the edit as a diff against a frozen published plan, with a closed list of 6 to 8 reason codes. A longer list collapses into one code used for everything.
- Cluster edits by type and stop, never by dispatcher. 2 planners making the same edit is the strongest evidence you will get.
- Some edits point at the objective rather than the data: a plan minimised for distance will always look wrong to a desk judged on windows kept.
- Not every constraint should be modelled. A rule affecting under 2 per cent of stops and changing weekly is cheaper as a pre-assignment the solver must respect.
If the desk rebuilds part of the plan every single morning, the plan is missing constraints the desk is holding. That is the first thing to assume, ahead of change resistance, ahead of trust, ahead of the interface. A dispatcher who moves the same 12 stops every day is not rejecting optimisation. They are patching it, by hand, at speed, against a specification nobody has ever written down.
The distinction that matters is recurrence. A plan that gets edited differently every day is being edited by judgement — traffic news, a phone call, a driver ringing in sick — and that is a healthy desk doing its job. A plan where the same edit reappears on 3 consecutive days is a plan with a hole in its model. Everything else in routing, dispatch and optimisation depends on knowing which of the two you have, and you cannot tell by watching.
Two weeks of edits, each with a reason attached
The instrumentation is small and the discipline is the hard part. You are building a dataset whose unit of observation is one manual change, and whose purpose is to survive an argument with an operations manager who believes the desk is simply set in its ways.
- Freeze the published plan. Before the desk touches anything, snapshot the plan version, the vehicle assignment for every stop, and the sequence position. Without this baseline you are comparing the final plan against nothing.
- Capture each change as a diff, not as a final state. One record per edit: edit type, the stop or vehicle affected, the planner, the timestamp, and the before-and-after values.
- Offer 6 to 8 reason codes and no more. Something like access restriction, customer relationship, wrong time window, vehicle will not fit, service time too short, load will not fit, promise at risk, other. A longer list gets one code used for everything, and the free-text box beside it is where the real information lands.
- Run it for 10 working days at minimum. Fewer and you cannot tell a Tuesday from a pattern; 10 days also picks up the weekly rhythm of a delivery schedule, which is where most territory edits live.
- Cluster by edit type and stop, never by planner. Two different dispatchers making the same edit independently is the strongest evidence this exercise can produce, and grouping by person hides it.
- Rank each cluster by frequency multiplied by the plan minutes it added or removed. A frequent edit that costs nothing is a preference. An occasional edit that adds 40 minutes to a round is a constraint worth modelling.
The five edits that keep coming back
Across delivery, collection and service work the recurring clusters are remarkably consistent, and 4 of the 5 are data faults rather than modelling faults. The 5th is a different animal.
| The edit you keep seeing | What is missing | Where it belongs |
|---|---|---|
| The same customer moved to the same driver, every day | An access or relationship constraint living in one person's memory — a key, a gate code, a site induction, a language | An allowed-vehicle or allowed-driver set on the stop, or a skill code on both sides |
| A stop dragged earlier, past what the window seems to allow | The recorded receiving hours are wrong, or the window is recorded as soft when the site treats it as absolute | The stop's window and, more often, its enforcement class |
| A large vehicle swapped out on one specific round | A physical site restriction absent from the data — a height barrier, a bridge, a bay a rigid cannot reverse into | The vehicle profile plus a per-stop vehicle exclusion |
| Extra minutes padded in at three or four named stops | Service time is a fleet-wide average that is badly wrong at these stops — a long walk, a goods-in queue, a signature chase | Per-stop service time, measured rather than estimated |
| Whole rounds re-cut across the same territory boundary | Nothing in the data. The objective is minimising distance and the desk is judged on windows kept | The objective weights — a management decision, not a data fix |
A dispatcher's hands are the requirements document. Nobody has read it, because nobody ever wrote it down.
When the last row is what you are looking at
The first 4 rows are fixable by putting a fact into a field. The 5th is not, and it is the one most often misdiagnosed as stubbornness. If the solver is minimising total distance or total driving hours while the desk's own performance is measured on windows kept and customer complaints avoided, the two are optimising different things and the desk will win, because the desk is the one being appraised. No amount of training closes that gap. The weights in the objective function are a policy statement, and somebody chose them — usually whoever configured the software, usually without being told they were making a commercial decision. That argument has its own page in what optimal meant and who chose it.
The tell is that these edits do not target specific stops. They redraw boundaries and rebalance whole rounds, and the dispatcher struggles to give a reason code for them because the reason is a value judgement rather than a fact about a customer.
Testing a claimed constraint before you encode it
Not everything the desk says is a constraint is one. Habits accumulate, and a rule that made sense when one depot served forty customers survives long after the reason has gone. 3 questions separate the 2, and all three are answerable from data you already hold.
- What happens if we break it? If the answer is a failed delivery, a locked gate or a penalty clause, it is hard. If the answer is that someone will be annoyed, it is a cost, and it belongs in the objective as a penalty rather than in the model as a wall.
- Has anyone else ever served this stop successfully? Query the delivery history. A customer who has been served by 9 different drivers over 12 months does not need a driver lock, whatever the desk believes.
- Does it apply to the stop or to the day? A constraint tied to a stop is stable and worth encoding. A constraint that only bites on the day a particular product is loaded is conditional, and encoding it unconditionally will produce plans the desk edits in the opposite direction — which is how a fix creates a new recurring edit.
Deciding what to model and what to leave in a human's hands
Every confirmed constraint ends at one of two places, and the second is a legitimate destination rather than a failure. Model it when it is stable, affects a meaningful share of stops, and can be expressed in the engine you have. Leave it human when it changes week to week, touches under roughly 2 per cent of stops, or cannot be represented without contorting the model.
Leaving it human is not the same as leaving it as an override. The mechanism that makes it work is a pre-assignment: the desk pins the stop to a vehicle before the solve, and the solver treats the pin as an input it may not break. The edit stops being a correction after the fact and becomes a constraint the plan was built around, which means the plan's own reported travel time is finally telling the truth. Capacity dimensions are the common case where an engine genuinely cannot express what the desk knows — a load that is simultaneously heavy, bulky and in cages is the subject of modelling weight, volume, pallets and cages together.
Four reasons the desk will keep rebuilding anyway
- The plan arrives after the desk needs it. If the solve finishes at 06:40 and the first of 24 vans loads at 06:30, the desk rebuilds from yesterday's plan regardless of quality — the deadline problem set out in the solve still has not finished and the first van is loaded.
- The plan comes back with stops missing. Nothing destroys confidence faster than a plan the desk has to complete, and the causes are diagnosable one constraint family at a time in the plan came back complete and forty stops are not in it.
- The vehicle list does not match the yard. If the optimiser plans around a van that is off the road, or starts a route from a depot the vehicle left last night, every plan needs correcting before it can be read. Which telematics path feeds that state is a real decision — see device ingest versus a provider API.
- The desk has no way to see why a stop sits where it does. An unexplained sequence gets relitigated every morning by whoever opens it first, and the fix is an explanation surface rather than a better plan.
Once the recurring edits are down to a handful, the logging itself becomes the thing worth keeping. A standing job that clusters last month's overrides and flags any new pattern turns a one-off exercise into a permanent feedback loop between the desk and the model, which is ordinary operations automation rather than anything exotic. Whoever builds it should be able to explain the model's constraint set to the desk in plain language — a fair test to apply when choosing an AI development partner, and the difference between a working plan and shelfware in most logistics and mobility projects.
Frequently asked questions
Short answers to the follow-ups this page tends to raise.
How do I tell a missing constraint from a dispatcher who dislikes the software?
Count how often the same edit repeats. A constraint produces the same change on the same stop or driver pairing day after day; dislike produces scattered, inconsistent edits that do not cluster. Over 10 observed days, an edit recurring 6 times or more is a defect in the model. Under 3 is judgement, and should be left alone.
What should a manual override log record?
One record per edit, holding the edit type, the stop or vehicle affected, the before-and-after values, the planner, the timestamp, and a reason code chosen from a short closed list with free text beside it. Capture it as a diff against a frozen published plan rather than saving the finished plan, because the finished plan tells you what happened and not what changed.
Should every constraint the dispatchers name be added to the model?
No, and adding them all is how a route model becomes unsolvable. Encode constraints that are stable, affect a meaningful share of stops, and are expressible in your engine; handle the rest as pre-assignments the solver must respect. A rule that changes weekly and touches a handful of stops costs more in model complexity and lost solutions than it saves.
The desk redraws whole territories rather than individual stops. What does that mean?
That the objective function is optimising for something other than what the desk is measured on. Stop-level edits point at missing data; boundary-level edits point at weights. A solver minimising distance will keep producing plans that a desk judged on windows kept and complaints avoided will keep rebuilding, and the fix is a management decision about weights rather than another field in the stop record.
- route optimisation
- dispatch
- constraints
- adoption
The work behind this page
Builds from our portfolio that this page draws on.
Read next
- The plan came back complete and forty stops are not in itA solver that reports success while leaving forty stops unassigned is answering a different question from the one you asked. Relaxing one constraint family at a time tells you which.diagnostic
- The solve still has not finished and the first van is loadedMost teams tune the solver and wait longer. In production systems the matrix is usually the slow half, and no search parameter touches it.diagnostic
- Service time: the minutes at the kerb that decide the planEvery route plan carries an assumption about how long a stop takes. In most fleets it is one number, applied everywhere, and nobody has ever measured it.definition
- The route crosses itself twice and the driver has already resequenced itA route that doubles back is either obeying a constraint the map cannot draw or genuinely bad. Only one of those is fixed by re-optimising; the other is fixed by explaining.diagnostic
- The travel-time matrix: the input that decides the planThe solver never sees a road. It sees a table of durations between every pair of stops, and every mistake in that table becomes a plan that cannot be driven.definition
- Vehicle profile: why a car route and a truck route are different networksA consumer navigation route given to a heavy vehicle is not a rough version of the right answer. It is a route through roads the vehicle is not allowed to use.definition
Working on something in this space?
Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.
Start the conversation