import type { Loop, LoopRun } from "../types.js"; export declare const MAX_RETRY_DELAY_MS: number; export declare const DEFAULT_CIRCUIT_BREAKER_THRESHOLD = 5; export declare const CIRCUIT_BREAKER_REASON_PREFIX = "circuit breaker open"; export declare const EXPIRY_REASON_PREFIX = "expired after consecutive successful runs"; /** Hard cap on rows examined while paging a streak window past skipped rows. */ export declare const MAX_BREAKER_WINDOW_SCAN = 1000; export type CircuitBreakerThreshold = number | ((loop: Loop) => number | undefined); export type LoopAdvancementPatch = Partial>; export type LoopAdvancementPlan = { kind: "none"; reason: "running" | "missing" | "inactive" | "archived" | "stale" | "already_applied"; } | { kind: "update"; reason: "retry" | "deferred_retry" | "recurrence"; patch: LoopAdvancementPatch; } | { kind: "circuit_breaker"; failures: number; reason: string; markerScheduledFor: string; patch: LoopAdvancementPatch; } | { kind: "expires_after_runs"; successes: number; reason: string; markerScheduledFor: string; patch: LoopAdvancementPatch; }; export declare function loopAdvancementPatchMatchesCurrent(current: Loop, patch: LoopAdvancementPatch): boolean; /** * Exponential retry backoff with jitter: * delay = retryDelayMs * 2^(attempt-1) * (0.5 + random), capped at 6h. * Provider-gated failures back off 4x harder. */ export declare function retryBackoffDelayMs(loop: Loop, run: LoopRun, random?: () => number): number; /** * Collect a streak window that pages past ordinary overlap-skip bookkeeping * rows. A hung overlap:"skip" loop mints one skipped row per due slot, so a * raw newest-N read can fill its window with neutral rows and push every real * outcome beyond the streak's reach. This pages the store read (created_at * DESC) until the window holds `windowLimit` meaningful rows or `maxScan` * rows have been examined. Circuit-breaker and expiry marker rows are kept: * the streak counters read them as watermarks, so a manual resume keeps * starting a fresh streak. Accepts both the synchronous local store read and * the hosted storage contract's async read. */ export declare function collectBreakerWindowRuns(listRuns: (opts: { limit: number; offset: number; }) => readonly LoopRun[], windowLimit: number, maxScan?: number): LoopRun[]; export declare function collectBreakerWindowRuns(listRuns: (opts: { limit: number; offset: number; }) => Promise, windowLimit: number, maxScan?: number): Promise; export declare function resolveBreakerThreshold(loop: Loop, override?: CircuitBreakerThreshold): number; /** * Count consecutive final failures from newest-first run history. * * Retryable failures and the known transient Bun/signal-exit loader mismatch * are neutral, a success resets the streak, and the newest circuit-breaker * marker is a watermark so a manual resume starts a fresh streak. */ export declare function consecutiveFailureCountFromRuns(runs: readonly LoopRun[], maxAttempts?: number): number; /** * Count consecutive successful runs from newest-first run history. * * Mirrors {@link consecutiveFailureCountFromRuns} with inverted polarity: * a final failure (or timeout/abandonment) resets the streak, a success * advances it, and retryable failures (attempt < maxAttempts) plus the * known transient Bun/signal-exit loader mismatch are neutral. Skipped runs * are neutral (they carry no outcome signal). The newest expiry marker is a * watermark so a manual resume starts a fresh streak. * * "Success" is run status `succeeded` (provider exited 0 with output). * Findings are not representable in the run record today, so a no-findings * check loop that exits 0 counts as successful — a deliberate, documented * approximation (a clean check loop expires after N runs). */ export declare function consecutiveSuccessCountFromRuns(runs: readonly LoopRun[], maxAttempts?: number): number; /** * Pure scheduling policy shared by the local scheduler and hosted API. * Callers gather current loop state, deferred retry state, and recent history, * then apply the returned storage mutations using their native sync/async API. */ export declare function planLoopAdvancement(input: { current: Loop | undefined; run: LoopRun; finishedAt: Date; succeeded: boolean; deferredRetry?: LoopRun; retryIntentRun?: LoopRun; recentRuns?: readonly LoopRun[]; retryRandom?: number; circuitBreakerThreshold?: CircuitBreakerThreshold; }): LoopAdvancementPlan;