/**
 * PeerVisibilityGuard — P2.2 rider (WORKING-SET-HANDOFF-SPEC §3.6): improper
 * revocations and silently-missing peers must surface LOUDLY.
 *
 * Earned 2026-06-06: the Mini was revoked with NO `revokedBy`/`revokeReason`
 * (a write that bypassed `revokeMachine()`), making it invisible to the mesh
 * for ~10 hours while it held a topic's entire overnight working set.
 *
 * Two detections, both HYGIENE SIGNALS (they detect sloppy state, not
 * malicious action — populated fields are NOT authenticated and must never
 * be read as "this revocation is legitimate"):
 *
 * 1. `detectImproperRevocations(registry)` — a PURE helper (deliberately NOT
 *    inside `loadRegistry()`, a hot dependency-free read called 41+ times
 *    per boot): an entry with `revokedAt` set but `revokedBy`/`revokeReason`
 *    missing. The consumer surfaces findings via the agent-health attention
 *    lane, deduped ACROSS boots keyed on the entry's `revokedAt` (a
 *    crash-loop cannot re-spam it).
 *
 * 2. Peer-disappearance notice — pool transitions from N≥2 online to fewer
 *    and stays past a 30-min grace → ONE agent-health notice naming the
 *    machine + last known reason, and — when pending-pulls reference it —
 *    the stranded topic working sets. Coalesced per machine per episode;
 *    FLAP-BOUNDED: 3 episodes for one machine in 24h collapses to a single
 *    "machine X is flapping" notice (Bounded Notification Surface). Clears
 *    silently on stable re-peer.
 */
import type { MachineRegistry } from './types.js';
export declare const DEFAULT_DISAPPEARANCE_GRACE_MS: number;
export declare const FLAP_EPISODE_LIMIT = 3;
export declare const FLAP_WINDOW_MS: number;
export interface ImproperRevocation {
    machineId: string;
    nickname?: string;
    revokedAt: string;
    missing: ('revokedBy' | 'revokeReason')[];
}
/**
 * PURE: entries revoked without authorship/reason — the §3.6 hygiene signal.
 * Never inside loadRegistry(); the consumer (boot/refresh path) calls this.
 */
export declare function detectImproperRevocations(registry: MachineRegistry): ImproperRevocation[];
export interface GuardNotice {
    kind: 'improper-revocation' | 'peer-missing' | 'peer-flapping';
    machineId: string;
    title: string;
    body: string;
}
export interface PeerVisibilityGuardConfig {
    /** Absolute path to the agent's `.instar/` directory (durable dedupe state). */
    stateDir: string;
    selfMachineId: string;
    /** Surface one notice (agent-health attention lane upstream). Never throws back. */
    notify: (notice: GuardNotice) => void;
    /** Topics with pending-pulls naming a machine (the stranded working sets). */
    strandedTopicsFor?: (machineId: string) => Promise<number[]>;
    graceMs?: number;
    now?: () => Date;
    logger?: (msg: string) => void;
}
export declare class PeerVisibilityGuard {
    private readonly d;
    private readonly stateFile;
    private state;
    /** In-memory per-episode tracking (a notice fires once per episode). */
    private missing;
    constructor(config: PeerVisibilityGuardConfig);
    /**
     * §3.6.1 — call on boot + registry refresh with the loaded registry.
     * Surfaces each improper revocation ONCE across boots (keyed on revokedAt).
     */
    checkRevocations(registry: MachineRegistry): ImproperRevocation[];
    /**
     * §3.6.2 — call on a presence cadence with the CURRENT online view.
     * `expected` = machines that should be online (active, not revoked, not
     * self); `online` = machines recorded this pass.
     */
    checkDisappearances(expected: string[], online: Set<string>): Promise<void>;
    private loadState;
    private persist;
    private safeNotify;
}
//# sourceMappingURL=PeerVisibilityGuard.d.ts.map