Skip to content

[Bug]: keep-native-v1 catalog pin is overridden by global V2 in fresh Codex CLI 0.149 processes #2409

Closed

Description

@rrmlima

Summary

keepNativeChatGptOnV1 remains ineffective at runtime when the global Codex multi_agent_v2 feature override is enabled.

With OpenCodex 2.29.0 and Codex CLI 0.149.0, OpenCodex correctly writes the native ChatGPT catalog row as multi_agent_version: "v1" while routed rows remain V2. However, a brand-new codex exec --ephemeral process with features.multi_agent_v2.enabled=true still creates an encrypted V2 child task. The routed child fails before provider dispatch with unreadable_encrypted_agent_task.

This is a current CLI regression/reproduction of #2184, which covered the same mismatch in the Codex App and was closed after asking users to restart and report if it reproduced. Every A/B run below starts a fresh CLI process, so stale sessions, picker cache and a long-lived app-server are excluded.

Reproduction

Environment and models:

  • OpenCodex: 2.29.0
  • Codex CLI: 0.149.0
  • OS: Linux x86_64
  • Parent: native gpt-5.6-luna
  • Child: routed command-code/deepseek-deepseek-v4-flash
  • OpenCodex config: multiAgentMode: "v2", keepNativeChatGptOnV1: true

The same generated catalog was used on both sides of the A/B test:

gpt-5.6-luna                                    multi_agent_version=v1
command-code/deepseek-deepseek-v4-flash         multi_agent_version=v2
google-antigravity/gemini-3.7-flash             multi_agent_version=v2
google-antigravity/claude-opus-4-6-thinking     multi_agent_version=v2

The test prompt required exactly one spawn_agent call to the routed DeepSeek child, waited for an exact sentinel response, used no shell/files, and ran under the read-only sandbox.

A. Global V2 override enabled

codex exec \
  --ephemeral \
  --json \
  --sandbox read-only \
  -c 'features.multi_agent_v2.enabled=true' \
  --model gpt-5.6-luna \
  '<spawn exactly one command-code/deepseek-deepseek-v4-flash child and wait for its sentinel>'

Actual:

Agent errored:
code=unreadable_encrypted_agent_task
Routed V2 worker task is encrypted for the native ChatGPT backend and cannot be read by the selected provider.

B. Global V2 override disabled

codex exec \
  --ephemeral \
  --json \
  --sandbox read-only \
  -c 'features.multi_agent_v2.enabled=false' \
  --model gpt-5.6-luna \
  '<the same child model and sentinel contract>'

Actual:

spawn_agent completed
child status=completed
child sentinel received
parent sentinel returned

Only the global feature override changed. The catalog, parent, child, prompt contract, OpenCodex process and providers stayed the same.

Routed-parent controls also passed:

Parent Child Result
google-antigravity/gemini-3.7-flash command-code/deepseek-deepseek-v4-flash PASS
command-code/deepseek-deepseek-v4-flash google-antigravity/gemini-3.7-flash PASS
google-antigravity/claude-opus-4-6-thinking command-code/deepseek-deepseek-v4-flash PASS

This isolates the failure to native-parent surface selection. Routed V2 collaboration remains functional.

Expected behavior:

  • With multiAgentMode=v2, keepNativeChatGptOnV1=true, and a native ChatGPT parent, the effective parent surface is V1.
  • Routed catalog rows remain V2.
  • Native -> routed delegation does not create an unreadable encrypted V2 NEW_TASK under the documented mitigation.
  • ocx v2 status reports the effective state without contradiction.

Likely cause and suggested remediation:

The catalog is correct. The A/B result suggests Codex 0.149 resolves the global features.multi_agent_v2.enabled=true override before the selected catalog entry's explicit multi_agent_version: "v1" pin.

OpenCodex currently reports a contradictory state:

multi_agent_v2: ON — v2 multi-agent surface active
multi_agent_mode: v2 — ALL models forced to v2 surface
keep_native_chatgpt_on_v1: ON — ChatGPT-native rows stay v1 when mode is v2

A supported fix should establish one effective contract:

  1. Prefer a catalog-driven hybrid mode when keepNativeChatGptOnV1=true: global V2 override off, native rows V1 and routed rows V2. Preserve thread-limit semantics during the transition.
  2. If an installed Codex version cannot honor the hybrid pins, warn or reject the incompatible combination instead of claiming the mitigation is active.
  3. If fixed upstream in Codex, resolve the selected catalog entry's multi_agent_version before constructing the collaboration surface so an explicit model pin takes precedence over the global default.

