[Windows][Codex App] Hidden avatar overlay receives all thread events unthrottled and amplifies long-session renderer/DWM lag
What version of the Codex App are you using (From “About Codex” dialog)?
26.730.61309 (build 6223). Microsoft Store/MSIX package: OpenAI.Codex_26.730.7989.0_x64.
What subscription do you have?
Authenticated ChatGPT account. The exact subscription tier is not exposed by the local About/log diagnostics used for this report.
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
- GPU: NVIDIA GeForce RTX 5060, driver
32.0.15.9186 - Physical display: 2560×1440 at 275 Hz
- A GameViewer virtual display adapter is also installed
- Packaged runtime: Electron 42.3.0 / Chromium 151.0.7922.71
What issue are you seeing?
After the Codex App has been running for a long time with multiple active/streaming tasks, the UI can progressively develop very high input, scrolling, and paint latency. The machine still has CPU, GPU, and memory headroom, but the whole Codex surface feels delayed. A full Windows reboot clears the condition. Restarting only the visible Codex window may not clear it when the tray/background main process remains alive. Restarting DWM can temporarily reset the visible composition latency, but it does not remove the application-side pressure.
A read-only inspection of the production package and a correlation against live Desktop logs found a multi-surface event/rendering chain that is not covered by the existing WMI sampler reports:
1. The hidden avatar overlay is explicitly unthrottled
The app creates an avatarOverlay BrowserWindow at startup even while it is hidden. In the packaged main-process JavaScript, that window is created with background throttling disabled and webContents.setBackgroundThrottling(false) is applied. The overlay initializes the same common React application stack, including account/bootstrap, feature configuration, thread state, and layout observers.
Runtime logs identify it as rendererWindowAppearance=avatarOverlay and rendererWindowVisible=false, but it continues to process thread activity.
2. App-server notifications are broadcast to every registered window
The packaged main process registers every Desktop window with each app-server connection. Its broadcast path iterates every registered, non-destroyed listener; it does not filter by window appearance, visibility, focus, route, or thread interest.
In one current session, the exact same Reasoning summary item completed event was delivered:
- 453 times to the visible primary window
- 453 times to the hidden avatar overlay
This is a 1:1 duplicate delivery count for that event class. The hidden overlay also logged unknown-conversation and placeholder-turn rebinding activity for tasks that were not visibly presented in the overlay.
3. The per-window chunked-message queue has no visible backpressure limit
The packaged ChunkedMessageSender keeps separate per-target criticalMessages and messages arrays. While a large transfer waits for renderer acknowledgements, subsequent messages are appended to the target queue. In the inspected implementation there is no byte limit, message-count limit, stale-update coalescing, or acknowledgement timeout visible on those arrays.
This is a proven static backpressure risk, not a claim that the live queue size was directly measured. A slow, hidden, or extra renderer can retain subsequent app-server traffic in the Electron main process until that target drains or is destroyed.
4. Streaming layout updates repeatedly fail to converge
The same current primary-renderer log recorded 85 occurrences of:
ResizeObserver loop completed with undelivered notifications.
The production renderer contains resize paths that observe code/diff/annotation dimensions and synchronously write CSS sizing variables on the observed layout, plus virtualized thread content whose height and scroll state are recomputed during streaming. This creates a measurement → style/height write → measurement feedback risk.
The main process also recorded four main_thread_jank_snapshot events. In this build that sampler checks at 100 ms intervals and records a snapshot when the delay reaches approximately 900 ms or more, so these entries represent substantial event-loop stalls.
5. Window multiplication and the physical composition path amplify the symptom
On an earlier affected build during the same investigation, an unintended second visible primary Codex window caused the Codex GPU Present rate to increase from approximately 271/s to 503/s. Both primary renderers consumed the same streaming events. Closing the extra renderer returned the Present rate and DWM load to baseline. The current production main-process bundle still models primary windows as a set and registers each one independently for app-server broadcasts.
On the physical 275 Hz NVIDIA display, the accumulated application-side load becomes visible as system-composition latency. The same Codex session was smooth on the virtual display. Disabling MPO substantially reduced the symptom at both 144 Hz and 275 Hz. A controlled DWM restart rebuilt the compositor in about 0.45 seconds and all ten Codex/ChatGPT processes survived; there was no NVIDIA reset or display error, only the expected Dwminit exit/restart warning. DWM resource usage returned near its normal steady state after ten seconds, so the restart appears to reset the symptom rather than fix the source.
Long-run resource observation
In a previous affected session after approximately 22 hours:
- Electron main process private memory: approximately 3.58 GiB
- A renderer private memory: approximately 1.23 GiB
- System free memory: approximately 11.7 GiB
This rules out simple whole-system memory exhaustion. The queue contribution is a strong inference from the packaged implementation and the slow-renderer evidence; a live heap/queue measurement was not possible because the production package ships no source maps and does not expose an inspector.
What steps can reproduce the bug?
- Start Codex App on Windows and leave the normal avatar/pet overlay lifecycle enabled. The overlay may remain hidden.
- Keep multiple tasks active and let several long turns stream reasoning summaries, tool output, code blocks, or diffs.
- Continue using the same Desktop process for hours; switching among active threads increases the reproduction rate.
- Inspect
%LOCALAPPDATA%\Codex\Logsand groupelectron-message-handlerevents byrendererWindowAppearance,rendererWindowVisible, andrendererWebContentsId. - Observe that the hidden
avatarOverlayreceives the same reasoning/turn events as the visible primary window. - During an affected period, observe bursts of
ResizeObserver loop completed with undelivered notificationsand occasionalmain_thread_jank_snapshotentries while scrolling/input becomes delayed. - If a second visible primary Codex window exists, leave both open during a stream and compare GPU Present/DWM activity; then close the extra window and compare again.
- Compare the physical high-refresh display with a virtual display, or restart DWM as a controlled diagnostic. The visible latency can reset while the Codex processes and underlying application state remain alive.
The progressive lag is intermittent, but duplicate hidden-window delivery is reproducible from a fresh launch.
What is the expected behavior?
- A hidden avatar/pet overlay should not bootstrap and continuously run the full thread renderer unthrottled.
- App-server events should be routed by surface/thread interest. The overlay should receive only the compact state needed to render the pet/tray UI.
- Every per-window IPC/chunk queue should have a byte/count bound, stale-delta coalescing, acknowledgement timeout, and slow/destroyed-target eviction.
- ResizeObserver callbacks should not synchronously mutate dimensions of the layout they observe; writes should be deferred and guarded against no-op/sub-pixel changes.
- Extra or background primary windows should not silently multiply full-rate streaming rendering and GPU presentation.
- Long-running sessions should remain responsive without requiring a Windows or DWM restart.
Additional information
Suggested labels: bug, app, performance, windows-os, pets
Relationship to existing issues
- #33996 reports the correlation between reasoning summaries, ResizeObserver loops, and Windows UI freezes. This report adds the packaged-code path, the hidden unthrottled overlay, and exact 1:1 duplicate delivery.
- #25779 and #21134 cover unbounded/hot thread state and long-session app-server/renderer memory growth. This report adds a separate unbounded per-window transport queue and window multiplication path.
- #24302 reports pet-tray thread-state inconsistency. It is functionally different, but supports treating the pet/overlay as a distinct surface rather than a second full thread consumer.
- #33258 and #33776 report DWM/composition degradation on Windows. #33776 is driven by a process/WMI storm; no such process storm or GPU reset was required for the current reproduction.
- #22912, #34879, #35697, and #35827 cover WMI sampling, startup/resume lag, and PowerShell/conhost behavior. In the current
26.730production bundle, the periodic Windows child-process snapshot is skipped in the normal sampler path; tool-launched PowerShell processes and a one-time startup WMI call are therefore not sufficient to explain the duplicate renderer traffic and layout stalls described here.
Suggested acceptance checks
- With the primary window visible and the avatar overlay hidden, one streamed turn should not be fully delivered/rendered twice.
- A deliberately stalled hidden renderer should not cause unbounded Electron-main memory growth.
- A long streamed diff/reasoning turn should produce zero ResizeObserver loop errors and no ≥900 ms UI-thread stalls.
- Opening an additional primary window should have an explicit lifecycle and should not make every background surface render at the physical refresh rate.
- A 5+ hour multi-task stress run should show bounded main/renderer memory and stable input latency.
All local usernames, repository paths, task IDs, conversation contents, and raw logs are intentionally omitted. Sanitized counts and bounded trace excerpts can be provided privately if maintainers request them.
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Closing this report as a duplicate of #36980. The evidence that was not already present in the existing issue/comment history—current
26.730validation, explicit background-throttling disablement, 453:453 duplicate delivery, per-target queue backpressure risk, ResizeObserver/jank counts, and the DWM/Present A/B—has been migrated to #36980 in https://github.com/openai/codex/issues/36980#issuecomment-5190579565.