Skip to content

fix(polyfill): short-circuit Statsig control plane at the Electron net.fetch layer - #58

Open
yorkane wants to merge 4 commits into
RyensX:mainfrom
yorkane:codex/net-fetch-statsig
Open

yorkane wants to merge 4 commits into
RyensX:mainfrom
yorkane:codex/net-fetch-statsig

Conversation

@yorkane

@yorkane yorkane commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

问题

无外网出口的机器上,隐藏 Electron renderer 仍会请求 Statsig 控制面,走的是 renderer 委托主进程发 HTTP 这条通道:polyfill 改写 window.fetch / XHR / sendBeacon 都覆盖不到它。没有出口时 socket 永久挂起,Statsig 初始化不 resolve,官方路由被 Suspense 边界挂住,页面只剩启动 splash;改用 /etc/hosts 屏蔽域名会把挂起变成 renderer 硬崩溃。

第二个症状:26.908.31748 bundle 上,若 initialize 0ms 立刻返回,authed-route 模块初始化会先于 app-primary 注册被调用的 side-effect export,刷新页面偶发 TypeError: n is not a function。真实 Statsig 往返本身要 100ms 以上。

改动(三个提交,各自单一主题)

  1. IPC 层短路遥测:按官方 fetch-response 协议对 chatgpt.com 的 /ces/v1/rgstr 与 /ces/v1/log_event 本地回 200,从源头消除请求与重试噪音。
  2. 在 electron.net.fetch 层短路 Statsig 控制面(新增 official-net-fetch-statsig-hook.cjs),返回与 web-shell polyfill 注入的同一份默认 feature-gate 配置(保留 505458 等新工作树门),renderer IPC 的 fetch 通道同步 noop。
  3. 给打桩的 initialize 加节奏延迟(OPENCODEX_STATSIG_INITIALIZE_DELAY_MS,默认 400ms)再投递,避开官方 bundle 的初始化竞态;telemetry 与 sdk_exception 响应保持即时。
  4. 新增独立修改点 gateway.runtime.electron.net-fetch-statsig 承载该 hook。此前它借用 gateway.runtime.node.electron-module-loader 上报命中,那是"包装官方 electron 模块导出"的点,会把两件不同的事在运行时兼容页混成一个计数。

#57 的关系

本 PR 现在直接基于 main,与 #57 无依赖(之前 #57 里夹带的 IPC 短路已移到本 PR 的第一个提交)。

#56 互补:#56 拦 renderer 侧 XHR/Beacon 通道,本 PR 拦主进程 net.fetch 通道,两者覆盖不同,互不冲突。

验证

独立克隆全新构建:build:gateway 退出码 0,catalog 点数 104;pnpm test 441 tests / 435 pass / 6 fail,失败集合与基线(f6fd79c 全新构建)逐字相同(3 条 official-desktop-compat 是测试机装有官方 ChatGPT Desktop 被扫到 app.asar;另 3 条是上游改了 i18n 标题与 effort 取值未同步测试期望)。

241.t 生产实测:guide(31748 bundle)与生产(3737)两个实例都从卡住的 spinner 变为完整工作台加载,控制台无 Statsig 报错,连续刷新不再出现 n is not a function。

…fetch

官方 renderer 的 Statsig 遥测走 IPC 委托给 main 进程发真实 HTTP; 受限网络下
Cloudflare 的 403 challenge 回包被转发回 renderer 会让 SDK 反复重试刷 NetworkError.
在 IPC 层按官方 fetch-response 协议本地回 200, 从源头消除该请求.
…t.fetch layer

On hosts without outbound internet, the hidden Electron renderer loads ab.chatgpt.com/v1/initialize through the main process httpFetch. Without egress the socket blackholes forever, Statsig never resolves, and the web page freezes on the loading splash; blocking the domain via /etc/hosts turns the hang into a hard renderer crash. Intercept the Statsig control plane at electron.net.fetch, serving the same default feature-gate configuration the web-shell polyfill injects, and mirror the noop for the renderer IPC fetch channel.

Verified on 241.t: both the guide (31748 bundle) and production (3737) instances go from a stuck spinner to the full workspace, no console Statsig errors.

(cherry picked from commit 15c59ab)
…al-bundle init race

On the 26.908.31748 bundle, answering ab.chatgpt.com/v1/initialize in 0ms lets authed-route module init run before app-primary registers the side-effect export it calls, which intermittently threw "n is not a function" on reload. A real Statsig round-trip naturally takes 100ms+; replay that pace with a small delay (OPENCODEX_STATSIG_INITIALIZE_DELAY_MS, default 400) before delivering the stubbed initialize, and keep telemetry/sdk_exception responses immediate.

(cherry picked from commit 5640a7f)
该 hook 之前借用 gateway.runtime.node.electron-module-loader 上报命中,那是"包装官方
electron 模块导出"的点,与 net.fetch 短路无关,会让运行时兼容页把两件不同的事混成一个
计数。改为独立点 gateway.runtime.electron.net-fetch-statsig 并同步点数与分布断言。
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