diff --git a/src/ClaudeDo.Worker/External/BatchMcpTools.cs b/src/ClaudeDo.Worker/External/BatchMcpTools.cs index 4d864718..aff487f8 100644 --- a/src/ClaudeDo.Worker/External/BatchMcpTools.cs +++ b/src/ClaudeDo.Worker/External/BatchMcpTools.cs @@ -45,6 +45,7 @@ public sealed record BatchTaskDetailDto( int? SortOrder = null, int? RoadblockCount = null, string? RoadblockText = null, + string? FailureReason = null, bool DescriptionTruncated = false, int? DescriptionFullLength = null, bool ResultTruncated = false, @@ -80,6 +81,7 @@ public sealed class BatchMcpTools { "listId", "title", "description", "status", "result", "createdBy", "createdAt", "startedAt", "finishedAt", "isMyDay", "sortOrder", "roadblockCount", "roadblockText", + "failureReason", }; private readonly ExternalMcpService _svc; @@ -187,6 +189,7 @@ public sealed class BatchMcpTools SortOrder: Want("sortOrder") ? t.SortOrder : null, RoadblockCount: Want("roadblockCount") ? t.RoadblockCount : null, RoadblockText: Want("roadblockText") ? ExtractRoadblockText(t.Result) : null, + FailureReason: Want("failureReason") ? t.FailureReason : null, DescriptionTruncated: descTruncated, DescriptionFullLength: descFullLength, ResultTruncated: resultTruncated, diff --git a/tests/ClaudeDo.Worker.Tests/External/BatchMcpToolsTests.cs b/tests/ClaudeDo.Worker.Tests/External/BatchMcpToolsTests.cs index 366d546f..db6e02f9 100644 --- a/tests/ClaudeDo.Worker.Tests/External/BatchMcpToolsTests.cs +++ b/tests/ClaudeDo.Worker.Tests/External/BatchMcpToolsTests.cs @@ -623,4 +623,38 @@ public sealed class BatchMcpToolsTests : IDisposable Assert.Equal(2, progress.Reports.Count); Assert.Equal(2, progress.Reports[1].Total); } + + [Fact] + public async Task BatchGetTasks_FailedTaskWithFailureReason_ReturnsReasonWhenRequested() + { + var listId = await SeedListAsync(); + var task = await SeedTaskAsync(listId, "failed", TaskStatus.Failed); + task.FailureReason = "max-turns-exceeded"; + await _tasks.UpdateAsync(task); + var sut = BuildSut(); + + var results = await sut.BatchGetTasks( + new[] { task.Id }, includeDescription: true, fields: new[] { "failureReason" }, + cancellationToken: CancellationToken.None); + + var found = results.Single(r => r.Id == task.Id).TaskFull!; + Assert.Equal("max-turns-exceeded", found.FailureReason); + Assert.Null(found.Description); + Assert.Null(found.Status); + } + + [Fact] + public async Task BatchGetTasks_IdleTaskWithoutFailureReason_ReturnsNullWhenRequested() + { + var listId = await SeedListAsync(); + var task = await SeedTaskAsync(listId, "idle", TaskStatus.Idle); + var sut = BuildSut(); + + var results = await sut.BatchGetTasks( + new[] { task.Id }, includeDescription: true, fields: new[] { "failureReason" }, + cancellationToken: CancellationToken.None); + + var found = results.Single(r => r.Id == task.Id).TaskFull!; + Assert.Null(found.FailureReason); + } }