feat(07-02): wire sweepStaleReviews into heartbeat timer
- Import sweepStaleReviews, resolveApprovalDecision, dispatchAgentMessage - Insert stale review sweep into per-company heartbeat loop after budget reset - Sweep runs on every 15-second heartbeat cycle for each active company - Local callback stubs for handleTaskStatusChange and handleApprovalResolved - Error handling prevents sweep failures from crashing the heartbeat loop - Fix test type casts to use as-unknown-as for vi.fn mock compatibility - TypeScript compiles cleanly, 249/249 tests pass Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
0bfbdec09b
commit
c4eb4423db
2 files changed
+38
-7
No files matched your search
@@ -4,6 +4,9 @@ import { getConnectorExecutionReadinessIssue } from "@shared/connector-policy";
|
||||
import type { DesktopResult } from "@shared/contracts";
|
||||
import type { ConnectorRecord } from "@shared/types";
|
||||
import type { NotificationOptions } from "./notification-service";
|
||||
import { sweepStaleReviews } from "./task-quality-gates";
|
||||
import { resolveApprovalDecision } from "./approval-policy";
|
||||
import { dispatchAgentMessage } from "./message-dispatch";
|
||||
|
||||
type WorkspaceLockMode = "exclusive" | "shared" | "none";
|
||||
|
||||
@@ -678,6 +681,34 @@ export function createOrchestrationService({
|
||||
db.setLastBudgetResetMonth(company.id, currentMonth);
|
||||
logger.info(`[heartbeat] Reset monthly budgets for company ${company.name} (${currentMonth})`);
|
||||
}
|
||||
|
||||
// TASK-04: Stale review escalation sweep
|
||||
try {
|
||||
const escalated = sweepStaleReviews(company.id, {
|
||||
db: db as unknown as import("./task-quality-gates").SweepStaleReviewsDeps["db"],
|
||||
dispatchAgentMessage: dispatchAgentMessage as unknown as import("./task-quality-gates").SweepStaleReviewsDeps["dispatchAgentMessage"],
|
||||
resolveApprovalDecision: resolveApprovalDecision as unknown as import("./task-quality-gates").SweepStaleReviewsDeps["resolveApprovalDecision"],
|
||||
notify: notify as unknown as import("./task-quality-gates").SweepStaleReviewsDeps["notify"],
|
||||
handleTaskStatusChange: (_taskId: string, _companyId: string, _prev: string, _next: string) => {
|
||||
publishDomainChanged();
|
||||
},
|
||||
handleApprovalResolved: (_approvalId: string, _companyId: string, _decision: string) => {
|
||||
publishDomainChanged();
|
||||
},
|
||||
emitEvent: (..._args: unknown[]) => {},
|
||||
publishDomainChanged,
|
||||
wakeAgentIfPossible: (agentId: string, cId: string, trigger: string) => {
|
||||
wakeAgentIfPossible(agentId, cId, trigger);
|
||||
},
|
||||
logger,
|
||||
});
|
||||
if (escalated > 0) {
|
||||
logger.info(`[heartbeat] Auto-escalated ${escalated} stale review(s) for company ${company.name}`);
|
||||
publishDomainChanged();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`[heartbeat] Stale review sweep failed: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`[heartbeat] Error processing company ${company.id}: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user