Dallas Crilley
← All writing

Treat timed-out agent writes as unknown outcomes

TraceFence · Agent reliability · October 2026 · ~3 min read

When an agent call times out, the caller may know only that it stopped hearing back. The tool may have completed its write. It may not have. That gap is where a retry can create a second invoice, ticket update, or notification.

I built TraceFence to make that uncertainty visible before someone retries a tool-call trace. It is a small browser inspector and command-line tool. It reads a normalized JSON, NDJSON, or CSV trace and produces an inspection plan. It does not call the tools.

Keep the outcome unknown until it can be checked

A timeout is not evidence that a write failed. It is evidence that the caller did not learn the outcome. Those are different statements, and a retry policy that turns one into the other can duplicate an effect.

Here is a synthetic example:

[
  {
    "id": "call-17",
    "tool": "invoice.create",
    "effect": "write",
    "status": "timeout",
    "arguments": {
      "invoice": "demo-17"
    },
    "idempotency_key": "invoice-17"
  }
]

TraceFence puts this call in review. It does that even though the trace includes an idempotency key. The trace alone cannot tell me whether the destination received the key, enforces it, or already committed the invoice. I would need to reconcile the effect with the system that owns it before retrying.

That distinction shaped the tool. It produces an inspection plan that proposes replay for explicitly declared reads, skips writes recorded as successful, and holds uncertain writes or unknown effects for review. A reused tool/key pair with different arguments is also held as a conflict. The output says why and links related call IDs, so a person or another system can inspect the decision.

Small rules, explicit limits

The planner is deterministic JavaScript with no model or application dependency. It normalizes object key order before comparing arguments, scopes key conflicts by tool, and rejects malformed rows rather than guessing their effects. Both the browser and CLI use the same rules. The CLI emits schema-versioned JSON for inspection by scripts or CI, but that output does not authorize execution.

The tests pin down the safety boundary: uncertain writes stay in review even with a key; a conflicting key fences both calls; and no combination schedules a write. The browser keeps input in page memory, supports a sample and JSON export, and has a clear action. Those details make it practical to inspect a trace without uploading it to a service.

There is a limit that matters more than the interface. TraceFence trusts the producer's effect and status labels. If a producer marks a side-effecting call as a read, this tool cannot discover the mistake. It also cannot query the destination, establish exactly-once behavior, or decide whether a repeated call with identical arguments is actually a duplicate. It makes the evidence in a trace easier to act on; it does not create evidence the trace never captured.

I like this boundary because automatic retry is an attractive place to hide uncertainty. A conservative plan makes the unknown visible and leaves the write decision with the system that can check the real effect.

TraceFence is open source, and the live demo runs the sample trace in your browser: repository · demo.

Get in touch

If you are working on agent reliability, email me at [email protected].