Skip to content

Build1 publisher3 min readPublished

Twelve timestamped events cannot say which tool call was the retry

A dev.to walkthrough logs an AI research-report run end to end, then asks four questions its own log cannot answer. The missing field is parentage: which event caused which, recorded when the event is emitted.

The Engineer · Build desk

Illustration accompanying Twelve timestamped events cannot say which tool call was the retry

What happened

  • A dev.to post publishes an example log of an AI research-report workflow: 12 timestamped events over 44 seconds, covering planning, two searches, a failed tool call, two model calls and a failed validation.
  • The post then asks four questions the log cannot answer, including whether the second tool call retried the failed one and whether the two searches ran sequentially or as parallel branches.
  • The post separates req_123 from a distinct execution_123 that owns three child jobs, search_job_A, search_job_B and tool_job_C, with a failure and retry beneath them.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Grouping stored events after the fact cannot recover an edge type nobody wrote down, so a generous retention policy still leaves a retry indistinguishable from a fresh call months later.
  • cost Whoever owns the workflow code pays for lineage, because no collector setting or sampling change can add a parent reference the emitting call never carried.
  • decision Teams that answer with 202 Accepted have to decide at enqueue time whether the resulting work gets an id of its own, because the choice cannot be applied retroactively to events already written.
  • exposure Where usage is billed or audited per execution, an ambiguous retry is a charge that cannot be defended from the log.

Timestamps order events without recording why one followed another. In the example log the failed tool call lands at 10:00:15 and another tool call at 10:00:18, three seconds later [16]. That gap fits a retry of the failure. It also fits a second, unrelated tool the planner queued during fan-out. The two searches sit one second apart [16], which fits a parallel branch whose emits happened to be a second apart and also fits two sequential calls. The example log is technically complete and answers none of the four questions [4].

The reframing in the post is a schema question. It asks not what events an AI runtime should preserve but "What identity and lineage must survive if we want to reconstruct how those events belonged together?" [13] Lineage here means a reference to the parent event plus a name for the kind of edge. The post enumerates five kinds: one operation spawned another, two ran as siblings, an attempt retried an earlier attempt, a worker continued work after the original request ended, and several branches contributed to the same result [6].

A single parent pointer covers the first of the five [7]. Retry-of, sibling, continuation and merge each need an edge label or a second id. The cost lands at the emit sites, because whatever code writes the event has to hold the parent id and the edge kind at that moment: the retry wrapper passes the id of the attempt it is retrying, the fan-out helper passes the parent job id to each branch. In my view those two helpers are where the instrumentation belongs, and the other emit sites can copy a parent id from context.

The identity split is the other half of the argument. In the post's example the API returns 202 Accepted and enqueues a job, so the HTTP request may live a few hundred milliseconds while the work it started runs for minutes [11]. After that, the queue message is delivered later, a worker creates several child jobs, one branch retries independently, another calls an external service and waits for a callback, and the workflow can pause and resume after the process that served the request no longer exists [18]. A request_id still correctly identifies the interaction that entered the system, the author writes, without necessarily being the right identity for everything that happens afterward [14].

The post credits distributed tracing with what it does, carrying context across services and process boundaries so related operations stay observable as part of one distributed flow [10]. The objection is narrower: propagation does not make the original request and the resulting domain execution the same concept [10].

This is one engineer's argument from a hand-built log, and the post does not publish field names, a schema or an implementation [17]. The author wrote it while working on AI monetization infrastructure [15]. On the shortcut of preserving events now and grouping them later, the author wrote, "I'm becoming less convinced that this is enough." [9] On what the example log lost: "We didn't lose the events. We lost the relationships between them." [5]

What to watch

  • Whether the author publishes field names or a schema for execution identity and edge kinds, since the post is argument only.
  • A tracing convention that labels retry-of and fallback-of edges would move this from each codebase into the tooling.
  • A production trace where retry-versus-new-call ambiguity caused a real misattribution would test the case beyond a hand-built log.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories