Skip to content

[Bug][Windows] Stale persisted CLI 0.135.0 strips max/ultra while Codex Desktop runs 0.153.4 #4204

Closed

Description

@lidge-jun

Summary

On Windows, OpenCodex 2.50.0 can strip max and ultra from the shared Codex catalog using a stale standalone CLI, while the running Codex Desktop app uses a newer runtime that supports both. Starting/syncing OpenCodex can therefore remove options that the actual Desktop runtime accepts.

The installed sources for runtime.ts, catalog/bundled.ts, and catalog/effort.ts were verified byte-for-byte against the corresponding Git blobs at upstream HEAD 2d4d7a22381a2e497c2442902104619e25f937c7 during this investigation.

Client / Area / Environment

  • Client: Codex App; area: Catalog / models, Windows runtime discovery.
  • Windows 11 Pro, build 26200, x64.
  • OpenCodex: @bitkyc08/opencodex 2.50.0.
  • Installed MSIX: OpenAI.Codex 26.903.9818.0; app.asar package version: 26.903.71938.
  • Persisted OpenCodex runtime: %LOCALAPPDATA%\Programs\OpenAI\Codex\bin\codex.exe, codex-cli 0.135.0, source configured.
  • Running Desktop child runtime, verified through the process table: %LOCALAPPDATA%\OpenAI\Codex\bin\<hash>\codex.exe, codex-cli 0.153.4.
  • Desktop parent executable: %ProgramFiles%\WindowsApps\OpenAI.Codex_<version>_x64__<publisher>\app\ChatGPT.exe.

Reproduction And Fresh Proof

The existing codex-runtime-clamp.json records removedEfforts: ["max", "ultra"], runtime version 0.135.0, at 2026-09-10T12:01:09.525Z. Affected rows include gpt-6-astra, the GPT-5.6 family, and routed Anthropic models.

A non-mutating probe imported the installed OpenCodex functions supportedCodexReasoningEffortsFromObservedCatalog and clampCatalogModelsToObservedCodexSupport. For each real executable it ran --version and debug models --bundled, then applied the derived support set to the same in-memory GPT-6 Astra row. It did not run live sync or rewrite the user's catalog.

Runtime Derived support Removed Surviving
persisted CLI 0.135.0 low, medium, high, xhigh max, ultra low, medium, high, xhigh
active Desktop CLI 0.153.4 low, medium, high, xhigh, max, ultra none low, medium, high, xhigh, max, ultra

Reproduction shape, with legacyCli and desktopCli set to the two real executable paths:

import { execFileSync } from "node:child_process";
import {
  supportedCodexReasoningEffortsFromObservedCatalog,
  clampCatalogModelsToObservedCodexSupport,
} from "./src/codex/catalog/effort";

for (const exe of [legacyCli, desktopCli]) {
  const bundled = JSON.parse(execFileSync(exe, ["debug", "models", "--bundled"], { encoding: "utf8" }));
  const rows = [{
    slug: "gpt-6-astra",
    default_reasoning_level: "medium",
    supported_reasoning_levels: ["low", "medium", "high", "xhigh", "max", "ultra"].map(effort => ({ effort })),
  }];
  console.log(clampCatalogModelsToObservedCodexSupport(
    rows, supportedCodexReasoningEffortsFromObservedCatalog(bundled),
  ));
}

The user reports disappearing picker options after starting OpenCodex. The full UI/startup sequence was not replayed during this investigation, to avoid restarting an active Desktop session. At inspection time the on-disk catalog already contained max/ultra for Astra and Sol (last write 2026-09-10T12:55:35Z), while the earlier clamp diagnostic remained. Thus that diagnostic is historical evidence, not a claim that the current file still lacks the options. The controlled probe reproduces the destructive projection itself.

OpenCodex Source Trace

  1. runtime.ts:576: resolution orders environment, persisted configuration, shim, PATH, fallback. A still-runnable persisted CLI wins even when another runtime is newer. This resolver does not reconcile its choice with the running Desktop child. resolveAndPersistCodexRuntime also persists automatically discovered selections, so configured alone does not establish that the user intentionally pinned an old runtime.
  2. catalog/bundled.ts:241: bundled-catalog loading probes the single selected runtime and defaults discoverAlternatives to false.
  3. catalog/effort.ts:313: the effort vocabulary is derived from bundled bare native models.
  4. catalog/effort.ts:348: unsupported rungs are removed from rows; the list-level helper applies this across models.
  5. catalog/sync.ts:1945: sync invokes the clamp. cli/index.ts:488 calls the startup sync gate.