Regression acceptance criteria:

  • A fresh native-parent CLI process respects the V1 pin.
  • Native -> routed and routed -> routed controls both pass.
  • Coverage starts a fresh process/session; catalog-only assertions are insufficient.
  • ocx v2 on, ocx v2 mode v2, ocx v2 keep-native-v1 on, sync, status, and thread-limit migration converge on the same contract regardless of command order.
  • Unsupported Codex versions receive a clear compatibility warning.

Related: #2184, #92, #1540 and #1533. The encrypted-task recovery in #1540 is a compatibility path after ciphertext exists; it does not make an ineffective keep-native-v1 contract correct.

Logs and screenshots

catalog native row: gpt-5.6-luna -> multi_agent_version=v1
catalog routed row: command-code/deepseek-deepseek-v4-flash -> multi_agent_version=v2

global override ON:
error.code=unreadable_encrypted_agent_task

global override OFF:
spawn_agent=completed
child=completed
parent=completed

No screenshots are required. Raw credentials, request headers, account identifiers, private prompts and raw encrypted_content were deliberately excluded.

Area

CLI

Version

OpenCodex 2.29.0; Codex CLI 0.149.0

OS

Linux x86_64

Config shape

{
  "multiAgentMode": "v2",
  "keepNativeChatGptOnV1": true,
  "subagentModels": [
    "gpt-5.6-luna",
    "command-code/deepseek-deepseek-v4-flash",
    "google-antigravity/gemini-3.7-flash",
    "google-antigravity/claude-opus-4-6-thinking"
  ]
}

Checks

