Skip to content

fix(codex-implementer): stop lanes colliding in /tmp and stalling forever - #14

Open
wooter wants to merge 1 commit into
DannyMac180:mainfrom
wooter:fix/lane-reliability
Open

fix(codex-implementer): stop lanes colliding in /tmp and stalling forever#14
wooter wants to merge 1 commit into
DannyMac180:mainfrom
wooter:fix/lane-reliability

Conversation

@wooter

@wooter wooter commented Aug 10, 2026

Copy link
Copy Markdown

Three defects in the lane, all observed repeatedly across parallel lanes on macOS. Independent of #12 — different hunks, the two merge cleanly in either order.

1. mktemp -t codex-spec.XXXXXX doesn't do what it looks like on macOS

BSD mktemp treats -t's argument as a prefix, not a template. The literal XXXXXX survives into the filename:

$ mktemp -t codex-spec.XXXXXX
/var/folders/ph/1j0k93y96x19llq06r2m0pn40000gn/T/codex-spec.XXXXXX.TJEjQBKZt2

So every lane on the host emits a path matching the same codex-spec.XXXXXX.* glob. That is the enabling condition for cross-lane pickup: a lane recovered its spec path by globbing and ran a different, concurrently executing lane's spec. I found two such stray files sitting in TMPDIR on my machine from real runs.

The block sits directly beneath the words "never a fixed path (parallel lanes on fixed paths corrupt each other)" — the intent is already right, the code just doesn't deliver it. Passing an explicit template as an operand substitutes the Xs on BSD and GNU alike.

Fix: one private scratch dir per lane, with spec.md and final.txt inside it.

2. Nothing said how to carry the path across tool calls

$SPEC only lives for one Bash call, so lanes improvise:

  • ls /tmp/codex-spec.* | tail -1 — sorts by random suffix, not mtime, so under concurrency it cheerfully returns another lane's spec
  • /tmp/.codex_spec_path — a fixed global sidecar; two lanes clobber it deterministically, not occasionally

Both are now called out explicitly, with the two safe options (same tool call, or echo the path and copy it forward).

3. Lanes background codex and then wait forever

The dominant failure in my logs — eight separate incidents. A lane launches codex exec as a background task, ends its turn "waiting for the completion notification", and nothing is wired to deliver that notification to a subagent. Observed shape: 60–100k tokens across dozens of tool calls, empty working tree, no report, while the caller believes work is in flight. One session hit it three times.

Related: a 600 s shell wrapper is meaningless when the Bash tool call itself defaults to 120 s. The tool kills the command long before the documented cap can apply, so the "ten-minute wall clock" is fiction unless the tool-call timeout is set to match.

Both are now stated plainly in step 2, plus a hard rule: never end your turn with a codex process still running.

Verification

Check Result
mktemp -d "${TMPDIR:-/tmp}/codex-lane.XXXXXX" on BSD mktemp Xs substituted, no literal XXXXXX
two simulated concurrent lanes distinct dirs, neither spec swapped
overlap with #12 none — disjoint hunks

Docs-only change.

…ever

Three defects, all observed repeatedly across parallel lanes on macOS.

1. `mktemp -t codex-spec.XXXXXX` does not do what it looks like on macOS.
   BSD mktemp treats -t's argument as a PREFIX, not a template, so the
   literal XXXXXX survives into the filename:

       /var/folders/.../codex-spec.XXXXXX.TJEjQBKZt2

   Every lane on the host therefore produces a path matching the same
   `codex-spec.XXXXXX.*` glob. That is what makes cross-lane pickup
   possible — one lane recovered its spec path by globbing and executed a
   *different, concurrently running* lane's spec. The block sits directly
   under the words "never a fixed path (parallel lanes on fixed paths
   corrupt each other)", which is the right intent; the code just did not
   deliver it. Passing an explicit template as an operand substitutes the
   Xs on BSD and GNU alike.

   Switch to one private scratch dir per lane and put spec/final inside it.

2. Document how to carry the path across tool calls. `ls /tmp/codex-spec.*
   | tail -1` sorts by random suffix, not mtime. Parking it in a fixed
   sidecar (/tmp/.codex_spec_path) is worse — concurrent lanes clobber that
   deterministically rather than occasionally.

3. Lanes background `codex exec`, then end the turn "waiting for the
   completion notification". Nothing delivers that notification to a
   subagent, so the lane waits forever: 60-100k tokens across dozens of
   tool calls, empty working tree, no report, while the caller believes
   work is in flight. Relatedly, a 600 s shell wrapper is meaningless when
   the Bash tool call itself defaults to 120 s — the tool kills the command
   long before the documented cap applies.

   State both plainly: foreground the call, set the tool timeout to match,
   and never end a turn with codex still running.

Verified: the new mktemp form yields distinct dirs on BSD mktemp with the
Xs substituted, and two simulated concurrent lanes keep their own specs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@wooter
wooter force-pushed the fix/lane-reliability branch from e92e8b3 to 0bc012a Compare August 10, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant