[Windows Desktop] Scheduled stop on active goal creates thousands of empty turns and hides transcript history
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using?
- Codex Desktop AppX:
26.908.4834.0(x64) - Bundled/available Codex CLI:
0.154.0
What subscription do you have?
Paid ChatGPT account. The incident crossed an account usage-limit boundary.
What platform is your computer?
- Windows 11 Pro x64
- OS build
26200 - Local Codex project/thread
What issue are you seeing?
A long-running goal worked normally until a one-time scheduled stop message was delivered to the same thread around the time the account reached its usage limit. The goal remained active after the stop message, and Codex generated thousands of synthetic goal-continuation turns, most with empty final_answer messages. The Desktop transcript then stopped rendering the real conversation history and showed a mostly blank viewport.
The stored history was not deleted. The app-server can still page through it, but the newest pages contain empty turns, and the Desktop UI does not progress to usable older messages.
This appears to combine three failure modes:
- A scheduled stop message can race with an active goal without actually pausing the goal.
- Goal continuation can enter a tight loop that emits empty completed turns, including across a usage-limit event.
- Transcript pagination/rendering does not skip empty turns or continue fetching until visible messages are available.
Observed sequence
All timestamps below are UTC.
- The long-running goal had operated normally for several days and was paused on
2026-09-05T18:30:25Z. - The same goal was reactivated on
2026-09-12T01:56:50Z. - A one-time thread heartbeat was scheduled for
2026-09-12T02:30:00Z(10:30 PM America/New_York). Its prompt told the task to stop new experiments, finish only necessary recovery, save a checkpoint, and stop. It also warned that the goal might need the app's Pause control. - The scheduled stop message appeared in the thread. The goal itself remained active.
- The first empty assistant
final_answerwas recorded at2026-09-12T02:32:23.137Z, shortly after the scheduled stop. - Usage-limit failures were recorded at
2026-09-12T06:52:49.074Zand2026-09-12T06:53:25.866Z. - Empty completed turns continued until
2026-09-12T12:13:10.784Z. - The goal was finally changed from active to paused at
2026-09-12T12:13:09.042Z. - Opening the thread in Desktop showed the scheduled message near the bottom and a large blank transcript area. Older messages could not be reached normally.
Quantified local evidence
Sanitized counts from the local rollout JSONL:
- Rollout size:
248,019,503bytes (236.53 MiB) turn_contextrecords:4,295- Internal goal-continuation prompts:
4,268 - Assistant
final_answermessages:4,273 - Empty assistant
final_answermessages:3,769 - Non-empty assistant
final_answermessages:504 - Empty turns were often created every 2–5 seconds.
A read-only thread/turns/list check returned:
- the thread itself as idle after the goal was paused;
hasMore: true, proving older pages still exist;- newest pages containing completed turns with
items: []or assistant messages whose text is empty.
The visible failure is therefore not message deletion. It is a goal/state runaway that produced a pathological history, followed by a Desktop pagination/rendering failure over that history.
I am intentionally omitting the full thread ID, local project paths, raw transcript, and tool output because they contain private operational details. I can provide a redacted event sample or the full session through a maintainer-approved private channel.
Steps to reproduce
- Start a long-running goal in a local Codex Desktop thread.
- Let it run long enough to approach an account usage limit.
- While the goal is active, add a one-time thread heartbeat whose message instructs the task to stop at a specified time but does not mark the unfinished goal complete or blocked.
- Let the scheduled stop message arrive while the goal runner is active.
- Allow the account usage limit to be reached before the goal is explicitly paused in the UI.
- Inspect the rollout JSONL for repeated internal goal-continuation prompts and empty assistant
final_answerrecords. - Reopen the thread and try to scroll through all messages.
Expected behavior
- Reaching a usage limit should transition the goal once into a non-running state without repeated continuation attempts.
- A scheduled stop instruction delivered to an active goal should not leave the goal runner generating synthetic continuation turns indefinitely.
- A completed model turn should not be persisted as an empty
final_answerunless it has meaningful visible content or error state. - Desktop history loading should skip empty synthetic turns and keep paging until visible messages are found.
- The complete stored conversation should remain reachable even when a thread contains many turns.
Actual behavior
- The goal stayed active after the stop message.
- Thousands of automatic continuation turns were created.
- Most assistant finals were empty.
- The rollout grew to 236.53 MiB.
- Desktop rendered a mostly blank transcript and did not expose the older stored messages.
Related issues
- #23828 —
/goalloops after usage limit and repeatedly triggers compaction (closed; this looks like a regression/variant) - #31995 — long conversations show only recent turns although full rollout history remains local
- #25779 — meta issue for unbounded session/turn state and lost active-turn control
This report adds the scheduled-stop interaction, a current Windows reproduction, exact lifecycle timestamps, and verified empty-turn counts.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the scheduled-stop and usage-limit sequence, then inspect the rollout JSONL and the thread/turns/list results described in the report. Trace the goal state transition, continuation records, and Desktop history loading; done means the goal stops once, empty turns do not accumulate, and older visible messages remain reachable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, desktop
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100