Do not infer retry safety from a tool's name. Reading an immutable report has no intended state change. A hardware register read may clear a status bit, pop a FIFO or acknowledge an event. Inspect the register contract before allowing a retry. Idempotence means repeating an operation has the same intended effect as applying it once; it does not require every observation to return the same value.
Tool | Kind | Repeat means |
|---|---|---|
| Read-only on an approved immutable snapshot. | Observation can normally be repeated within access and resource limits. |
| Depends on register access semantics. | Clear-on-read and FIFO-pop reads change state; do not retry blindly. |
| A job, not a free observation. | May create artifacts and consume licenses or compute; apply job permissions and budgets. |
| Side-effecting write. | State changes, so repeats need a key. |
| Side-effecting submit. | Each repeat could launch new work. |
A side-effecting tool takes an idempotency key so the executor can detect repeats; only durable, atomic deduplication makes them apply once. Keys turn a retry storm into duplicates the program can skip.
A key alone does not guarantee exactly-once execution. The executor must atomically bind the key to the operation and its result in durable storage, reject the same key with different arguments, and define recovery after a crash. The in-memory example below shows duplicate detection within one process only; after restart its seen list is empty. For an unknown hardware-write outcome, stop and reconcile state unless the actual execution system provides the required retry guarantee.
Each tool receives only the arguments its schema allows. Risky tools also need human approval per call, secrets never enter tool text, and proprietary blocks enter it only where the deployment is approved for them.
Only idempotent tools may repeat freely. For a chain where every step must work, per-step success multiplies, so assume each of 4 steps succeeds with probability 0.98 as a stated example parameter.
chain success with per-step 0.98 (stated example parameter)
0.98^2 = 0.9604
0.98^3 = 0.9604 x 0.98 = 0.941192
0.98^4 = 0.941192 x 0.98 = 0.92236816
four-step chain succeeds with probability 0.92236816, about 92.24%The program below replays three reads and three same-key writes with scripted fakes. Seven checks show three reads changeless and three same-key writes applying once.
store = {"cfg": 0}
reads = 0
def read_register(addr):
global reads
reads += 1
return store["cfg"]
applied = 0
seen = []
def write_register(key, value):
global applied
if key in seen:
return "duplicate-skipped"
seen.append(key)
store["cfg"] = value
applied += 1
return "applied"
bad = 0
if read_register(0) != 0 or read_register(0) != 0 or read_register(0) != 0:
bad += 1
if reads != 3:
bad += 1
if store["cfg"] != 0:
bad += 1
r1 = write_register("k7", 42)
r2 = write_register("k7", 42)
r3 = write_register("k7", 42)
if r1 != "applied" or r2 != "duplicate-skipped" or r3 != "duplicate-skipped":
bad += 1
if applied != 1:
bad += 1
if store["cfg"] != 42:
bad += 1
r4 = write_register("k8", 43)
if r4 != "applied" or store["cfg"] != 43 or applied != 2:
bad += 1
if bad == 0:
print("PASS: 7 safety checks show 3 reads changeless and 3 same-key writes applying once")
else:
print("FAIL: " + str(bad) + " of 7 safety checks went wrong")
raise SystemExit(1)No. Retry only if the executor actually provides durable, atomic deduplication for that operation and arguments. Otherwise reconcile or escalate; an in-memory seen list does not cover crashes or hardware side effects.
A run can drift across turns while the risk stays per action. Each side effect earns its own sign-off.