Skip to content

codex-bridge: one wake can start two turns during turn/start #870

Description

@ainyan03

Thanks for agmsg — it's become a daily driver for multi-agent messaging here. Filing a timing-sensitive race in the Codex bridge, with a deterministic harness reproduction.

Symptom: a single wake occasionally produces two injected turns — the second an empty poll ("No new messages.") that burns a turn on the live thread. Observed in live use (on a v1.1.13-era install); the affected code path is unchanged on current main.

Mechanism: turn/completed and thread/status idle arrive independently and both funnel into the bridge's turn-end handling (#41 is why idle has to count as an end). App-server requests and notifications can arrive before an outstanding RPC response — the approval-collision test already exercises that interleaving. So:

  1. Turn A ends; the bridge delivers a deferred wake and sends turn/start for turn B.
  2. Before B's ACK arrives, turn A's trailing end signal (an idle, or a completed without a usable id) lands.
  3. The bridge attributes it to B, believes B already ended, and re-delivers the wake → a second turn from the same wake.

Reproduction: a bats harness driving the bridge against a scripted app-server reproduces the duplicate deterministically; two additional regression tests cover the legitimate orderings a fix must not break (pre-ACK completion, stale-idle attribution). On live current main (f7de22a, codex-cli 0.147.0) I could not provoke it in 13 rounds of mid-turn message bursts — the harness is what reproduces the relevant ordering reliably.

Fix shape (running locally, holding up in daily use): claim the pending wake before sending turn/start, and attribute mid-start end signals by turn id — only an id-matching completed defers the end; an idle or id-less signal landing during start is discarded, since the #41 watchdog already covers the pathological no-signal case. As defense in depth, the injected prompt reads the inbox with --quiet so an empty read cannot become a turn prompt. Patch + the three regression tests are ready; happy to PR if this direction fits.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions