Stale Final-Response Ownership After Turn Transition
What version of the Codex App are you using (From “About Codex” dialog)?
0.142.4
What subscription do you have?
pro
What platform is your computer?
windows running WSL Ubuntu 22.04..5
What issue are you seeing?
Using a 1 million context window in GPT-5.4. "Stale Final-Response Ownership After Turn Transition" is a stale final-response ownership defect: a new user request is accepted strongly enough to trigger the correct tool activity, but the final visible reply is still sourced from stale prior-turn workflow state and emits the wrong closeout or answer. This appears more consistent with turn-completion / replay ownership drift than with raw context-window exhaustion or a hidden reasoning limit, and it seems easier to trigger in long-lived or compaction-heavy threads, especially right after strong procedural closeout.
Codex Defect Analysis Note: Stale Final-Response Ownership After Turn Transition
Date: 2026-06-30
Summary
Observed a failure class where a new user request is accepted strongly enough to trigger tool
activity, but the final visible reply is still owned by stale prior-turn state and emits the wrong
closeout or answer text.
Short label: SFROTT
Expanded name: Stale Final-Response Ownership After Turn Transition
This appears more consistent with stale turn-completion or replay ownership drift than with raw
model context exhaustion or a hidden internal reasoning limit.
User-visible symptom
- A prior workflow completes or is near completion.
- The user sends an unrelated new request in the same thread.
- Codex begins processing the new request and may even select tools correctly.
- The final visible reply is still the prior workflow closeout, prior summary, or other stale
answer content.
The key point is that the new request is not ignored. It becomes active enough to drive tool
selection, but final response ownership appears to stay attached to stale state.
Why this does not primarily look like context-window exhaustion
- The new request is parsed and acted on.
- Tool selection begins for the new request.
- The failure is specifically at final visible answer ownership, not broad inability to recall the
new prompt.
This makes the symptom look more like turn-boundary state drift than like generic "the model ran
out of room and forgot everything".
Strongest candidate mechanism
The most plausible upstream mechanism is stale completion-copy ownership in the TUI/runtime path.
Relevant paths:
codex-rs/tui/src/chatwidget/protocol.rscodex-rs/tui/src/chatwidget/turn_runtime.rscodex-rs/tui/src/chatwidget/transcript.rs
Specifically:
TurnCompletedflows intohandle_turn_completed_notification(...).- That calls
on_task_complete(...). on_task_complete(...)can source the completion-visible text from either:- the
last_agent_messagein the turn-complete payload, or - fallback transcript state such as
transcript.last_agent_markdownwhen turn-local copy-source
state indicates the turn already produced a copyable response.
Because transcript.last_agent_markdown is persistent cross-turn state, any turn-boundary or
replay-state bug that leaves stale copy-source state eligible can produce exactly this failure
shape.
Evidence supporting that mechanism
1. Existing upstream regression already guards an adjacent bug
There is already a targeted regression in:
codex-rs/tui/src/chatwidget/tests/slash_commands.rs
Test name:
agent_turn_complete_notification_does_not_reuse_stale_copy_source
That test strongly suggests upstream already recognizes stale prior-turn completion-copy reuse as a
real failure category.
2. Replay state is first-class and must be filtered
There is dedicated replay and pending interactive state machinery in:
codex-rs/tui/src/app/pending_interactive_replay.rscodex-rs/tui/src/chatwidget/replay.rscodex-rs/tui/src/app/thread_routing.rs
This means the product already has explicit resume/thread-snapshot paths where old turn state can
be replayed unless carefully filtered or cleared.
3. Long-thread and compaction risk is explicitly acknowledged upstream
Current Codex emits a warning in:
codex-rs/core/src/compact.rs
Message:
- long threads and multiple compactions can make the model less accurate
This does not prove the exact SFROTT mechanism, but it does make long-lived and compaction-heavy
threads credible amplifiers of stale-state failures.
Secondary contributing condition
This failure may be easier to trigger in threads with:
- very long lifetime,
- multiple compactions,
- a strong prior procedural closeout state,
- immediate switching into an unrelated new task,
- replay or resume activity around the same boundary.
In downstream observation, this was seen under a gpt-5.4 configuration with an overridden large
context window, which likely increased thread lifetime and stale-state exposure. That looked more
like an amplifier than a root cause.
Candidate reproduction shape
This is a candidate reproduction pattern, not a minimal proven repro:
- Run a task that ends with strong completion ownership, such as a checkpoint-style closeout or a
summary-heavy procedural workflow.
- Keep the same thread alive long enough that compaction or replay-related state becomes plausible.
- Immediately ask an unrelated new question in the same thread.
- Observe whether tool activity starts for the new question while the final visible reply still
comes from the prior task's closeout state.
Expected behavior
- Once a new user request becomes the active turn, final visible reply ownership should belong only
to the current turn.
- Prior workflow closeout text should not remain eligible to answer the new request.
- If replayed or persistent state conflicts with current-turn ownership, the safe behavior is to
block stale completion emission rather than answer with old text.
Actual behavior
- New request becomes active enough for tool selection or partial processing.
- Final visible reply can still come from stale prior-turn completion state.
Investigation targets
Most suspicious surfaces:
codex-rs/tui/src/chatwidget/turn_runtime.rson_task_complete(...)- selection of
notification_response saw_copy_source_this_turnreset timing- interaction with
maybe_send_next_queued_input()
codex-rs/tui/src/chatwidget/transcript.rs- lifecycle of
last_agent_markdown - lifecycle of
saw_copy_source_this_turn - rollback/replay truncation semantics
codex-rs/tui/src/chatwidget/protocol.rshandle_turn_completed_notification(...)- replay vs live completion handling differences
codex-rs/tui/src/app/pending_interactive_replay.rs- whether stale interactive state can survive a turn transition that should fully displace prior
ownership
codex-rs/tui/src/chatwidget/replay.rs- whether replayed completion or item state can leave stale transcript copy-source state eligible
Bounded hypothesis
The bug is likely not "the model internally reasoned badly because of a hidden thinking limit".
The stronger hypothesis is:
- current-turn execution state and final visible completion-copy ownership can diverge,
- stale transcript or replayed state can stay eligible longer than it should,
- long-lived or compaction-heavy threads make this easier to trigger.
Workaround
Until the underlying ownership path is hardened:
- avoid switching to an unrelated new task immediately after a strong closeout in the same long
thread,
- prefer starting a fresh thread before changing task family,
- if staying in the same thread, insert an explicit handoff or reset boundary before the new task.
This is a mitigation only, not a fix.
Non-claims
- This note does not prove a hidden internal reasoning ceiling.
- This note does not prove that large context windows are themselves broken.
- This note does not provide a minimal deterministic repro yet.
- This note does not claim the issue is confined to checkpoint-like workflows only.
Suggested next steps
- Add a focused regression test for "new turn starts, stale prior completion text must not be used
as final reply source".
- Audit
on_task_complete(...)for any path wheretranscript.last_agent_markdownor
saw_copy_source_this_turn can survive into the wrong turn.
- Stress the same path under replay, resume, and compaction-heavy thread conditions.
- Consider a stronger invariant: final visible answer ownership must be bound to exactly one
current turn, or no final answer should be emitted.
What steps can reproduce the bug?
Candidate reproduction shape
This is a candidate reproduction pattern, not a minimal proven repro:
- Run a task that ends with strong completion ownership, such as a checkpoint-style closeout or a
summary-heavy procedural workflow.
- Keep the same thread alive long enough that compaction or replay-related state becomes plausible.
- Immediately ask an unrelated new question in the same thread.
- Observe whether tool activity starts for the new question while the final visible reply still
comes from the prior task's closeout state.
What is the expected behavior?
Expected behavior
- Once a new user request becomes the active turn, final visible reply ownership should belong only
to the current turn.
- Prior workflow closeout text should not remain eligible to answer the new request.
- If replayed or persistent state conflicts with current-turn ownership, the safe behavior is to
block stale completion emission rather than answer with old text.
Actual behavior
- New request becomes active enough for tool selection or partial processing.
- Final visible reply can still come from stale prior-turn completion state.
Additional information
My customized Codex agent harness investigated the Codex source code based on this self-observed defect and generated this analysis.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