How to catch ambiguous and unsafe PLC control behaviour before commissioning: the six bug classes, simulation-first testing, and structured test injection.

Commissioning is the most expensive place to find a logic bug. On the plant floor, every wrong rung costs a stopped crew, a consumed startup window, and — in the bad cases — a machine doing something nobody intended with real motors and real product. Yet most PLC logic is still tested for the first time at commissioning, against the physical machine, because "we'll sort it out on site" is tradition. This post is about the alternative: catching ambiguous and unsafe control behaviour while the logic is still on a screen — what to look for, and how to test for it systematically before commissioning ever starts.

Unsafe PLC Logic Before Commissioning: The Six Bug Classes

Decades of commissioning war stories reduce to a short list of recurring logic-level failures. Every one of them is findable in simulation.

1. Ambiguous specification, silently resolved. The spec said "stop the pump if the inlet valve closes." The programmer picked a reading — say, auto-resume when the valve reopens — and nobody noticed a decision had been made until the pump restarted itself with a fitter's hand in the line of the discharge. Any place the written spec doesn't answer "and then what?", the code contains an unreviewed decision. (Why natural-language specs are systematically ambiguous — latching vs. following, edge vs. level, auto-restart, priority — is covered in Plain English to PLC Code.)

2. Duplicate coil / last-write-wins. Two rungs write Motor. Rung 14 says on, rung 62 says off, and only rung 62 reaches the output — but rung 14's author tested rung 14 and went home happy. The scan cycle's last-write-wins rule makes this silent: no error, no warning on many platforms, just an output that ignores half its logic.

3. Startup-state surprises. What is every output doing on the first scan after power-up? Retentive memory, latches that survive a power cycle, and TOF timers mid-delay all mean the answer isn't always "off." Machines that lurch on power restoration are this bug.

4. One-scan races. Logic that reads a coil before the rung that writes it gets last scan's value. Usually invisible; occasionally it means a permissive is checked one scan stale, and a fast condition slips through. Sequencers that skip steps intermittently are the classic symptom.

5. Missing edge detection. A level-driven counter or one-shot action that fires on every scan of a held input — 400 counts from one button press, or a "single" lube shot that runs for the whole press duration. The mechanics are in PLC Counters Explained.

6. Interlock gaps under unusual sequences. The forward/reverse contactors are interlocked in the "operator presses buttons" order everyone tested — but not when the auto sequence and a manual command land in the same scan. Interlocks tested only along the happy path are interlocks untested.

Notice what these have in common: none of them require the physical machine to find. They live entirely in the logic and the scan cycle, which means they can all be caught at a desk.

The Method: Simulate First, Then Inject, Then Break

Stage 1 — Exploratory simulation. Before any structured testing, run the program in a simulator and play operator: start it, stop it, mash buttons, kill permissives mid-cycle. Watching rungs and FBD networks animate catches a surprising share of class-1 and class-2 bugs in minutes, because the wrong behaviour is visible as power flow. This is what the free browser simulator exists for — logic exercised dozens of times before it ever meets an I/O rack.

Stage 2 — Structured test injection. Exploration finds what you stumble into; commissioning-critical behaviour deserves written test sequences, replayed identically after every logic change. A test is just a timed table of inputs plus expected outputs:

time_ms, TankLow, TankHigh, InletOpen, EXPECT_Pump
0,       0,       0,        1,         0
100,     1,       0,        1,         1
500,     0,       0,        1,         1
900,     0,       0,        0,         0
1000,    0,       0,        1,         ?   <- the ambiguity, now a test row

That last row is the point: the auto-resume question from bug class 1 is no longer a latent decision buried in a rung — it's an explicit row where you must write down the expected value, which forces the conversation with the process engineer before commissioning. Protection engineers have tested relays exactly this way (COMTRADE/CSV playback) for decades; applying it to ordinary machine logic is overdue.

Stage 3 — Adversarial sequences. Now test the sequences nobody performs on purpose: both start and stop true in the same scan; every permissive dropped at every step of the sequence, one step at a time; power-cycle (re-initialize) at each state and check the outputs' first scan; held inputs where the logic expects pulses. This is where classes 3, 4 and 6 surface. It's tedious on hardware and fast in simulation, which is exactly why it only happens when it's done before site.

What a Pre-Commissioning Logic Review Signs Off

A practical checklist that fits on one page:

  • Every output written by exactly one rung/network (class 2)
  • First-scan state of every output verified from a cold start (class 3)
  • Every operator input and sensor treated explicitly as edge or level (class 5)
  • Every "spec didn't say" decision written down and confirmed by the process owner (class 1)
  • Structured test file per sequence, passing, stored with the project (stage 2)
  • Adversarial pass done: simultaneous commands, mid-cycle permissive loss, re-init at each step (classes 4, 6)

Two boundaries to state plainly. Simulation verifies logic, not the plant: wiring, sensor calibration, valve stroke times and mechanical reality still need real commissioning checks — the goal is arriving on site with only those left. And safety functions are their own discipline: e-stops, guard circuits and anything with a required safety rating belong in certified safety hardware and formal validation, not in this checklist — see Safety PLC vs Standard PLC for where that line sits.

The economics are lopsided. A bug found in stage 1 costs a minute; the same bug at commissioning costs hours of a full crew, and the same bug in production costs whatever the machine was holding at the time. Write the test rows while the spec conversation is fresh, run them in the simulator on every change, and commissioning becomes what it should be: confirming the machine matches the logic — not discovering what the logic was.