Cookwala / SDK and scenarios / 018
An execution request with the wrong recipe hash is refused; the right hash still needs a person
An agent sends an ExecuteRequest naming a recipe and its hash. The executor compares the hash with the revision it holds and refuses a mismatch; with the right hash, the device's own dry run still applies. Nothing heats up in this scenario.
Read first: /docs/CORE/ /docs/API/
Steps
Fetch the recipe the agent wants cooked.
getRecipeCompute the hash the request must carry.
hashSend a request with a zero hash: HTTP 202 with state refused, reason recipe_hash_mismatch. A refusal is a result, not an error.
startExecutionSend the right hash with nobody present: the hub's device is the example arm, and cutting needs a person. Refused before any motion.
startExecutionThe hub told the agent which hash it holds.
Outcome
You have seen two refusals an agent must handle before cooking starts, and that both arrive as a status, not a crash. Scenarios 040 onwards start, watch, stop and log an accepted execution.
Command line
cookwala hash examples/shakshuka.cookwala.json
curl -s -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: sc018-wrong-hash' -d '{"core": "0.2.0", "kind": "ExecuteRequest", "id": "sc018-wrong-hash", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:0000000000000000000000000000000000000000000000000000000000000000", "requestedBy": "agent:scenario-018", "idempotencyKey": "sc018-wrong-hash", "x-hub-human-present": true}'Recorded output
Status: ok
[1] getRecipe: {"$schema": "https://cookwala.ai/v1/schemas/recipe.schema.json", "cookwala": "0.1.0", "id": "example-shakshuka", "revision": 2, "updated": "2026-10-03", "hash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "verification": {"level": "V2", "evidence": {"simulatorRuns": 1, "humanReviews": 1, "fieldReports": 0}, "reviewedBy": "fifi.cooking editorial", "notes": "Illustrative example for the spec; values are realistic but not field-verified."}, "dish": {"names": {"en": "Shakshuka", "ar": "شكشوكة", "fr": "Chakchouka"}, "cuisine": ["TN", "MA", "DZ", "LY"], "course": "main…
[2] hash: {"hash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841"}
[3] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "sc018-wrong-hash", "seq": 0, "state": "refused", "request": "sc018-wrong-hash", "updatedAt": "2026-10-06T23:29:14Z", "refusal": {"reason": "recipe_hash_mismatch", "detail": "this hub holds sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841"}}
[4] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "sc018-right-hash", "seq": 0, "state": "refused", "request": "sc018-right-hash", "updatedAt": "2026-10-06T23:29:14Z", "refusal": {"reason": "needs_human_present", "detail": "cw.op.cut may not run unattended", "node": "n1"}}Code
Run: python scenarios/out/018-wrong-hash-refuses-an-execution/python.py
# Scenario 018: An execution request with the wrong recipe hash is refused; the right hash still needs a person
# An agent sends an ExecuteRequest naming a recipe and its hash. The executor compares the hash with the revision it holds and refuses a mismatch; with the right hash, the device's own dry run still applies. Nothing heats up in this scenario.
# 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: Fetch the recipe the agent wants cooked.
recipe = c.get_recipe("shakshuka")
assert pick(recipe, "id") == "example-shakshuka", pick(recipe, "id")
print("ok", "id", "=", "example-shakshuka")
# Step 2: Compute the hash the request must carry.
h = c.hash(recipe)
assert pick(h, "hash") == "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", pick(h, "hash")
print("ok", "hash", "=", "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841")
# Step 3: Send a request with a zero hash: HTTP 202 with state refused, reason recipe_hash_mismatch. A refusal is a result, not an error.
try:
wrong = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "sc018-wrong-hash", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:0000000000000000000000000000000000000000000000000000000000000000", "requestedBy": "agent:scenario-018", "idempotencyKey": "sc018-wrong-hash"}, "sc018-wrong-hash", True)
except CookwalaProblem as p:
wrong = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(wrong, "state") == "refused", pick(wrong, "state")
print("ok", "state", "=", "refused")
assert pick(wrong, "refusal.reason") == "recipe_hash_mismatch", pick(wrong, "refusal.reason")
print("ok", "refusal.reason", "=", "recipe_hash_mismatch")
# Step 4: Send the right hash with nobody present: the hub's device is the example arm, and cutting needs a person. Refused before any motion.
try:
right = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "sc018-right-hash", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "requestedBy": "agent:scenario-018", "idempotencyKey": "sc018-right-hash"}, "sc018-right-hash", False)
except CookwalaProblem as p:
right = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(right, "state") == "refused", pick(right, "state")
print("ok", "state", "=", "refused")
assert pick(right, "refusal.reason") == "needs_human_present", pick(right, "refusal.reason")
print("ok", "refusal.reason", "=", "needs_human_present")
assert pick(right, "refusal.node") == "n1", pick(right, "refusal.node")
print("ok", "refusal.node", "=", "n1")
# Step 5: The hub told the agent which hash it holds.
assert pick(wrong, "refusal.detail") == "this hub holds sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", pick(wrong, "refusal.detail")
print("ok", "refusal.detail", "=", "this hub holds sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841")
print("scenario complete")