Reading OEE¶
How-to. What each segment of the OEE screen means and what to do about the grey one.
The OEE screen follows ISO 22400 in its arithmetic and house rule 2 in its honesty: a KPI that cannot be computed returns unknown and says why. That is the grey segment.
The segments¶
| Segment | Source | Becomes unknown when |
|---|---|---|
| Availability | machine state history from the tag map's state tag | the MES was not subscribed for part of the window (it started later, the connection dropped, the machine went stale) |
| Performance | counter deltas against the rated cycle time in master data | the rated cycle time is blank, the machine was not seen running, nothing was counted, or the counted work will not fit inside the run time |
| Quality | good and scrap counters | there is no scrap counter in the tag map — quality reads unknown, not 100 % |
The screen states its data source in a line under the number; a screenshot without that line is not a screenshot of this product.
Performance is not a share, and it is never capped¶
Availability and quality are each a share of something the MES watched itself, so neither can pass 100 %. Performance is not a share. It is
rated cycle time × units counted ÷ time the machine was seen running
and only the second half of that is measured. The first half is a number somebody typed into master data.
There is no cap on it and there never will be. There used to be, in both places that computed it, and on 2026-09-14 a lab run showed what that cost: nine stations across two simulated plants all reported performance of exactly 100 % while the script that generated their data said between 94.3 % and 99.9 %. A factor that reads 100 % whatever the line does is not a measurement, and the OEE built on it overstates the plant.
When the counted work will not fit inside the run time, there is no figure¶
Divide those two numbers and you can get an answer above 1.0. That answer is the same statement as the work the MES counted will not fit inside the run time the MES recorded: units × rated cycle came out larger than the running seconds. Two of the MES's own numbers disagree.
Until 2026-09-18 the screen printed that answer as a percentage. It stopped, because a percentage on a screen is read as a measurement of the machine and this one measures the gap between two records. A plant replaying a recorded line overnight showed performance 881 % and OEE 980 % on its dashboard, and the person reading it called it an error; he was right, twice over — see two clocks below for the other half.
So where the counts outrun the run time, the screen shows:
- no performance figure, and no OEE — a dash, hatched bar, and the same unknown the rest of the product uses for a number it will not state;
- the sentence, naming both numbers: how many units at what rated cycle is how many seconds of work, inside how many seconds of running, and that the MES cannot tell which of the two is wrong;
- units counted outside run time, where there are any (below);
- the ratio itself, kept in the API answer as
performance_ratioand incounts_outrun_run_time. Nothing is thrown away. It is simply not called performance, because it is not a measurement of the machine.
Neither is it capped at 100 %, which would be the same lie pointing the other way: a station reading exactly 1.0 is a station that made exactly what its rating allows, and that has to keep meaning what it says.
What that disagreement actually tells you¶
It does not tell you which of the two numbers is wrong, because the MES cannot tell. Three things produce it:
- The rating is slower than the machine. Somebody entered a cycle time the machine beats, or the counter counts something other than what the rating rates. Fix it in the worksheet and the figure comes back.
- The run time is short of what the machine really ran. State comes from a tag the MES samples, and a machine that changes state faster than the publish interval is running and stopping in gaps nobody saw. A lab run on 2026-09-14 found exactly this: a deburring cell changing state every 2.7 seconds, watched about every 15, reported 1,878 seconds of running where the line had 1,996 — and the MES blamed the master data, which was right to a tenth of a percent. Nothing in the MES can recover this; the fix is at the machine, in the publish interval and the deadband on its state tag.
- Units were counted outside the run time. A counter catching up after a stop books units at an instant the machine was not running.
The third is the one the MES can measure, so it does: units counted outside run time is reported beside the sentence, and named in it when there are any. Those units are not taken out of anything — they are units the plant made, they stay in good, scrap, quality and in the ratio (house rule 1). They are a clue about which of the two numbers to distrust, nothing more.
Where to start: if units counted outside run time is near zero, suspect the rating. If it is a large share of the count, suspect what the MES saw — the machine's publish interval and the deadband on its state tag — because a machine whose state the MES samples too coarsely produces exactly this: counts that are right, landing beside a state history that is not. Decision records 0025 and 0026 have the arithmetic and the options that lost.
What it is not. A machine cannot make more than it made. A missing performance figure never means extra units were invented — that rule is house rule 1 and lives in never invent production. It means two of the MES's numbers do not agree, and it says so rather than choosing one.
A replayed plant has two clocks¶
A plant that replays a recorded line faster than it was recorded counts at the line's pace and measures every duration on the wall's. Performance is the one OEE factor that divides a count by a duration, so at ten times real time it comes out ten times too big; availability and quality are ratios of things measured the same way, and are unaffected.
The MES is told the speed rather than guessing it. fsmes fleet start --speed
10 puts MES_SIM_SPEED=10 into the environment of every process of that
plant, the API included, and the API restates the run time on the line's clock
before it divides. Where it has done so it says so, everywhere a reader can
be:
- a Replay 10× bar across the top of every screen, the way shadow mode puts one there — it is a fact about the installation, not a notification;
replayon/health, which is public, so a fleet console shows the plant as replay 10× rather than as live;mes_replay_factorin/metrics, present only on a plant that is replaying;clockbeside the figures in/analysis/oeeand/kpis/oee/{code}.
Durations stay on the clock the MES measured — runtime_seconds is wall
seconds — with the factor beside them, so a reader converts rather than
having numbers silently restated under them.
A plant meant to be looked at runs at 1×. Above 1× a plant is a test harness: its window is an hour of the line in six minutes of yours, its shift boundaries are not the line's, and its figures are only readable with the factor in hand. Replay fast to test the MES; stand a plant up at 1× to look at one.
Restating the run time is not a cap by another name. A replayed plant whose counts still will not fit inside its line-clock run time has a real disagreement, and it is named exactly as above.
Stale is not stopped, and unseen is neither¶
A machine whose tags stopped changing is stale, not down. Stale means the MES stopped hearing, which is a different fact from the machine stopping. Downtime is only booked from a state tag that says so.
A machine the MES cannot reach is a third thing again, and since
2026-09-14 it is recorded as one. For the minutes the connection is gone the
machine has no state at all — not down, which would invent a breakdown, and
not the state it was last seen in, which would invent availability. Those
seconds leave availability's denominator rather than its numerator, and
every OEE answer says how many of them there were:
| Figure | What it means |
|---|---|
runtime_seconds |
seconds the MES saw the machine running |
observed_seconds |
seconds the MES could see the machine at all |
unknown_seconds |
seconds inside the window a recorded disconnection covered |
unknown_share |
that, as a share of the window |
coverage |
how much of the window anybody watched, all causes together |
ledger |
every second of the window, in one disposition, with the unwatched ones named |
So 92 % availability over forty observed minutes of an eight-hour window is
still 92 %, and coverage says it was 8 %. Read both. A shift whose coverage
is two thirds is not a shift to make a decision from, however good its OEE
looks — and a plant that would rather be told unknown than shown such a
figure sets a floor in its pack and is.
Since 2026-09-17 availability is derived from that ledger rather than
computed beside it, so the two can never disagree, and the ledger's seconds
are checked against the window: one that does not add up is a bug, not a
rounding difference. How much of the window did the MES
see is the whole story — the four causes, the floor,
and fsmes oee explain, which prints the ledger as a table you can argue
with.
Losing sight of a machine is the connection half of it, including the one case that does not cover.
Unlabelled is reported as unlabelled¶
A downtime pareto that files unlabelled stops under "other" convinces a plant it has data it does not have. Here the unlabelled bar is named unlabelled.
Reason codes are configuration, and since 2026-09-19 a plant can name its
own: a list somebody drafts and somebody else puts in force, which the
station screen then offers instead of a text box. See
who names the reasons. The pareto
groups by code where there is one and by typed text where there is not — the
two never merge — and GET /analysis/downtime says how many seconds of the
window came from each, beside the unlabelled share. The three account for
every second of downtime in the window.
To shrink the grey segment¶
- Fill the rated cycle time for every machine in the worksheet.
- Give every machine a scrap counter, or accept that quality is unknown.
- Keep the agent running: the window it was not watching cannot be
reconstructed later, by design.
/healthsays how many machines this plant can currently see, which is the thing to alert on.
A rated cycle time that is wrong does not make grey either; it makes a machine with no performance figure and a sentence saying its counted work will not fit inside its run time. Both are worth a walk to the machine, and neither looks like a problem at first glance — one of them used to look like a triumph.
See also¶
- Never invent production
- How much of the window did the MES see
- Losing sight of a machine
- Engineering guide — the worksheet
- Decision record 0004
- Decision record 0025
- Decision record 0026
- Decision record 0033