With several ChatGPT accounts on, failover writes openai_base_url into
~/.codex/config.toml so a turn the signed-in account can't pay for goes on
to the next account. With Codex's switch off, the row said only "not
connected", but every request still went through the gateway, and the
gateway's /backend-api/codex/models answer added all of magpie's models
(62 for the reporter).
- agent: Agent.FailingOver means not wired, while the stash's codex.failover
(or a CC Switch mirror's codex.mirror_failover) base URL points at magpie.
FailoverSaid is the line the CLI list and the TUI show. CodexOwnOnly is
true for this machine's Codex when it is failing over and no WSL Codex is
connected, since a WSL Codex shares the gateway path. Sync ages a
models_cache.json that isn't tagged with the own-only list.
- gateway: codexModels leaves out provider.CodexListed when
gateway.CodexOwnOnly (set by main to agent.CodexOwnOnly) says so. The
ETag and X-Models-Etag carry provider.CodexOwnListTag. Neither tag
contains the other, so Codex fetches the list again when it is connected
or disconnected.
- gui: /api/state carries failover. The row says "Not connected · goes
through magpie only to fail over to your other ChatGPT accounts". Its
title says what turns it off. A "ChatGPT accounts" button opens
Providers › Codex. Strings are in zh, zh-TW, ja and de. openProvider no
longer draws the Providers list before it has loaded. It was only safe
once the tab had been opened, and this is its first caller from another
page.
- docs: agent-wiring and gateway-routing describe the failover-only Codex
and list the new tests.
A user's hand-written openai_base_url (#856) isn't failover's, so it stays a
plain not-connected row.
Verified:
- TestCodexFailoverOnlyKeepsOwnModels (agent) builds the reporter's state in
a temp HOME: Codex signed in, two more ChatGPT logins on, Sync, so the
stash has codex.failover=1 and no joined/beside. It checks that the row is
not wired and is FailingOver, that FailoverSaid names Providers › Codex,
and that the real gateway handler's /backend-api/codex/models lists only
the backend's gpt-5.5. It also checks that the cached full list is aged,
and that after Join magpie's fake/m1 is back.
- TestCodexModelListOwnOnlyForFailover (gateway) checks the list and both
ETags with the hook on and off.
- agent-failover.test.cjs checks the row text, title and button in en, zh,
zh-TW, ja and de, at 980px and 420px, in Chromium and WebKit (20 pass).
It also checks that the button opens Codex's editor, that the page
doesn't scroll sideways, and that no click moves it.
- Broken by hand, each test goes red:
- codexModels ignoring the hook fails both Go tests.
- failingOver returning false fails the agent test.
- dropping the Sync cache case fails the agent test.
- removing the GUI branch fails the GUI test.
- drawing the list before it has loaded (the old openProvider) fails the
GUI test.
- go test -tags nogui ./internal/agent ./internal/gateway ./internal/provider
./internal/gui ./internal/tui ./internal/codexcat . in a temp HOME: all ok.
- node --test agent-*.test.cjs (254 pass) and i18n-keys, gui-ja, gui-de,
click-scroll: all pass.
- gofmt -l is clean.
- go vet -tags nogui on darwin, linux and windows: clean.
- go build, and GOOS=windows go build: ok.