fix(server): fork Codex threads at the native turn boundary - #11490
fix(server): fork Codex threads at the native turn boundary#11490saphid wants to merge 1 commit into
Conversation
Retry/edit of an earlier turn in a paginated native Codex thread forked at head and then issued thread/rollback, which paginated threads reject. Resolve the selected provider turn nativeTurnRef and pass it as lastTurnId to thread/fork so later turns are excluded atomically and no rollback is needed. Fall back to fork-then-rollback only when no native reference is available, and fail honestly when that fallback hits a paginated fork. rollbackThread now probes historyMode and reports an explicit unsupported error for paginated threads instead of sending a request Codex will reject. Adapts the approach from pingdotgg#9169 by Yusuf007R. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — The production change is confined to the Codex adapter and corrects existing fork-boundary behavior using the provider’s native turn ID, with legacy and paginated-history cases explicitly covered by tests. Other modifications are test fixtures or documentation, with no schema, deployment, security, billing, or product-default impact. You can add or adjust custom eligibility rules. Learn more. |
|
CI note for reviewers: the three failing checks are pre-existing on the base branch, not caused by this diff.
|
Summary
CodexAdapterV2.forkThreadforked the full native Codex thread and then issuedthread/rollbackto reach the selected turn. Newer Codex versions default to paginated durable threads, which rejectthread/rollback, so retry/edit of an earlier turn created the fork but failed the following provider turn.nativeTurnRef.nativeIdand passes it aslastTurnIdon the originalthread/forkrequest. Codex's inclusive boundary semantics exclude later turns atomically, so no rollback is issued on that path.historyModeislegacy. A paginated fallback fork now fails with an explicitProviderAdapterForkThreadErrorinstead of sending a request Codex rejects.rollbackThreadnow probeshistoryModefirst and returns an honestProviderAdapterRollbackThreadErrorfor paginated threads rather than issuing an unsupportedthread/rollback. Legacy-thread rollback is unchanged.Focused proof
thread_fork_native(latest-turn boundary),thread_fork_native_prior_turn(inclusive earlier boundary, later source turns absent from the emitted fork, no rollback frames),thread_merge_back_continue/thread_merge_back_siblings(boundary on merge-back forks), andthread_rollback(history-mode probe + preserved legacy rollback).nativeId, missing provider turn, missing source-turn history, and turn-not-in-source.vp teston the touched suites: 84 passed / 1 skipped acrossCodexAdapterV2.test.ts(71),ThreadFork(7),ThreadMergeBack(4),CodexReplayFixtures(3); broader replay/contract suites previously green (81). Typecheck exit 0.Credit
Adapts the approach first proposed in #9169 by @Yusuf007R, including the
lastTurnIdboundary and updated fork fixtures, reworked for the current adapter shape with the paginated-history probes added.Work performed by SWE-2 (Devin) in T3 Code.
Coordination trace: thread
5c350af2-1c4e-4243-9aa9-de40f39b548d, campaign https://github.com/saphid/t3code-personal/issues/298