Stale chat wakes expire instead of resuming days later

Live incident: the founder DMed the CEO and got silence — the reply run
sat 13th in a FIFO queue behind chat wakes from four days ago, which the
reopened app was faithfully executing (necro-replies that woke yet more
agents). A wake run is a conversation reply; past one hour the moment is
gone. expireStaleChatWakes (chat-agent-wake-service) fails queued
chat_mention runs older than the TTL and closes their vehicle tasks;
the worker tick runs it before claiming, with one log line. Real work
(heartbeat/kickoff triggers) never expires. Red-green tested.
This commit is contained in:
ZacharyZhang-NY committed 2026-07-14 20:44:37 -04:00
1 parent c7eafb2836
commit 39aa292d09
3 files changed
+143

No files matched your search

+9
View File
@@ -1,6 +1,7 @@
import type { BrowserWindow } from "electron";
import type { DatabaseConnection } from "../database/connection";
import { IPC_CHANNELS } from "../../shared/ipc";
import { expireStaleChatWakes } from "../services/chat-agent-wake-service";
import { OrganizationService } from "../services/organization-service";
import { spawnGoalReviews } from "../services/goal-review-service";
import { TaskExecutionService } from "../services/task-execution-service";
@@ -77,6 +78,14 @@ export function startTaskQueueWorker(input: TaskQueueWorkerInput): () => void {
wasPaused = paused;
}
if (paused) return;
// Stale conversation wakes die before anything is claimed: replying to
// a thread hours later is noise, and a backlog of them would starve
// fresh messages (the founder's included) for the whole grind.
const expired = input.connection.transaction(() => expireStaleChatWakes(input.connection.db, new Date().toISOString()));
if (expired > 0) {
console.info(`[task-queue] expired ${expired} stale chat wake run(s); newer messages re-wake their agents.`);
notifyDataChanged();
}
// Goal checkpoints first, so a review task created this tick is
// eligible for the same tick's heartbeat enqueue below.
const reviews = input.connection.transaction(() => spawnGoalReviews(input.connection.db, organization));