Repository navigation
Pin Claude Code CLI to 2.1.263 - #1797
Merged
Merged
Conversation
The 2.1.193 pin predates ~70 CLI releases and every flag the harness emits was last verified against it. The floating `@~2.1.0` lanes have been resolving to 2.1.263 for some time, so the exact-pinned lanes were certifying an older CLI than the ones actually exercising the product. Verified against the real 2.1.263 binary before bumping: every argv token and value the harness emits still parses (`--permission-mode` echoes back both `plan` and `bypassPermissions` in the init event; the `default` -> `manual` rename in that flag's choice list does not touch us, and upstream still accepts `default` anyway); the transcript-path encoder is byte-identical, re-extracted from the binary and confirmed live against a directory the CLI itself created; and the real-CLI MCP smoke passes on the new binary. Also moves the agent-cli stage to node:22, because claude-code 2.1.263 raises `engines.node` to >=22 (2.1.193 wanted >=18). node:20 still installs it, but only because EBADENGINE is a warning rather than an error - the shipped `claude` is a self-contained binary that never runs under the image's node. Tracking the declared floor keeps an `engine-strict` npm, or a future install script using node-22 syntax, from turning that warning into a failed image build. codex 0.142.2 declares >=16, so it is unaffected. Adds a pin test asserting real-model.yml's exact-pinned installs equal CLAUDE_CODE_VERSION, so a workflow left behind on a future bump fails at test time instead of silently gating on a CLI the worker never ships.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
2.1.193to2.1.263(npmlatest) across the worker image ARG,ClaudeCodeHarness.DefaultVersion, and the four exact-pinned installs inreal-model.yml. The five deliberately floating@~2.1.0installs are left floating — they already resolve to2.1.263, which is why the exact pins were the ones certifying an older CLI than the lanes actually exercising the product.agent-clistage tonode:22. claude-code2.1.263raisesengines.nodeto>=22(2.1.193wanted>=18);node:20still installs it, but only becauseEBADENGINEis a warning. The shippedclaudeis a self-contained binary that never runs under the image's node, so this is about keeping anengine-strictnpm — or a future install script using node-22 syntax — from turning that warning into a failed image build. codex0.142.2declares>=16and is unaffected.@anthropic-ai/claude-code@<version>literal inreal-model.ymlequalsCLAUDE_CODE_VERSION. Nothing asserted this before, so a workflow left behind on a bump would have silently gated on a CLI the worker never ships. The floating installs are excluded by the version pattern.Note: npm's
stabledist-tag is2.1.236, behindlatest. This PR targetslatestas specified; say the word ifstableis the better pin for the worker image.Test plan
--helpfrom both versions and diffed. Every token the harness emits still exists:--print,--output-format stream-json,--verbose,--resume,--append-system-prompt,--setting-sources user,--settings,--model,--allowedTools/--allowed-tools,--permission-mode,--mcp-config,--strict-mcp-config. Value choices for--output-format(text|json|stream-json) and--setting-sources(user|project|local) are unchanged. The one rename that touches this flag —--permission-modelisting"manual"where 2.1.193 listed"default"— misses us: the harness only ever emitsplanorbypassPermissions, and both are still in the choice list. Proven at runtime, not just in help text: running the full harness argv against the real 2.1.263 binary reached auth (i.e. past argument validation) and thesystem/initevent echoed back"permissionMode":"plan"and"permissionMode":"bypassPermissions"respectively.anthropics/claude-codeCHANGELOG across the 2.1.194–2.1.263 window. Nothing breaking for our surfaces. The entries that touch us and why they are safe: "Changed the "default" permission mode to "Manual" across the CLI...--permission-mode manualand\"defaultMode\": \"manual\"are accepted alongsidedefault" (a display rename;defaultstill accepted, and we emit neither). "Changed project-level.claude/settings.jsonenvto no longer setCLAUDE_CONFIG_DIR..." — we setCLAUDE_CONFIG_DIRas a real process env var viaConfigHomeEnvVars, never through project settings, and we pass--setting-sources userwhenever we write settings, so project layers do not load. "Fixed hooks silently treating a stdout{…}object that isn't valid JSON as plain text; it's now reported as a hook error" — our Stop hook writes its block reason to stderr and exits 2, and drains stdin outright, so it never presents stdout JSON. "SIGTERM in print/SDK mode no longer records an interrupted turn or synthetic tool denials before exiting... still exits with code 143" — exit code preserved; a timed-out run may simply carry fewer trailing events. Two fixes land in our favour: blocking Stop hooks no longer lose the turn's reasoning, and session transcripts are no longer overwritten when a directory change relocates a session onto an existing same-ID transcript.RA(e){let n=k(e);if(n.length<=az)return n;return \${n.slice(0,az)}-${Te(e)}`}withk=replace(/[^a-zA-Z0-9]/g,"-"),az=200,Te=Math.abs(gz(e)).toString(36),gz=(e<<5)-e+charCodeAt(r)|0— byte-identical in algorithm to 2.1.193'sab/Byu/hRe/pXe; only minified symbol names moved.defaultPath()still builds the projects segment asRA(cwd). (2) Ran the extracted functions over the existing ground-truth corpus: every pinned pair reproduces exactly, including the truncation branch's-e2qqelhash suffix at 207 chars. (3) Live: ran the real 2.1.263 binary from a cwd containing a space,_,.and non-ASCII and it created exactly-private-tmp-cs-enc-my-project-v2----x, whichClaudeTranscriptPath.EncodeCwd` reproduces. That pair is now pinned as regression data — it closes a corpus hole (no prior pair covered a space or non-ASCII).CODESPACE_RUN_REAL_CLI_MCP_SMOKE=1 CODESPACE_CLAUDE_CODE_PATH=<2.1.263> dotnet test --filter On_demand_the_real_claude_cli→ 1 passed, 5s (11s wall). Not sub-second, so it genuinely launched the binary: the runner wrote the declaration into the per-run config home and the MCP handshake was observed.docker build --target agent-clion the realDockerfile.workersucceeds with noEBADENGINE. Separately replicated the load-bearing runtime smoke (theclaude.exesymlink +codex --version && claude --versionat lines 113–115) on bothnode:20andnode:22;node:22printscodex-cli 0.142.2and2.1.263 (Claude Code)cleanly. Also confirmedclaude.exeis a self-contained ELF that runs with nonodeonPATH.CodeSpace.UnitTestsgreen: 9199 passed, 0 failed (HarnessVersionPinTests,ClaudeTranscriptPathTests,AgentNativeRecordPumpTests,ClaudeCodeHarnessTests: 158 passed).Not logged in,total_cost_usd: 0, zero tokens), and auth was left untouched. From the auth-failing run the envelope surfaces the harness parses were still confirmed on 2.1.263:system/initwith a canonical UUIDsession_id,assistantwithmessage.content[]textblocks andmessage.model, and the terminalresultwithis_error,result,session_id,usageandtotal_cost_usd. Thetool_use/tool_result/thinkingblock shapes were not exercised; the changelog records no change to them, and the real-model lane covers them.