Notes
Three alert rules and a simulated clock
Watch is meant to tell the nearest free colleague when a customer is waiting and nobody is near. The demo does not analyse video. It runs the alert logic on a scripted list of events and plays pre-recorded clips next to it. This post is about that logic, which is real code with tests, and about where the demo stops.
What the demo is
The store simulation is a list of events. A customer enters, moves to a zone, gets served, leaves. A colleague moves to a zone. Times are seconds since the store opened. The data file begins with "Illustrative sample data only. Nothing here is measured."
The clips next to the floor plan are pre-recorded footage. The boxes and the blurred faces in them were added offline when the clips were made. No detection or blurring code runs in the page, and the page sends no video anywhere. It plays files.
Three rules
The rules live in one small object.
export const RULES = {
waitSec: 120, // customer unserved in a service zone
highWaitSec: 240,
queueMax: 3, // alert when more than this many wait at the till
highQueue: 5,
unstaffedSec: 90, // staffed zone with nobody in it
};
- Waiting. A customer stands in a service zone that needs staff and has not been served for 120 seconds. The alert is high from 240 seconds.
- Queue. More than 3 unserved customers at a till. It is high at 5 or more.
- Unstaffed. A zone that needs staff has had nobody in it for 90 seconds. It is high if a customer is standing there, and low if not.
A customer who moves to a new zone starts a new wait, and counts as unserved again.
From events to a snapshot
A function called replay folds every event up to a given time into a snapshot. It records who is in which zone, who has been served, and since when each staffed zone has been empty. The rule functions read that snapshot and nothing else. There is no clock and no page code in this file, which keeps it easy to test. The repo has 15 tests for it, and 21 in total. We ran them on the demo branch and all 21 pass.
Opening and closing an alert
A second function, alertTimeline, steps through time in 5 second intervals and runs all three rules at each step. An alert opens the first time its condition holds. It closes when the condition stops. While it is open it keeps the highest severity it reached and the latest value. If the same condition comes back later, that is a new alert.
Here is what it produces for the optics store in the demo, which is Store 07.
alertTimeline for Store 07, in simulated seconds. Illustrative sample data.The numbers follow from the rules. The colleague at the eye-test area leaves at 150 seconds, so the zone has been empty for 90 seconds at the 240 second step. A customer walks into that area at 140 seconds and is still unserved at 260, which is 120 seconds later. Four customers are at the till by 330 seconds, which is one more than the limit of 3. Each alert closes when the situation ends: the colleague comes back, the customer is served, the queue shrinks to 3 or fewer.
What it does not do yet
Nothing here reads video. The step from pixels to "a customer is in the till zone" is not in this repo. The rules assume that step exists and hands them zones and ids. Whether the rules are correct is something the tests can tell us. How well a real camera feed would drive them is something we have not measured.
The demo also does not remember anything. Acknowledging an alert is held in memory, and it resets when the loop restarts. Nothing is saved.
The thresholds are five numbers in one object. If they look wrong for your store, tell us.