OpenClaw's Codex Final-Reply Race Is the Kind of Bug That Makes Agents Feel Haunted

OpenClaw's Codex Final-Reply Race Is the Kind of Bug That Makes Agents Feel Haunted

The most annoying agent bugs are not the ones where the model says something foolish. Those at least have the decency to look like model failures. The worse class is when the model does the work, the runtime captures the answer, and the user still sees nothing because a transport boundary closed at the wrong millisecond.

That is the bug OpenClaw PR #90790 is trying to fix. The pull request, opened on June 6 at 00:20 UTC and updated shortly after, targets a Codex app-server finalization race: a completed assistant reply can be lost if the Codex client closes before the terminal turn/completed signal arrives. The patch is narrow — three files, one commit, +131/-4 — but the surface is important. In channel-backed automation, final delivery is not an implementation detail. It is the product.

The PR preserves captured completed assistant text as the final reply only when the turn is otherwise quiet: no active turn request, no active item, and no pending dynamic tool completion. That last clause is the whole story. A naive fix would say, “we have text, ship it.” A correct fix asks whether that text is actually final, or whether the app-server still has work in flight that could change the answer.

A closed pipe is not a failed turn

The linked issue, #90771, sits in the same family of failures every agent platform eventually meets: confusing transport lifecycle with task lifecycle. EOF, closed stdin, websocket termination, or an app-server client close tells you something about a connection. It does not necessarily tell you whether the agent failed. OpenAI Codex app-server has a terminal turn concept — turn/completed — and OpenClaw has to integrate against that, not against the comforting Unix-era assumption that a subprocess either prints and exits or exits and fails.

That distinction matters because Codex is no longer just a terminal assistant that emits text into a shell. Recent Codex releases have been adding app-server and multi-agent control-plane features: remote-control grant listing and revocation, plugin workflow JSON output, multi-agent v2 metadata, and richer runtime behavior. Once Codex becomes a distributed agent surface, OpenClaw has to track item completion, tool completion, turn completion, transport close, and channel delivery as separate facts.

Collapse those facts and users get haunted software. The work happened, but the reply vanished. The model answered, but the channel stayed quiet. The human retries, or a parent agent retries, and now the same operation may run twice. In a coding workflow that can mean duplicate edits. In an ops workflow it can mean duplicate tickets, repeated tool calls, or needless provider spend. “Lost final reply” sounds like a UI bug until you remember agents increasingly mutate real state.

The guard conditions are the engineering

The useful part of #90790 is not merely that it saves completed output. It saves completed output under explicit conditions. Completed assistant text is recoverable if no active turn request remains, no active item is underway, and no dynamic tool completion is pending. Partial assistant deltas still fail. Completed text while another current-turn item is active still fails. Completed text while a dynamic tool result is pending still fails.

That is the right conservative posture. Partial output can look plausible and still be dangerously incomplete. A tool result can invalidate the sentence the assistant wrote before the tool returned. Another active item can mean the apparent “final answer” is only one part of a larger turn. In agent runtimes, premature success is often worse than visible failure because it trains operators to trust a boundary that is actually guessing.

ClawSweeper’s review captured the same point from the other side. It rated the patch quality highly — “diamond lobster,” because apparently even automated reviewers need taxonomy — but blocked merge pending live channel or gateway proof. That is not bureaucracy. Unit tests can show that finalization state transitions behave correctly. They cannot prove that a Telegram, Slack, Discord, or other channel user receives the recovered answer exactly once through the real delivery path.

That “exactly once” is not pedantry. Delivery recovery bugs love turning into duplicate delivery bugs. If OpenClaw preserves completed text after a close, it must also avoid replaying the answer if the normal turn/completed path later delivers, or if the parent channel retry machinery wakes up. The target behavior is not “more replies.” It is one durable final reply when the model actually completed.

What operators should test

If you run Codex-backed OpenClaw in chat channels, do not treat this as an abstract upstream concern. Build a small failure drill. Start a Codex turn from the channel you actually use. Force the window where completed output has been captured but the app-server client closes before the terminal signal. Then verify three things: the final answer lands, it lands once, and no retry path re-executes the work.

Also test the negative cases. A partial assistant stream should not be promoted to final. A turn with pending tool work should not be promoted to final. A turn with another active item should not be promoted to final. The happy path matters less than the boundary cases because boundary cases are where agent systems spend your money while insisting everything is fine.

For developers building similar integrations, the design lesson is straightforward: model output is not enough. You need a turn state machine with typed events and a delivery contract. “The client closed” should be one input to that state machine, not the verdict. “The assistant item completed” should be another input, not automatic success. “The channel delivered” should be recorded separately, because user-visible success is the only success that matters in a channel-backed agent.

This is also why agent observability has to include delivery semantics, not just token usage and latency. Operators need to see whether a turn completed at the model layer, completed at the runtime layer, and completed at the channel layer. If those three diverge, the system should say so plainly. Otherwise every lost reply becomes a ghost story told in logs.

The broader trend is clear. Codex app-server is becoming a control plane, and OpenClaw is becoming one of the runtimes that has to make that control plane useful outside a terminal. That means the boring distributed-systems work — terminal events, transport events, idempotent delivery, retry safety, and proof artifacts — becomes the real product work.

The take is not “OpenClaw fixed a race.” The take is that app-server agents need delivery semantics as strict as any distributed system. If completed work can disappear at the channel boundary, the model is not the weak link. The runtime is.

Sources: OpenClaw PR #90790, OpenClaw issue #90771, OpenClaw PR #90305, OpenAI Codex rust-v0.137.0 release