Why This Appears On Windows

The inspected Windows Desktop app and OpenCodex do not share executable discovery. Desktop runs a relocated, hash-addressed runtime under %LOCALAPPDATA%\OpenAI\Codex\bin, while OpenCodex retains a runnable older executable under %LOCALAPPDATA%\Programs\OpenAI\Codex\bin.

The installed Desktop app.asar was read directly, without modifying it. In .vite/build/main-CMBCj4XL.js:1, runtime resolution contains Windows-specific bundled-path and WindowsApps relocation handling (Zr, Qr, $r; relocateWindowsApps). This differs from OpenCodex's persisted/PATH resolver. The process table and both --version probes confirm that these paths actually differ on the affected machine.

This is a Windows packaging/runtime-discovery mismatch, not evidence that Windows cannot support these efforts. The clamp itself is platform-independent, and the same stale-runtime arrangement could affect other OSes. No macOS machine was tested, so strict Windows exclusivity is not established.

Separate Desktop Display Conditions

The installed Desktop renderer also filters efforts independently of the catalog:

  • webview/assets/app-initial-f094ef01c64d.js:1, M2i: intersects model effort rows with enabledReasoningEfforts, and removes Ultra when includeUltraReasoningEffort is false.
  • The same bundle defines enabled-reasoning-efforts; its default list omits max. Ultra additionally has a feature gate in the model query (1186680773) and a show-ultra-in-model-picker-slider preference defaulting to false.
  • webview/assets/agent-settings-bfb770313a62.js:1: the available-efforts settings depend on hasModelSupportingMaxReasoningEffort / hasModelSupportingUltraReasoningEffort. A clamped model list can therefore remove the settings choices themselves.

These are source-observed conditions, not a claim about the affected user's current feature-gate values. They explain why restoring catalog bytes alone is insufficient to guarantee visible controls. No Windows-only max/ultra exclusion was established in these inspected filter functions.

Expected Behavior / Suggested Fix

For Desktop catalog synchronization, detect and report the consuming Desktop runtime and compare it with the selected OpenCodex CLI before destructively reducing the shared catalog. Distinguish explicit runtime pins from automatically persisted discovery. Account for Windows MSIX relocation and process identity; do not simply probe a protected WindowsApps path or silently replace an intentional pin.

Keep old-CLI compatibility handling where it is actually needed. Do not unconditionally enable arbitrary efforts: a newer Desktop and an older CLI may share the catalog, so runtime-specific projections or an explicit mismatch/recovery flow may be necessary. Diagnostics should separate runtime mismatch, catalog clamp, stale Desktop model cache, and renderer visibility preferences/gates.

Regression coverage should include a runnable legacy configured CLI beside a newer MSIX Desktop child, and verify that Desktop synchronization does not silently use the legacy ladder.

Related / Checks

