Admit codex-cli 0.147.0 after repeating the pin's policy checks - #272
Merged
Conversation
st2's controlled Codex launch refused the installed 0.147.0, taking native delivery out of service on any machine that ran `codex update`. The schema comparison 0.146.0 -> 0.147.0 is complete: no definition was removed, no `ServerRequest` arm was added or renamed, and every message envelope st2 parses is byte-identical after canonicalization. The raw diff is noise because 0.147.0 emits object keys in sorted order. Live evidence reached a submitted `turn/start` against the real binary: the delivered prompt rendered in the remote TUI, which then failed on the account's usage limit, with a reset estimated at 2026-08-20. Everything gated behind a completed model turn is therefore unproven on 0.147.0. The constant's doc comment names that gap rather than asserting a check that did not finish. The existing gate test asserted 0.147.0 was rejected. It now derives its admitted cases from the constant, and pins rejection of an older unadmitted release and of the 0.148.0 alpha. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2 tasks
schickling
marked this pull request as ready for review
August 18, 2026 06:57
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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.
Why
SUPPORTED_CODEX_CLI_VERSIONSadmitted0.145.0and0.146.0only, andensure_supported_version(src/codex_app_server.rs:2101) is a hard gate: on a machine wherecodex --versionreportscodex-cli 0.147.0— the current npmlatest, and whatcodex updateinstalls — every controlled Codex launch aborts before it spawns the app-server, so native delivery is out of service for that agent until the constant is edited. The constant's doc comment is right to be strict, and this PR does not relax it: it repeats the two checks the policy demands for0.147.0and records exactly how far each one got.What
codex-cli 0.147.0alongside0.145.0and0.146.0. Nothing else about the gate changes: the comparison stays an exact string match against the allowlist.0.147.0does not yet satisfy. A version whose live evidence is partial must say so at the constant, or the comment asserts something false about one of its own entries.protocol_version_gate_accepts_only_the_exact_allowlistto derive its accepted cases fromSUPPORTED_CODEX_CLI_VERSIONSitself, so a future bump cannot widen the allowlist without the test following it. It pins rejection of an older unadmitted release (0.144.0) and of0.148.0-alpha.21.0.148.0-alpha.21stays rejected deliberately. An unreleased prerelease cannot carry live evidence, so admitting it would assert a check that is impossible to perform.--remoteTUI is the interactive client that answers server→client requests. TheServerRequestarm list is byte-identical across the two versions, so no new request class appeared that st2's observer could stall on by ignoring it.Impact
0.145.0or0.146.0. Both remain admitted, and the gate's accept/reject logic, error text, and call site are untouched.INVARIANTS.mdis unchanged; no invariant is claimed, relaxed, or added.Checks
Check 1 — delivery-critical schema comparison, complete.
codex app-server generate-json-schema --out <dir>for both versions (0.146.0installed to a scratch npm prefix;0.147.0is the system binary). The raw diff is unusable —0.147.0emits object keys in sorted order, so all 246 files "differ":After canonicalizing every file with sorted keys, the real diff is ~40 files. Comparing the two aggregate
definitionsmaps:Every definition st2 parses, checked individually against the code rather than against a supplied list —
src/codex_app_server.rsreadsinitialize,initialized,hooks/list,thread/loaded/list,thread/resume,thread/started,thread/status/changed,turn/started,turn/completed,item/started,item/completed,turn/start,turn/steer:ThreadStatusandThreadActiveFlagare byte-identical,activeFlagsincluded: armsnotLoaded/idle/systemError/active, withactivestill carrying requiredactiveFlags: ThreadActiveFlag[]and the enum still exactlywaitingOnApproval,waitingOnUserInput.ServerRequestarms, byte-identical in both versions — no arm added, removed, or renamed:ServerNotification(70 arms) andClientNotification(1) are unchanged.ClientRequestgained 5 arms, allThreadSection*, none of which st2 calls.Every difference found in the surface st2 consumes, classified:
Thread.isPinnedremovedThreadisPinned; st2 reads only/result/thread/{id,status/type,turns}Thread.section,Thread.sectionEnteredAtadded (both nullable, default null)ThreadThreadItem.mcpToolCall.readOnlyHintadded (nullable)ThreadItemThreadItem.imageGeneration.transparentBackgroundadded (nullable, default null)ThreadItemCommandAction.read.path$refAbsolutePathBuf→LegacyAppPathStringCommandAction{"type":"string"}, andLegacyAppPathStringalready existed in 0.146.0; st2 never reads itInitializeCapabilities.extensionsadded (nullable object)InitializeCapabilitiesexperimentalApiis unchanged and is the only capability st2 sendsToolRequestUserInputParams.isBlockingadded, requiredToolRequestUserInputParams--remoteTUI is the client that answers itResponseItem.encrypted_function_argsadded (nullable array)ResponseItemThreadSection*RPCsClientRequestNothing st2 parses changed shape. No definition was removed.
Check 2 — live remote-TUI evidence, partial. See Limits.
A real controlled launch,
st2 codex-app-serverdriving the realcodex-cli 0.147.0under a PTY, with the version gate patched to admit it. Reproduced twice; artifacts are the wrapper's own diagnostics.That exercises, against the real binary: the version gate, the controlled app-server spawn, the control socket, the WebSocket handshake,
initialize+initialized, andthread/startedparsed for/params/thread/idand/params/thread/status/type— the binding carries a real thread id and the observed status resolved toidle.The resume path polls
thread/loaded/listand parses/result/dataas a string array without bailing:With a message queued through
st2 message send, the delivery path selected the inbox head and submittedturn/start:The TUI rendered
[id: 0ny64d], matching the inbox filename1787034315897-0ny64d.md: st2's delivered prompt reached the thread and was submitted to the model on0.147.0. The turn then failed on the account's usage limit, andthread/status/changed→systemErrorwas parsed from/params/threadIdand/params/status/type.The independent confirmation of the limit:
Test suite.
nix develop --command cargo test --locked --no-fail-fastreports 8 failing targets:catalog_diff,eval_run_e2e,eval_up,materialize,native_only,nomad_survival,targeted_reconcile,transport_isolation. None is introduced here, and the honest reason is twofold.catalog_diff::classification_only_and_nested_agent_filename_changes_are_exactis the known stale-KDL-fixture failure.native_only::tracked_product_surface_contains_only_native_namesfails on tracked repo content unrelated to this branch:The rest are fleet- and process-level targets —
eval_upboots real supervised agents,nomad_survivalcrosses a systemd scope — and they were run while three sibling agents executed the same suite concurrently on this machine, which is enough to explain them:Because this branch changes exactly one file, the classifying run is the same eight targets with
src/codex_app_server.rsreverted to its parent state, run serially in the same worktree. The failure sets are identical — same eight targets, same thirteen test names, in both directions:Every one of those thirteen fails identically with this branch's single file reverted, so none is introduced here. The scoped signal is the one that actually covers the change: all 34
codex_app_serverunit tests pass, including the rewritten gate test.Formatting:
cargo fmt --checkis dirty across the repo and is not a usable gate.rustfmt --check src/codex_app_server.rsreports the same 10 pre-existing hunks before and after this change (lines 1851, 1881, 1896, 1903, 1915, 1925, 1940, 1950, 3275, 4119); none is in an edited region.On the issue's optional fourth item. Not done, and this bump is the argument against the simple form of it. A digest of the raw generator output would have flagged 100% of files as changed here —
0.147.0sorts its object keys — while telling a reviewer nothing. A digest of the canonicalized output changes on every additive field too, so it cannot separate additive from breaking either. What made this comparison mechanical was canonicalization plus selecting the definitions st2 actually parses; that is a small tool with its own tests, not a committed blob, and it does not belong in a version-pin PR.Limits
The live half of the policy is not fully met for
0.147.0, and the reviewer should weigh that before merging.The account was over its usage limit for the whole of this work, with the reset estimated at
Aug 20th, 2026 5:31 AM, so no model turn could complete. Evidence stops at a submittedturn/start. Specifically, these remain unproven on0.147.0:turn/startresponse body.delivery-state.jsonis written atphase: "attempted"before the request goes out, so its presence does not prove a response came back;/result/turn/idwas never observed to parse.turn/started— the observed state never reachedActive { turn_id }, so this notification was not seen.turn/completed.item/completed/userMessagereceipt. Delivery never advanced pastattemptedtoaccepted.turn/steerand the whole steer path, which needs an active turn.thread/resumesubscription path —/result/thread/id,/result/thread/status/type,/result/thread/turns— andreconcile_resume. A resume needs a persisted rollout, and a thread with zero completed turns has none. The attempt failed with, from the real binary:These are the same schema definitions the comparison above found byte-identical to
0.146.0, which is the basis for admitting the version now — but that is a schema argument, not the live evidence the doc comment asks for. Re-running the live half after the quota resets would close it.Unrelated to this bump, and not a regression. With
--listen— the only mode st2's controlled launch uses — the app-server refuses a symlinked$CODEX_HOME/app-server-control:This reproduces identically on
0.146.0, an already-admitted version, so it is a live failure on the current pin rather than anything admitting0.147.0introduces. If it argues either way about this PR, it argues mildly for it: the bug is present today on a version st2 already launches. (0.145.0untested.)The scope is narrow, and bare
codex app-serveris unaffected — a symlinked control directory only refuses on the--listenpath. It is not the--listensocket path (a real directory there still refuses), notCODEX_HOMEitself being symlinked (a realCODEX_HOMEwith a symlinkedapp-server-controlchild is enough), and not a broken link (the target directory exists in every failing case).~/.codex/app-server-controlis symlinked on this machine, which is why the live runs above used a scratchCODEX_HOMErather than disturbing the operator's setup.Filed as #275. This is a provider-side behaviour, not an st2 contract, and it is not addressed here.
Ready for review.
Related
Closes #267. Its first and third acceptance boxes are met; the second — live remote-TUI evidence — is partial, as set out above, and is the reason this is a judgment call rather than a clean tick. The fourth was explicitly optional and separable, and is argued against on the evidence of this bump.
#263 read
activeFlagsoff the 0.147.0 schema while st2 still refused that version. The comparison here confirmsThreadActiveFlagis byte-identical across 0.146.0 and 0.147.0, so that reading also holds on a supported version — but on 0.145.0/0.146.0 it remains schema-confirmed only, not live-captured.