/** * Policy-gate health — the grace window that stops fail-closed machines from * blocking end users on a single network blip. * * The problem this solves: hooks are short-lived processes that call the * policy service per action. One slow/timed-out call used to translate * DIRECTLY into a blocked command on Block-mode machines, punishing the user * for transient Wi-Fi/DNS/backend jitter (~1% of calls in the field). * * The rule: fail-closed only engages when the outage is PERSISTENT — * - >= FAIL_CLOSED_AFTER_FAILURES consecutive gate failures, OR * - the first failure of the current streak is older than FAIL_CLOSED_AFTER_MS. * Until then, failures degrade to allow (spooled + reported as distress, so * the fleet console and org-admin email alerts still see everything). * Local Safety deterministic rules are NOT affected — they always run first * from cache and keep blocking dangerous commands even fully offline. * * State survives across hook invocations in a small JSON file. All I/O is * best-effort: health tracking must never break enforcement itself. */ export declare const FAIL_CLOSED_AFTER_FAILURES = 3; export declare const FAIL_CLOSED_AFTER_MS: number; export interface GateHealth { consecutiveFailures: number; firstFailureAt?: string; lastFailureAt?: string; } /** Current streak WITHOUT recording a new failure — for skip paths (probe * window) that must not refresh lastFailureAt, or the gate would never be * re-probed and the machine would stay in the degraded stance forever. */ export declare function currentGateHealth(): GateHealth; /** A successful gate round-trip ends the failure streak. */ export declare function recordGateSuccess(): void; /** Record one failed gate round-trip and return the updated streak. */ export declare function recordGateFailure(now?: Date): GateHealth; /** * True when the gate failed very recently. Monitor/shadow surfaces use this to * skip the synchronous policy call entirely during an outage (reporting rides * the async spool instead), so a dead/hanging backend costs a monitor machine * ZERO added latency after the first bounded miss. The 60s window guarantees * an automatic retry, which resets the streak via recordGateSuccess(). */ export declare function gateRecentlyDown(now?: Date): boolean; /** Fail closed only for persistent outages, never for a single blip. */ export declare function shouldFailClosed(health: GateHealth, now?: Date): boolean;