feat(FN-832): add event-driven scheduling on task unpause and auto-resume in-progress tasks

- Auto-resume in-progress tasks that were paused and then unpaused, picking up from their last step
- Add event-driven scheduler trigger on task unpause so resumed tasks are immediately scheduled
- Update Store and TaskStore with unpause handling, type changes for resume tracking
- Refactor executor, merger, and scheduler tests for improved reliability
- Remove dead code: mission-interview, pr-comment-handler, taskStuck util, OpenRouter model sync changeset
- Update AGENTS.md documentation for pause/unpause behavior
This commit is contained in:
gsxdsm
2026-04-04 00:40:32 -07:00
parent e46d357a6a
commit e9dcca0a28
6 changed files with 345 additions and 1 deletions

View File

@@ -89,6 +89,8 @@ export class Scheduler {
private pollInterval: ReturnType<typeof setInterval> | null = null;
/** The interval (ms) of the currently active `setInterval` timer. */
private activePollMs: number | null = null;
/** Tracks which task IDs are currently paused, to detect unpause transitions. */
private pausedTaskIds = new Set<string>();
constructor(
private store: TaskStore,
@@ -179,8 +181,24 @@ export class Scheduler {
/**
* PR Monitoring: Start monitoring when PR is linked to an in-review task.
* Also detects task-level unpause transitions and triggers immediate scheduling.
*/
this.store.on("task:updated", (task) => {
// Track pause state transitions for event-driven scheduling on unpause.
// When a previously-paused task is unpaused in a schedulable column,
// trigger a scheduling pass immediately instead of waiting for the next
// poll interval (up to 15 seconds).
if (task.paused) {
this.pausedTaskIds.add(task.id);
} else if (this.pausedTaskIds.has(task.id)) {
// Task was paused, now unpaused — trigger scheduling
this.pausedTaskIds.delete(task.id);
if (this.running && (task.column === "todo" || task.column === "triage")) {
schedulerLog.log(`Task ${task.id} unpaused — triggering scheduling`);
this.schedule();
}
}
if (!this.options.prMonitor) return;
if (task.column !== "in-review") return;
if (!task.prInfo) return;