Cookwala / حزمة التطوير والسيناريوهات / 030
missing_sensor_no_fallback: the one refusal a person present cannot lift
Deep frying has a single rung, an oil thermometer. A robot that lists the operation but lacks the sensor is refused with a person present, with or without estimates; a robot that does not list the operation hands the frying to the person.
اقرأ أولًا: /docs/CORE/ /docs/QUICKSTART/
الخطوات
The basic hob robot lists deep_fry but has no oil thermometer: thirteen steps are planned, then refused at n14.
dryRunForbidding estimates changes nothing here: a model was never a rung for deep frying.
dryRunThe hob robot with thermometers does not list deep_fry at all, so the person fries the onions and the rest is the robot's.
dryRunThe fryer robot has the sensor: the device fries, verified by the oil thermometer.
dryRun
النتيجة
You know the difference between claiming an operation and being able to verify it, and that a capability document should not list deep_fry without an oil thermometer. Next: scenario 034 runs the fryer robot with estimates forbidden.
سطر الأوامر
cookwala dryrun examples/koshari.cookwala.json --device examples/capabilities/demo-hob-robot-basic.json --human-present
cookwala dryrun examples/koshari.cookwala.json --device examples/capabilities/demo-hob-robot-basic.json --human-present --no-model
cookwala dryrun examples/koshari.cookwala.json --device examples/capabilities/demo-hob-robot.json --human-present
cookwala dryrun examples/koshari.cookwala.json --device examples/capabilities/demo-fryer-robot.json --human-presentالمخرجات المسجلة
الحالة: ok
[1] dryRun: {"state": "refused", "refusal": {"reason": "missing_sensor_no_fallback", "node": "n14", "detail": "no way to verify cw.op.deep_fry on this device"}, "plan": [{"node": "n1", "op": "cw.op.boil", "by": "device", "verifiedBy": "model", "rung": "model"}, {"node": "n2", "op": "cw.op.simmer", "by": "device", "verifiedBy": "model", "rung": "model"}, {"node": "n3", "op": "cw.op.drain", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n4", "op": "cw.op.boil", "by": "device", "verifiedBy": "model", "rung": "model"}, {"node": "n5", "op": "cw.op.boil", "by": "device", "verifiedBy": "model",…
[2] dryRun: {"state": "refused", "refusal": {"reason": "missing_sensor_no_fallback", "node": "n14", "detail": "no way to verify cw.op.deep_fry on this device"}, "plan": [{"node": "n1", "op": "cw.op.boil", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n2", "op": "cw.op.simmer", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n3", "op": "cw.op.drain", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n4", "op": "cw.op.boil", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n5", "op": "cw.op.boil", "by": "device", "verifiedBy": "time", "rung"…
[3] dryRun: {"state": "accepted", "plan": [{"node": "n1", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n2", "op": "cw.op.simmer", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n3", "op": "cw.op.drain", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n4", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n5", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n6", "op": "cw.op.drain", "by": "d…
[4] dryRun: {"state": "accepted", "plan": [{"node": "n1", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n2", "op": "cw.op.simmer", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n3", "op": "cw.op.drain", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n4", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n5", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n6", "op": "cw.op.drain", "by": "d…الكود
التشغيل: python scenarios/out/030-refusal-missing-sensor-no-fallback/python.py
# Scenario 030: missing_sensor_no_fallback: the one refusal a person present cannot lift
# Deep frying has a single rung, an oil thermometer. A robot that lists the operation but lacks the sensor is refused with a person present, with or without estimates; a robot that does not list the operation hands the frying to the person.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem
def load(path):
with open(path, encoding="utf-8") as f:
return json.load(f)
def pick(obj, path):
for part in path.replace("]", "").replace("[", ".").split("."):
obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
return obj
c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))
# Step 1: The basic hob robot lists deep_fry but has no oil thermometer: thirteen steps are planned, then refused at n14.
basic = c.dry_run(recipe_id="koshari", device_id="demo-hob-robot-basic", human_present=True)
assert pick(basic, "state") == "refused", pick(basic, "state")
print("ok", "state", "=", "refused")
assert pick(basic, "refusal.reason") == "missing_sensor_no_fallback", pick(basic, "refusal.reason")
print("ok", "refusal.reason", "=", "missing_sensor_no_fallback")
assert pick(basic, "refusal.node") == "n14", pick(basic, "refusal.node")
print("ok", "refusal.node", "=", "n14")
assert pick(basic, "refusal.detail") == "no way to verify cw.op.deep_fry on this device", pick(basic, "refusal.detail")
print("ok", "refusal.detail", "=", "no way to verify cw.op.deep_fry on this device")
assert pick(basic, "plan.length") == 13, pick(basic, "plan.length")
print("ok", "plan.length", "=", 13)
# Step 2: Forbidding estimates changes nothing here: a model was never a rung for deep frying.
basicNoModel = c.dry_run(recipe_id="koshari", device_id="demo-hob-robot-basic", human_present=True, allow_model=False)
assert pick(basicNoModel, "state") == "refused", pick(basicNoModel, "state")
print("ok", "state", "=", "refused")
assert pick(basicNoModel, "refusal.reason") == "missing_sensor_no_fallback", pick(basicNoModel, "refusal.reason")
print("ok", "refusal.reason", "=", "missing_sensor_no_fallback")
assert pick(basicNoModel, "refusal.node") == "n14", pick(basicNoModel, "refusal.node")
print("ok", "refusal.node", "=", "n14")
# Step 3: The hob robot with thermometers does not list deep_fry at all, so the person fries the onions and the rest is the robot's.
thermometers = c.dry_run(recipe_id="koshari", device_id="demo-hob-robot", human_present=True)
assert pick(thermometers, "state") == "accepted", pick(thermometers, "state")
print("ok", "state", "=", "accepted")
assert pick(thermometers, "plan.length") == 20, pick(thermometers, "plan.length")
print("ok", "plan.length", "=", 20)
assert pick(thermometers, "plan[13].op") == "cw.op.deep_fry", pick(thermometers, "plan[13].op")
print("ok", "plan[13].op", "=", "cw.op.deep_fry")
assert pick(thermometers, "plan[13].by") == "human", pick(thermometers, "plan[13].by")
print("ok", "plan[13].by", "=", "human")
# Step 4: The fryer robot has the sensor: the device fries, verified by the oil thermometer.
fryer = c.dry_run(recipe_id="koshari", device_id="demo-fryer-robot", human_present=True)
assert pick(fryer, "state") == "accepted", pick(fryer, "state")
print("ok", "state", "=", "accepted")
assert pick(fryer, "plan[13].by") == "device", pick(fryer, "plan[13].by")
print("ok", "plan[13].by", "=", "device")
assert pick(fryer, "plan[13].rung") == "cw.sense.oil_temp", pick(fryer, "plan[13].rung")
print("ok", "plan[13].rung", "=", "cw.sense.oil_temp")
print("scenario complete")