import { and, eq, sql } from "drizzle-orm"; import { heartbeatRuns, issueRecoveryActions, type Db } from "@paperclipai/db"; import { canonicalExecutionUuid } from "./execution-identity.js"; import { noRetainedExecutionPredicate } from "./pre-dispatch-execution-evidence.js"; import { LEGACY_WORKSPACE_RECOVERY_SCHEMA } from "./workspace-restore-recovery-state.js"; /** Admission denied by an existing hold is not a provider attempt. Require the * dispatcher's receipt and absence of execution authority, resources and events. */ function preDispatchExecutionWaitPredicate() { return sql`coalesce( ${heartbeatRuns.runtimeMode} = 'legacy' AND ${heartbeatRuns.status} = 'cancelled' AND ${heartbeatRuns.finishedAt} IS NOT NULL AND ${heartbeatRuns.errorCode} = 'execution_reconciliation_required' AND ${heartbeatRuns.resultJson}->>'stopReason' = 'execution_reconciliation_required' AND ${heartbeatRuns.resultJson}->>'timeoutSource' = 'stale_queued_run_gate' AND ${canonicalExecutionUuid(sql`${heartbeatRuns.resultJson}->'executionWait'->>'issueId'`)} = ${canonicalExecutionUuid(sql`${heartbeatRuns.contextSnapshot}->>'issueId'`)} AND (${heartbeatRuns.issueId} IS NULL OR ${heartbeatRuns.issueId} = ${canonicalExecutionUuid(sql`${heartbeatRuns.contextSnapshot}->>'issueId'`)}) AND ${canonicalExecutionUuid(sql`${heartbeatRuns.resultJson}->'executionWait'->>'recoveryActionId'`)} IS NOT NULL AND ${noRetainedExecutionPredicate()}, false)`; } export async function isPreDispatchExecutionWaitVerified(db: Db, run: typeof heartbeatRuns.$inferSelect): Promise { if (run.errorCode !== "execution_reconciliation_required" || run.runtimeMode !== "legacy") return false; const [verified] = await db.select({ id: heartbeatRuns.id }).from(heartbeatRuns).where(and( eq(heartbeatRuns.companyId, run.companyId), eq(heartbeatRuns.id, run.id), preDispatchExecutionWaitPredicate(), )).limit(1); return Boolean(verified); } /** Re-evaluate old false incidents with the same proof; retain their audit rows * and leave the original execution/workspace hold to its own recovery policy. */ export function preDispatchExecutionWaitRecoveryActionPredicate() { return sql`(${issueRecoveryActions.cause} = 'legacy_execution_requires_reconciliation' AND coalesce(${issueRecoveryActions.evidence}->>'workspaceRestoreFailure', '') <> 'restore_unsafe_archive' AND coalesce(${issueRecoveryActions.evidence}->'workspaceRestoreRecovery'->>'schema', '') <> ${LEGACY_WORKSPACE_RECOVERY_SCHEMA} AND EXISTS (SELECT 1 FROM ${heartbeatRuns} WHERE ${heartbeatRuns.companyId} = ${issueRecoveryActions.companyId} AND ${heartbeatRuns.id} = ${canonicalExecutionUuid(sql`coalesce(${issueRecoveryActions.evidence}->>'runId', ${issueRecoveryActions.evidence}->>'sourceRunId')`)} AND ${issueRecoveryActions.sourceIssueId} = ${canonicalExecutionUuid(sql`${heartbeatRuns.contextSnapshot}->>'issueId'`)} AND ${preDispatchExecutionWaitPredicate()}))`; }