Repository navigation
Stale Final-Response Ownership After Turn Transition #30767
Description
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.
- the
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
- lifecycle of
-
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
- whether stale interactive state can survive a turn transition that should fully displace prior
-
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_turncan 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.
Activity
lagordon70 commentedon Jun 30, 2026
My Agentic harness produced the resultant analysis.
• Findings
The strongest concrete fault I found is in on_task_started() at external/openai-codex/codex-rs/tui/src/chatwidget/turn_runtime.rs:49: it resets turn flags, but
it does not clear a stale pending_notification.
Notification::AgentTurnComplete is stored in pending_notification at external/openai-codex/codex-rs/tui/src/chatwidget/notifications.rs:10. If a new task
starts before that stale completion notification is consumed, it remains eligible.
Separately, on_task_complete() at external/openai-codex/codex-rs/tui/src/chatwidget/turn_runtime.rs:81 can still source completion text from fallback
transcript state (last_agent_markdown) when saw_copy_source_this_turn says the turn already had a copy source.
Replay is a plausible amplifier because replayed AgentMessage completion still records agent markdown in external/openai-codex/codex-rs/tui/src/chatwidget/
streaming.rs:261, and replay is first-class in external/openai-codex/codex-rs/tui/src/chatwidget/replay.rs:1.
Upstream already has an adjacent regression at external/openai-codex/codex-rs/tui/src/chatwidget/tests/slash_commands.rs:1952, which supports the diagnosis
that this is stale ownership state, not a hidden reasoning limit.
Recommended fix
Minimal fix:
Robust fix:
output, not replayed history.
Tests to add:
Workaround
The best single fix to recommend upstream is the minimal one plus the turn-keyed copy-source hardening.
lagordon70 commentedon Jun 30, 2026
Identifed as duplicate of #8648 and added the potential defect analysis and fix there.
lagordon70 commentedon Jun 30, 2026
closed as duplicate
etraut-openai commentedon Oct 12, 2026
(response from codex)
Closing as a duplicate of #8648, as the reporter already requested. That issue remains open and includes your follow-up investigation of old-task answers after a new request. Please continue tracking it there; no fix is implied by this closure.