When an AI Agent Met a Real Motor: Energized Is Not Spinning
The board said energized: true. The motor did not move.
That one line is the whole experiment. Underneath it sits a supervisory language model, a policy engine, a serial gateway, Arduino firmware, an L293D H-bridge, and a three-dollar DC motor: six layers, each capable of reporting success while the physical world stays perfectly still. The interesting work was not wiring them together. It was refusing to believe any one of them until the shaft actually turned.
Here is the honest result up front. A real supervisory model, given a hot-and-rising cold-box snapshot, produced a governed decision to cool without choosing PWM or timing. Separately, deterministic policy produced a bounded command that made the physical motor spin and return to a safe state. What was not proven: the reviewed Tamoz-to-Agentic Stream conversion seam, the full multi-service runtime, or independent instrumented feedback. Rotation was confirmed by a human eye. Everything after this paragraph is how those boundaries were earned.
This experiment sits at the actuation edge of Tamoz, the supervisory agent framework that produced the decision, and the wider three-repository system around it.
Six layers, six chances to lie
The bench is deliberately small: an ELEGOO Mega 2560, a DHT11 temperature and humidity module on pin D2, an L293D motor driver, a 3-6 V DC motor with a fan blade, and the Mega's onboard LED. The stack above it is not small. A reading becomes a situation; a situation becomes a decision; a decision becomes a bounded intent; an intent becomes a materialized command; a command crosses USB into firmware; firmware drives the H-bridge; the H-bridge drives the motor.
Every arrow in that chain is a place where the system can report that something happened when nothing did. The discipline of the experiment is to name the exact kind of evidence at each arrow and never promote one kind to another:
- firmware state (
energized: true) is a claim about a pin, not a shaft; - a receipt is admission of a command, not its effect;
- an operator observation is physical truth, but not a measurement;
- a deterministic materialization is policy, not model output.
Collapse any two of those and you get a demo that lies to you. Keep them separate and you get an experiment.
The board was flawless. The motor was dead.
The firmware exposes exactly one bounded actuation: set_pwm_lease on fan-01, capped at 60% duty and a ten-second lease, with a local watchdog that de-energizes the output when the lease expires. Sending that command produced a textbook trace every time: an accepted receipt, an executed result, a queried state showing value: 600, energized: true, and, after the lease, a clean return to safe_state: true. The firmware digest and capability-catalog digest matched the checked-in build on every boot.
And the motor did not move. Not at 45% duty. Not at the 60% ceiling. Not audibly, not visibly.
This is the first and most important lesson of physical work: energized: true is a statement about a GPIO register. It says the firmware set the enable line high. It says nothing about whether 3 volts reached a shaft. The temptation is to trust the trace (the trace is beautiful), and the trace is exactly what you must not trust.
Ruling out the software, at full power
To find the fault you have to cut the problem in half. So we left the governed firmware behind and flashed a throwaway sketch that does nothing but drive the H-bridge directly at full 255 PWM (forward, pause, reverse, loop) with no serial protocol, no lease, no 60% ceiling, no policy. It was the maximum duty cycle available in that setup.
Still nothing. No rotation, no twitch, no hum, in either direction.
That result is worth more than it looks. Full-power drive in both directions with zero movement eliminates, in one shot, the governed firmware, the duty ceiling, the startup-torque theory, and the serial command path. Whatever was wrong lived in the copper, not the production control path. The enable signal was switching, but the driver stage was not delivering motor voltage.
The usual suspects for that are the L293D's motor-supply pin, a missing common ground, incorrect input/output wiring, or a bad motor. A single isolation test narrowed it: lift the motor leads off the driver outputs and touch them straight across the supply rails. The motor spun instantly. The motor and supply rails were good; the fault was in the driver stage or its wiring.
The root cause was two wrong pins
The firmware drives three lines: an enable on D5, and two direction inputs on D6 and D7. The bench had the two inputs on D4 and D3, pins the firmware never touches. With both direction inputs sitting low, the L293D holds the motor in its brake state. You can put the enable line at full PWM forever; a braked H-bridge produces exactly what we saw: energized: true, and a shaft that will not turn.
Moving two jumpers (D4 to D6, D3 to D7) was the entire fix. No firmware change, no recompile; the wiring was brought to match the pin map the checked-in build already declared, which kept the firmware and capability digests intact. On the next governed command the motor spun, and a human confirmed it. Board-side proof had been real all along; it had simply been proof of the wrong claim.
The harder claim: putting a model in the loop
A spinning motor driven by a hand-issued command is a wiring result. The experiment wanted more: a real language model, reasoning over sensor state, deciding to cool, and the physical world obeying that decision without the model ever being allowed to touch anything dangerous.
The supervisor runs a fixed episode graph against a real model. Given a snapshot (a cold box reading 8 °C against a 4 °C setpoint, rising at +0.6, sensors valid, no recent door event, ambient a normal 20 °C) it is asked for one governed decision. And it reasoned correctly, in its own words: a genuine sustained thermal excursion not explained by ambient or a transient. It recommended bounded cooling.
Then the episode failed.
Not because the reasoning was wrong (it was right) but because of what the model tried to write. It proposed the cooling action with parameters duty_pct: 50, lease_ms: 5000. It reached for the PWM. And the decision layer rejected the whole thing, because in this domain the supervisor is explicitly forbidden from owning timing or PWM; those are materialized downstream by deterministic policy. The model produced a field it was not allowed to produce, and strict validation killed the decision.
Read that again, because it is the point of the entire project: the safety property worked by refusing a decision that a well-meaning, correctly-reasoning model had written. The failure was the feature.
The fix is the governance, not the model
The repair was not to coax the model or swap it. It was to give the cooling action the shape the production experiment already uses: a single writable field, mode, constrained to an enum of hold or bounded_cooling. Nothing else is expressible. The model chooses what mode; it cannot choose how hard or how long. Once the surface was constrained that way, the same model on the same snapshot produced a clean, valid decision (mode: bounded_cooling, and not one PWM digit) and the episode passed.
From there the intended bridge is deterministic and dull, which is exactly what you want at an actuation boundary. Agentic Stream's fixed policy maps bounded_cooling to a bounded set_pwm_lease, using preset duty and lease values from the capability catalog rather than model output. That materialization and the physical command path are tested independently. The remaining integration gap is the reviewed conversion from Tamoz's request_bounded_cooling intent to Agentic Stream's select_thermal_mode action.
The real-model run is honest about its own reliability. The model does not produce a schema-valid governed decision every time; a bounded retry can land a valid one within a couple of attempts, and only a decision that passes validation is eligible to continue. Until the open conversion seam is joined and reviewed, that eligibility is not evidence that the production system issued a physical command.
What is proven, and what is a stand-in
Proven in the model run: a real model's governed reasoning selected a bounded mode without owning PWM or timing. Proven independently on hardware: a governed direct-serial command stayed within the catalog envelope, the real motor ran, and an explicit safe-stop returned the board to a safe state; a human observed rotation. The runtime, simulator, and research suites provide separate software evidence, and the firmware booted with the expected firmware and capability digests.
Not proven, and labeled as such: rotation was seen, not measured. There is no tachometer or current probe in this bench, so physical feedback is operator-grade, not instrumented. The complete Tamoz-to-Agentic Stream-to-board route has not yet produced one joined physical evidence artifact, and its intent-conversion contract remains open. The reasoning is real and the actuation is real; their production seam is not yet proven.
Three rules for anyone wiring a model to the world
- Separate the claim from the effect at every layer, and never promote one.
energizedis not spinning; a receipt is not a result; a green trace is not a turning shaft. Most "it works" failures are a promoted claim. - Constrain what the model can write, not just what it should do. A correct decision with a forbidden field is still a rejected decision. Make the unsafe thing inexpressible (an enum, not a plea in a prompt) and let deterministic policy own the physical envelope.
- When in doubt, drive it at full power with nothing in the loop. The fastest way to find out whether your problem is code or copper is to remove the code. Ours was three pins to the left the whole time.
The model reasoned inside its boundary, and the motor ran inside a separately verified physical boundary. Joining those facts safely is the next experiment. Both results are useful because nobody promoted the board's claim into proof that the shaft had moved.