Skip to content

Stale Final-Response Ownership After Turn Transition #30767

Closed as duplicate

Description

@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.
  2. Keep the same thread alive long enough that compaction or replay-related state becomes plausible.
  3. Immediately ask an unrelated new question in the same thread.
  4. 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".
  2. Audit on_task_complete(...) for any path where transcript.last_agent_markdown or
    saw_copy_source_this_turn can survive into the wrong turn.
  3. Stress the same path under replay, resume, and compaction-heavy thread conditions.
  4. 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.
  2. Keep the same thread alive long enough that compaction or replay-related state becomes plausible.
  3. Immediately ask an unrelated new question in the same thread.
  4. 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

  1. added
    appIssues related to the Codex desktop app
    on Jun 30, 2026
  2. added
    bugSomething isn't working
    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal display
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    contextIssues related to context management (including compaction)
    on Jun 30, 2026
  3. lagordon70 commented on Jun 30, 2026

    @lagordon70
    Author

    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:

      • Clear stale Notification::AgentTurnComplete when a new user turn is submitted or when on_task_started() runs.
      • Do not clear higher-priority prompts like approval or plan-mode prompts; only clear stale agent-turn-complete notifications.
    • Robust fix:

      • Key transcript copy-source ownership by turn_id and source_kind (live vs replay).
      • In on_task_complete(), only allow fallback to last_agent_markdown when that copy source belongs to the same turn and was produced by live current-turn
        output, not replayed history.
    • Tests to add:

      • new task start clears stale AgentTurnComplete,
      • replayed prior-turn agent message followed by live completion cannot reuse replayed copy source,
      • immediate task switch after closeout in replay/thread-snapshot conditions does not surface prior-turn completion text.

    Workaround

    • Yes: avoid switching to an unrelated task immediately after strong closeout in a long-lived or compaction-heavy thread.
    • Prefer a fresh thread before changing task family.
    • If staying in the same thread, force an explicit boundary first instead of asking the unrelated new task in the same immediate post-closeout turn.

    The best single fix to recommend upstream is the minimal one plus the turn-keyed copy-source hardening.

  4. lagordon70 commented on Jun 30, 2026

    @lagordon70
    Author

    Identifed as duplicate of #8648 and added the potential defect analysis and fix there.

  5. lagordon70 commented on Jun 30, 2026

    @lagordon70
    Author

    closed as duplicate

  6. etraut-openai commented on Oct 12, 2026

    @etraut-openai
    Contributor

    (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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displayappIssues related to the Codex desktop appbugSomething isn't workingcontextIssues related to context management (including compaction)sessionIssues involving session (thread) management, resuming, forking, naming, archiving

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions