A late flag does not measure whether somebody was late. It measures the distance between a punch and a number in a schedule, and when half your records are flagged, the schedule is the thing that is wrong.
We found this in our own production data. Of 40,970 attendance records, 20,296 carry a late flag. That is 49.5 per cent. The mean lateness across those flagged records is 271 minutes.
Four and a half hours. Half the time. That is not a workforce problem.
What the number is really made of
A lateness calculation has two inputs: the time somebody punched, and the time they were supposed to start. The first comes from a terminal and is close to unarguable. The second comes from a roster, which somebody configured, possibly months ago, possibly for a different shift pattern than the one currently being worked.
The subtraction is trivial. The trouble is that all the uncertainty sits in the second number and none of it in the first, so a system reports lateness with the confidence of the terminal and the accuracy of the roster.
When a night-shift employee is attached to a day-shift schedule, the arithmetic does its job perfectly and reports them as many hours late, every single day, forever. Nothing is broken. The answer is just meaningless.
How to tell which kind you have
Real lateness and configuration lateness look completely different once you know what to check.
Real lateness clusters in minutes. Traffic, school runs, a slow lift. The distribution sits in the ten-to-forty minute band and has a long thin tail.
Real lateness varies. The same person is fine on Tuesday and twenty minutes late on Wednesday.
Real lateness concentrates. A minority of people account for most of it, which is why it is actionable at all.
Configuration lateness inverts all three. The gap is measured in hours rather than minutes. It does not vary, because the same wrong offset applies every day. And it spreads evenly across whole groups of people, because rosters are assigned in groups.
If your exception list has a flat distribution around a large number, you are looking at the second kind, and no amount of conversation with employees will move it.
The diagnostic that takes five minutes
Sort your people by average flagged lateness, descending. Look at the top twenty.
For each one, ask a single question: is this person's average measured in minutes or in hours? Anybody in hours is on the wrong roster. You have just found them without investigating anyone.
Then look at whether the flagged individuals share a site, a shift or a start date. Configuration errors arrive in batches, because that is how rosters are applied. One wrong assignment usually explains a whole department.
We would expect most operations running this to find that a small number of roster assignments explain the majority of their exceptions.
Why this matters more than it sounds
An exception report exists to tell a supervisor where to look. That only works if the list is short enough to read and trustworthy enough to act on.
At 49.5 per cent, neither holds. Nobody reads twenty thousand exceptions, so the report gets ignored, and once it is ignored the genuine lateness inside it is invisible too. A system that flags half of everything has the same practical value as a system that flags nothing, with the added cost of having taught everybody to dismiss it.
There is a second cost that shows up later. Lateness flags feed deduction policies and performance conversations in a lot of companies. A flag that is actually a roster artefact, used in either, is a real unfairness applied to a real person. And if it ever reaches a labour dispute, the employer is holding a record that is provably wrong half the time, which is worse than holding no record at all.
What to fix, in order
Fix the rosters, not the flags. The temptation is to raise the tolerance threshold until the list looks reasonable. That hides configuration errors underneath a wider band and destroys the genuine signal at the same time.
Attach people to the shift they actually work. Including the ones who swapped, the ones who moved site, and the ones whose pattern changed when a contract changed. This is unglamorous and it is the whole job.
Then set a tolerance you can defend. Once the roster is right, a threshold is a policy decision rather than a way of suppressing noise.
Check the rate quarterly. A roster is not a thing you configure once. People move, and every move is a chance for the schedule and the reality to separate again.
The three roster mistakes behind almost all of it
Having gone through this in our own data, the causes fall into three groups and they are not equally common.
The night shift on a day roster. The biggest single producer of hours-long lateness. Somebody works 22:00 to 06:00 and is scheduled against an 08:00 start, so the system computes fourteen hours late every night. It is obvious once you see it and invisible in a list of twenty thousand rows.
The person who moved and the roster that did not. Staff transfer between sites far more often than schedules get revisited. The new site runs different hours, the assignment still points at the old ones, and the flag appears the day after the transfer with nothing in the record explaining why.
The rotation nobody modelled. Two-week rotations, four-on-four-off, alternate weekends. These are extremely common in the multi-site operations that run biometric terminals, and they are the hardest thing to represent in a scheduling system. The usual outcome is that somebody picks the more common of the two patterns, applies it permanently, and accepts that half the weeks will be wrong.
That third one is worth dwelling on, because it is where good intentions go wrong. A rotation modelled as a fixed schedule is not slightly wrong, it is exactly wrong half the time, and the flags it produces alternate in a pattern that looks almost like real behaviour. It is the hardest of the three to spot and the one most likely to end up in a performance conversation.
What a useful exception report looks like
Once the rosters are right, the report changes shape rather than just shrinking.
It should be short enough that a supervisor reads all of it. If it is not, the threshold or the roster is still wrong.
It should say what the schedule was, not just that somebody was late. A flag without the comparison is an accusation without evidence, and the first question anybody sensible asks is "late against what?"
It should separate a first occurrence from a pattern. One late morning is information for nobody. Six in a month is information for a manager.
And it should be possible to mark a flag as explained without deleting it. The record of what happened and the record of what it meant are different things, and a system that forces you to erase one to express the other is throwing away the audit trail you will want later.
The uncomfortable version
We build attendance software and we shipped the thing that produces this flag. The number above is from our own live data, which means our own product has been reporting half its records as exceptions and we did not notice until we went looking.
The lesson we took is that a metric which is almost always triggered is not a metric. It is a background colour. Any system with an exception rate near half should treat the rate itself as the first bug, before anybody looks at a single employee.
We fixed it the way this post recommends. In Wurxa attendance, lateness is worked out at read time from the first IN punch against the person's own roster and their site's grace period, never from a flag stored on the day, so correcting a roster corrects every report at once. Rosters, rest days and duty hours are set per site in Wurxa Workforce, and punches arrive live from the ZKTeco terminals you already own. It is free for up to 5 employees on one site, and every new workspace gets every feature for 14 days with no card. Start your free trial, or read the full dataset.
Put the workflow into practice.
Start with every Wurxa feature for 14 days. No credit card required.



