Stale Final-Response Ownership After Turn Transition

Open 💬 3 comments Opened Jun 30, 2026 by lagordon70

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.rs
  • codex-rs/tui/src/chatwidget/turn_runtime.rs
  • codex-rs/tui/src/chatwidget/transcript.rs

Specifically:

  • TurnCompleted flows into handle_turn_completed_notification(...).
  • That calls on_task_complete(...).
  • on_task_complete(...) can source the completion-visible text from either:
  • the last_agent_message in the turn-complete payload, or
  • fallback transcript state such as transcript.last_agent_markdown when 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.rs
  • codex-rs/tui/src/chatwidget/replay.rs
  • codex-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:

  1. Run a task that ends with strong completion ownership, such as a checkpoint-style closeout or a

summary-heavy procedural workflow.

  1. Keep the same thread alive long enough that compaction or replay-related state becomes plausible.
  2. Immediately ask an unrelated new question in the same thread.
  3. 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.rs
  • on_task_complete(...)
  • selection of notification_response
  • saw_copy_source_this_turn reset 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.rs
  • handle_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

  1. Add a focused regression test for "new turn starts, stale prior completion text must not be used

as final reply source".

  1. Audit on_task_complete(...) for any path where transcript.last_agent_markdown or

saw_copy_source_this_turn can survive into the wrong turn.

  1. Stress the same path under replay, resume, and compaction-heavy thread conditions.
  2. 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:

  1. Run a task that ends with strong completion ownership, such as a checkpoint-style closeout or a

summary-heavy procedural workflow.

  1. Keep the same thread alive long enough that compaction or replay-related state becomes plausible.
  2. Immediately ask an unrelated new question in the same thread.
  3. 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.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