Let's talk
engineering

The booking screen named a driver who was never assigned

In a car rental system, nine places answered who the driver was. Eighty-one legs got an arbitrary answer, sixteen named the wrong person, seventeen a phantom.

· · updated

A phone in a hire car at a kerbside handover; beside it the Sazinga Rentals driver app booking card naming the drop-off driver.

A customer gets a confirmation naming the person who will bring the car. The dispatch board shows someone else, or shows the pick-up as unassigned. Sometimes the confirmation names a driver, with a phone number, who was never given that job. You cannot tell which screen to believe, and neither can your staff.

That was the state of a car rental business’s system after we fixed a fault that had written a driver’s name onto the wrong record. The obvious next question was whether anything else looked up the driver as carelessly. It did, in eight more places.

What was actually going on

The places were ordinary: the bookings list, the booking detail screen, a lookup by reservation code, an active-booking view, a photo page, two customer-facing pages and the booking PDF. Each one worked out “who is the driver on this leg of the journey” in its own way. None of them ignored deleted records, and none of them picked the newest one. Only the assignment board did it correctly, because it had been rewritten a fortnight earlier and its author happened to think about it.

We measured before changing anything, because “this could be wrong” and “this is wrong on 81 bookings” are different conversations to have with a client.

Eighty-one legs, across eighty live bookings, had both a current record and a deleted one. Which one a screen showed was arbitrary. On sixteen of those, the two records named different people, so the screen showed the wrong driver. Not a blank or an error, somebody else’s name.

Eighteen other legs had only a deleted record, and on seventeen of them that record still named a driver. Those screens reported a phantom assignment, a driver with a name and phone number on a leg the assignment board correctly showed as unassigned. Two views of the same data gave opposite answers. The same counts appeared in the test copy of the database, which ruled out a one-off artefact of a past clean-up.

The cause was not carelessness. “Who is this leg assigned to” has a real answer, the newest current record for that leg, and it existed nowhere as a single thing to ask. It lived as a habit in the heads of the people who wrote each screen.

What we changed

There is now one lookup that answers the question, and every one of the nine places uses it. It ignores deleted records, takes the newest current one, and recognises the leg by how its name begins.

That last part needed care. The leg name is free text, written at least six different ways over the life of the system. Our first draft matched a fixed list of spellings, which is exactly the mistake that a comment in another part of the code warns about: a list silently loses any spelling nobody thought of. I had read that warning earlier the same day and wrote the thing it warns against anyway, then caught it before it was wired in. Matching by the beginning of the name classifies every current record on both databases with none left over.

To check the new lookup, we ran it against every current leg and compared it with the assignment board, the one screen known to be right: 5,425 legs in production and 5,337 in the test copy, with no disagreements. Comparing against a second implementation you trust is stronger than a test that only confirms what its author expected. The eighteen phantom legs now correctly show no driver.

Fixing the reads exposed a data problem. Seventeen legs on expired or completed bookings had only deleted records, because a duplicate clean-up months earlier had deleted 115 records and left some legs with none current. Every screen now correctly showed no driver on pick-ups that had certainly happened. The history could not be rebuilt from the audit log, because every past removal had been logged with no driver name, a separate fault fixed that week, too late for these rows.

A one-off repair restores exactly one record per affected leg, the newest that names a driver, with a check that stops it restoring a duplicate or running twice. It was tried read-only first on both databases: seventeen rows each, no duplicates. After it was applied, legs with no driver went from eighteen to one on both. The last one has no driver on any record, so there was nothing to restore.

Reinstating records on old bookings might have put old jobs back on drivers’ phones or inflated the dashboard. We checked that specific fear by running the real functions against production data. The app’s job list only looks at recent dates, and the monthly count had already been changed to exclude closed bookings. A driver whose seventeen expired bookings were reinstated still sees two jobs, not nineteen.

What it did not fix

The one leg with no driver on any record is still blank. The repair chooses the newest record that names a driver, which is the best available evidence, not proof of who actually drove.

The pattern, for anyone whose screens disagree with each other

If two screens give different answers to the same question, look for the question being answered in more than one place. The test is simple: is there one named thing that answers it, or is it a habit each screen repeats? A habit held in nine heads decays, and the decay is invisible because each copy looks reasonable alone.

When your data is repaired, write down the specific thing you are afraid the repair will do, then check that. “The repair ran” is not a check. “The driver whose seventeen expired bookings came back still sees two jobs” is.

Where this ends up

That single lookup is now the only place Rentals works out who is driving, so the booking screen, the customer view and the printed document cannot disagree about it.

This came out of building Sazinga Rentals

Bookings, availability and the fleet standing behind them. The problem above is one we met while building it, and what we did about it is in the product.

If you run something like this, there is one thing you can do without a call: send one week's booking sheet.