Payouts · Money · Food halls

The preview showed fifty instalments. It saved twelve

A payout preview had no ceiling on instalments and the raise capped at twelve, then dropped the dates it was given. Now both refuse the same things.


A food hall pays its kitchens on a schedule, and sometimes a payout is better split into parts: a big week settled in three instalments rather than one lump. Our payout screen has a preview that shows what will be raised, and a button that raises it. The preview’s own comment in the code says it is the same calculation as the raise. It was not, quite.

Where they disagreed

We asked both for £1,000 over a week in fifty parts. The preview happily showed fifty instalments that reconciled to the penny. The raise quietly capped the count at twelve and saved twelve. Nothing told anyone that thirty-eight of the parts they had just looked at did not exist.

The dates were the worse half. When a payout is split you can give it a date per part, and the raise only kept that list if its length matched the number of parts. It compared against the capped count. So thirteen dates for thirteen parts became twelve instalments all falling due on the same day, which is precisely what splitting a payout exists to prevent. Twenty lines earlier the code had walked the balance forward to pick sensible dates, then threw them away.

Nobody had hit it

The office screen offers a split of one to four, so no shipped button could reach the ceiling. This was a trap waiting for whoever widened that menu, not a fault a hall has lived with. It is worth a small release and an honest note, not an apology.

Refuse, do not clamp

A clamp has to throw something away silently, and this one threw away two things. Both routes now share one answer: a single ceiling of twelve parts and a single check that the dates match, and when they do not the request is refused with a sentence that says what to do. Thirteen dates for twelve instalments gets: give one date each, or none at all and they all take the first date. The preview and the raise cannot drift again because they are asking the same function.

What running it corrected in us

Reading the two routes side by side, we also thought the raise was missing the preview’s check that the period runs forwards, so a backwards period would be accepted as a payout. It is refused. The raise calls a shared period calculation before it writes anything, and that calculation refuses an inverted period for both of them. A route with no check of its own, correct because of the call it already makes. Had we fixed it from the reading alone we would have patched something that already worked.

The fences were checked while we were there: every read of a payout goes through the same visibility test, both writes require the payment permission and the venue check, and the standing charge is recomputed on the server rather than trusted from the request. The test we left behind pins the agreement, not the number twelve: whatever the preview accepts the raise honours part for part and date for date, and whatever one refuses, both refuse.


Try it on tonight’s service.

Nothing to install, no card. Not better by the weekend? Close the tab.