import type { ManagedSessionRow, SessionLifecycle } from "../../db/repositories/managed-sessions.repository"; /** * Boot reconciliation (C1 Phase 3a). * See docs/architecture/2026-07-24-durable-session-runtime.md. * * On startup the registry holds rows from previous runs. Some of those * processes are gone; some are still alive (the crash and dev-takeover paths * exit without reaching ptyManager.dispose(), so agents genuinely outlive the * streamer today — they are simply invisible when they do). This module decides * which is which. * * Two rules make it safe: * * 1. **A stored status is never trusted over a live probe.** A SIGKILLed * streamer never ran its exit writes, so a row can claim `running` * indefinitely. Only the pid probe decides liveness. * * 2. **Liveness is never treated as identity.** Pids are recycled. A live pid * whose command line does not carry the recorded token is reported * `orphaned` and never signalled — that is the difference between a * durability feature and one that kills an unrelated user process. */ /** * Reason attached to a row whose pid was never probed because it was recorded * under a previous machine boot. Exported so the caller can recognise the * abstention and log it, without matching on a free-text string that could * drift away from the one produced here. */ export declare const PRE_BOOT_REASON = "recorded before this machine boot"; /** Result for a single registry row. Pure data — nothing here acts. */ export interface ReconcileVerdict { sessionId: string; lifecycle: SessionLifecycle; /** Why this verdict was reached, for logs and the diagnostics surface. */ reason: string; } export interface ReconcileProbe { /** Whether a process currently exists at this pid. */ isPidAlive: (pid: number) => boolean; /** Full command line for a live pid, or "" when it cannot be read. */ getProcessArgs: (pid: number) => Promise; /** * Whether the provider's own history shows this session ended cleanly. * Distinguishes `completed` from `failed` for a process that is gone. */ endedCleanly?: (row: ManagedSessionRow) => boolean; } /** * Classify one registry row against live process state. * * Exported separately from reconcileSessions so the decision table can be * tested without a database. `currentBootToken` is passed in rather than read * here for the same reason — this stays a pure function of its arguments. * Omitted/null means the caller has no boot identity, which skips the pre-boot * check entirely; the server always supplies one. */ export declare function classifySession(row: ManagedSessionRow, probe: ReconcileProbe, currentInstanceId: string, currentBootToken?: string | null): Promise; /** * Classify every non-terminal row. Returns verdicts only — the caller decides * what to persist or broadcast. This function never signals a process. */ export declare function reconcileSessions(rows: ManagedSessionRow[], probe: ReconcileProbe, currentInstanceId: string, currentBootToken?: string | null): Promise; //# sourceMappingURL=reconcileSessions.d.ts.map