Skip to content

Latency budgets

CounterFire is judged by one unbroken loop, and that loop has explicit wall-clock budgets. The budgets are not aspirations; they are asserted in the automated test suite so a regression turns the pipeline red instead of silently shipping.

The budgets

PathBudget
Paid order appears on the KDSunder 2 seconds
86 a dish reaches the customer portalwithin a few seconds
Customer places an orderunder 60 seconds (a usability target for the flow)

The first two are platform latency budgets the system is engineered and tested against. The third is a user-experience target for how long checkout should take a customer, and it shapes the customer portal design (sticky category tabs, a one-tier modifier sheet, a persistent cart with a live subtotal, guest checkout).

What spans each budget

Order to KDS, under 2 seconds

When a customer pays, the chain is: the Worker handles POST /v1/orders/:id/pay, emits the order_paid event, writes it to the D1 order_event log, and OrderHub fans it out to connected KDS clients, where a new ticket appears and the chime sounds.

To keep this under budget, the paid event is emitted to OrderHub before or in parallel with non-critical work, so the ticket is not waiting on anything the kitchen does not need.

86 to portal, within a few seconds

When an owner toggles a dish sold out via PATCH /v1/products/:id/sold-out, the chain is: the Worker flips is_sold_out, invalidates the MENU_CACHE entry for that restaurant, and the next customer menu load no longer offers the dish.

To keep this under budget, the menu cache is invalidated synchronously with the write, so there is no stale window in which a customer can still add a sold-out item.

Why measurement matters

These budgets span several moving parts: the Worker, the OrderHub Durable Object, the D1 write, and cache invalidation. Latency that crosses that many layers regresses silently if nobody is watching it. The mitigation is to measure it: explicit wall-clock assertions are baked into the Playwright end-to-end suite, so the budgets are continuously verified rather than assumed.

Where the budgets are enforced

The CI pipeline runs on every change: typecheck, lint, unit and Workers-runtime tests (with the 100 percent coverage gates on packages/core and on the apps/api business logic), component tests, then Playwright end to end. The latency assertions (order to KDS under 2 seconds, 86 to portal within a few seconds) are part of that end-to-end stage. Merges are blocked unless every stage passes, which keeps the budgets measured and the signature loop reliably green.