Activity

  1. added
    platformOS/service/tray/ACL (Windows-heavy, not Windows-only)
    on Sep 10, 2026
  2. Ingwannu commented on Sep 10, 2026

    @Ingwannu
    Owner

    The reported two-runtime probe is evidence of a consumer-identity mismatch, not evidence that Windows lacks max/ultra support. I am treating the saved clamp diagnostic as historical, as your report explicitly does—not claiming the currently materialized catalog is still clamped.

    The paired failure in #4207 matters for the fix: remote-client downloads can be too permissive for the legacy CLI, whereas using that same legacy CLI's ladder globally can be too restrictive for Desktop. Keep the existing compatibility clamp; bind any local projection to its consumer rather than globally enabling efforts or silently replacing an intentional runtime pin. This needs mixed-runtime coverage and a distinction between catalog compatibility and Desktop renderer visibility. I have not probed proprietary app binaries or changed the live runtime/catalog in this review.

  3. lidge-jun commented on Sep 10, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 45 / 80

    Windows 에서 OpenCodex 가 디스크에 남은 오래된 standalone Codex CLI(0.135.0)로 공유 카탈로그를 clamp 하면 max/ultra 가 빠지는데, 실제로 돌아가는 Codex Desktop 은 더 새 런타임(0.153.4)이라 그 rung 을 지원합니다. 시작/동기화만으로 Desktop 이 쓸 수 있는 옵션이 사라집니다. “어떤 Codex consumer 기준으로 카탈로그를 깎을 것인가” 설계 문제입니다.

    현재 dev HEAD 6101140ff(2.51.0) 에서 src/codex/catalog/sync.ts 는 clampCatalogModelsToCodexSupport(:1945) 로 모델을 깎고, src/codex/catalog/bundled.ts 의 discoverAlternatives 기본값은 false(:261)라 대체 런타임 탐색이 기본 꺼져 있습니다. runtime resolve 는 persisted CLI 를 선호합니다. Feasibility L4 에서는 이 이슈를 lane 작업에서 빼 두었고(design), #4207 은 클라이언트 투영/readiness 쪽 잘못된 lane 위험을 따로 적었습니다. product freeze tip 6d3ad12e3 근처 맥락과도 맞습니다. 지금은 열어 두되 이번 round lane 에 넣지 않는 것이 맞습니다.

    라인 - src/codex/catalog/sync.ts ~:1945 — clampCatalogModelsToCodexSupport(catalog.models) 가 동기화 경로에서 항상 적용
    라인 - src/codex/catalog/bundled.ts ~:261 — discoverAlternatives 기본 false; Desktop 자식 런타임 자동 채택 약함
    경로/심볼 - persisted CLI vs Desktop child runtime — 낮은 CLI 로 clamp 하면 높은 Desktop 옵션이 공유 카탈로그에서 사라짐
    경로/심볼 - #4207 — 관련하나 client catalog projection; 이 이슈는 Desktop consumer identity 설계

    메인테이너의 판단이 필요한 지점

    너의 추천
    PARKED design 으로 열어 두세요. 이번 round lane 작업에 넣지 마세요. 필요할 때 consumer-specific catalog projection 설계 이슈를 따로 열고, 실행 가능한 쪽은 #4207 클라이언트 projection/readiness 를 먼저 하세요.

    이 댓글은 grok-bot이 작성했습니다

  4. lidge-jun commented on Sep 14, 2026

    @lidge-jun
    OwnerAuthor

    Fixed on dev by #4585, merged as dfa0e2f985e32df8263c87ad43d17ce0123a42be.

    codex-runtime.json now records origin: "pinned" | "discovered". resolveAndPersistCodexRuntime stamps its automatic selections discovered, and a record with no origin reads as discovered too, because auto-discovery is what wrote every one of them — which is exactly the point this report makes about configured not establishing intent. An unpinned record now hands over to a strictly newer valid runtime and reports it as supersededDiscovered; a pin is never touched, equal versions stick, and an unknown version on either side is not treated as evidence of an upgrade.

    The report's source trace item 2 is also addressed: the bundled-catalog loader passes discoverAlternatives: false, so the comparison could never have run where the bug bites. That fast path now still probes the bounded Codex App roots under %LOCALAPPDATA%\OpenAI\Codex\bin when the persisted record is unpinned, while PATH-wide discovery stays off.

    Closing as resolved for the runtime-selection defect. Two things this does not claim: the renderer-side enabledReasoningEfforts / show-ultra-in-model-picker-slider conditions you documented are Desktop preferences outside this repository, and no live Windows Desktop reproduction was replayed — the fix is covered by regression tests that reconstruct the 0.135.0-beside-0.153.4 arrangement. Please reopen if the picker still loses rungs after a sync on the affected machine.

  5. lidge-jun commented on Sep 14, 2026

    @lidge-jun
    OwnerAuthor

    Fixed on dev by dfa0e2f.

    The runtime record now carries whether its version was pinned by an operator or merely discovered, and an unpinned stale entry yields to a newer runtime that is actually installed. So a persisted 0.135.0 no longer strips max and ultra from the ladder while Codex Desktop is running 0.153.4. The resolver also gained an installed-runtime source — newest-first for the Windows App layout, and a POSIX fallback after PATH — plus a deferred memo that never publishes a half-probed result into the process cache.

    Focused handover tests cover the Programs versus LOCALAPPDATA App layouts. An earlier head was red on one of those tests writing a Windows PATH into a Linux shard, which is worth mentioning only because it is the kind of test bug that looks like a product bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions