# The dispatch algorithm, demonstrated

```powershell
php artisan dispatch:demo --fresh
```

Needs Redis running. Uses `FakeRoutingEngine`, so it needs no Google key and no network — which
is the point: the whole pipeline can be shown, argued with and regression-checked today, and the
day a real key arrives only `DISPATCH_ROUTING_ENGINE` changes.

## What it shows, in order

**1. The ranked list, with the arithmetic beside each captain.** Distance, road ETA, how long a
busy captain needs to finish what they are carrying, the handoff buffer, and the Adjusted ETA that
decides the order.

**2. The claim the whole design rests on: the closest captain is not the fastest.** The command
compares the nearest captain with the winner and says which is which. In the worked example a
captain 0.01 km from the store ranks fourth, because they still have to finish a delivery and hand
it over, while an idle captain 1.5 km away can simply drive. *Phase 1 only filters by distance;
Phase 2 decides.*

It says so either way. "Nearest also won" is a legitimate outcome — it means that fixture did not
separate the two — and a demo that only ever announces the happy case is one nobody believes
twice.

**3. Who was excluded, by not appearing.** The scenario seeds captains the rules must reject: one
at capacity, one whose GPS has gone stale, one on a break, one offline. None of them reach the
list.

**4. The assignment, and the route the captain is told to drive.** Stops in order, the leg to each
one, and the arrival time.

**5. A second order joining the same captain.** The route is *rebuilt*, not appended to: both
pickups are collected before either drop-off, because a captain cannot hand over a parcel they
have not picked up.

**6. The promise kept.** The first customer's arrival time before and after, against
`MAX_BATCH_DETOUR_MIN`. The batch check refuses a batch over that limit before the order is ever
assigned, so this printing a breach would mean the batch check and the route planner disagree.

## Options

| | |
|---|---|
| `--fresh` | Re-seed the worked example first. Use this every time unless you are deliberately continuing a run. |
| `--order=ORD-990002` | Dispatch the two-store order instead of the single-store one. |

## Things worth knowing

**It runs the queue inline.** The route plan is built by a queued job, and a demo has no worker.
The command sets the queue to `sync` for its own run so the plan appears here instead of waiting
in Redis for a worker nobody started — the same listeners, the same job, the same service.

**`--fresh` clears the replan locks, and it has to.** `RecomputeRoutePlan` is unique per captain
for two minutes. A run that dispatched it to a real queue with no worker listening leaves that
lock held, and the next run's recompute is swallowed as a duplicate — the captain is assigned the
order and silently gets no route, with nothing in the output to say why. That is how the
repeatability bug was found, and `DemoCommandTest` now runs the command twice in a row to keep it
found.

**The plan version counts the captain's whole history.** Run the demo repeatedly and you will see
version 5 and 6 rather than 1 and 2. That is the real number the apps compare on, so it is printed
as it is.

**Other seeded captains compete.** The demo runs against whatever fleet is in the database, so on
a development database the scenario captains share the list with `DriverSeeder`'s. That is honest
— it is the same query a dispatcher makes — and the nearest-versus-winner line adapts to whoever
actually turns up.
