feat(mcp/planning): allow status changes and post-finalize edits in active session
Extend UpdateChildTask with a status parameter (restricted to Draft, Manual, Queued, Waiting) and replace the 'only Draft is editable' rule with 'planning session is active'. Same loosening applied to DeleteChildTask. Lets planning agents iterate on children that already escaped Draft state.
This commit is contained in:
@@ -138,11 +138,11 @@ public sealed class PlanningMcpServiceTests : IDisposable
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.UpdateChildTask(otherChild.Id, "new", null, null, null, CancellationToken.None));
|
||||
sut.UpdateChildTask(otherChild.Id, "new", null, null, null, null, CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateChildTask_NotDraft_Throws()
|
||||
public async Task UpdateChildTask_AfterFinalize_Throws()
|
||||
{
|
||||
var parent = await SeedPlanningParentAsync();
|
||||
var c = await _tasks.CreateChildAsync(parent.Id, "c", null, null, null);
|
||||
@@ -150,7 +150,75 @@ public sealed class PlanningMcpServiceTests : IDisposable
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.UpdateChildTask(c.Id, "new", null, null, null, CancellationToken.None));
|
||||
sut.UpdateChildTask(c.Id, "new", null, null, null, null, CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateChildTask_SetsTags()
|
||||
{
|
||||
var parent = await SeedPlanningParentAsync();
|
||||
var c = await _tasks.CreateChildAsync(parent.Id, "c", null, null, null);
|
||||
_ctx.ChangeTracker.Clear();
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
var result = await sut.UpdateChildTask(c.Id, null, null, new[] { "agent", "custom-tag" }, null, null, CancellationToken.None);
|
||||
|
||||
Assert.Contains("agent", result.Tags);
|
||||
Assert.Contains("custom-tag", result.Tags);
|
||||
Assert.Equal(2, result.Tags.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateChildTask_ReplacesTagSet()
|
||||
{
|
||||
var parent = await SeedPlanningParentAsync();
|
||||
var c = await _tasks.CreateChildAsync(parent.Id, "c", null, new[] { "agent" }, null);
|
||||
_ctx.ChangeTracker.Clear();
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
var result = await sut.UpdateChildTask(c.Id, null, null, new[] { "manual" }, null, null, CancellationToken.None);
|
||||
|
||||
Assert.Single(result.Tags);
|
||||
Assert.Equal("manual", result.Tags[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateChildTask_SetsStatus()
|
||||
{
|
||||
var parent = await SeedPlanningParentAsync();
|
||||
var c = await _tasks.CreateChildAsync(parent.Id, "c", null, null, null);
|
||||
_ctx.ChangeTracker.Clear();
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
var result = await sut.UpdateChildTask(c.Id, null, null, null, null, "Queued", CancellationToken.None);
|
||||
|
||||
Assert.Equal("Queued", result.Status);
|
||||
var loaded = await _tasks.GetByIdAsync(c.Id);
|
||||
Assert.Equal(TaskStatus.Queued, loaded!.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateChildTask_DisallowedStatus_Throws()
|
||||
{
|
||||
var parent = await SeedPlanningParentAsync();
|
||||
var c = await _tasks.CreateChildAsync(parent.Id, "c", null, null, null);
|
||||
_ctx.ChangeTracker.Clear();
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.UpdateChildTask(c.Id, null, null, null, null, "Running", CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateChildTask_UnknownStatus_Throws()
|
||||
{
|
||||
var parent = await SeedPlanningParentAsync();
|
||||
var c = await _tasks.CreateChildAsync(parent.Id, "c", null, null, null);
|
||||
_ctx.ChangeTracker.Clear();
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.UpdateChildTask(c.Id, null, null, null, null, "NotARealStatus", CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -215,7 +283,7 @@ public sealed class PlanningMcpServiceTests : IDisposable
|
||||
_ctx.ChangeTracker.Clear();
|
||||
|
||||
var sut = BuildSut(parent.Id);
|
||||
await sut.UpdateChildTask(c.Id, "new title", null, null, null, CancellationToken.None);
|
||||
await sut.UpdateChildTask(c.Id, "new title", null, null, null, null, CancellationToken.None);
|
||||
|
||||
var ids = TaskUpdatedIds();
|
||||
Assert.Contains(c.Id, ids);
|
||||
|
||||
Reference in New Issue
Block a user