Let's talk
product

The board showed fifty jobs. There were a hundred

The owner asked whether the operations board told the truth. Its two busiest queues showed the fifty newest jobs and hid the oldest; two columns were always empty.

· · updated

An operations desk with a laptop showing the operations board in Sazinga Rentals.

Every morning your office opens one screen and works from it: which cars are going out today, which are due back, which returned cars still need checking over, which bookings are waiting to be settled. The counts in the column headers are how you judge the day. Forty settlements to do is a different morning from ninety-five.

The owner of a self-drive car rental business in Goa (the system behind GOI Car & Taxi) asked a plain question about that screen: is it telling us the truth? For the two queues that matter most, it was not. The post-return audit column said 50 when there were 100. The settlement column said 50 when there were 95. And the fifty it chose to show were the newest returns, which meant the ones it hid were the oldest: 45 settlements from returns between 19 July and 8 August, and 50 audits from returns between 27 July and 10 August, every one older than anything on the screen. A work queue that hides its backlog and shows only the fresh arrivals is the exact inverse of what it is for.

Two other columns had been empty for as long as anyone could remember, and the owner wanted to know whether they were needed at all.

What was actually going on

Each queue on the board was cut off at fifty rows to keep the page fast, and the count in the header was taken after the cut. So the header could never say more than fifty, however long the real list was, and the summary strip across the top, which added up the same cut-down lists, was short by the same amount. The cut would have been survivable if the oldest rows had been kept. These two queues were the only ones on the board sorted newest-first, so the cut threw away precisely the overdue work.

The empty columns were two separate stories, and measuring rather than reasoning gave opposite answers. “Drop-off due” was legitimately empty: on the day we looked, 15 cars were out on the test system and 25 on the live one, and not one was due back that day or overdue. That column is an exception monitor correctly reporting nothing wrong. “Pickup handover” should have shown six bookings, six cars going out that day with no odometer or fuel reading captured yet, which is exactly what the column exists to surface. It showed nothing because of a slip in the code that built it: the list was copied by name rather than by value, then emptied, then filtered, and since both names were the same list, it filtered an empty one. The settlement queue had the identical slip, which corrected something we had told the owner that same morning. We had reported it as showing 50 of 95, from reading the row cap. It had in fact been returning nothing at all.

Also found: the date filter on the three pickup queues excluded nothing, because it asked for pickups today or later, or before today, which is every booking. So those queues ran out to the end of December. And four bookings in both databases carried an old status that no column matches, so they were invisible to the board entirely.

What we changed

The cut-off was raised to 500 so real volumes are never trimmed, and if it is ever reached the header now says “500+” in amber rather than a short, confident number. The flag is worked out from the database count, not from what survived the filters, because the whole defect was a count that silently meant “at least this many”. The two backlog queues were flipped to oldest-first, so settlement now opens on a return from 19 July and audits on one from 27 July. The copy-by-name slip was replaced with a plain filter in both queues, and both now populate: six and ninety-five on the test system. A column that never meant what its label said, “Drop-off due / overdue”, was renamed “Return not started”, because every one of the 14 cars due back that day was on the board already, 12 of them one column across. Deployed to both stacks the same day.

What it did not fix

Whether the pickup queues should be bounded to a window of days is the owner’s decision, and it was not smuggled in as a bug fix. The filter that did nothing was replaced with an honest one that does nothing on purpose, with a note saying so.

The four bookings in the unmatched status were flagged and left. The settlement queue also filters on invoices not yet finalised, and with no invoices anywhere in the system yet, that filter removes nothing, so the queue can only grow until invoicing is in use.

And the day produced one wrong answer given to the owner and corrected within hours. Reading the code found the cap; only running the query found the empty list behind it.

The mechanism, briefly

A per-queue row cap with the header count taken post-cap, on the only two queues ordered by drop-off descending; a tautological date predicate (pickup >= today OR pickup < today); and an aliasing bug where const filtered = raw; filtered.length = 0; filtered.push(...raw.filter()) cleared its own input. Fixed with a 500 backstop, a truncation flag computed from the database count, ascending order on backlog queues, and plain filters into new arrays, measured against real data rather than reasoned from the source.

Where this ends up

A board the office has stopped believing is a board the office stops reading, which is why the operations view in Sazinga Rentals counts what is in the database and shows the oldest work first.

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.