fix(worker,data): honor wait_for_task_change's NotFound contract, harden TaskNumberAllocator
wait_for_task_change resolved #<number>/bare-number ids up front via TaskIdResolver, which throws for an unknown number -- breaking the tool's own documented promise that an unknown id reports status "NotFound" instead of failing the whole call. Resolve per id and fall back to the original id on a resolution failure so CheckOnceAsync can still report it. TaskNumberAllocator.AddWithNumberAsync indexed into the app_settings UPDATE...RETURNING result without checking for an empty result, throwing on a missing singleton row; it also caught any DbUpdateException as a number collision, burning up to 5 numbers on an unrelated failure (e.g. FK violation) before the real error surfaced. Now recreates the missing row and only retries on the actual unique-index collision (SQLite error 19 on tasks.number), rethrowing everything else immediately. Audited the other TaskIdResolver.ResolveAsync/ResolveManyAsync call sites (ExternalMcpService, HandoffMcpTools, ConfigMcpTools, RunHistoryMcpTools, AttachmentMcpTools, LifecycleMcpTools, BatchMcpTools): none of their tool descriptions promise a found/NotFound flag for the id itself (BatchMcpTools.BatchGetTasks already handles this correctly via its own per-id try/catch; PreviewMergeSet promises a per-task "error" field, not a found/NotFound flag; the rest are single-id tools that already throw on a missing task downstream) -- left throwing behavior as-is.
This commit is contained in:
+13
-1
@@ -109,7 +109,19 @@ public sealed class TaskWaitMcpTools
|
||||
var tasks = new TaskRepository(ctx);
|
||||
var resolved = new string[ids.Length];
|
||||
for (var i = 0; i < ids.Length; i++)
|
||||
resolved[i] = await TaskIdResolver.ResolveAsync(tasks, ids[i], ct);
|
||||
{
|
||||
try
|
||||
{
|
||||
resolved[i] = await TaskIdResolver.ResolveAsync(tasks, ids[i], ct);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// A #<number>/bare-number id with no matching task -- keep the original,
|
||||
// unresolvable id so CheckOnceAsync's lookup misses and reports "NotFound",
|
||||
// per this tool's documented contract, instead of failing the whole call.
|
||||
resolved[i] = ids[i];
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user