feat(FN-938): add feature triage, mission pause/stop/resume, and scheduler blocked check

- Add mission store methods for pausing, stopping, and resuming missions with proper state transitions
- Implement feature triage flow that evaluates and classifies mission features
- Add scheduler blocked-task check to prevent scheduling when dependencies are unmet
- Create dashboard mission management UI with pause/stop/resume controls
- Add mission API routes for triage, pause, stop, and resume operations
- Add e2e tests for mission routes and unit tests for mission store and scheduler
This commit is contained in:
gsxdsm
2026-04-04 18:03:03 -07:00
parent a67bd31f3c
commit 950c78c797
10 changed files with 1080 additions and 20 deletions

View File

@@ -450,12 +450,39 @@ export class Scheduler {
if (available <= 0) return;
const now = Date.now();
const todo = tasks.filter((t) => {
let todo = tasks.filter((t) => {
if (t.column !== "todo" || t.paused) return false;
// Skip tasks with a recovery backoff that hasn't elapsed yet
if (t.nextRecoveryAt && new Date(t.nextRecoveryAt).getTime() > now) return false;
return true;
});
// Filter out tasks belonging to blocked missions
if (todo.length > 0 && this.options.missionStore) {
const blockedSliceIds = new Set<string>();
for (const t of todo) {
if (t.sliceId && !blockedSliceIds.has(t.sliceId)) {
try {
const slice = this.options.missionStore.getSlice(t.sliceId);
if (slice) {
const milestone = this.options.missionStore.getMilestone(slice.milestoneId);
if (milestone) {
const mission = this.options.missionStore.getMission(milestone.missionId);
if (mission && mission.status === "blocked") {
blockedSliceIds.add(t.sliceId);
}
}
}
} catch {
// If lookup fails, don't block the task
}
}
}
if (blockedSliceIds.size > 0) {
todo = todo.filter((t) => !t.sliceId || !blockedSliceIds.has(t.sliceId));
}
}
if (todo.length === 0) return;
/**