fix(combo): auto-resume pinned native Codex turns (re-land of #13180) - #14162
Merged
diegosouzapw merged 9 commits intoSep 19, 2026
Merged
Conversation
…13180) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…reland Resolves the combo.ts conflict against #13564 (merged 2026-09-18), which also touches the native-Codex-turn-pin-unusable path: it now releases the pin and falls through to full combo routing instead of terminating the turn. Kept #13180's bounded, safety-gated auto-resume (canAutoResumeNativeCodexTurn: sibling-connection preference, pending tool-call / opaque continuation-state blocks, 1-resume-per-turn cap) as the first recourse when the pinned model becomes model-scoped unusable; when auto-resume is not eligible, fall through to #13564's general release-and-full-combo-routing path instead of the PR's original terminate-the-turn fallback, so neither fix regresses the other. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…ter base merge The base merge renamed the module-level pin map from `pins` to `turns`, but releaseNativeCodexTurnPin() still called the old, now-undefined `pins.delete(key)`. The remaining `rec.pins.*` calls are a record field on turn entries and are unaffected. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…13564 merge The base merge brought in #13564 (release the native Codex turn pin and fall through to full combo routing whenever the pinned model is model-scoped unusable). The merge conflict resolution applied that same "release pin and fall through" behavior to #13180's auto-resume-not-eligible branch too, which silently dropped #13180's explicit safety constraints: - "Pending tool calls or opaque/provider-specific continuation state reject auto-resume" only meant reject AUTO-RESUME in the original design; falling through to #13564's plain combo routing hands that same unsafe state to an untested alternate model instead, which is exactly what the check exists to prevent. - "At most one auto-resume is allowed per logical turn" was bypassed: once eligibility was rejected for `max_resumes_exceeded`, falling through let the request cascade to a THIRD model instead of terminating. Confirmed via tests/unit/native-codex-auto-resume.test.ts: 4 of 15 tests failed against the merged tip before this fix (opaque continuation state, pending tool call, no healthy alternate, and max-resumes cascade all dispatched to an alternate model instead of terminating with 400 NATIVE_CODEX_PINNED_MODEL_UNAVAILABLE). Fix: only the reasons that indicate unsafe state or an exhausted resume budget (pending_tool_call, unsafe_provider_state, no_alternate_target, no_healthy_alternate_target, max_resumes_exceeded) still terminate the turn. Every other rejection reason (e.g. a request body that doesn't use the Responses-API input/messages shape #13180's eligibility check needs) keeps #13564's plain fallback, so non-native-turn-shaped Codex requests are unaffected. Verified: tests/unit/native-codex-auto-resume.test.ts (15/15) and tests/unit/native-codex-turn-pin-model-scoped-fallback.test.ts (7/7, #13564's own suite) both pass; typecheck:core and ESLint (with suppressions) clean. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…ection branch typechecks Without strictNullChecks the truthiness test on the `eligible` discriminant does not remove the eligible:true member in the else branch, so `.reason` raised TS2339 x3 in check:api-typecheck and check:open-sse-typecheck (both red on the PR run, both green on the tip). `=== true` narrows in both directions.
…ex-auto-resume.test.ts The re-landed suite was 1540 lines, above the 1200-line cap for new test files. The three cases that only exercise hasUnresolvedToolCalls / hasProviderSpecificUnsafeContinuationState / MAX_AUTORESUMES_PER_TURN need no DB or combo fixture, so they move verbatim to native-codex-auto-resume-guards.test.ts (416 lines); the combo-flow file drops to 1131. 15/15 across both files.
….ts 1258->1273, own growth)
This was referenced Sep 21, 2026
diegosouzapw
added a commit
that referenced
this pull request
Sep 21, 2026
Three squash merges on release/v3.8.51 lost the contributor attribution that the pipeline had preserved on the branches: - 7a92129 (#14159) re-landed #12630: the dual-layer semantic cache is @BillyOutlast's work; the squash author is the maintainer. - cd4c6f6 (#14162) re-landed #13180: the native Codex auto-resume fix is Felipe Reis's (@mdigitalbh81); the squash author is the maintainer. - 53a147c (#13295) shipped the same one-line resolvedExtensionEnd reorder that @ggiak landed first in #13036; the squash carried no trailer. The changelog fragment and these trailers record that credit in the branch history, the contributors graph and the release notes. Co-authored-by: BillyOutlast <172061051+BillyOutlast@users.noreply.github.com> Co-authored-by: Felipe Reis <mdigitalbh81@gmail.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: ggiak <20743694+ggiak@users.noreply.github.com>
This was referenced Sep 21, 2026
Merged
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…uzapw#13180) (diegosouzapw#14162) Re-land of diegosouzapw#13180 by @mdigitalbh81 (their commits carried with authorship intact), merged via /merge-batch (2026-09-19) on top of the current `release/v3.8.51` tip. **Reconciled before landing (three maintainer commits on top of the re-land):** - `fe80cfb5` — `check:api-typecheck` / `check:open-sse-typecheck` were red on the PR's own head with `TS2339 'reason' does not exist on type 'AutoResumeDecision'` ×3 in `open-sse/services/combo.ts` (green on the tip). Without `strictNullChecks` the truthiness test on the `eligible` discriminant does not narrow the else-branch; `=== true` does. - `7ee0e5d5` — `tests/unit/native-codex-auto-resume.test.ts` was 1540 lines, above the 1200-line new-test cap. The three pure guard cases (`hasUnresolvedToolCalls`, `hasProviderSpecificUnsafeContinuationState`, `MAX_AUTORESUMES_PER_TURN`) moved verbatim to `native-codex-auto-resume-guards.test.ts`; the combo-flow file is now 1131 lines. - `93d75989` — `executeTargetAttempt.ts` 1258→1273 rebaselined with a dated justification (own growth: generation advance + log at the pin site). **Evidence on the merged tree:** `native-codex-auto-resume{,-guards}.test.ts` 15/15; `native-codex-turn-pin-model-scoped-fallback`, `native-codex-turn-pin-10379`, `chatgpt-web-codex-turn-pin` 33/33 total; broader combo sweep (`combo-responses-sse-failure-fallback`, `combo-context-window-filter`, `perf-waterfall-elimination`, `chatgpt-web-codex`, `combo-context-overflow-compression-probe`) 70/70; api/open-sse typecheck clean for the PR's files; file-size, changelog-integrity, complexity and cognitive-complexity gates OK. **Inherited, not from this PR** (reproduced on the pure tip): the 23 unit reds in the fast-path shards (vi locale parity, pack-artifact allowlists, `.env.example` sync, casing, budget fallback, etc.), the 5 `no-unused-vars` lint errors (`cliRuntime.ts`, `arena-elo-sync-redesign`, `compressionAnalyticsWriterFlatRate`, `waitForServer-slow-first-response`), the `omni-version-manager` generated-skill drift, `tinycmsDomMocks.ts` / `rerankProviderNodes.ts` / `antigravity.ts` typecheck errors, and the 4 env vars missing from `.env.example`. Supersedes diegosouzapw#13180. Follow-up to diegosouzapw#12240.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-land of #13180 by @mdigitalbh81 — the fork does not accept maintainer pushes, so this PR carries their commits with authorship intact.
Follow-up to #12240. Supersedes #13180.
.env.exampledocs-sync gap opened by #13344; not touched by this PR).Summary (original, by @mdigitalbh81)
Native Codex turns remain pinned to the same provider/model while eligible sibling connections for that model still exist.
If every target for the pinned provider/model becomes unusable for a model-scoped reason, such as quota exhaustion or model lockout, this change safely advances the logical turn generation and resumes the same Codex turn on another healthy model from the combo.
The resumed model is then pinned for the new logical generation, so subsequent requests for the same
thread_id + turn_idcontinue consistently on that model.Safety constraints
thread_id + turn_id; it is not global.What this PR adds on top of #13180
The base branch moved from under this PR while it was parked: #13564 (merged today,
2026-09-18) independently changed the same code path — when a pinned native Codex turn's
model becomes model-scoped unusable, release the pin and fall through to full combo
routing instead of terminating with
400 NATIVE_CODEX_PINNED_MODEL_UNAVAILABLE.Re-landing #13180 on top of #13564 needed two small follow-up commits, both under my own
authorship, on top of Felipe's unmodified commits:
releaseNativeCodexTurnPinrenamed map — fix(providers): codex: long native sessions die with NATIVE_CODEX_PINNED_MODEL_UNAVAILABLE instead of falling back to a healthy combo model #13564 renamed the module-level pin mapfrom
pinstoturns; one straypins.delete(key)call needed the same rename.Reconcile auto-resume's safety bounds with fix(providers): codex: long native sessions die with NATIVE_CODEX_PINNED_MODEL_UNAVAILABLE instead of falling back to a healthy combo model #13564's fallback — the merge conflict
resolution had applied fix(providers): codex: long native sessions die with NATIVE_CODEX_PINNED_MODEL_UNAVAILABLE instead of falling back to a healthy combo model #13564's "release pin and fall through" behavior to fix(combo): auto-resume pinned native Codex turns #13180's
auto-resume-not-eligible branch as well. That silently dropped two of fix(combo): auto-resume pinned native Codex turns #13180's explicit
safety constraints:
was only supposed to reject the auto-resume mechanism — falling through to plain
combo routing instead hands that same unsafe state to an untested alternate model,
which is exactly what the check exists to prevent.
was rejected for
max_resumes_exceeded, falling through let the request cascade to athird model instead of terminating.
Fix: only the rejection reasons that mean unsafe state or an exhausted resume budget
(
pending_tool_call,unsafe_provider_state,no_alternate_target,no_healthy_alternate_target,max_resumes_exceeded) still terminate the turn with400. Every other reason (e.g. a request body that doesn't use the Responses-APIinput/messagesshape fix(combo): auto-resume pinned native Codex turns #13180's eligibility check needs) keeps fix(providers): codex: long native sessions die with NATIVE_CODEX_PINNED_MODEL_UNAVAILABLE instead of falling back to a healthy combo model #13564's plainfallback, so non-native-turn-shaped Codex requests are unaffected.
Validation
tests/unit/native-codex-auto-resume.test.ts: 15/15 passed (4 failed against the rawmerge before the reconciliation fix above — opaque continuation state, pending tool
call, no healthy alternate, and the max-resumes cascade all dispatched to an alternate
model instead of terminating; TDD-verified per Hard Rule fix(ci): add environment for npm token access #18)
tests/unit/native-codex-turn-pin-model-scoped-fallback.test.ts(fix(providers): codex: long native sessions die with NATIVE_CODEX_PINNED_MODEL_UNAVAILABLE instead of falling back to a healthy combo model #13564's own suite):7/7 passed
chatgpt-web-codex-turn-pin,chatgpt-web-codex,native-codex-turn-pin-10379,combo-context-overflow-compression-probe,combo-context-window-filter,combo-responses-sse-failure-fallback,perf-waterfall-elimination: 81/81 passednpm run typecheck:core: passednpx eslint --suppressions-location config/quality/eslint-suppressions.jsonon alltouched files: clean
node scripts/check/check-complexity-ratchets.mjs --base-ref origin/release/v3.8.51:flags a pre-existing new-code complexity regression in
open-sse/services/combo/nativeCodexTurnPin.ts, entirely inside fix(combo): auto-resume pinned native Codex turns #13180's original~500-line addition (not touched by either follow-up commit here). Not rebaselined or
refactored in this PR — flagging for an owner decision rather than restructuring a
contributor's logic without a failing test driving it.
Antigravity Opus 429/quota exhaustion — the pinned turn became eligible for auto-resume,
routed to Gemini, completed with HTTP 200, and subsequent requests for the same turn
remained pinned to Gemini.