Cyber-policy detection only inspected response.failed, and the ingress check ran after error-specific early returns. As a result, error-shaped failures and the connection-pool, HTTP-bridge, and WSv2 paths could miss cyber-policy hits.
Centralize event marking and invoke it before retry and failover returns across the WebSocket implementations. Preserve the recorded guard during account failover and defer connection blocking until the logical failover chain completes, avoiding duplicate records while ensuring subsequent turns are blocked.
Accept service_tier=ultrafast on the OpenAI/Codex gateway, advertise it
on GPT-5.6 Sol in the Codex model catalog, and include it in ChatGPT
OAuth routing hints so Codex clients can select Ultrafast.
classifySelectionFailureError upgrades a selection failure to 429
rate_limit_error whenever the scheduler's compact reason string matches
model_rate_limited=(\d+) with a positive count. It does so unconditionally,
including when the fallback it was handed is the authoritative 404
model_not_found classification.
Selection failure reasons are additive, so both can appear at once, e.g.
"pool=9, filtered: model_not_supported=8 model_rate_limited=1": eight accounts
cannot serve the model at all and the ninth happens to sit in a per-model
cooldown. classifyNoAccountError only produces ModelNotFound through
DiagnoseModelAvailabilityForPlatform, a dedicated database query over
persistent eligibility (active + schedulable + model_mapping), so it has
already established that no account in the group can serve the model. One
transient cooldown does not make "All available accounts are currently
rate-limited" true.
The mislabel is not cosmetic:
- Retrying can never succeed, yet 429 explicitly invites a retry.
- Clients that treat 429 as a rate limit retry hard and swallow the body;
Codex surfaces only "exceeded retry limit, last status: 429", discarding the
one message that names the real problem. Operators then look for capacity
and rate limits instead of a model whitelist.
- Ops attribution becomes self-contradictory: classifyNoAccountErrorFromGin
has already marked the request business-limited for local model
configuration, while call sites gate markOpsRoutingCapacityLimitedIfNoAvailable
on ModelNotFound, which the override clears, so the same request is also
counted as routing capacity limited.
Return the fallback untouched when it is ModelNotFound. The 429 upgrade is
preserved for every other fallback, which is the case it was written for:
accounts that can serve the model exist but are all cooling down, where the
fallback is 503 and retrying is meaningful.
Claude-Session: https://claude.ai/code/session_01LwvyJVV2sdqiu41Z9JDNUq
OpenAI/Composite groups can now reject requests that exceed the max
reasoning effort instead of always rewriting them down to the ceiling.
Existing groups keep the previous auto-downgrade behavior.
Allow OpenAI/Composite group mappings to match by exact model name,
prefix, or suffix. Empty type and model still apply to every model.
The admin form groups multiple request-to-forward pairs under one
type+model scope.