Skip to content

fix(cancel): report a cancelled job as cancelled, not as a failure - #66

Merged
StuartCameronCode merged 1 commit into
mainfrom
fix/cancel-reports-as-cancelled
Aug 8, 2026
Merged

fix(cancel): report a cancelled job as cancelled, not as a failure#66
StuartCameronCode merged 1 commit into
mainfrom
fix/cancel-reports-as-cancelled

Conversation

@StuartCameronCode

Copy link
Copy Markdown
Owner

Third attempt at the same report. The first two missed the actual cause, so this
one starts from the evidence.

Cause

The worker sends complete(false) on its way out of a cancellation as well as
on a real failure, and _handleStdoutLine builds that into a CompletionResult
with no cancelled flag — so it defaults to false.

_pendingCompletion is therefore always set when the worker exits, which made
the previous fix inert: it put cancelled: _cancelRequested in a ?? fallback
behind _pendingCompletion, where it could never be reached. Cancelling still
looked exactly like a failure.

That distinction drives the queue. _handleQueueItemCompletion stops on
cancelled, but on a plain failure it marks the item failed and calls
_processNextItem(). So cancelling silently started the next job and left
_isQueueProcessing true — and the next conversion the user asked for sat on
"processing" with a spinner and no progress, because the queue believed it was
already busy.

Fix

The decision is now a pure function, WorkerManager.completionFor, with the
cancellation check first, so it overrides the worker's own report rather than
filling in for it.

Why it is extracted

Both previous attempts were verified by tests that read the source. Those passed,
and the bug shipped twice. This is testable directly, and the decisive case —
cancelled with a pending complete(false), which is the only case that
actually occurs — fails against the shipped logic and passes against this one.

The stale source-scanning assertion is reduced to checking the handler routes
through completionFor and hands over the flag; what it was trying to assert is
now covered by behaviour instead of by text.

Third attempt at the same report, and the first two missed the actual cause.

The worker sends `complete(false)` on its way out of a cancellation as well as on
a real failure, and `_handleStdoutLine` builds that into a CompletionResult with
no `cancelled` flag -- so it defaults to false. `_pendingCompletion` is therefore
ALWAYS set when the worker exits, which made the previous fix inert: it put
`cancelled: _cancelRequested` in a `??` fallback behind `_pendingCompletion`,
where it could never be reached. Cancelling still looked exactly like a failure.

That distinction drives the queue. `_handleQueueItemCompletion` stops on
`cancelled`, but on a plain failure it marks the item failed and calls
`_processNextItem()`. So cancelling silently started the next job and left
`_isQueueProcessing` true -- and the next conversion the user asked for sat on
"processing" with a spinner and no progress, because the queue believed it was
already busy.

The decision is now a pure function, WorkerManager.completionFor, with the
cancellation check first so it overrides the worker's own report rather than
filling in for it.

Why extract it: the previous two attempts were verified by tests that read the
source. Those passed, and the bug shipped twice. This is testable directly, and
the decisive case -- cancelled WITH a pending complete(false), which is the only
case that actually occurs -- fails against the shipped logic and passes against
this one.

The stale source-scanning assertion in worker_manager_generation_test is reduced
to checking the handler routes through completionFor and passes the flag; what it
was trying to assert is now covered by behaviour.
@StuartCameronCode
StuartCameronCode merged commit fef17e7 into main Aug 8, 2026
4 checks passed
@StuartCameronCode
StuartCameronCode deleted the fix/cancel-reports-as-cancelled branch August 8, 2026 23:29
StuartCameronCode added a commit that referenced this pull request Aug 8, 2026
Artifacts on the draft predate the cancellation-reporting fix in #66. Version
string stays at 0.9.12; build number 30 -> 31.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant