Change the machine. Know in a minute what you broke.
Every controls engineer knows the feeling of opening working machine code to add one thing. The change takes ten minutes. The worry about what else it touched lasts until the next production run.
StateTick has a test suite built into it. Not a bolt-on, not a separate tool — the same project, the same signals, the same drawing.
Two ways in
Cover a machine that already works, or write the tests first. Both are supported; neither is required.
Start from the machine you have
This is how most suites begin, because most machines already exist. You point tests at a finished sequence: put the machine into a known state, apply the scene, fire the trigger, and assert what should have happened. Nothing about the machine has to be rewritten or instrumented to become testable — the states, conditions and variables the test refers to are the ones already on the drawing.
That is usually the fastest return, too. Cover the paths you are most afraid of breaking, and you have a regression net by the end of the afternoon.
Or write the test before the logic
The other direction is available, and it is unusual enough in controls to be worth knowing about. Test-driven development never really landed here for a practical reason: there was nothing to write a test against until the code existed.
StateTick removes that obstacle, because the equipment model — the interfaces, the instances, the variables — is authored before any sequence is drawn. The moment those signals exist, a test can name them. Given the clamp closed feedback, when the start command rises, the outlet valve should open within twenty cycles. That is writable on day one, and it fails on day one, because there is no logic yet. Then you draw the machine until it passes.
Useful when the sequence is being agreed with a customer, or when a machine is genuinely new. Not something to adopt because it is fashionable — if you have a working machine, start from it.
Test tooling in controls tends to arrive from outside — a separate application, a scripting layer, a simulator with its own copy of the tag list. Anything that lives outside the project can only be pointed at logic that already exists. Here the suite is part of the project, so it can be written against signals that exist and logic that does not.
Every test reads the same way
One four-step spine, so a colleague can read your test without asking what it does.
A test case is not a script. It is four steps in a fixed order, and once you have read one you can read all of them:
Time is a step, not a hope
The step that makes a control test trustworthy is advance N cycles. You are not sleeping and hoping; you are running the machine an exact number of scans and then asserting. A wall-clock wait exists for the cases that need one, and the editor treats it as the flaky-test hazard it is.
The rest of the vocabulary is the one a controls engineer already thinks in: wait for a variable to reach a value, wait for a bus action, disconnect a bus or a single signal to see what the machine does when it loses something.
Assertions that watch for what must never happen
Checking that the right thing happened is half the job. The other half is proving the wrong thing never did.
None of this asks you to stimulate a signal by hand and watch a lamp. You describe the scene once, and the suite drives every input for you — the same way, at the same cycle, every run.
Regression stops being a gamble
The suite runs; the result is compared with the last one; you get a straight answer instead of a feeling.
Every run stores its report and a snapshot of the machine it ran against. That second half is what makes the comparison honest, because the obvious version of this feature cries wolf: change anything, and every difference looks like a regression.
StateTick compares both sides, and the four answers are different answers:
Fail fast, before anything runs
Compiling the suite is its own step. Every reference in every case — injected variables, validated variables, condition instances, buses, fixtures, twin tags — is resolved against the current project, and you get the full list of what no longer exists, located to the step: Case 'Cold start' · step 3. A rename that orphaned four cases is a list, not a surprise mid-run.
Steps reference things by stable identity rather than by name, so renaming a variable, an instance or a whole machine does not break a single test. Deleting one asks first, and tells you how many cases and fixtures depend on it.
And when a case does fail
The report opens on the failed step, expanded, with the passing steps collapsed out of the way. From there you drill into that step's FSM log and bus log — the conditions the machine evaluated and what each returned. You can also re-run the case one step at a time and watch it move, which is usually faster than reasoning about it.
Coverage names what you never tried
Not a percentage. A list of the transitions your suite has never taken, and how to take each one.
A green suite tells you the things you thought of are fine. It says nothing at all about the things you did not think of — and in control logic that is where the bad ones live: the recovery path nobody exercised, the abort nobody triggered, the transition that only happens when two conditions land in the wrong order.
After a run, StateTick compares what the suite actually exercised against everything the machine can do. States entered, transitions taken, abort and interrupt paths reached. The percentage is the headline; the gap list is the payload.
States 9 / 11 Transitions 14 / 18 Abort & interrupt 1 / 3
NEVER REACHED
state Draining via Filling→Draining [LevelLow]
transition Settle → Fault drive condition [VentStuck]
transition Fault → Idle drive condition [ResetPressed]
abort EStopHit drive condition [EStop]
state Rework Unreachable: no incoming transition.
FSM design issue — not a test gap.
Four gaps, each with the route to close it. And one line that is not about testing at all.
The line that is worth the whole feature
Rework is not uncovered because nobody wrote a test for it. It is uncovered because nothing can ever reach it — a state sitting in the machine with no incoming transition at all. Somebody drew it, the plan around it changed, and it was left stranded.
StateTick separates the two cases and says so in the report. A test gap is your homework. An unreachable state is a bug in the machine, found by a tool that was only asked about coverage, in a drawing that looked complete.
For everything that is a test gap, the report does not stop at naming it. It names the route: which transition to drive, and which condition to make true. Closing the gap is a step you add, not an investigation you open.
Coverage analysis is normal in software and almost unheard of on the plant floor, because it needs a formal model of what the program can do to measure against. A drawn state machine is exactly that model — which is why the numbers exist at all.
What you hand over
The evidence side, for the projects where somebody has to sign.
Every case carries a tag and a requirement ID, and reports group by them — so “show me every test covering R-142 and whether it passed” is a filter rather than a spreadsheet afternoon. Runs export to PDF, with the coverage section and its gap list attached if you want it.
A run can be filtered to a tag, repeated N times to shake out anything intermittent, and given a per-case timeout so one bad case cannot hang the batch. The project and the twin scene reset between cases, so nothing leaks from one test into the next.
What the suite produces is verification evidence: a record of which behaviours were exercised, which transitions were covered and what the machine did each time, repeatable on demand and stored alongside the project. That is the evidence a functional acceptance conversation runs on. If you need it mapped to a particular standard or validation plan, send us the project specification and we will work through it with you.
What actually changes
The reason to care, in one paragraph.
The machine stops being something you are afraid to touch.
A machine with a suite behind it can be improved. You can take the change that has been sitting on the list for a year, make it properly rather than carefully, and run the suite. Ten minutes later you know — not believe — whether the other forty sequences still behave.
That is the difference between a plant that gets better over its life and one that gets slowly more fragile because nobody dares open it.
The Machine, Drawn — the plan the suite runs against: reusable states, fault and pause paths as standard, and a drawing the whole project can read.
Three in the Morning — when something does get through: the live plan, focused observability, and the log that says why.