Files
fusion/packages/engine/src/mission-feature-sync.ts
2026-04-13 17:14:06 -07:00

79 lines
2.0 KiB
TypeScript

import type { MissionFeature, Task, TaskStore } from "@fusion/core";
import { getTaskCompletionBlockerForStore } from "./task-completion.js";
export type MissionFeatureSyncTargetStatus = "done" | "in-progress" | "triaged";
export type MissionFeatureSyncDecision =
| { kind: "failure"; reason: string }
| { kind: "blocked"; reason: string }
| { kind: "update"; status: MissionFeatureSyncTargetStatus; reason: string }
| { kind: "noop" };
export async function reconcileMissionFeatureState(
taskStore: Pick<TaskStore, "getTask">,
task: Task,
feature: Pick<MissionFeature, "id" | "status">,
): Promise<MissionFeatureSyncDecision> {
if (task.status === "failed" && feature.status === "in-progress") {
return {
kind: "failure",
reason: `task ${task.id} failed while feature ${feature.id} is in-progress`,
};
}
if (task.column === "done") {
const blocker = await getTaskCompletionBlockerForStore(taskStore, task);
if (blocker) {
return { kind: "blocked", reason: blocker };
}
if (feature.status !== "done") {
return {
kind: "update",
status: "done",
reason: `task ${task.id} completed`,
};
}
return { kind: "noop" };
}
if (task.column === "archived") {
if (feature.status !== "done") {
return {
kind: "update",
status: "done",
reason: `task ${task.id} was archived after completion`,
};
}
return { kind: "noop" };
}
if (
(task.column === "in-progress" || task.column === "in-review")
&& (feature.status === "triaged" || feature.status === "defined")
) {
return {
kind: "update",
status: "in-progress",
reason: task.column === "in-review"
? `task ${task.id} is in review`
: `task ${task.id} started`,
};
}
if (
(task.column === "triage" || task.column === "todo")
&& feature.status === "in-progress"
) {
return {
kind: "update",
status: "triaged",
reason: `task ${task.id} returned to triage`,
};
}
return { kind: "noop" };
}