Skip to content

fix(inject): restore remote control tabs for relay profiles with ChatGPT identity - #2657

Closed
Rat0323 wants to merge 3 commits into
BigPizzaV3:mainfrom
Rat0323:fix/remote-control-connections-gate
Closed

Rat0323 wants to merge 3 commits into
BigPizzaV3:mainfrom
Rat0323:fix/remote-control-connections-gate

Conversation

@Rat0323

@Rat0323 Rat0323 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Codex desktop 26.1016.6573.0 gates the Connections page on a new desktop feature flag:

  • renderer feature payload: control: ke where ke = useGate("2171042036")
  • main-process shouldLoadRemoteControlConnections defaults to false; while it stays false, refreshRemoteControlConnections() writes remote_control_connections_state = { available: false }
  • the Connections page only renders control-this-mac / access-other-devices when that state is available; SSH is unconditional

With a relay profile that keeps the ChatGPT session identity (activeRelaySessionProvider = "openai", upstream API configured), the control gate evaluates to false under the relay launch even though the account is still signed in and the device enrollment is valid. This PR does not try to decide whether an account is genuinely in the rollout; it exposes an explicit opt-in repair for the UI gate.

The original hard-forcing behavior is intentional. Users who are not affected, or who want the native Statsig result, keep the default-off state.

Fix

This PR is limited to the remote-control gate repair. The separate app-shared-* dispatcher discovery issue was already merged in 9e5360c; this branch has been synced against latest main accordingly.

The repair is controlled by a new backend setting:

"codexAppRemoteControlGateRepairEnabled": false

It only rewrites electron-desktop-features-changed to control: true when all of the following are true:

  • codexAppRemoteControlGateRepairEnabled === true
  • enhancements and relay profiles are enabled
  • the active relay profile has a real upstreamBaseUrl
  • activeRelaySessionProvider === "openai"

Pure API profiles (activeRelaySessionProvider = "custom") and official-only profiles without a relay upstream stay untouched: official remote control requires ChatGPT authentication, so forcing the flag there would only create a broken entry or a sign-in prompt.

The renderer also keeps a lightweight replay path:

  • it caches the last electron-desktop-features-changed payload
  • it re-dispatches it when backend settings load or the active relay profile changes
  • each replay recomputes whether the repair is allowed

That avoids two known edge cases:

  • the first feature message arriving before backend settings are loaded
  • a previously forced control: true sticking around after switching from an OpenAI-identity relay profile to a pure API profile

Tests

  • node scripts/assemble-renderer-inject.mjs --check
  • cargo test --release -p codex-plus-core --lib remote_control_gate_repair_defaults_off_for_legacy_settings
  • cargo test --release -p codex-plus-core --test cdp_bridge injection_script_preserves_native_tiers_and_shared_provider_contracts
  • npm test in apps/codex-plus-manager
  • npm run check in apps/codex-plus-manager

The contract test asserts:

  • legacy settings without the new key load with the switch off
  • an OpenAI-identity relay profile still leaves control untouched while the switch is off
  • turning the switch on repairs the gate
  • switching to a pure API provider reverts it
  • an official profile without a relay upstream remains untouched

@Rat0323
Rat0323 force-pushed the fix/remote-control-connections-gate branch 2 times, most recently from f23a41c to 94d8d48 Compare October 22, 2026 01:49
@Rat0323

Rat0323 commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

