feat(FN-996): add in-review to todo retry transition with UI and state cleanup

- Add valid board transitions from todo to in-review and in-review to todo (retry)
- Clear transient fields (agentId, worktree, branch, prInfo, mergeRetries, etc.) on in-review→todo transition
- Add Retry button to TaskDetailModal for in-review tasks
- Add tests for retry transition and transient field cleanup in store
This commit is contained in:
gsxdsm
2026-04-05 18:29:44 -07:00
parent a747474d74
commit 54e46387ec
5 changed files with 33 additions and 3 deletions

View File

@@ -79,7 +79,7 @@ describe("board", () => {
});
it("returns correct transitions for in-review", () => {
expect(getValidTransitions("in-review")).toEqual(["done", "in-progress"]);
expect(getValidTransitions("in-review")).toEqual(["done", "in-progress", "todo"]);
});
it("returns correct transitions for done", () => {

View File

@@ -2775,6 +2775,33 @@ Task with acceptance criteria
expect(reopened.blockedBy).toBeUndefined();
expect(reopened.workflowStepResults).toBeUndefined();
});
it("allows retrying in-review tasks back to todo and clears transient fields", async () => {
const task = await store.createTask({ description: "test retry in-review task to todo" });
await store.moveTask(task.id, "todo");
await store.moveTask(task.id, "in-progress");
await store.moveTask(task.id, "in-review");
await store.updateTask(task.id, {
status: "completed",
error: "stale error",
worktree: "stale-worktree",
blockedBy: "FN-456",
workflowStepResults: [{
workflowStepId: "wf-1",
workflowStepName: "Workflow step 1",
status: "passed",
startedAt: new Date().toISOString(),
}],
});
const retried = await store.moveTask(task.id, "todo");
expect(retried.column).toBe("todo");
expect(retried.status).toBeUndefined();
expect(retried.error).toBeUndefined();
expect(retried.worktree).toBeUndefined();
expect(retried.blockedBy).toBeUndefined();
expect(retried.workflowStepResults).toBeUndefined();
});
});
describe("columnMovedAt", () => {

View File

@@ -980,7 +980,7 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
// preserved here — the recovery-policy module manages those fields. They are
// only cleared on terminal transitions (in-review, done, archived).
if (
(fromColumn === "in-progress" || fromColumn === "done")
(fromColumn === "in-progress" || fromColumn === "done" || fromColumn === "in-review")
&& (toColumn === "todo" || toColumn === "triage")
) {
task.status = undefined;

View File

@@ -1119,7 +1119,7 @@ export const VALID_TRANSITIONS: Record<Column, Column[]> = {
triage: ["todo"],
todo: ["in-progress", "triage"],
"in-progress": ["in-review", "todo", "triage"],
"in-review": ["done", "in-progress"],
"in-review": ["done", "in-progress", "todo"],
done: ["todo", "triage", "archived"],
archived: ["done"],
};