Activity

  1. github-actions commented on Aug 22, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  2. changed the title [-][Regression of #2184][Codex CLI 0.149] keep-native-v1 catalog pin is overridden by global V2 at runtime[/-] [+][Bug]: keep-native-v1 catalog pin is overridden by global V2 in fresh Codex CLI 0.149 processes[/+] on Aug 22, 2026
  3. added
    bugSomething isn't working
    cliCLI, config inject, packaging flags
    on Aug 22, 2026
  4. lidge-jun commented on Aug 22, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 62 / 80

    설명: 이 이슈는 네이티브 챗지피티 부모를 브이원으로 붙잡아 두는 핀이, 코덱스 0.149 새 프로세스에서 전역 브이투 스위치에 밀린다고 한다. 지금 CURRENT dev HEAD 는 4f41a8e93 이다. 이번 시간에 origin/dev 는 그대로다. 새 머지는 없다. 착지는 여전히 2396 사용량 CLI 오늘 비용이다. package.json 은 2.27.0 이다. src/config.ts 는 3975줄이다. src/runtime 폴더는 지금 HEAD 에 없다. 지금 HEAD 의 src/codex/catalog/parsing.ts 485줄 applyMultiAgentMode 는 모드가 v2 이고 keepNativeChatGptOnV1 이 참이면 네이티브 챗지피티 줄만 v1, 나머지는 v2 로 찍는다. 작성자가 본 카탈로그와 같다. 카탈로그는 맞다. src/cli/v2.ts 113줄 상태는 그 핀이 켜졌다고 말한다. 같은 파일 98줄은 모드 v2 가 모든 모델을 v2 로 강제한다고 말한다. 110줄은 전역 multi_agent_v2 가 켜졌는지도 따로 찍는다. 세 줄이 서로 다른 말을 한다. 189줄 모드 v2 는 전역 스위치를 켠다. 카탈로그 핀을 끄거나 전역을 끄는 일은 없다. src/types/config.ts 426줄 주석은 네이티브 줄만 v1 로 남겨 네이티브 부모가 라우트 자식을 만들 수 있게 하라고 적혀 있다. 작성자 에이비는 같은 카탈로그, 같은 부모, 같은 자식에서 전역만 끄면 자식이 성공하고, 켜면 unreadable_encrypted_agent_task 가 난다. 라우트 부모 컨트롤은 통과했다. 작성자 버전은 2.29.0, 코덱스 0.149.0 이다. 지금 origin/dev 패키지는 2.27.0 이지만 같은 찍기 길과 같은 상태 문구가 있다. PR 이 아직 없다. bug, catalog, cli 라벨이 있다. 2184 는 앱 쪽 같은 구멍으로 이미 닫혀 있다. 1540 암호화 복구는 암호문이 생긴 뒤 길이다. 2113 은 암호화 통과 실험이다. 사용자 길이로는 네이티브 부모가 라우트 자식을 못 만드는 계약 구멍이라서 62. 카탈로그 팁은 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. Cursor 정적 카탈로그는 opus-4-8-fast / opus-5-fast. 2334 CursorCredentialRouter 는 여전히 src/providers/cursor-pool.ts 모듈+테스트만 있고 어댑터에 연결되지 않았다. 2332 H2 는 discovery 전용. 2320 overflow + 2342 는 이미 dev. 2188 사이드카는 이미 dev. 2382 데스크톱 앱 재시작은 이미 dev. 2292 는 아직 연다.

    src/codex/catalog/parsing.ts 라인 485 - 모드 v2 와 keepNativeChatGptOnV1 이 참이면 네이티브 줄만 v1, 나머지는 v2. 카탈로그 찍기는 작성자 증거와 같다
    src/cli/v2.ts 라인 98 - 모드 v2 문구는 모든 모델을 v2 로 강제한다고 말한다. 핀과 모순이다
    src/cli/v2.ts 라인 113 - 핀이 켜졌다고 말한다. 110줄 전역 스위치 줄과 세 줄이 한 계약이 아니다
    src/cli/v2.ts 라인 189 - 모드 v2 는 전역 스위치를 켠다. 카탈로그 핀을 살리려고 전역을 끄지 않는다
    src/types/config.ts 라인 426 - 핀의 약속은 네이티브 부모가 라우트 자식을 만드는 것이다. 지금 코덱스 0.149 전역이 이긴다
    이슈 본문 2.29.0 / 코덱스 0.149.0 - 작성자 버전이다. 지금 origin/dev 는 2.27.0 이지만 같은 상태 구멍과 같은 찍기 길이 있다

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

    • 전역 브이투를 끄고 카탈로그 핀만 살리는 길을 받을지. 작성자 에이비는 전역만 끄면 성공했다
    • 상태 세 줄을 한 계약으로 고칠지. 지금은 전역 켜짐, 모두 v2, 네이티브만 v1 이 같이 찍힌다
    • 코덱스 버전이 핀을 못 지키면 경고하거나 거절할지. 지금은 핀이 켜졌다고만 말한다
    • 2184 와 1540 과 2113 을 이 이슈와 묶지 말지. 2184 는 이미 닫혀 있고 1540 은 암호문 뒤 복구다

    너의 추천
    카탈로그 찍기는 그대로 둔다. 전역 브이투를 끄고 카탈로그 핀만 살리는 작은 길을 먼저 검토한다. 상태 세 줄은 한 계약으로 맞춘다. 이슈는 열어 둔다. 2184 1540 2113 92 는 닫지 않는다. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.

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

  5. lidge-jun commented on Aug 25, 2026

    @lidge-jun
    Owner

    Resolved on dev by #2630 (squash 324c1aa87) — though not in the way the issue title implies, and the difference matters.

    OpenCodex was already writing the catalog split correctly. The precedence lives in the Codex client: multi_agent_version_override() returns V2 whenever the global feature is enabled, before multi_agent_version_for_model() ever consults the row pin. Session and child-spawn selection consult that same override first. So no amount of catalog stamping on our side could have fixed this — your fresh-process A/B was measuring a client-side override winning, which is why the restart advice on #2184 went nowhere.

    Writing a row that cannot take effect and calling it fixed would have been the wrong answer. Instead the pin and the global flag are now reconciled where OpenCodex actually owns the decision:

    • enabling keepNativeChatGptOnV1 disables the global override before syncing
    • ocx v2 mode v2 honours an existing native-v1 pin instead of re-enabling it
    • a later ocx v2 on is rejected with the precedence explained, rather than silently producing the broken hybrid
    • PUT /api/v2 follows the same contract, and ocx v2 now reports the global-override and hybrid state accurately

    A user who set the pin and got unreadable_encrypted_agent_task deserves to be told why it did not take effect. That is the real fix.

    Your A/B methodology is what made this diagnosable — every run starting a fresh CLI process is what ruled out stale sessions and picker cache, and that is exactly what #2184 was missing.

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 workingcatalogModel catalog, slugs, visibility, routed entriescliCLI, config inject, packaging flags

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions