Skip to content

A cancelled ticket waits for nobody - #872

Merged
sridharkalaibala merged 1 commit into
developfrom
fix/a-cancelled-ticket-waits-for-nobody
Sep 17, 2026
Merged

sridharkalaibala merged 1 commit into
developfrom
fix/a-cancelled-ticket-waits-for-nobody

Conversation

@sridharkalaibala

Copy link
Copy Markdown
Contributor

The complaint

"when i very first time it took only few seconds to print. then after than it took almot 30 to 60 seconds."

What the till's log says

The printer was never the problem. Every print in the log is 50-63 ms:

18:37:54.971  [KOT] sale event -> printing now (created)
18:37:55.038  [KOT] Printed -> POS-80C (53 ms)

18:38:57.432  POST /api/sales/updateOrder        <- a cancellation
18:39:01.489  POST /api/sales/updateOrder        <- another
18:39:24.705  [KOT] Polling server...            <- 23 s and 27 s later
18:39:24.783  [KOT] Printed -> POS-80C (57 ms)
18:39:24.855  [KOT] Printed -> POS-80C (63 ms)

A new order announces itself and prints in 53 ms. The two cancellations announced nothing and were found only by the poller's 30-second safety net. The whole delay is discovery, not printing.

Why

updateOrderModel has two write paths. The cancel flow writes its change record at line 9677 and returns at 9682 without notifying. The edit flow's updateOne at 10028 does notify at 10036. The notify sat on the path that moves a table or changes covers; the path that actually produces a kitchen ticket returned one branch earlier.

So a cancellation was the only ticket in the product left to a timer. Nothing was lost, which is why it lasted - and it made two earlier rounds of work invisible: the cancellation had been barred from the fast byte path (#849), and its struck line cost 1,736 bytes a row whatever the dish (#850, now 188). Neither could show while the paper waited 30 seconds to be noticed.

The fix

notifyKotReady({ reason: 'cancelled' }) after the cancel flow's updateOne, gated on changesItems.length > 0 because changes[].items is what the poller builds a cancellation ticket out of - a cancellation with nothing printable must not wake the printer. The till's handler does not filter on reason (it logs it and polls after a 250 ms debounce), so a cancelled ticket now prints about 300 ms after the tap.

The test that should have caught it

tests/kot-event-driven.test.js counted notifyKotReady( calls in the whole 12,000-line file and matched reason: 'created' / 'updated' anywhere in it. Five sites in other methods kept it green while the cancel flow had none at all. It now slices the source between the CANCEL FLOW and EDIT FLOW markers and checks each flow inside its own branch.

New: api/tests/unit/repositories/a-cancelled-order-tells-the-kitchen.test.js cancels a real order against a real mongod and listens on the bus - the announcement, its branch, that the record is written regardless, and that an unprintable cancellation stays silent.

Both fail on the old code (Expected length: 1, Received length: 0; "the cancel flow returns without telling the kitchen") and pass on the new.

Tests

API 11,123 passed / 0 failed (398 suites). Desktop 2,912 / 2,912.

Shipping

This is API-side, so it needs the release to main to reach the cloud tenants, and a new installer for the till's bundled API. Exe rebuilt and staged.

Everything else that needs a kitchen ticket says so the moment it is saved:
the API is require()d into the till's own process, the sale emits on
`process`, and the printer runs within a few hundred milliseconds. The
cancel flow wrote its change record and returned one branch too early, so a
cancellation was the only ticket left to the poller's thirty second safety
net.

Nothing was lost, which is why it lasted. From the owner's counter: two
cancellations at 18:38:57 and 18:39:01, both printed by the 18:39:24 poll -
23 and 27 seconds of waiting, then 57 ms and 63 ms to print. "when i very
first time it took only few seconds to print. then after than it took almot
30 to 60 seconds."

It also hid two earlier rounds of work. The cancellation had been barred
from the fast byte path, and its struck line cost 1,736 bytes a row whatever
the dish; both were fixed, and neither could show while the ticket was found
by a timer rather than announced.

Gated on a change record existing, because `changes[].items` is what the
poller builds a cancellation ticket out of: a cancellation with nothing
printable must not wake the printer.

The test that covered this counted notifyKotReady calls in the whole twelve
thousand line file and matched its reason strings anywhere in it, so five
sites in other methods kept it green while the cancel flow had none. Each
flow is now checked inside its own stretch of the method, and a new test
cancels a real order against a real mongod and listens.
@sridharkalaibala
sridharkalaibala merged commit c2217e7 into develop Sep 17, 2026
9 checks passed
@github-actions github-actions Bot added the ready for QA Merged to develop and live on develop.posnic.io - anyone can test it label Sep 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Merged to develop. Anyone can test this - you do not need write access.

Try it at https://develop.posnic.io, or run it yourself:

git fetch origin develop && git checkout develop
npm install && npm --prefix api install
npm run dev   # then http://localhost:3000

When you have tested it, say what you did and what happened, and set
QA passed or QA failed. If you cannot set labels, just comment -
a maintainer will.

Reporting that something is broken is as useful as fixing it. It is
better found here than by a shopkeeper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for QA Merged to develop and live on develop.posnic.io - anyone can test it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant