Skip to content

fix(codex): port five upstream fixes - #32

Merged
vibecodedapps-dev merged 5 commits into
mainfrom
port/upstream-fixes
Sep 20, 2026
Merged

vibecodedapps-dev merged 5 commits into
mainfrom
port/upstream-fixes

Conversation

@vibecodedapps-dev

Copy link
Copy Markdown

Ports five open upstream fixes into our fork, one commit each so any of them can be reverted alone. Nothing here is a feature. Each upstream pull request is open and unreviewed, so each was reviewed as if written here rather than applied as given, and each test was run against the unfixed code first to confirm it fails for the reason the bug describes.

What now works

Reasoning efforts max and ultra are accepted. The validator stopped at xhigh while the models people run support two tiers above it, so those tiers were unreachable from the plugin. The tier list is repeated in the usage text, the error message, the rescue command's argument hint and the runtime skill, and all of them now agree. Upstream openai#761.

A file-change event that arrives before its change list is known no longer aborts the run. The code that describes a started item assumed the list was always there and threw a type error, which killed the turn. A missing list now counts as zero changes. Upstream openai#775.

A status check that waits and then times out now says so and exits non-zero. It used to print an ordinary running job and exit zero, so anything polling it read a timed-out wait as a finished check. The machine-readable output still carries the same timeout flag it always did. Upstream openai#774.

A connection attempt to the background broker that never completes now gives up instead of hanging forever, and a timeout is treated like the other connection failures that already fall back to running the server directly. Upstream openai#773.

The stop-time review gate now finishes a minute before the harness kills it, so a slow review reports the timeout and says how to bypass it instead of ending the turn silently. Both timers were set to the same fifteen minutes, so the message could never be delivered. Upstream openai#772.

Deviations from the upstream patches

The broker fix as written upstream capped each connection attempt at a tenth of a second even though the overall budget is two seconds. That would report a working broker as down whenever a connection took longer than that, which is realistic on a loaded machine and on Windows named pipes. Each attempt now uses the remaining budget instead; the hang is still bounded by the overall budget, which is the actual bug. Upstream also armed two separate timers per attempt and repeated the loop's own exit condition inside it; one timer is kept and the repetition is dropped. Upstream left the broker client's new timeout untested, so a test was added for it. Upstream's new test file for the readiness wait is kept as written, and the client test is a second new file, because this repo pairs one test file with one source file and the client lives elsewhere. The new client option is declared in the type definitions alongside the other options.

The stop-gate test upstream pulled the timeout constant out of the source with a pattern and evaluated it as code. That is replaced with a direct numeric comparison, which reads the same values without evaluating anything. It still fails if either the constant or the message drifts from the other.

The crash-fix test upstream also asserted on the exact wording of the runtime's type error. That assertion is dropped: the wording comes from the runtime, not from us, and the check that the run succeeds already fails for the right reason.

New tests that launch the tool use the absolute path of the running interpreter rather than the name node, because the test helper falls back to a shell on Windows for a relative program name and that mangles arguments.

Left out

Upstream openai#770 rewrites the prebuild step so it stops creating a directory literally named -p on Windows. Our prebuild step no longer creates that directory at all; it was dropped in an earlier commit here, and the type generator creates the directory itself. Verified by deleting the generated directory and running the build, which succeeds. The upstream change cannot apply and the problem it fixes does not exist here.

Two further upstream changes were considered and left for a separate decision: openai#768, broker teardown when a live broker misses its readiness probe, and openai#742, a sandbox mode flag, which is a feature rather than a fix and edits contract files that were rewritten here recently.

How it was checked

The full suite and the build were run before and after. Before: 220 tests, 219 pass, 1 skipped, 0 fail, build exits 0. After: 227 tests, 226 pass, 1 skipped, 0 fail, build exits 0. Every pre-existing test still passes. Each fix's test was run against the unfixed code and observed to fail first. All of this ran on macOS; Windows coverage comes from the existing continuous integration job.

One behavior is not covered by a test, stated rather than hidden: adding a timeout to the list of connection failures that fall back to running the server directly. That list lives in a private function reachable only through calls that cannot be given a short timeout, and its two existing entries have no coverage today either. Building that harness was judged out of proportion to a one-word change. The behavior that produces the timeout is covered.

Noticed, not fixed

Two pre-existing problems turned up while reading the code and are untouched here.

The fallback to running the server directly only triggers when the broker address is in the environment. A broker reused from a saved session does not put it there, so a hung connection on that path raises the error instead of falling back. The timeout added in this branch inherits that limit exactly as the two existing connection failures already do, so this widens nothing, but the gap is real. It is in the function that wraps a server call, in the file that holds the Codex client logic.

The usage text for the status command does not list its own wait and timeout options, so the only way to learn them is to read the source.

What to watch after merge

The status change is the one callers will notice: a wait that times out now exits non-zero, in both the readable and the machine-readable forms. Anything scripted around it that treated exit zero as "the check ran" will now see a failure. Also watch for a working broker being reported as unreachable, which would mean the per-attempt budget is still too tight, and for the review gate's timeout message appearing where the turn used to end quietly.

The validator, usage text, and docs stopped at xhigh, so the max and ultra
tiers supported by the models this plugin drives were unreachable through
--effort. Extend the accepted set and the strings that describe it.

Ports openai#761.
describeStartedItem assumed item.changes was always an array on a
fileChange item/started notification. Codex can emit the start event
before the change list is known, so item.changes is undefined and the
length read throws a TypeError that aborts the whole turn. Guard the
read the same way the other consumer of this field already does, and
treat a missing or non-array list as zero changes.

Ports openai#775.
waitForSingleJobSnapshot already computed waitTimedOut and timeoutMs
on the snapshot, but the status handler discarded both before
rendering: text output showed a normal running job and the process
exited 0. Callers that poll with `/codex:status <id> --wait` therefore
treated a timed-out wait as a finished check. Set a non-zero exit code
and print the timeout in both the text and JSON forms, while keeping
waitTimedOut in the JSON payload for existing consumers.

Ports openai#774.
A connect attempt that never completes (a named pipe or Unix socket
stuck accepting) left waitForBrokerEndpoint and the broker app-server
client hanging past their readiness budget instead of failing over to
a direct app-server. Bound each connect attempt to the remaining
readiness budget, and let the broker client's own connect timeout out
after connectTimeoutMs, treating ETIMEDOUT like the other broker
connection failures that already fall back to a direct app-server.

Ports openai#773, with three fixes to the upstream
patch: the per-attempt cap now uses the full remaining budget instead
of capping at 100ms (which would silently fail a working broker whose
connect legitimately takes longer, notably Windows named pipes); each
attempt arms one timeout mechanism (a plain setTimeout) instead of
both a setTimeout and socket.setTimeout; and the redundant
remainingMs <= 0 check duplicating the while condition is dropped.
The Stop hook's own budget (hooks.json, 900s) matched the stop-review
child's spawnSync timeout (STOP_REVIEW_TIMEOUT_MS, 15 * 60 * 1000ms).
Claude Code killed the hook process at the same instant the child would
have hit ETIMEDOUT, so the bypass/manual-review message never made it
out and the turn ended silently. Lower the inner timeout to 14 minutes
so it fires with headroom to spare before the outer hook budget runs
out.

Port of openai#772 (upstream openai#766).
@vibecodedapps-dev
vibecodedapps-dev merged commit c67fdee into main Sep 20, 2026
3 checks passed
@vibecodedapps-dev
vibecodedapps-dev deleted the port/upstream-fixes branch September 20, 2026 19:06
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