You cannot scan what is not there
We shipped a feature that let a picker record a shortage from the floor, and gated it behind scanning the product that was missing. The handheld had carried the same mistake for a day before anyone noticed.
Picking is mostly a solved problem until something is not where the system says it is. Then the operator needs a way to say so, and what they are given is usually one of two bad options: leave the line open forever, or cancel the whole task and let someone in an office work out what happened.
So we shipped a third. A picker who cannot find the goods closes the line short from the floor, picks a reason: not found, damaged, location empty, or other. The system releases the unpicked remainder back to available stock in the same transaction, keeps the shortage named on the order, and lets the task complete. The order says what it is missing and why. Nothing hangs.
Then we added scan verification to the desktop pick, so that confirming a line requires scanning the bin and then the product, the way the packing bench already worked. Good rule. We applied it to closing a line short as well, for consistency.
Consider what that means on the floor.
The picker walks to the bin. The shelf is empty. They reach for the one control that exists for exactly this situation, close short, reason: not found, and the system asks them to scan the product.
The product is not there. That is the entire message they are trying to send.
Two of the four reasons became unreachable
Not found and location empty are the two reasons a picker uses when there is nothing to scan. Both were now impossible to record. The only shortages the system would accept were the ones where the operator was holding the goods: damaged, or the catch-all other. The feature we had shipped to stop lines from hanging could not be reached by the two cases that most often cause them.
And it was worse than a blocked button, because the button was not blocked. It rendered enabled. The picker clicked it, the click was swallowed by a guard, and nothing happened. No refusal, no message, no recorded shortage. The control that existed to report a problem had itself become one.
The handheld had it first
When we traced it, the desktop was not where it started. The same rule had shipped on the handheld a day earlier, in the sprint that built close-short in the first place. It required both scans before the button would enable.
It went unnoticed for one reason: the operator smoke tests had all been run on the desktop. The handheld path had been covered by automated tests that exercised the happy sequence (scan, scan, confirm) and never the sequence a real picker walks when the shelf is bare.
That is the more useful half of the story. Automated tests check that the thing you built does what you said. They do not check whether what you said makes sense to someone standing in an aisle. The bug was not in the code; the code did exactly what the design document asked for. The bug was in the sentence.
The rule now
Closing a line short never requires scanning the product, on either floor, for any reason code.
The location scan stays required when the line names an assigned bin, and that one is not bureaucracy: it proves the picker went where the system sent them. Scanning an empty shelf is precisely how location empty becomes a recorded fact instead of an opinion typed from a desk. What makes the shortage credible is the reason code, the note, the operator’s name and the timestamp, all of which the system already writes.
We also fixed the shape that let it hide. A control that renders enabled must act. The button’s disabled state and the handler’s guard now share one predicate, so a control can never again be offered and then silently refuse. If the system will not accept the action, the operator sees that before clicking, not after.
The instinct to watch for
Parity is a good instinct. Two surfaces doing the same job should behave the same way, and most of our floor rules exist because someone noticed a divergence and closed it.
But parity is a rule about similar situations, and it is applied by people reading two designs side by side, which is exactly the position where you stop picturing the person doing the work. At the packing bench the goods are in front of you, so scanning before you confirm is right. At the pick face, in the one case this feature exists for, the goods are absent by definition.
The question that would have caught it takes five seconds and no tooling: what is the operator holding when they press this?
Questions
- Why require any scan to close a line short?
- The location scan proves the picker went to the bin the system named. Scanning an empty shelf is how 'the location is empty' becomes a fact rather than an opinion. The product scan proves nothing about a product that is not in your hand.
- How did it ship in the first place?
- The rule was written as parity with the packing bench, where scanning before confirming is correct because the goods are in front of you. Parity is a good instinct and it was applied one step too far. The design document said the two should match; nobody asked what the picker would be holding.
- How was it caught?
- An end-to-end test failed on a branch that had nothing to do with picking. The button rendered enabled and the click did nothing, which is a shape worth recognising: a control that is offered and then refuses is usually a rule that was added in one place and not the other.