Silent model reroute after a safety check: requests served by gpt-5.5 while the app kept showing gpt-6-astra
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using (From "About Codex" dialog)?
Version 26.903.71938
What subscription do you have?
ChatGPT Pro
What platform is your computer?
Darwin 27.0.0 arm64 arm
What issue are you seeing?
On 2026-09-09, in a Codex desktop thread with gpt-6-astra selected, the additional-safety-check notice appeared ("This request requires additional safety checks, which can take extra time"), linking to https://help.openai.com/en/articles/20001326-additional-safety-checks-for-biological-and-cybersecurity-requests-in-chatgpt-codex-and-the-api and offering to retry with a faster model. I did not take that option. I dismissed the notice once and kept waiting.
The model selector kept showing gpt-6-astra, and no message about a model change ever appeared. The usage page later showed that most of that day's requests had been served by gpt-5.5, not gpt-6-astra. So after the safety check my requests were silently rerouted to gpt-5.5 while the app kept presenting gpt-6-astra as the active model.
Why this matters
- My work was done by a less capable model than the one I selected, without notice or consent, while the UI said the opposite.
- Neither the help article nor the notice says a request can be moved to another model automatically. Both describe the faster model as the user's choice ("If you'd rather not wait, retry with a faster model").
- Nothing in the app or on disk records which model served a turn, so a user has no way to check this afterwards.
Evidence (local session files, the app-server log, and the codex-rs source at ddea03ad04)
- The session files record model gpt-6-astra for every turn of the affected threads. The client never asked for gpt-5.5; the switch happened on the server.
- The only reroute signal the client understands is an
openai-modelresponse header (websocket handshake or SSE response) or aheaders.openai-modelobject inside a stream event; the standardresponse.modelfield is not read (codex-api/src/sse/responses.rs,response_model()). None of the 55 websocket handshakes in the app-server log since 2026-09-02 carried that header, and a connection is reused for hours (two handshakes in the whole 16-hour thread), so a header sent only at the handshake cannot reflect a reroute that starts later. - The app does have a reroute notice: on a
model/reroutednotification it inserts the divider "Your request was routed to {toModel}." It never appeared. ModelRerouteandSafetyBufferingevents are transient (rollout/src/policy.rs), so neither the safety check nor a reroute is written to the session file.
The same day, the context was compacted several times while the context usage indicator was still well below the limit. I had the experimental context-management feature enabled, so this may be unrelated; I mention it only for completeness.
What steps can reproduce the bug?
Not reproducible on demand. It followed a safety check on the thread.
What is the expected behavior?
Transparency. If a request is served by a different model than the one selected, the app must say so clearly and keep showing it, the model selector must show the model actually in use, and the served model must be recorded in the session. The served model should be reported on every response, not only in a header the client may never see.
Additional information
This issue was drafted with the help of an AI assistant.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with codex-api/src/sse/responses.rs and response_model(), then trace the model/rerouted notification and the transient ModelReroute and SafetyBuffering events in rollout/src/policy.rs. Compare these paths with the session files and app-server log evidence. Done means the served model is reported on each response, displayed consistently, and recorded in the session.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- ai, api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100