The program below replaces the model with a FAKE scripted decision function. Two fake tools stand in for real ones: a sensor read and a setting write.
Treat the plan as a stand-in, not intelligence. It replays fixed choices so the loop mechanics can be checked exactly.
The loop runs at most 6 steps, logs each action, and checks its own end state. The listing is schematic: no real model is called.
import sys
# FAKE scripted stand-in for a model: a fixed action plan, not a real model.
PLAN = ["sense", "sense", "act", "finish"]
SENSE_VALUES = [20, 42]
STEP_BUDGET = 6
reads = []
applied = None
log = []
steps = 0
stopped_clean = False
sense_calls = 0
step = 0
while step < STEP_BUDGET:
if step < len(PLAN):
action = PLAN[step]
else:
action = "finish"
log.append("step" + str(step) + ":" + action)
steps += 1
if action == "sense":
reads.append(SENSE_VALUES[sense_calls % len(SENSE_VALUES)])
sense_calls += 1
elif action == "act":
applied = reads[-1]
elif action == "finish":
stopped_clean = True
break
else:
print("FAIL: unknown action " + action)
sys.exit(1)
step += 1
if steps != 4:
print("FAIL: steps " + str(steps))
sys.exit(1)
if reads != [20, 42]:
print("FAIL: reads " + str(reads))
sys.exit(1)
if applied != 42:
print("FAIL: applied " + str(applied))
sys.exit(1)
if len(log) != 4:
print("FAIL: log size " + str(len(log)))
sys.exit(1)
if STEP_BUDGET - steps != 2:
print("FAIL: budget left " + str(STEP_BUDGET - steps))
sys.exit(1)
if not stopped_clean:
print("FAIL: stopped flag unset")
sys.exit(1)
print("PASS: 4 steps 2 reads applied 42 log 4 budget left 2")The log holds one entry per step, in order. Four entries appear: two reads, one write, and the stop.
The budget allows 6 steps and the run uses 4, so 2 remain. Each number here follows from the plan, the two sense values, and the budget constant in the code.
Three calls: two sensor reads and one write. The applied value is 42, the second sense value.
The finish step. Steps 0 to 2 use the budget, so the loop ends on the budget after the write with no clean stop.