/** * src/models/availability-cache.ts — shared model eligibility cache. * * Mirrors the ZOB harness probe cache (successCache / inFlight dedupe keyed by * [repoRoot, model, providerExtension]) but WITHOUT any process spawn and with * a fully injectable probe function. The core never launches a probe — it only * consults cached results and invokes the injected probe function lazily, * keeping the critical path free of probes. * * Design (per port manifest B.5): * - long success TTL (default 5 min) instead of the harness 60 s; * - short failure TTL with backoff to avoid a probe storm; * - in-flight dedupe: concurrent checks for the same key share one probe; * - injectable clock `now()` for deterministic tests. * * Pure module: zero @earendil-works/* imports, zero child_process. */ export interface ProbeResult { ok: boolean; reason?: string; } /** Injectable availability probe. Never spawns a process on its own here. */ export type AvailabilityProbe = (model: string) => Promise; export interface AvailabilityCacheInput { repoRoot: string; model: string; providerExtension?: string; } export interface AvailabilityCacheOptions { /** Success TTL in ms (default 300_000 = 5 min). */ successTtlMs?: number; /** Failure TTL in ms (default 30_000 = 30 s). */ failureTtlMs?: number; /** Inject a clock for deterministic tests. */ now?: () => number; } export declare class AvailabilityCache { private readonly successCache; private readonly failureCache; private readonly inFlight; private readonly probe; private readonly successTtlMs; private readonly failureTtlMs; private readonly now; private readonly failureBackoffMs; constructor(probe: AvailabilityProbe, options?: AvailabilityCacheOptions); /** * Synchronous cache-only lookup. NEVER invokes the probe — safe on the * critical path. Returns a positive result only if a success entry is still * fresh; returns a negative result only if a failure entry is still fresh. */ peek(input: AvailabilityCacheInput): ProbeResult | undefined; /** * Resolve availability, probing lazily off the critical path. Shares a single * in-flight probe across concurrent callers for the same key. Honors the * cache: fresh success/failure entries short-circuit without probing. */ check(input: AvailabilityCacheInput): Promise; /** Force-cache a positive result without probing (e.g. lane boot proof). */ markAvailable(input: AvailabilityCacheInput): void; clear(): void; /** Number of live cache entries (success + failure), excluding in-flight. */ get size(): number; }