fix(1632): cancel_queued reports the removal it observed, not the one it requested - #1636
Draft
artokun wants to merge 3 commits into
Draft
fix(1632): cancel_queued reports the removal it observed, not the one it requested#1636artokun wants to merge 3 commits into
artokun wants to merge 3 commits into
Conversation
… its stub as an observation
… never reads as absent
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.
Fixes #1632.
The bug
queue action:"cancel_queued"saidQueued job <id> removed successfully.unconditionally. ComfyUI's/queuedelete silently no-ops for a prompt it has already started, so a job that won the race kept rendering and still delivered its outputs while the agent told the user it had been cancelled. In the reporter's session the job started ~1s before the cancel landed, and four stale images arrived 70s after the "success".Two unconditional paths, and the first made the second unavoidable:
cancelQueuedJob()returnedPromise<void>— it fired the delete and read nothing. The caller had nothing to branch on.cancel_queuedcase therefore hardcoded the success string.This is the one queue mutation that never got the verify-then-report contract
action:"cancel"right above it already has.The fix
cancelQueuedJobnow reads/queueon both sides of the delete and returns{ removed, state, verified }. The tool returnsisError:truefor anyremoved:false, with prose naming what the job is actually doing — forrunning, explicitly that the outputs will still be delivered and thataction:"cancel"is the tool for it.absent) from one we removed; after the delete those two are indistinguishable. Also short-circuits an already-runningjob without a pointless delete.verified:false(an incomplete observation) is not an error — the request did go through. It just may not say "removed successfully", which claims a proof no read supplied.The verification needed a read that can FAIL
The first version of this fix built the check on
client.getQueue(), and that was worse than the bug. Measured against a real HTTP server,getQueue()never throws: it goes through the vendored client, whose failure path resolves a document with noRunning/Pendingkey, and the?? []normalizer turns that into an empty queue./queueanswersgetQueue()resolves{queue_running:[],queue_pending:[]}{queue_running:[],queue_pending:[]}{}{queue_running:[],queue_pending:[]}{queue_running:[],queue_pending:[]}So "this job is not pending" and "I could not look" were the same value. With ComfyUI merely unreachable, a genuinely pending job read as
absent→ "it already finished, its outputs already exist" — the #1632 lie with a new cause — and the delete was never even attempted, which the old code at least always did. A failed after-read was the same collapse pointed the other way: empty looks like a successful removal, re-earningremoved successfully.now stampedverified:true.This adds
getQueueVerified()inclient.ts— same normalization, but over the guarded JSON path (comfyApiFetch+readComfyJson+expectShape) that every other verifying read here uses. Network errors, non-2xx, HTML, and a JSON body that is not a queue document all throw.nullincancelQueuedJobnow means ignorance and nothing else: it never decides an early return, never skips the delete, and never counts towardverified.getQueue()is unchanged — collapsing is fine for a summary, where an unreachable ComfyUI genuinely has no jobs to list.Comfy Cloud
cloudClient.getQueue()returns a hardcoded empty queue with no network call — there is no/queueendpoint. Verifying against it would report every cloud job asabsentand swallow the delete, replacing a correctCLOUD_UNSUPPORTEDerror that namesaction:"cancel"with a false one. Cloud mode goes straight to the delete, exactly as before.Proof
Deleted-fix verified, not just green. Five mutations against committed code:
{removed:false,state:"absent"}— the exact regression)getQueueVerified()back togetQueue()queue-manager-cancel-queued-unreachable.test.tsmocks nothing — real queue-manager, realclient.ts, real fetch, real sockets, retargeted viasetComfyuiTarget. A stubbed client is exactly what hid this defect: the first version's suite was green over it by construction.Full suite: 519 files, 9700 passed, 3 skipped.
tsc --noEmit,check:vocabulary(1464 files),i18n:check,check:docs-links,check:docs-localeall clean.Codex gate
codex was unavailable (account exhausted until 2026-08-19); gated by an independent adversarial review instead —
.claude/autopilot/claude-gate.mjs, which spawns a fresh reviewer that has not seen this reasoning. It returned NO-SHIP twice, and both findings were real and are fixed above: the Comfy Cloud stub (round 1) and the never-throwing/queueread (round 2, P0). Verdicts recorded in comments below.Observed, deliberately not fixed
cancelRunningJobEscalating(action:"cancel") has the same collapsing read. It verifies viagetQueueSummary()→getQueue(), so an unreachable ComfyUI reports an empty queue and its "nothing is running" check can settle on that. Pre-existing, a different action, and out of scope for queue cancel_queued reports "removed successfully" for a job that is already running (and still completes) #1632 — flagged here rather than widened into this diff.clearAllQueued/action:"clear"— the reporter suggested it as the same shape. It isn't: its message is already scoped to pending items, and a job that started running is no longer a pending item, so nothing in that sentence is falsified by the race./historyread on every cancel.cancel_queuedis orchestrator-only;grep -rn "cancel_queued"overcomfyui-mcp-panelreturns zero hits.🤖 Generated with Claude Code