Repository navigation
Codex Desktop compaction does not bound transcript hydration/rendering; valid long thread becomes unscrollable #33285
Description
Summary
Codex Desktop becomes nearly unusable when opening a long, repeatedly compacted thread: the conversation pane cannot be scrolled reliably, renderer/app-server memory rises into the GiB range, and CPU remains active.
This reproduction is materially different from malformed legacy-history or image/tool-output bloat cases:
- the rollout parses with zero JSON or protocol-shape errors in a complete streaming scan;
- it contains no inline images and no invalid
image_urlvalues; - persisted tool-output text is only about
0.07 MiB; - the latest compacted checkpoint is valid and only about
0.97 MiBof rollout data follows it; - nevertheless, Desktop still appears to hydrate/replay the full pre-compaction transcript/event stream.
The model context is compacted, but the UI workload is not. Long threads therefore eventually become effectively unsafe to open even when compaction succeeds.
Environment
- Codex Desktop:
26.707.9981.0 - Codex CLI:
0.144.2 - Windows 11 x64, version
10.0.22631, build22631 - 31.4 GiB physical memory; about 8.3 GiB remained free during the sample
Reproduction
- Use a single Desktop thread for a long-running, agent-heavy workflow.
- Let automatic context compaction occur repeatedly.
- Fully restart Codex Desktop.
- Open the long thread while it has an active or recently active turn.
- Try to scroll the conversation pane or interact with the thread.
- Observe severe UI lag or an effectively unscrollable pane, while app-server and renderer memory/CPU remain elevated.
This is reproducible after removing closed descendant threads and restarting Desktop. Continued work can regenerate descendants, but the main rollout itself is sufficient to expose the unbounded transcript/event replay path.
Sanitized measurements
Complete streaming scan of the affected main rollout at one snapshot:
rollout size: ~79.3 MiB
JSONL records: 32,834
JSON parse errors: 0
response_item records: 21,547
event_msg records: 11,148
event_msg/user_message: 3,079
response_item/message user role: 4,629
response_item/message assistant: 284
token_count events: 5,648
reasoning records: 5,453
compacted checkpoints: 8
data:image references: 0
invalid image_url values: 0
persisted tool-output text: ~0.07 MiB
encrypted reasoning content: ~7.99 MiB
text fields: ~34.6 MiB
data after latest checkpoint: ~0.97 MiB / 255 records
The latest checkpoint was valid. The rollout file remained byte-stable during a short sample while the UI was still slow.
Observed process footprint while the affected thread was open:
codex app-server private memory: ~2.6 GiB
largest renderer working set: ~1.15 GiB
other renderer working set: ~0.88 GiB
renderer CPU in 3-second sample: ~8-19%
app-server CPU in sample: ~5%
system free physical memory: ~8.3 GiB
There were no relevant rollout parsing errors in the current logs. The only recent warnings were unrelated plugin-manifest warnings.
Compaction/cleanup experiment
Before this snapshot, local maintenance successfully:
- reduced the main rollout from about
73.5 MiBto69.1 MiBby retaining one compacted checkpoint while preserving prompt-bearing records; - removed
449closed child threads and about5.28 GiBof child rollout files; - verified SQLite integrity, zero residual closed-thread references, zero JSON parse errors, and preservation of the main thread.
After continued execution, the main rollout grew back to about 79.3 MiB, accumulated eight compacted checkpoints, and the conversation pane again became effectively unscrollable. This shows that storage cleanup and model-context compaction do not bound Desktop's active transcript/rendering cost.
Expected behavior
- Opening a compacted thread should hydrate metadata plus the latest checkpoint and a bounded recent tail, not all pre-compaction event records.
- The conversation list should use real virtualization/pagination so DOM/renderer work remains bounded by the viewport rather than total thread length.
- Durable audit history should remain available on demand without being part of the initial renderer/app-server payload.
- Hidden technical records such as token counts, reasoning envelopes, tool-call metadata, and old lifecycle events should not be materialized into the active UI unless requested.
- Active-turn updates should append bounded deltas and must not repeatedly rebuild or rebroadcast the full transcript.
- Compaction should expose a clear contract separating model context, durable history, and active UI history.
Actual behavior
Compaction reduces the model's current context, but opening the thread still causes Desktop to process enough of the old event stream that scrolling and interaction become work-blocking. Repeated local slimming can temporarily reduce disk usage but does not prevent the same UI failure from recurring.
Why this report is separate from related issues
- Regression: Desktop 26.707 replays legacy thread history and emits 1,282 parse errors per page, freezing the Windows UI #32198 covers legacy records that emit parse errors during full replay. This reproduction has zero parse errors.
- Codex Desktop: opening a large thread causes sustained 100%+ CPU until app restart #25251 and Codex app can freeze with very large rollout/history JSONL files #22991 cover very large files dominated by tool output or hundreds of MiB of rollout data. This reproduction occurs around 79 MiB with negligible persisted tool-output text.
- Codex Desktop meta-bug: unbounded session/turn state causes freezes, context bloat, and lost active-turn control #25779 tracks the broader unbounded-session-state problem. This report isolates the missing contract between successful context compaction and bounded transcript hydration/rendering.
- [Windows Desktop 26.707.8479.0] New windows still fan out full conversation snapshots for every streaming thread #32722 covers full snapshot fan-out to newly connected windows. The same bounded/paginated protocol principles likely apply, but this report is specifically about opening and scrolling one compacted long thread.
Requested regression coverage
Please add a Desktop/app-server performance test that:
- creates a valid long thread with tens of thousands of pre-compaction events and a small latest checkpoint/tail;
- opens that thread in a fresh Desktop client;
- asserts initial hydration bytes, in-memory turn items, rendered rows, and DOM nodes remain bounded;
- asserts scrolling remains responsive;
- asserts active-turn deltas do not trigger full transcript reconstruction or snapshot rebroadcast;
- verifies old history can still be fetched lazily in pages.
I did not attach the rollout or local databases because they contain private prompts and local paths. I can provide a synthetic valid JSONL generator if maintainers specify the current supported fixture format.
Activity
github-actions commentedon Jul 15, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
SimpleZion commentedon Jul 15, 2026
Additional verification on the latest Windows build:\n\n- Codex Desktop: 26.707.9981.0\n- Codex CLI:
SimpleZion commentedon Jul 15, 2026
I inspected the renderer bundle shipped in Desktop 26.707.9981.0 and found the concrete client-side cause.
Tail hydration is already enabled by default. On resume the client sends:
However, immediately after the five-turn page is installed, the resume path checks
olderCursorand callsloadRemainingConversationTurns(). That helper loops throughthread/turns/listuntil the complete history has been loaded. This negates pagination and eventually rehydrates/renders the whole long legacy transcript.The UI already has a separate on-demand path:
load-older-conversation-history-pageis invoked from the conversation scroll-to-top callback and callsloadOlderConversationTurnsPage(). Therefore the likely fix is to remove or disable the unconditional post-resumeloadRemainingConversationTurns()prefetch, leaving the existing scroll-driven page loader in place.This explains why
excludeTurnsandinitialTurnsPageare present in the latest build but the thread still becomes unresponsive after opening.