Repository navigation
fix(claude-queue): priority-aware queue reconstruction — completed agents stuck as queued + queued prompt vanishing - #469
Merged
Juliusolsson05 merged 1 commit intoJul 7, 2026
Conversation
…-head
Two soak bundles from one Claude session (render pipeline flag on) captured
the same root cause:
- debug-bundles/manual/2026-07-07T13-17-20-472-5b19529f
"completed agents renders as queued"
- debug-bundles/manual/2026-07-07T13-17-48-452-5b19529f
"a queued prompt did not get shown in the feed"
Root cause: useIpcSubscriptions replayed Claude's `queue-operation` transcript
records into `queuedMessages`, but reconstructed a dequeue/remove as a blind
`slice(1)` (drop the head). Claude's real queue
(vendor/claude-code-src/full/utils/messageQueueManager.ts) is a PRIORITY queue:
user prompts enqueue at 'next' (1), `<task-notification>` payloads at 'later'
(2), and dequeue removes the LOWEST priority number, FIFO within a level. So a
user prompt is delivered ahead of already-parked task-notifications regardless
of insertion order. When the queue mixes priorities, the head-drop removed the
wrong logical item, permanently desyncing our reconstruction from Claude's
provider-owned queue (which the idle-clear invariant deliberately never
repairs — queueInvariants.ts). Both symptoms fall out of that drift:
completed-agent notifications get stuck in the QueueStrip, and the user's own
queued prompt vanishes from it (the only surface a Claude queued prompt shows,
since claude has usesOptimisticUserEcho:false).
Fix:
- New claudeQueueReconstruction.applyClaudeQueueDequeue mirrors Claude's
priority dequeue by inferring priority from content (task-notification =
'later', else 'next'); it collapses to slice(1) for a homogeneous queue, so
the common all-prompts path is unchanged.
- Wire it into the dequeue/remove branch in useIpcSubscriptions.
- QueueStrip: stop appending the raw <status> after the summary — Claude's
summary already reads `Agent "X" finished`, so the append produced the
"finished completed — delivering to agent…" nonsense the user screenshotted;
the ✓/✗ glyph already carries the outcome.
Tests: unit coverage for the priority reconstruction (mixed + homogeneous
queues). Extended the bundle corpus with the two new fixtures (ledger feed is
at parity for both — the bug lived in the QueueStrip, outside the ledger diff).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause (one defect, both symptoms)
Two soak bundles from the same Claude session (render pipeline flag on) captured the same underlying bug:
debug-bundles/manual/2026-07-07T13-17-20-472-5b19529f— "A lot of problems, completed agents renders as queued.."debug-bundles/manual/2026-07-07T13-17-48-452-5b19529f— "a queued prompt did not get shown in the feed. a lot of issues."useIpcSubscriptionsreplays Claude'squeue-operationtranscript records intoqueuedMessages, but reconstructed eachdequeue/removeas a blindslice(1)(drop the head). Claude's real queue is a PRIORITY queue, not FIFO (vendor/claude-code-src/full/utils/messageQueueManager.ts):enqueue(user prompts) → priority'next'(1)enqueuePendingNotification(<task-notification>) → priority'later'(2)dequeueremoves the lowest priority number, FIFO within a level, and logs no content/identity.So a user prompt is delivered ahead of already-parked completed-agent notifications regardless of insertion order. Whenever the queue mixed priorities, the head-drop removed the wrong logical item and permanently desynced our reconstruction from Claude's provider-owned queue — which the idle-clear invariant deliberately never repairs (
queueInvariants.ts, capability-gated to skip Claude). Both symptoms fall out of that single drift:html-clean.htmlpainted2 queuedwithAgent "Audit structural conventions + isolation" finished completed — delivering to agent….usesOptimisticUserEcho: false, so it never mints optimistic feed rows). The "agent-feed blending into main feed" hypothesis was disproven: QueueStrip renders unconditionally, outside the ledger, regardless of the pipeline flag.Fix
claudeQueueReconstruction.applyClaudeQueueDequeue(new) mirrors Claude's priority dequeue by inferring priority from content (<task-notification>='later', else'next'). It collapses toslice(1)for a homogeneous queue, so the common all-prompts path is byte-for-byte unchanged.dequeue/removebranch inuseIpcSubscriptions.ts.<status>after the summary — the summary already readsAgent "X" finished, so the append produced thefinished completed …nonsense; the ✓/✗ glyph already carries the outcome.Tests / gates
claudeQueueReconstruction.test.ts(6 cases: mixed + homogeneous queues, the exact bundle shapes). Passes.agent-voice-dictation/.../hotkeyBinding.test.tsreports "no test suite found" — anode --testfile, not mine.)tsc -b tsconfig.node.json: clean (exit 0).tsc --noEmit -p tsconfig.web.json(after node build, TS6305 ignored): the only error is pre-existing and unrelated —collectLedgerInput.ts(113): Property 'lookups' does not exist on type 'RuntimeSemanticTurn', introduced by the last-merged PR fix(rendering): collapsed-running tail gate — first live soak catch #465 (collapsed-running tail gate), confirmed present with my edits stashed. Left untouched to avoid conflicting with in-flight work; flagging for the owner.🤖 Generated with Claude Code