Diese Seite wurde maschinell übersetzt und wurde noch nicht von einer Person überprüft. Englisch ist die Referenz; Korrekturen auf GitHub sind willkommen. GitHub
Cookwala / SDK und Szenarien / 097
An agent request without start_cooking in its mandate is refused
Core rule 6.5: an agent's request carries an AgentMandate and the executor refuses what is outside it (mandate_scope). Start shakshuka twice with the recipe's real hash: once with a planning-only mandate, once with start_cooking, then stop the accepted run.
Zuerst lesen: /docs/CORE/ /docs/HUB/
Schritte
Fetch shakshuka; its id is example-shakshuka and the hub addresses it as cw:cookwala.ai:example-shakshuka.
getRecipeThe request must carry the recipe hash; a wrong one is refused as recipe_hash_mismatch before the mandate is even read.
hashAn agent with scopes plan_meals and search_recipes asks the device to cook: refused, reason mandate_scope. The refusal is a result with HTTP 202, not an error.
startExecutionThe same request under a mandate that includes start_cooking is accepted; the device still runs its own dry run and limits first.
startExecutionStop it: a stop is never refused for authorization once the caller can reach the executor (Core rule 6.2).
stopExecution
Ergebnis
You have seen the executor enforce the mandate; the MCP server's check_mandate tool does the same check before a request is sent, and irreversible and safety_override always need the principal's confirmation. Next: 098 reads recipe text in two languages.
Kommandozeile
curl -s -X POST ${COOKWALA_HUB:-http://localhost:7878}/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: scenario-097-planning-only' -d '{"core":"0.2.0","kind":"ExecuteRequest","id":"ex-097-planning-only","recipe":"cw:cookwala.ai:example-shakshuka","recipeHash":"sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841","requestedBy":"agent:planner-example","idempotencyKey":"scenario-097-planning-only","mandate":{"principal":"person-1","agent":"agent:planner-example","scopes":["plan_meals"],"expires":"2027-01-01T00:00:00Z"},"x-hub-human-present":true}'
cookwala hash examples/shakshuka.cookwala.jsonAufgezeichnete Ausgabe
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": "ex-097-planning-only", "seq": 0, "state": "refused", "request": "ex-097-planning-only", "updatedAt": "2026-10-07T00:54:54Z", "refusal": {"reason": "mandate_scope", "detail": "the agent mandate lacks start_cooking"}}
[4] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-097-with-scope", "seq": 0, "state": "accepted", "request": "ex-097-with-scope", "updatedAt": "2026-10-07T00:54:54Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute…
[5] stopExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-097-with-scope", "seq": 1, "state": "stopping", "request": "ex-097-with-scope", "updatedAt": "2026-10-07T00:54:54Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute…Code
Ausführen: python scenarios/out/097-agent-mandate-scope-refusal/python.py
# Scenario 097: An agent request without start_cooking in its mandate is refused
# Core rule 6.5: an agent's request carries an AgentMandate and the executor refuses what is outside it (mandate_scope). Start shakshuka twice with the recipe's real hash: once with a planning-only mandate, once with start_cooking, then stop the accepted run.
# 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 shakshuka; its id is example-shakshuka and the hub addresses it as cw:cookwala.ai:example-shakshuka.
recipe = c.get_recipe("shakshuka")
assert pick(recipe, "id") == "example-shakshuka", pick(recipe, "id")
print("ok", "id", "=", "example-shakshuka")
# Step 2: The request must carry the recipe hash; a wrong one is refused as recipe_hash_mismatch before the mandate is even read.
h = c.hash(recipe)
assert pick(h, "hash") == "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", pick(h, "hash")
print("ok", "hash", "=", "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841")
# Step 3: An agent with scopes plan_meals and search_recipes asks the device to cook: refused, reason mandate_scope. The refusal is a result with HTTP 202, not an error.
try:
refused = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-097-planning-only", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "requestedBy": "agent:planner-example", "idempotencyKey": "scenario-097-planning-only", "mandate": {"principal": "person-1", "agent": "agent:planner-example", "scopes": ["plan_meals", "search_recipes"], "expires": "2027-01-01T00:00:00Z"}}, "scenario-097-planning-only", True)
except CookwalaProblem as p:
refused = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(refused, "state") == "refused", pick(refused, "state")
print("ok", "state", "=", "refused")
assert pick(refused, "refusal.reason") == "mandate_scope", pick(refused, "refusal.reason")
print("ok", "refusal.reason", "=", "mandate_scope")
# Step 4: The same request under a mandate that includes start_cooking is accepted; the device still runs its own dry run and limits first.
try:
accepted = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-097-with-scope", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "requestedBy": "agent:planner-example", "idempotencyKey": "scenario-097-with-scope", "mandate": {"principal": "person-1", "agent": "agent:planner-example", "scopes": ["plan_meals", "start_cooking"], "confirmBefore": ["any_payment"], "expires": "2027-01-01T00:00:00Z"}}, "scenario-097-with-scope", True)
except CookwalaProblem as p:
accepted = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(accepted, "state") == "accepted", pick(accepted, "state")
print("ok", "state", "=", "accepted")
assert pick(accepted, "id") == "ex-097-with-scope", pick(accepted, "id")
print("ok", "id", "=", "ex-097-with-scope")
# Step 5: Stop it: a stop is never refused for authorization once the caller can reach the executor (Core rule 6.2).
try:
stopped = c.stop_execution("ex-097-with-scope", "requested")
except CookwalaProblem as p:
stopped = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(stopped, "state") == "stopping", pick(stopped, "state")
print("ok", "state", "=", "stopping")
print("scenario complete")