Why Operators Code Everything as "Other" — Fixing an MES Downtime List
Designing downtime reason codes operators pick correctly under pressure: prompt timing, auto-coding from PackML state, and the fields reports need.
Pull a month of downtime records off a line that has been on MES for a year and sort by total duration per reason. If "Other", "Unassigned", or one catch-all equipment fault sits in the top three, the code list is broken. Operators are not being lazy. They are picking the fastest exit from a menu that does not contain their situation, while the line is down and somebody is standing behind them.
Almost every downtime project I have seen fail, failed at one of three points: detection, prompt timing, or list length. The taxonomy argument everyone wants to have is fourth at best.
Detection and explanation are two different jobs
The control system knows the filler stopped. It does not know that a lane jam at the depalletizer starved two conveyors upstream, and it never will. Keep the layers separate:
| Layer | Example | Where it comes from |
|---|---|---|
| Machine state | Running, stopped, blocked, starved, faulted | PLC and SCADA tags |
| Downtime event | Line stopped 10:14:22 → 10:22:05 | Time-bounded record, start/end |
| Reason code | Changeover, upstream starved, capper fault | Automatic or operator classification |
| Comment | "No bottles from depal after lane jam" | Free text, exceptions only |
If your event boundaries are wrong, no reason code fixes the report. A stop that gets logged 8 seconds late because the running tag is derived from a motor run feedback instead of a line speed threshold will misallocate every duration in the shift, and nobody will notice until the OEE number is argued about in a meeting.
The state model already does half the coding
On packaging lines, ISA-TR88.00.02 (PackML) draws a distinction most reason-code lists throw away: Held means the unit stopped for an internal cause and needs operator action; Suspended means an external cause — starved by upstream, blocked by downstream — and it clears itself when material flows again. That single bit is the difference between "our filler is unreliable" and "our depalletizer is the bottleneck", and it is available for free in the state machine.
In semiconductor plants, SEMI E10's six basic states (Productive, Standby, Engineering, Scheduled Downtime, Unscheduled Downtime, Non-Scheduled) already carve up the top of the tree, and E79 builds the OEE metric on top of them. ISO 22400-2 defines availability and the related MOM KPIs if you need a definition to point at when finance disagrees with production about what counts as a stop.
Use those states to pre-select the reason, not to lock it. Suggest, let the operator override, and store which one happened.
Keep the list short enough to finish
Two-thirds of the codes on a typical day-one list are never used. I aim for six or seven top-level groups and 25–40 leaf codes per line, with the leaves specific only where the extra detail changes what somebody does about it.
| Group | Useful leaves | What ruins it |
|---|---|---|
| Planned stop | Changeover, sanitation, scheduled PM | Mixing planned and unplanned loss in one bucket |
| Equipment fault | Filler fault, labeler fault, conveyor drive fault | A single "machine problem" for the whole line |
| Material | No material, bad material, packaging shortage | Codes that name a department instead of a fact |
| Flow | Starved by upstream, blocked by downstream | Hiding flow problems inside local equipment faults |
| Quality hold | Lab hold, inspection reject, rework | Quality stops filed under mechanical stops |
| Utilities | Air pressure, steam, chilled water, power | Site-wide causes surviving as free text only |
A code used twice a year is not a code. It is a comment, or it belongs in the CMMS work order. Rare forensic detail on the operator screen costs every selection a scroll.
Prompt timing, not menu design, decides data quality
Prompting the instant a stop is detected is how you get "Other". The operator is clearing a jam with both hands.
I set the prompt threshold at 120 seconds on most lines and auto-bucket anything shorter as a micro-stop, coded from the machine state alone. Sixty works where stops are genuinely rare and long; below that you are interrupting people to classify noise. Whatever the number, it needs to be per-equipment configurable, because a changeover-heavy line and a continuous filler do not share a definition of "long stop".
The rest of the entry screen:
- Current state and running stop duration beside the picker, so the operator sees what they are coding.
- Never a modal that sits on top of the alarm summary or blocks recovery controls.
- Most-used reasons near the top, fixed order. Adaptive reordering feels clever and destroys muscle memory.
- Correction allowed for authorized users, with the original value kept.
- Show the source: automatic, operator, supervisor edit.
- Comments required only for long events or specific codes, never for every stop.
Fields the report will need later
| Field | Why |
|---|---|
| Equipment / line ID | Rollups by asset, per the ISA-95 equipment hierarchy |
| Start and end timestamp | Duration checks, shift allocation |
| Detected state at stop | Preserves what the control system actually saw |
| Reason code ID + label | Stable key, separate from display text |
| Source of the reason | Automatic, operator, supervisor, imported |
| Product, batch, or order | Ties loss to production context |
| User and edit history | Review without blame |
| Comment | Detail that does not deserve a permanent code |
Two things people get wrong here. First, use a stable numeric or string ID and let the label change — otherwise renaming "Capper Fault" to "Capper Jam" for clarity breaks eighteen months of trend. Second, store the event whole and split it at report time. Cutting a stop that crosses 06:00 into two records at write time makes the event unrecoverable, and every downstream query then has to guess whether two adjacent records are one stop or two.
Also: blank, "Unknown", and "Not required" are three different values. Collapsing them into empty string is how you lose the ability to tell a missing answer from a deliberate one.
The first month is when the list actually gets designed
Weekly for the first month, then monthly once it settles:
- Sort by unassigned duration, descending. That is your work list.
- Find codes two operators use differently — usually two codes that mean the same thing to one shift and different things to the other.
- Merge duplicates. Split only where the split changes a decision.
- Compare the automatic state against the selected reason and look at the disagreements.
That last comparison is the one worth doing before you touch the taxonomy at all. Every event where the state machine says Suspended and the operator picked an equipment fault is either a detection bug or a training gap, and both are cheaper to fix than an argument about categories.