fix: sync kanban card stage with live agent phase (fixes #1885)

The emitPhaseFromState method in TaskStateManager was using Date.now()
as the sequenceNumber for TASK_EXECUTION_PROGRESS events. Since agent
processes use small sequential integers (1, 2, 3...) for their sequence
numbers, the timestamp-based value (e.g., 1708512345678) was always
much larger. This caused the out-of-order drop check in updateExecutionProgress
to permanently block all subsequent agent execution-progress events once
XState emitted any phase update.

The result: after XState fired the initial "planning" phase via emitPhaseFromState,
all agent events reporting the "coding" (or later) phase would be silently dropped
because their sequential numbers were less than the stored timestamp. The kanban
card would remain frozen on the "planning" badge while the task detail view
(which reads from task logs) correctly showed the "coding" stage.

Fix: use sequenceNumber=0 in emitPhaseFromState. With value 0, the incoming
sequence check (incomingSeq > 0 && currentSeq > 0) is not triggered, so the
XState phase update always applies. Subsequent agent events with their small
sequential numbers are then correctly accepted and can continue updating
phaseProgress.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
AndyMik90
2026-02-21 21:48:33 +01:00
co-authored by Claude Opus 4.6
parent 60c4890218
commit c8e24eb720
+7 -2
View File
@@ -362,7 +362,12 @@ export class TaskStateManager {
const phase = XSTATE_TO_PHASE[xstateState] || 'idle';
// Emit execution progress with the phase derived from XState
// Emit execution progress with the phase derived from XState.
// IMPORTANT: Do NOT use Date.now() as sequenceNumber here — doing so would
// permanently block all subsequent agent execution-progress events, because
// the agent uses small sequential integers (1, 2, 3…) that are always less
// than a timestamp. Instead emit with sequenceNumber=0 so the agent's own
// events can continue updating phaseProgress once the phase is established.
safeSendToRenderer(
this.getMainWindow,
IPC_CHANNELS.TASK_EXECUTION_PROGRESS,
@@ -372,7 +377,7 @@ export class TaskStateManager {
phaseProgress: phase === 'complete' ? 100 : 50,
overallProgress: phase === 'complete' ? 100 : 50,
message: `State: ${xstateState}`,
sequenceNumber: Date.now() // Use timestamp as sequence to ensure it's newer
sequenceNumber: 0
},
projectId
);