feat(FN-4990): complete Step 3 — guard out-of-order done updates
Fusion-Task-Id: FN-4990 Fusion-Task-Lineage: 167a6011-d246-45bd-ad7a-1f2fe8b99323
This commit is contained in:
committed by
gsxdsm
parent
7bcffa5a58
commit
dca221829d
57
packages/core/src/__tests__/store-update-step-order.test.ts
Normal file
57
packages/core/src/__tests__/store-update-step-order.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { beforeAll, beforeEach, afterEach, afterAll, describe, expect, it } from "vitest";
|
||||
import { createSharedTaskStoreTestHarness } from "./store-test-helpers.js";
|
||||
|
||||
describe("TaskStore.updateStep step-order guard", () => {
|
||||
const harness = createSharedTaskStoreTestHarness();
|
||||
|
||||
beforeAll(harness.beforeAll);
|
||||
beforeEach(harness.beforeEach);
|
||||
afterEach(harness.afterEach);
|
||||
afterAll(harness.afterAll);
|
||||
|
||||
it("no-ops out-of-order done updates when an earlier step is pending", async () => {
|
||||
const store = harness.store();
|
||||
const task = await harness.createTaskWithSteps();
|
||||
|
||||
await store.updateStep(task.id, 0, "done");
|
||||
const updated = await store.updateStep(task.id, 2, "done");
|
||||
|
||||
expect(updated.steps[2].status).toBe("pending");
|
||||
expect(updated.log.some((entry) => entry.action.includes("Ignored out-of-order done for step 2"))).toBe(true);
|
||||
});
|
||||
|
||||
it("allows done when prior steps are skipped", async () => {
|
||||
const store = harness.store();
|
||||
const task = await harness.createTaskWithSteps();
|
||||
|
||||
await store.updateStep(task.id, 0, "done");
|
||||
await store.updateStep(task.id, 1, "skipped");
|
||||
const updated = await store.updateStep(task.id, 2, "done");
|
||||
|
||||
expect(updated.steps[2].status).toBe("done");
|
||||
expect(updated.currentStep).toBe(3);
|
||||
});
|
||||
|
||||
it("allows done when prior steps are done and advances currentStep", async () => {
|
||||
const store = harness.store();
|
||||
const task = await harness.createTaskWithSteps();
|
||||
|
||||
await store.updateStep(task.id, 0, "done");
|
||||
await store.updateStep(task.id, 1, "done");
|
||||
const updated = await store.updateStep(task.id, 2, "done");
|
||||
|
||||
expect(updated.steps[2].status).toBe("done");
|
||||
expect(updated.currentStep).toBe(3);
|
||||
});
|
||||
|
||||
it("keeps done→in-progress regression guard behavior", async () => {
|
||||
const store = harness.store();
|
||||
const task = await harness.createTaskWithSteps();
|
||||
|
||||
await store.updateStep(task.id, 0, "done");
|
||||
const updated = await store.updateStep(task.id, 0, "in-progress");
|
||||
|
||||
expect(updated.steps[0].status).toBe("done");
|
||||
expect(updated.log.some((entry) => entry.action.includes("Ignored done→in-progress regression"))).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -5190,14 +5190,34 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
return task;
|
||||
}
|
||||
|
||||
if (status === "done") {
|
||||
for (let i = 0; i < stepIndex; i++) {
|
||||
const priorStatus = task.steps[i].status;
|
||||
if (priorStatus === "pending" || priorStatus === "in-progress") {
|
||||
const ts = new Date().toISOString();
|
||||
task.updatedAt = ts;
|
||||
task.log.push({
|
||||
timestamp: ts,
|
||||
action:
|
||||
`Ignored out-of-order ${status} for step ${stepIndex} (${task.steps[stepIndex].name}) — ` +
|
||||
`earlier step ${i} (${task.steps[i].name}) is still ${priorStatus}`,
|
||||
});
|
||||
await this.atomicWriteTaskJson(dir, task);
|
||||
if (this.isWatching) this.taskCache.set(id, { ...task });
|
||||
this.emit("task:updated", task);
|
||||
return task;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task.steps[stepIndex].status = status;
|
||||
task.updatedAt = new Date().toISOString();
|
||||
|
||||
// Advance currentStep to first non-done step
|
||||
// Advance currentStep to first non-done/non-skipped step
|
||||
if (status === "done") {
|
||||
while (
|
||||
task.currentStep < task.steps.length &&
|
||||
task.steps[task.currentStep].status === "done"
|
||||
(task.steps[task.currentStep].status === "done" || task.steps[task.currentStep].status === "skipped")
|
||||
) {
|
||||
task.currentStep++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user