import type { Kysely } from 'kysely';
import type { Database } from '../db/types.js';
import type { ScalerEvent } from './types.js';
/**
 * Snapshot of a spawning-agent record. Mirrors the row shape in
 * `scaler_spawning_agents`.
 */
export interface SpawningAgentSnapshot {
    agentId: string;
    scalerName: string;
    labelSet: string[];
    runId?: string;
    jobId?: string;
    boundJobId?: string;
    spawnedAt: Date;
}
/**
 * Snapshot of an agent-job correlation. Mirrors the row shape in
 * `scaler_agent_jobs`.
 */
export interface AgentJobCorrelationSnapshot {
    agentId: string;
    runId: string;
    jobId: string;
}
/**
 * Snapshot of a resource reservation. Mirrors the row shape in
 * `scaler_reservations`.
 */
export interface ReservationSnapshot {
    agentId: string;
    scalerName: string;
    cpus: number;
    memBytes: number;
}
/**
 * DB persistence for `ScalerManager` HA-critical state.
 *
 * Backed by three tables — `scaler_spawning_agents`, `scaler_agent_jobs`,
 * `scaler_reservations` — so a Raft leader switch / coord crash no
 * longer:
 *
 *  - orphans an agent that is mid-spawn (lost `boundJobId` → eager
 *    dispatch silently downgraded to a generic queue drain),
 *  - strands a reservation (resource counted as used until the agent's
 *    backend GC eventually disconnects, minutes later),
 *  - drops the agent → run/job correlation (execution-tracker loses
 *    scaler-lifecycle events emitted by the new coord).
 *
 * The consumer keeps the in-memory Maps as L1 caches. On boot /
 * become-leader the caches are hydrated via `recoverState()`.
 *
 * `perScalerUsage` / `globalUsage` are NOT stored — they are derived
 * state recomputed from `SUM(...) FROM scaler_reservations` on
 * recovery, which means the on-disk reservation rows are the single
 * source of truth for the cap-check critical section.
 *
 * The `eventBuffer` Map is also not persisted: events emitted before
 * correlation are observability, not correctness. A coord crash before
 * `correlateAgentToJob()` runs accepts losing those events (see the
 * wishlist for the rationale).
 */
export declare class ScalerStateStore {
    private readonly db;
    constructor(db: Kysely<Database>);
    upsertSpawningAgent(snapshot: SpawningAgentSnapshot): Promise<void>;
    deleteSpawningAgent(agentId: string): Promise<void>;
    listSpawningAgents(): Promise<SpawningAgentSnapshot[]>;
    /**
     * Delete every spawning-agent row whose `spawned_at` is older than the
     * given cutoff. Used by the leader-gated GC sweep so a coord that
     * crashed mid-spawn doesn't leave the row blocking the spawn-timeout
     * detection forever. Returns the row count GC'd.
     */
    sweepStaleSpawningAgents(olderThan: Date): Promise<number>;
    upsertAgentJob(snapshot: AgentJobCorrelationSnapshot): Promise<void>;
    deleteAgentJob(agentId: string): Promise<void>;
    listAgentJobs(): Promise<AgentJobCorrelationSnapshot[]>;
    upsertReservation(snapshot: ReservationSnapshot): Promise<void>;
    deleteReservation(agentId: string): Promise<void>;
    listReservations(): Promise<ReservationSnapshot[]>;
}
/**
 * Aggregate event surface for "the scaler manager fully replayed its
 * state from the DB after a leader switch". Kept here (vs in
 * manager.ts) so `ScalerManager.recoverState()` can declare a clean
 * return type. `bufferedEventsLost` always returns 0 today — the
 * `eventBuffer` Map is intentionally not persisted — but the field
 * exists so a future buffer-table addition is type-compatible.
 */
export interface ScalerStateRecovery {
    spawningAgentsRehydrated: number;
    agentJobsRehydrated: number;
    reservationsRehydrated: number;
    bufferedEventsLost: number;
}
/**
 * Re-export for the buffered-events note above; sole reason
 * `ScalerEvent` is imported is to keep that comment compile-checked.
 */
export type { ScalerEvent };
//# sourceMappingURL=scaler-state-store.d.ts.map