fix: use canonical task ID in stuck-task-detector for step-session mode

In step-session mode each step is registered with StuckTaskDetector
under a compound key (e.g. "FN-1452-step-1") rather than the bare
task ID. When stuck detection fired, event.taskId was that compound
key, breaking three things simultaneously:

1. beforeRequeue("FN-1452-step-1") → store.getTask() threw (no such
   task) → stuckKillCount never incremented on the real task.

2. markStuckAborted("FN-1452-step-1") → activeStepExecutors.get()
   returned undefined (keyed by "FN-1452") → terminateAllSessions()
   never called, other step sessions kept running.

3. stuckAborted.set("FN-1452-step-1") → executor checks
   stuckAborted.has("FN-1452") → miss → stuckRequeue never set
   → task never moved to todo.

Fix: add a canonicalTaskId field to TrackedTask (defaults to the
tracking key for single-session mode where they are identical).
StepSessionExecutor now passes taskDetail.id as the third arg to
trackTask(). killAndRetry() uses entry.canonicalTaskId for all
external callbacks so they always resolve to the real task ID.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-09 18:16:55 -07:00
parent 4f80cfc507
commit 9b30cc323d
2 changed files with 42 additions and 16 deletions

View File

@@ -726,10 +726,13 @@ export class StepSessionExecutor {
});
session = createResult.session;
// Track session for termination and stuck-task detection
// Track session for termination and stuck-task detection.
// Pass the canonical task ID (e.g. "FN-1452") as the third argument so
// that stuck-kill callbacks (beforeRequeue, onStuck) operate on the real
// task rather than the compound step key ("FN-1452-step-1").
const handle: SessionHandle = { dispose: () => session?.dispose() };
this.activeSessions.set(stepIndex, handle);
stuckTaskDetector?.trackTask(trackingKey, { dispose: () => session?.dispose() });
stuckTaskDetector?.trackTask(trackingKey, { dispose: () => session?.dispose() }, taskDetail.id);
stepExecLog.log(
`Step ${stepIndex} attempt ${attempt + 1} session created ` +