fix(install): give the codex CLI install the same retry window - #910
fix(install): give the codex CLI install the same retry window#910tend-agent wants to merge 3 commits into
Conversation
The codex action's `npm install -g @openai/codex` ran bare — one attempt, no timeout, no backoff — while the two CDN installers around it ride out a blip on the shared window. It is the action's only third-party reach and it sits ahead of `Run Codex`, so a registry blip cost the whole run. Extracted to shared/steps/install-codex-cli.sh, which sources lib/retry.sh the way install-proxy-uv.sh does. 60s stands as the timeout: measured on a GitHub-hosted runner with an empty npm cache, the install is 2.6-3.1s across three runs — `@openai/codex` ships a prebuilt binary, so there is no dependency tree to resolve and no toolchain to run. No third parameter on retry_install. Closes #909
tend-agent
left a comment
There was a problem hiding this comment.
The extraction is faithful and the retry contract is now identical across the three installers. Passing CODEX_VERSION through env: instead of interpolating ${{ inputs.codex_version }} into the run: body is a real improvement over the block it replaces. Tests pass locally (52 in test_shared_steps.py), shellcheck -S warning is clean on the touched scripts.
One gap the new lib/retry.sh header surfaces rather than causes: it now enumerates the pre-agent third-party reaches as three, but there is a fourth. proxy/setup-sandbox.sh warms the uvx cache with "$UVX" --from "$MITMPROXY" mitmdump --version (under the "Warm the uvx cache first" comment) before it backgrounds the proxy — that resolves mitmproxy==$MITMPROXY_VERSION from PyPI on a cold UV_CACHE_DIR, under set -euo pipefail, ahead of the agent step in the Claude action. A cache miss (first run on a new pin, or an evicted actions/cache entry) plus a PyPI blip reddens the run having done none of the work the trigger asked for — the same failure this stack exists to close. It's the wrong PR to fix it in (different harness, different issue, and CLAUDE.md's atomic-PR rule), but happy to open a follow-up that puts that resolve on the window and updates the header's enumeration.
Non-blocking on the test suite: FAKE_NPM reads the package spec off $3 positionally, so it silently mis-parses if the install command ever grows a flag. The version assertion in the happy-path test is what would catch it, which is enough — just worth knowing the coupling is there.
The fake took it from $3, which is the spec only while the install command is exactly `install -g <spec>`; a flag added anywhere ahead of it would have the fake echo `-g` as the installed version instead. Raised in review of this PR as non-blocking, and cheap enough to remove the coupling outright.
|
Both points from the review, as author. The fourth reach. Confirmed and out of scope here:
Still based on #908 and will retarget to |
Problem
install-claude-binary.shandinstall-proxy-uv.shboth ride out a CDN blip on the shared window inshared/steps/lib/retry.sh. The codex harness's third pre-agent installer wasn't on it:npm install -g "@openai/codex@..."ran as a bare inlinerun:block — one attempt, no timeout, no backoff. It is the codex action's only reach to a third party, and it sits ahead ofRun Codex, so a registry blip took the whole run red having done none of the work the trigger asked for.Solution
Extracted the install to
shared/steps/install-codex-cli.sh, sourcinglib/retry.shthe wayinstall-proxy-uv.shdoes; the action step becomes abash .../install-codex-cli.shwithCODEX_VERSIONinenv:. The version-pin rationale stays incodex/action.yamlnext to the input it explains.The 60s timeout stands
#909 flagged that
retry_installhardcodestimeout 60, sized for acurl | shthat fetches one installer script, and asked whether a global npm install could legitimately exceed it — in which case dropping codex under the current lib would convert slow installs into failures.Measured on a GitHub-hosted runner with an empty npm cache, three cold installs of
@openai/codex@0.131.0-alpha.22: 3.08s, 2.60s, 2.63s (218 MB unpacked, 2 packages). The package ships a prebuilt per-platform binary, so there is no dependency tree to resolve and no toolchain to run — the shape that would justify a longer window isn't there. 60s leaves ~20x headroom, so no optional third parameter onretry_install; the measurement and its date are recorded in the script's header so a future bump can re-check it rather than re-derive it.Testing
Four tests in
generator/tests/test_shared_steps.pymirroring the claude and uv suites, with a fakenpmanswering503 Service Unavailableon a schedule: rides out a four-failure burst, backs off 5/10/20/40 with jitter, reddens after five attempts, and installs first-try without sleeping. The happy-path test asserts the installed version echoes back, which keeps the pin honest — the step has to install thecodex_versionit was handed, not npm'slatest.Against the bare install the burst, backoff and redden tests fail (one attempt, no
after 5 attemptsmessage); against the new script all 52 tests in the file pass.shellcheck -S warningand the rest of pre-commit are clean on the touched files.Stacking
Based on #908, where
lib/retry.shlands — it will retarget tomainwhen that merges. The diff against #908 is this commit alone.Closes #909