fix(FN-7224): clear workflow pins on retry
Fusion-Task-Id: FN-7224
This commit is contained in:
7
.changeset/fn-7224-retry-clears-workflow-pins.md
Normal file
7
.changeset/fn-7224-retry-clears-workflow-pins.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
summary: Make dashboard retry clear stale workflow step pins before re-execution.
|
||||||
|
category: fix
|
||||||
|
dev: Clears persisted workflow step instances on manual execution retry so parse-steps can repin the current plan.
|
||||||
@@ -216,6 +216,7 @@ function createMockStore(overrides: Partial<TaskStore> = {}): TaskStore {
|
|||||||
getWorkflowStep: vi.fn(),
|
getWorkflowStep: vi.fn(),
|
||||||
updateWorkflowStep: vi.fn(),
|
updateWorkflowStep: vi.fn(),
|
||||||
deleteWorkflowStep: vi.fn(),
|
deleteWorkflowStep: vi.fn(),
|
||||||
|
clearWorkflowRunStepInstances: vi.fn(),
|
||||||
getMissionStore: vi.fn().mockReturnValue({
|
getMissionStore: vi.fn().mockReturnValue({
|
||||||
listMissions: vi.fn().mockReturnValue([]),
|
listMissions: vi.fn().mockReturnValue([]),
|
||||||
createMission: vi.fn(),
|
createMission: vi.fn(),
|
||||||
@@ -808,6 +809,7 @@ describe("POST /tasks/:id/retry", () => {
|
|||||||
baseCommitSha: null,
|
baseCommitSha: null,
|
||||||
...buildManualRetryResetPatch({ resetMergeRetries: true }),
|
...buildManualRetryResetPatch({ resetMergeRetries: true }),
|
||||||
});
|
});
|
||||||
|
expect(store.clearWorkflowRunStepInstances).toHaveBeenCalledWith("KB-001");
|
||||||
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo");
|
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -896,6 +898,7 @@ describe("POST /tasks/:id/retry", () => {
|
|||||||
error: null,
|
error: null,
|
||||||
...buildManualRetryResetPatch(),
|
...buildManualRetryResetPatch(),
|
||||||
});
|
});
|
||||||
|
expect(store.clearWorkflowRunStepInstances).toHaveBeenCalledWith("KB-001");
|
||||||
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo", { preserveProgress: true });
|
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo", { preserveProgress: true });
|
||||||
expect(store.logEntry).toHaveBeenCalledWith(
|
expect(store.logEntry).toHaveBeenCalledWith(
|
||||||
"KB-001",
|
"KB-001",
|
||||||
@@ -927,6 +930,7 @@ describe("POST /tasks/:id/retry", () => {
|
|||||||
error: null,
|
error: null,
|
||||||
...buildManualRetryResetPatch(),
|
...buildManualRetryResetPatch(),
|
||||||
});
|
});
|
||||||
|
expect(store.clearWorkflowRunStepInstances).toHaveBeenCalledWith("KB-001");
|
||||||
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo", { preserveProgress: true });
|
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo", { preserveProgress: true });
|
||||||
expect(store.logEntry).toHaveBeenCalledWith(
|
expect(store.logEntry).toHaveBeenCalledWith(
|
||||||
"KB-001",
|
"KB-001",
|
||||||
@@ -963,6 +967,7 @@ describe("POST /tasks/:id/retry", () => {
|
|||||||
error: null,
|
error: null,
|
||||||
...buildManualRetryResetPatch(),
|
...buildManualRetryResetPatch(),
|
||||||
});
|
});
|
||||||
|
expect(store.clearWorkflowRunStepInstances).toHaveBeenCalledWith("KB-001");
|
||||||
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo", { preserveProgress: true });
|
expect(store.moveTask).toHaveBeenCalledWith("KB-001", "todo", { preserveProgress: true });
|
||||||
expect(store.logEntry).toHaveBeenCalledWith(
|
expect(store.logEntry).toHaveBeenCalledWith(
|
||||||
"KB-001",
|
"KB-001",
|
||||||
|
|||||||
@@ -1683,6 +1683,11 @@ export function registerTaskWorkflowRoutes(ctx: ApiRoutesContext, deps: TaskWork
|
|||||||
// and merge failures (all steps done).
|
// and merge failures (all steps done).
|
||||||
if (isInReviewRetry) {
|
if (isInReviewRetry) {
|
||||||
if (isExecutionFailureInReview) {
|
if (isExecutionFailureInReview) {
|
||||||
|
/*
|
||||||
|
FNXC:WorkflowRetry 2026-06-29-02:18:
|
||||||
|
Dashboard retry for an in-review execution failure re-enters the workflow graph from parse/execution, so it must clear persisted foreach step-instance pins. Otherwise a stale pin from the failed run makes the retry hit the same parse pin-mismatch immediately.
|
||||||
|
*/
|
||||||
|
clearRebuiltSpecWorkflowPins(scopedStore, req.params.id);
|
||||||
await scopedStore.updateTask(req.params.id, {
|
await scopedStore.updateTask(req.params.id, {
|
||||||
status: null,
|
status: null,
|
||||||
error: null,
|
error: null,
|
||||||
@@ -1734,6 +1739,12 @@ export function registerTaskWorkflowRoutes(ctx: ApiRoutesContext, deps: TaskWork
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
FNXC:WorkflowRetry 2026-06-29-02:18:
|
||||||
|
Non-planning manual retry is also a fresh execution boundary. Clear graph step-instance rows before moving back to todo so parse-steps can repin the current PROMPT.md instead of inheriting failed foreach state.
|
||||||
|
*/
|
||||||
|
clearRebuiltSpecWorkflowPins(scopedStore, req.params.id);
|
||||||
|
|
||||||
// Reset steps if the branch has no unique commits (work was lost with worktree)
|
// Reset steps if the branch has no unique commits (work was lost with worktree)
|
||||||
const completedSteps = task.steps.filter(
|
const completedSteps = task.steps.filter(
|
||||||
(s: { status: string }) => s.status === "done" || s.status === "in-progress",
|
(s: { status: string }) => s.status === "done" || s.status === "in-progress",
|
||||||
|
|||||||
Reference in New Issue
Block a user