Cookwala / حزمة التطوير والسيناريوهات / 050
The same execution id with a new Idempotency-Key is a 409 conflict
The Idempotency-Key makes a retry safe; the execution id makes the run unique. Reusing the id with a different key is a conflict, while the original key still returns the original run.
اقرأ أولًا: /docs/CORE/ /docs/HUB/
الخطوات
Start a run with key ex-050-dup-k1.
startExecutionSend the same request with a different key. The id already exists, so the answer is a Problem with title conflict.
startExecutionThe first run advances to the step that needs a person.
Send it again with the original key: the hub returns the first run, at its current state.
startExecution
النتيجة
You know how the two identifiers divide the work: one for retries, one for the run. Next: scenario 051 moves to the catalog side with an incident report.
سطر الأوامر
cookwala hub --recipes examples --speed 200
jq '. + {"x-hub-human-present": true}' examples/core/execute-request.json | curl -s -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: ex-2026-10-04-001-a' -d @-
jq '. + {"x-hub-human-present": true}' examples/core/execute-request.json | curl -s -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: ex-2026-10-04-001-b' -d @-المخرجات المسجلة
الحالة: ok
[1] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-050-dup", "seq": 0, "state": "accepted", "request": "ex-050-dup", "updatedAt": "2026-10-07T00:54:31Z", "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", "by": "huma…
[2] startExecution: {"type": "https://cookwala.ai/errors/conflict", "title": "conflict", "detail": "execution id already exists"}
[4] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-050-dup", "seq": 6, "state": "needs_human", "request": "ex-050-dup", "updatedAt": "2026-10-07T00:54:33Z", "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", "by": "h…الكود
التشغيل: python scenarios/out/050-duplicate-execution-id-is-a-conflict/python.py
# Scenario 050: The same execution id with a new Idempotency-Key is a 409 conflict
# The Idempotency-Key makes a retry safe; the execution id makes the run unique. Reusing the id with a different key is a conflict, while the original key still returns the original 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: Start a run with key ex-050-dup-k1.
try:
first = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-050-dup", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-050-dup-a"}, "ex-050-dup-k1", True)
except CookwalaProblem as p:
first = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(first, "state") == "accepted", pick(first, "state")
print("ok", "state", "=", "accepted")
assert pick(first, "id") == "ex-050-dup", pick(first, "id")
print("ok", "id", "=", "ex-050-dup")
# Step 2: Send the same request with a different key. The id already exists, so the answer is a Problem with title conflict.
try:
conflict = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-050-dup", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-050-dup-a"}, "ex-050-dup-k2", True)
except CookwalaProblem as p:
conflict = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(conflict, "title") == "conflict", pick(conflict, "title")
print("ok", "title", "=", "conflict")
assert pick(conflict, "detail") == "execution id already exists", pick(conflict, "detail")
print("ok", "detail", "=", "execution id already exists")
# Step 3: The first run advances to the step that needs a person.
import time; time.sleep(4)
# Step 4: Send it again with the original key: the hub returns the first run, at its current state.
try:
retry = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-050-dup", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-050-dup-a"}, "ex-050-dup-k1", True)
except CookwalaProblem as p:
retry = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(retry, "id") == "ex-050-dup", pick(retry, "id")
print("ok", "id", "=", "ex-050-dup")
assert pick(retry, "state") == "needs_human", pick(retry, "state")
print("ok", "state", "=", "needs_human")
assert pick(retry, "seq") == 6, pick(retry, "seq")
print("ok", "seq", "=", 6)
print("scenario complete")