The Action Code Nobody Was Checking
The Action Code Nobody Was Checking
The lighting command has two fields: an action, and a level. The controller honoured exactly one action value. Every other value was accepted, queued, acknowledged and logged — and then ignored.
Nothing rejected it. That was the problem.
What it looked like from the UI
A button that meant “on at full” sent one of the older action codes along with a level of zero. The controller ignored the action, applied the level, and left the light off. The interface showed a success toast. The command was in the log. The acknowledgement came back. The light didn’t change.
Three systems reporting success, and a physical outcome that contradicted all of them.
Why it was allowed to happen
The contract was written in prose — a list of action codes with meanings — and both sides were implemented against that prose independently. Nothing in the loop compared the code being sent against the code being honoured. When one side quietly stopped supporting a value, the other side had no way to find out, because the value was still accepted.
That’s the shape of it: an ignored field plus a valid-looking field equals the wrong physical outcome, delivered with a successful acknowledgement.
The level was doing all the work anyway. Every command that mattered was really a level. The action field had become decorative, and decorative fields on a protocol are fields nobody tests.
What changed
One action value. Everything is expressed in the level, so there’s nothing left to ignore. Off is level zero. Full is the top of the range.
The contract is a table now. One row per value, one meaning per row, and a test per row. The prose version of this contract was written by me, for me, and read by nobody else. The table version gets checked.
Confirmation reads the state back. A command is confirmed when a new status arrives after it and the observed level matches what was asked for. If it doesn’t match, the interface says so — “level mismatch, observed X” — instead of claiming it worked. Accepted, sent, done and confirmed are four different words and they mean four different things.
The general shape
The bug wasn’t clever. It was two systems that both believed they were right, with no check between them. The fix wasn’t clever either — it was writing down what each side promises, and then verifying.
I think the version of me that wrote the contract in prose is the one to be most suspicious of. Prose is for humans. Machines need tables.