← back to the lab

Methodology

Every number in eta-lab is produced by the code in the repository and can be re-run with one command: npm run bench -- --recorded.

What the two runs are

Both runs execute the same seeded order set on the same real road network(OSRM on OpenStreetMap data, Berlin). Couriers drive real roads with identical speed assumptions. Only two things differ:

BEFORE (naive) — assigns the idle courier with the smallest straight-line distance to the restaurant, ignoring rivers, parks and one-way streets. When nobody is idle it waits FIFO for the next free courier. The customer gets a naive ETA: straight lines at a constant 25 km/h plus a flat 10-minute kitchen guess.

AFTER (smart) — assigns by real road travel time (OSRM table), including couriers that are still finishing their previous job (planned chaining). The customer ETA is road-aware: pickup ride overlaps kitchen prep (whoever comes later wins), then the delivery ride, plus a 2-minute operational buffer.

Determinism

Order arrivals, restaurants, customers, kitchen prep times and per-leg traffic noise are drawn from a seeded PRNG (mulberry32). Route durations come from OSRM; the exact values used for the published numbers are frozen in public/data/recorded-routes.json, so npm run bench -- --recorded reproduces the published tables byte-for-byte, offline. Re-running against live OSRM may shift numbers slightly when the road graph is updated upstream — the reports record the provider and date of each run.

Metric definitions

  • Pickup wait — order placed → courier picks up the food (includes dispatch wait and kitchen prep).
  • Delivery — order placed → food at the customer's door.
  • ETA error — actual delivery time − promised time; reported as MAE and p95 of the absolute error. Late — actual delivery later than the promise.
  • Deadhead km — kilometres ridden without food (courier → restaurant), summed and divided by orders.

What is modelled, what is not

  • Kitchen prep and road traffic are randomised per order with a realistic spread — both modes get the same draws.
  • Couriers start at real Berlin squares and stay in the district they last delivered to.
  • Not modelled: weather, handover frictions beyond 1 minute, batching (two orders per trip) — batching is a separate, larger lever we deliberately left out of scope.
  • Venue names are synthetic; coordinates sit on real streets. No real personal data is used.

Stack

Next.js (App Router) · TypeScript · MapLibre GL with the free OpenFreeMap Liberty basemap · OSRM public routing with an offline recorded snapshot · deterministic engine in plain TypeScript shared between the browser app and the Node benchmark script · deployed on Vercel.