note
The bug.
An intern came back from lunch. Tapped "End lunch" on their phone. Walked back into the work area. By the time the coach checked the dashboard fifteen minutes later, the intern was still showing as "On lunch."
It happened twice in one week. Different interns, different days, same symptom. The tap had registered visually — the button had animated, the screen had advanced — but somewhere between the tap and the database, the event had been lost.
Why it happened.
The original implementation used a short timer. When an intern tapped "End lunch", we'd wait three seconds before persisting the event, in case they wanted to undo. The undo was a thoughtful touch — we don't want a fat-finger tap to break their working day record. But three seconds is an eternity on a mobile browser.
What we hadn't accounted for: mobile browsers throttle background JavaScript aggressively. If the intern locked their phone, or switched to a different app, or walked into a low-signal area in those three seconds, the timer would never fire. The event would sit in memory, the database would never hear about it, and the dashboard would lie.
The rule we wrote into the engineering doc.
After the second occurrence, we made a decision: any user action that an intern might walk away from after performing has to persist to the database synchronously, before the screen transitions away from the action.
This rules out a whole pattern of UX we'd been using — optimistic UI with delayed writes. It also rules out the undo affordance, at least in its original form. If a user wants to correct a mis-tap, they now do it from the timeline view, not from a three-second window after the action.
What we trade off.
The new pattern is slower in good network conditions. The user waits — briefly — for the write to complete before the screen advances. We add a small loading state. It feels less snappy.
We've accepted that trade. Snappy is a nice-to-have on a productivity app. The integrity of the working-day record is a non-negotiable on a safeguarding-relevant platform that feeds into EHCP reporting. Snappy lost.
The broader lesson.
It's tempting, especially when you're shipping fast against a live cohort, to optimise for the happy path — the path where the network is good, the phone is awake, the user is paying attention. But the platform doesn't live in the happy path. It lives in noisy fulfilment centres, on phones that sometimes lock, with users who legitimately walk away from a tap.
Build for the moment the user might walk away. Everything else is easier.
