fix(FN-2384): schedule triage and todo tasks by priority-aware FIFO

- Sort eligible todo tasks in Scheduler by priority first, then createdAt/id for stable FIFO ordering within each tier
- Sort eligible triage tasks using the same priority-aware ordering while preserving existing pause/status/recovery gating
- Add regression tests for scheduler and triage ordering, including blocked/paused/recovery-gated edge cases
- Update architecture docs to describe priority-first task dispatch behavior
This commit is contained in:
Fusion
2026-04-24 04:08:17 -07:00
committed by gsxdsm
parent 6453fc771e
commit d74295f7dc
5 changed files with 219 additions and 6 deletions

View File

@@ -6,7 +6,11 @@ import type {
TaskAttachment,
Settings,
} from "@fusion/core";
import { buildTriageMemoryInstructions, resolveAgentPrompt } from "@fusion/core";
import {
buildTriageMemoryInstructions,
resolveAgentPrompt,
sortTasksByPriorityThenAgeAndId,
} from "@fusion/core";
import type { ImageContent } from "@mariozechner/pi-ai";
import { Type, type Static } from "@mariozechner/pi-ai";
import type {
@@ -577,7 +581,7 @@ export class TriageProcessor {
// Fetch all tasks (not just triage) to count active agents across columns.
const allTasks = await this.store.listTasks({ slim: true, includeArchived: false });
const now = Date.now();
const triageTasks = allTasks.filter(
const eligibleTriageTasks = allTasks.filter(
(t) => t.column === "triage" && !this.processing.has(t.id) && !t.paused
// Skip tasks awaiting manual plan approval — they should not be auto-discovered
&& t.status !== "awaiting-approval"
@@ -587,6 +591,7 @@ export class TriageProcessor {
// Skip tasks with a recovery backoff that hasn't elapsed yet
&& !(t.nextRecoveryAt && new Date(t.nextRecoveryAt).getTime() > now),
);
const triageTasks = sortTasksByPriorityThenAgeAndId(eligibleTriageTasks);
// Respect both per-project maxTriageConcurrent and the global semaphore.
// Only specifying tasks count against the triage limit; execution is governed by maxConcurrent.