CI note: macOS DMG (universal) passes. The Windows job currently fails in codex-plus-data test provider_sync_skips_rollout_locked_after_planning (assertion left == right), which is outside this diff (the change only touches assets/inject/* and crates/codex-plus-core/tests/cdp_bridge.rs). I reproduced that exact failure locally on a clean tree as well, so it looks flaky/environment-dependent rather than caused by this PR. The targeted test for this change passes locally:

  • cargo test -p codex-plus-core --test cdp_bridge injection_script_preserves_native_tiers_and_shared_provider_contracts
  • node --test src/renderer-inject.test.ts (95 pass)
  • node scripts/assemble-renderer-inject.mjs --check

@Rat0323
Rat0323 force-pushed the fix/remote-control-connections-gate branch 2 times, most recently from 664c5e1 to 2821af1 Compare October 22, 2026 20:28
@Rat0323

Rat0323 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

排查补充:手机端远程会话仍可用,说明设备登记与会话链路正常;桌面端 Connections 布局缺失来自 renderer 的 control desktop feature。当前 Codex 26.1016 已把 dispatcher 单例移到 app-shared-*.js(导出后由 Object.values(module) 可识别),而 Codex++ 仍只探测 setting-storage- / vscode-api- / app-initial-,导致该层从未安装。本 PR 现已补上 app-shared- 探测,使 remote control gate repair 能真正挂载。

@BigPizzaV3

Copy link
Copy Markdown
Owner

感谢排查,Connections 页只剩 SSH 的现象和 dispatcher 搬到 app-shared-* 的分析都很有价值。不过目前还不能合入,需要以下修改:

  1. 拆分 app-shared- 探测:dispatcher 探测前缀新增 app-shared- 是独立修复,影响所有用户(新版 Codex 上整个 service-tier 请求改写层会重新生效)。请单独提 PR,并附上在 26.1016 上 service tier 改写行为正常的验证。
  2. 强开 control 需要 opt-in:control 来自 Statsig gate,补丁无法区分「中转启动导致误判」和「账号本来就不在灰度内」。按项目约定,新行为需要默认关闭、显式开启。请加一个后端设置开关(默认关),只有用户打开时才改写 electron-desktop-features-changed。
  3. 补充根因说明:请说明中转下 gate 为什么会变成 false(例如 Statsig 用户身份或环境字段在中转下有什么不同)。如果能从根因修复(让 gate 正常计算),就比强制改写更好。
  4. 测试 fixture 请改成真实会出现的组合(官方 + 混入 API Key,或真实的 sessionProvider=openai 形态),并补一条开关关闭时不改写的用例。
  5. 改完后请取消 draft,并确认 node scripts/assemble-renderer-inject.mjs --check 和 cdp_bridge 契约测试通过。

再次感谢!

BigPizzaV3 added a commit that referenced this pull request Oct 25, 2026
Codex 26.1016 起 dispatcher 类定义并导出在 app-shared-*(getInstance 单例),
app-initial-* 只导入不再导出,setting-storage-* / vscode-api-* 已不存在。
原来三个前缀全部落空,补丁失败 8 次后自动放弃,纯 API / 聚合 / 官登混入 Key
下 thread/start、thread/resume、turn/start 的 modelProvider 改写整层失效。
本机日志与 app.asar 解析均已确认。补按 26.1016 实际模块结构构造的回归测试。

思路来自 PR #2657(Rat0323)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BigPizzaV3

Copy link
Copy Markdown
Owner

补充一下:你发现的 app-shared- 探测前缀问题,我们在本机 Codex 26.1016 上核实过,确实是一个影响面很大的缺陷,已经单独修复并合入 main(9e5360c0),提交信息里注明了思路来自这个 PR。

核实过程:

  • 解析 26.1016 的 app.asar:dispatcher 类(带 getInstance 单例、dispatchMessage/subscribe)定义并导出在 app-shared-*.js;app-initial-*.js 只是导入它,不再导出;setting-storage-*、vscode-api-* 已经不存在。
  • 本机 Codex++ 日志里一直是 Codex dispatcher unavailable (setting-storage-: 未找到…; vscode-api-: 未找到…; app-initial-: dispatcher export unavailable),失败 8 次后补丁自动放弃,纯 API / 聚合 / 官登混入 Key 下的 modelProvider 改写整层失效。

PR 剩下的部分(在没有开关的情况下强开 Statsig 的 control 灰度特性)仍按上一条评论的意见处理:需要改为 opt-in,并区分「中转导致误判」和「账号本来就不在灰度内」。欢迎基于最新 main 调整后更新本 PR。感谢!

@Rat0323
Rat0323 marked this pull request as ready for review October 25, 2026 17:45
@Rat0323

Rat0323 commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

已按 review 意见把这个修复收窄为 opt-in:

  • 新增 codexAppRemoteControlGateRepairEnabled,旧配置默认读作 false
  • 只有开关显式开启时才改写 electron-desktop-features-changed 的 control
  • 保留原 replay 逻辑,settings 加载和 profile 切换后会按当前状态重新计算
  • pure API / 无 relay upstream 的 profile 不受影响
  • 分支已同步最新 main,app-shared-* 探测部分沿用你合入的 9e5360c

本地验证:

  • node scripts/assemble-renderer-inject.mjs --check
  • cargo test --release -p codex-plus-core --lib remote_control_gate_repair_defaults_off_for_legacy_settings
  • cargo test --release -p codex-plus-core --test cdp_bridge injection_script_preserves_native_tiers_and_shared_provider_contracts
  • npm test
  • npm run check

PR 已从 draft 转为 ready for review。

BigPizzaV3 added a commit that referenced this pull request Oct 25, 2026
Codex 26.1016 起 dispatcher 类定义并导出在 app-shared-*(getInstance 单例),
app-initial-* 只导入不再导出,setting-storage-* / vscode-api-* 已不存在。
原来三个前缀全部落空,补丁失败 8 次后自动放弃,纯 API / 聚合 / 官登混入 Key
下 thread/start、thread/resume、turn/start 的 modelProvider 改写整层失效。
本机日志与 app.asar 解析均已确认。补按 26.1016 实际模块结构构造的回归测试。

思路来自 PR #2657(Rat0323)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Rat0323
Rat0323 force-pushed the fix/remote-control-connections-gate branch from 8fe42fc to 7a696cd Compare October 25, 2026 22:59
@Rat0323

Rat0323 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor Author

Status update after checking Codex Desktop 26.1021

I re-checked this against the current Codex Desktop build. The 26.1016-specific control gate is no longer used for remote-control Connections visibility:

  • 26.1016 used the control desktop feature / useGate("2171042036") path that this PR targets.
  • 26.1021 still emits control from useGate("2171042036") and stores it in desktop feature state, but the Connections page now computes visibility through remote-control-connections-visibility, driven by slingshotEnabled, remoteControlConnectionsState, and the related features.remote_connections handling. I did not find a remote-control consumer of control in the 26.1021 main-process bundle.
  • On my local 26.1021 + Codex++ 1.12.1, the app-shared-* dispatcher patch installs successfully and the remote connections entry is visible again.

This PR is therefore closing as superseded by the current Codex Desktop behavior. The more general app-shared-* dispatcher compatibility fix is already in main as 2429854 and included in Codex++ 1.12.1, so we will not keep a version-specific opt-in switch for 26.1016. If a concrete need to support that older build appears, this can be revisited separately.

@Rat0323 Rat0323 closed this Oct 26, 2026
@Rat0323
Rat0323 deleted the fix/remote-control-connections-gate branch October 26, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants