Esta página foi traduzida por máquina e ainda não foi revisada por uma pessoa. O inglês é a referência; correções são bem-vindas no GitHub. GitHub

Cookwala / SDK e cenários / 057

Stop works at every moment and a stopped run stays stopped

Stop a waiting run, stop it again, try to resume it, then read the log: the second stop and the resume change nothing, and the log records the outcome aborted_safe.

Público: robot maker · Objetivo: Robôs para pessoas · Nível: beginner

Leia primeiro: /docs/CORE/ /docs/HUB/

Passos

  1. Start a shakshuka run with a person present. startExecution

  2. The run reaches the first step that needs a person.

  3. Stop: the state becomes stopping at once. stopExecution

  4. The device completes the stop.

  5. Stop again: the hub returns the final status unchanged, same seq. stopExecution

  6. Resume with the current seq: a stopped run cannot be resumed, so the status comes back unchanged. resumeExecution

  7. The log records the outcome. executionLog

Resultado

You have exercised the end of the state machine. Next: scenario 058 reads the log fields that matter for data protection.

Linha de comando

cookwala hub --recipes examples --speed 200
curl -s -X POST http://localhost:7878/v1/executions/ex-2026-10-04-001/stop -H 'Content-Type: application/json' -H 'Idempotency-Key: stop-0002' -d '{"reason":"test"}'
curl -s -X POST http://localhost:7878/v1/executions/ex-2026-10-04-001/resume -H 'If-Match: 8' -H 'Idempotency-Key: resume-0002'

Saída gravada

Status: ok

[1] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-057-final", "seq": 0, "state": "accepted", "request": "ex-057-final", "updatedAt": "2026-10-07T00:54:35Z", "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": "…
[3] stopExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-057-final", "seq": 7, "state": "stopping", "request": "ex-057-final", "updatedAt": "2026-10-07T00:54:39Z", "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": "…
[5] stopExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-057-final", "seq": 8, "state": "stopped", "request": "ex-057-final", "updatedAt": "2026-10-07T00:54:39Z", "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…
[6] resumeExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-057-final", "seq": 8, "state": "stopped", "request": "ex-057-final", "updatedAt": "2026-10-07T00:54:39Z", "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…
[7] executionLog: {"core": "0.2.0", "kind": "ExecutionLog", "id": "log-ex-057-final", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "device": {"vendor": "Example Robotics", "model": "CounterArm 2", "firmware": "hub-0.1", "safetyLimits": "[email protected]"}, "startedAt": "2026-10-07T00:54:35Z", "endedAt": "2026-10-07T00:54:39Z", "outcome": "aborted_safe", "servings": 4, "steps": [{"node": "n1", "op": "cw.op.cut", "verifiedBy": "sensor", "envelopeOk": true, "startedAt": "2026-10-07T00:54:36Z", "endedAt": "2026-10-07T00:…

Código

Executar: python scenarios/out/057-stop-is-never-refused-and-is-final/python.py

# Scenario 057: Stop works at every moment and a stopped run stays stopped
# Stop a waiting run, stop it again, try to resume it, then read the log: the second stop and the resume change nothing, and the log records the outcome aborted_safe.
# 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 shakshuka run with a person present.
try:
    started = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-057-final", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-057-final-a"}, "ex-057-final-key", True)
except CookwalaProblem as p:
    started = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(started, "state") == "accepted", pick(started, "state")
print("ok", "state", "=", "accepted")

# Step 2: The run reaches the first step that needs a person.
import time; time.sleep(4)

# Step 3: Stop: the state becomes stopping at once.
try:
    stop = c.stop_execution("ex-057-final", "test")
except CookwalaProblem as p:
    stop = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(stop, "state") == "stopping", pick(stop, "state")
print("ok", "state", "=", "stopping")
assert pick(stop, "seq") == 7, pick(stop, "seq")
print("ok", "seq", "=", 7)

# Step 4: The device completes the stop.
import time; time.sleep(1.5)

# Step 5: Stop again: the hub returns the final status unchanged, same seq.
try:
    again = c.stop_execution("ex-057-final")
except CookwalaProblem as p:
    again = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(again, "state") == "stopped", pick(again, "state")
print("ok", "state", "=", "stopped")
assert pick(again, "seq") == 8, pick(again, "seq")
print("ok", "seq", "=", 8)

# Step 6: Resume with the current seq: a stopped run cannot be resumed, so the status comes back unchanged.
try:
    resume = c.resume_execution("ex-057-final", 8)
except CookwalaProblem as p:
    resume = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(resume, "state") == "stopped", pick(resume, "state")
print("ok", "state", "=", "stopped")
assert pick(resume, "seq") == 8, pick(resume, "seq")
print("ok", "seq", "=", 8)

# Step 7: The log records the outcome.
log = c.execution_log("ex-057-final")
assert pick(log, "outcome") == "aborted_safe", pick(log, "outcome")
print("ok", "outcome", "=", "aborted_safe")
assert pick(log, "kind") == "ExecutionLog", pick(log, "kind")
print("ok", "kind", "=", "ExecutionLog")

print("scenario complete")

scenarios/057-stop-is-never-refused-and-is-final.json

Anterior: 056 Próximo: 058