refactor(data): retire legacy TaskStatus values and backfill existing rows
Slice 6 of the worker state and queue consolidation refactor. * Drop Manual, Planning, Planned, Draft, Waiting from the TaskStatus enum and from the EF value converter; only the lifecycle values remain (Idle, Queued, Running, Done, Failed, Cancelled). * Add migration RetireLegacyTaskStatus that rewrites existing rows: manual/draft -> idle, planning -> idle+planning_phase=active, planned -> idle+planning_phase=finalized, waiting -> queued+blocked_by derived from sort_order via a CTE with LAG(). * Reroute every call site that compared/set legacy values to the new three-field model (Status + PlanningPhase + BlockedByTaskId), including the planning repo helpers, MCP services, the planning chain coordinator, and the UI view-models. TaskRowViewModel now exposes PlanningPhase to drive the planning badge. * Refresh Worker/CLAUDE.md and Data/CLAUDE.md, the docs/plan.md status section, and the planning verification notes in docs/open.md.
This commit is contained in:
@@ -40,7 +40,8 @@ public sealed class TaskStateServiceTests : IDisposable
|
||||
TaskStatus status,
|
||||
string? parentId = null,
|
||||
int sortOrder = 0,
|
||||
string? blockedBy = null)
|
||||
string? blockedBy = null,
|
||||
PlanningPhase phase = PlanningPhase.None)
|
||||
{
|
||||
var id = Guid.NewGuid().ToString();
|
||||
await using var ctx = _factory.CreateDbContext();
|
||||
@@ -50,6 +51,7 @@ public sealed class TaskStateServiceTests : IDisposable
|
||||
ListId = _listId,
|
||||
Title = "task",
|
||||
Status = status,
|
||||
PlanningPhase = phase,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ParentTaskId = parentId,
|
||||
SortOrder = sortOrder,
|
||||
@@ -256,15 +258,15 @@ public sealed class TaskStateServiceTests : IDisposable
|
||||
// ─── StartPlanningAsync ───────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task StartPlanningAsync_FromManual_FlipsStatus_AndPlanningPhase()
|
||||
public async Task StartPlanningAsync_FromIdle_SetsPlanningPhase()
|
||||
{
|
||||
var id = await SeedTaskAsync(TaskStatus.Manual);
|
||||
var id = await SeedTaskAsync(TaskStatus.Idle);
|
||||
|
||||
var result = await _sut.StartPlanningAsync(id, default);
|
||||
|
||||
Assert.True(result.Ok);
|
||||
var t = await GetTaskAsync(id);
|
||||
Assert.Equal(TaskStatus.Planning, t.Status);
|
||||
Assert.Equal(TaskStatus.Idle, t.Status);
|
||||
Assert.Equal(PlanningPhase.Active, t.PlanningPhase);
|
||||
}
|
||||
|
||||
@@ -283,7 +285,7 @@ public sealed class TaskStateServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task FinalizePlanningAsync_OnActivePhase_TransitionsToFinalized()
|
||||
{
|
||||
var id = await SeedTaskAsync(TaskStatus.Manual);
|
||||
var id = await SeedTaskAsync(TaskStatus.Idle);
|
||||
await _sut.StartPlanningAsync(id, default);
|
||||
|
||||
var result = await _sut.FinalizePlanningAsync(id, default);
|
||||
@@ -297,7 +299,7 @@ public sealed class TaskStateServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task FinalizePlanningAsync_OnNonePhase_Rejects()
|
||||
{
|
||||
var id = await SeedTaskAsync(TaskStatus.Manual);
|
||||
var id = await SeedTaskAsync(TaskStatus.Idle);
|
||||
|
||||
var result = await _sut.FinalizePlanningAsync(id, default);
|
||||
|
||||
@@ -335,18 +337,6 @@ public sealed class TaskStateServiceTests : IDisposable
|
||||
Assert.True(_built.WakeCount() > wakesBefore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UnblockAsync_OnWaitingTask_FlipsToQueued()
|
||||
{
|
||||
// Bridge to legacy chain layout: a Status=Waiting sibling becomes Queued on unblock.
|
||||
var task = await SeedTaskAsync(TaskStatus.Waiting);
|
||||
|
||||
var result = await _sut.UnblockAsync(task, default);
|
||||
|
||||
Assert.True(result.Ok);
|
||||
Assert.Equal(TaskStatus.Queued, await GetStatusAsync(task));
|
||||
}
|
||||
|
||||
// ─── RecoverStaleRunningAsync ─────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
@@ -371,7 +361,7 @@ public sealed class TaskStateServiceTests : IDisposable
|
||||
[Fact]
|
||||
public async Task CompleteAsync_OnChild_AdvancesNextBlockedSibling()
|
||||
{
|
||||
var parent = await SeedTaskAsync(TaskStatus.Planned);
|
||||
var parent = await SeedTaskAsync(TaskStatus.Idle, phase: PlanningPhase.Finalized);
|
||||
var c0 = await SeedTaskAsync(TaskStatus.Running, parentId: parent, sortOrder: 0);
|
||||
var c1 = await SeedTaskAsync(TaskStatus.Queued, parentId: parent, sortOrder: 1, blockedBy: c0);
|
||||
var c2 = await SeedTaskAsync(TaskStatus.Queued, parentId: parent, sortOrder: 2, blockedBy: c1);
|
||||
|
||||
Reference in New Issue
Block a user