Repository navigation
Description
Problem
Saved debug bundles show a Codex queued prompt remaining in QueueStrip after the agent has already processed it and the session has returned to idle. This is separate from the earlier user-prompt ordering issue: here the stale queue item is still present in state-snapshot.json, so the HTML is faithfully rendering bad runtime state rather than merely leaving behind a stale DOM artifact.
Evidence
Saved debug manifest notes:
2026-05-19T09:23:48.299Znote on bundle~/.config/agent-code/debug-bundles/2026-05-19T09-23-36-093-21e655e8:weird thing? que is not cleared in this example UI wise.2026-05-19T09:26:18.873Znote on bundle~/.config/agent-code/debug-bundles/2026-05-19T09-26-14-911-21e655e8:same issue, no user propmt
First bundle state:
- manifest captured at
2026-05-19T09:23:35.966Z sessionStatus: runningstreamPhase: thinkingprocessActive: truequeuedMessages.length: 1- queued timestamp:
1779182503356(2026-05-19T09:21:43.356Z) - queued content begins:
After that, you can post a new issue for me. Actually, can you read the two scripts we had left? ...
Second bundle state:
- manifest captured at
2026-05-19T09:26:14.828Z sessionStatus: idlestreamPhase: idleprocessActive: falseawaitingAssistant: falsequeuedMessages.length: 1- same queued content and timestamp still present
HTML confirms the queue strip is rendering from state:
<div ... aria-label="queued messages">
<div ...>1 queued</div>
... After that, you can post a new issue for me ...
</div>The later screen / recentScreen in the same idle bundle do not contain that queued prompt text, but they do contain later assistant output and later user input. The assistant clearly progressed through subsequent turns while the local queue surface remained stuck.
Likely Cause
addOptimisticCodexUserEntry() queues follow-up Codex submits when shouldQueueOptimisticCodexUserEntry() sees a live semantic turn. The clearing path in useIpcSubscriptions.ts removes a queued item only when an authoritative Codex rollout user row maps to matching prompt text:
if (queuedMessages.some(q => codexPromptsMatchForOwnership(q.content, mappedText))) {
queuedMessages = queuedMessages.filter(q =>
!codexPromptsMatchForOwnership(q.content, mappedText),
)
}That assumes every queued follow-up will later appear as a committed user rollout entry. The saved bundle disproves that assumption: the prompt was submitted/processed, but no matching committed user row arrived in the captured durable feed, leaving queuedMessages permanently non-empty.
Desired Behavior
A queued prompt should not remain visible after the app has convincing evidence that the queued turn has been accepted or superseded.
Potential fixes to investigate:
- Clear the head queued item when a queued follow-up transitions into a new provider turn, even if no committed user rollout row arrives.
- Add an idle/session-complete reconciliation guard: if
streamPhase === 'idle',processActive === false, andawaitingAssistant === false,queuedMessagesshould be empty unless the provider explicitly reports pending queued work. - Emit feed-debug events when queue items are added, reconciled by committed user row, or force-cleared by lifecycle state, so future saved bundles show exactly which invariant fired.
Acceptance Criteria
- Add a regression fixture/script for: queued Codex follow-up, provider responds, no matching committed user rollout row, session returns idle.
- The queued strip disappears by the time the session is idle.
- Existing behavior still preserves genuinely pending follow-up prompts during an active semantic turn.
- Saved debug bundle state cannot show
sessionStatus: idle,streamPhase: idle,processActive: false,awaitingAssistant: false, andqueuedMessages.length > 0for a Codex pane unless there is a real provider queue signal explaining it.
Related
- Optimistic submitted user prompts are buried behind semantic/work rows #239 tracks submitted user prompts being present but visually buried behind semantic/work rows. This issue is different:
queuedMessagesitself remains stale.
Activity
Juliusolsson05 commentedon May 19, 2026
Review-agent correction
The stale QueueStrip symptom is confirmed, but the root-cause statement needs correction.
Confirmed:
queuedMessages.length === 1persisted while the saved runtime was idle:sessionStatus: "idle"streamPhase: "idle"processActive: falseawaitingAssistant: falseQueueStripfrom that stalequeuedMessagesstate.Correction:
The issue body says the matching committed user rollout row never appeared in the captured durable feed. A review agent found that the actual Codex rollout file did contain the matching user row on disk.
Evidence from review:
~/.codex/sessions/2026/05/19/rollout-2026-05-19T10-12-27-019e3f4b-1c22-7962-b85b-0f09f03eb68d.jsonl:1063was aresponse_itemuser message with the queued STT prompt.:1064was the pairedevent_msg.user_message.Sharper likely cause:
The renderer's committed-rollout ingestion/tailing appears to have gone stale or attached to an old cursor. The saved bundles reported
lastJsonlEntryAt: 1779181656586(2026-05-19T09:07:36.586Z), while the queued prompt committed later at2026-05-19T09:21:44.497Z. So the clearing logic probably never saw the committed user row, even though it existed on disk and should have mapped through the rollout ingestion path.Code references from review:
src/renderer/src/workspace/hook/actions/streaming.ts: queued follow-up prompts are added when a semantic turn is live.src/renderer/src/workspace/hook/ipc/useIpcSubscriptions.ts: queued prompts are cleared only when a mapped rollout user entry matches.src/renderer/src/workspace/tile-tree/TileLeaf/QueueStrip.tsx: QueueStrip directly rendersqueuedMessages.src/renderer/src/workspace/codex/rollout.ts: expected mapping path for committed Codex rollout user rows.The desired idle invariant is still reasonable: an idle Codex pane should not retain stale
queuedMessages. But the fix should investigate rollout tail/ingestion staleness, not only queue reconciliation matching.Merge pull request #304 from Juliusolsson05/fix/241-codex-queue-idle-…
Juliusolsson05 commentedon Jun 21, 2026
Fixed and merged in #304 (fix(#241): clear stale Codex queued prompts via idle-convergence reconciliation). Closing.