Fault Injection: the failure taxonomy at run time

Pick a fault. Watch the same execute_tool wrapper classify it, retry it or not, and feed back the outcome.

Wrapper config: deadline 2.0s  ·  up to 2 retries  ·  backoff x2 (0.5s, then 1.0s)  ·  retries fire ONLY on transient failures.
Call
Five categories, one recovery policy each
transient → RETRY (bounded, exponential backoff), then feed back if exhausted
permanent → FEED BACK as an Observation, no retry
empty-result → FEED BACK as an Observation, no retry
malformed → FEED BACK (Part 1 validator catch), no retry
unknown-tool → FEED BACK (Part 1 validator catch), no retry

"Feed back" means the failure becomes an Observation the controller reads and reasons about, not a crash. The loop survives a bad tool call the way it survives a good one.

The side-effecting tool: why a retry needs a guard

A refund posts, then its acknowledgement times out. The wrapper retries. Without a guard, that retry refunds the customer twice.

Same transient, both sides: process_refund(ORD-5510, $80.00)  ·  attempt 1 posts to the gateway, then the confirmation times out  →  the wrapper schedules retry 1/2 after 0.5s.
no idempotency guard UNSAFE
attempt 1 → posts $80.00, ack times out (TransientError)
transient → retry 1/2 after 0.5s backoff
attempt 2 → posts $80.00 AGAIN, ack returns OK
ledger: 2 refunds posted for ORD-5510 → $160.00 DOUBLE REFUND. The blind retry re-ran the side effect.
with idempotency guard (by order_id) EXACTLY ONCE
attempt 1 → records ORD-5510, posts $80.00, ack times out
transient → retry 1/2 after 0.5s backoff
attempt 2 → guard sees ORD-5510, skips re-acting, returns prior result
ledger: 1 refund recorded for ORD-5510 → $80.00 Exactly once. The retry hit the guard and skipped re-acting.
Note: a read-only tool is safe to retry for free; a tool that moves money is not. The guard records the effect keyed by order_id before the point where the call can fail, so a retry recognizes it. This is a local in-memory guard; Part 9 hardens it into durable idempotency keys that survive a process crash.