/**
 * AnomalyAutoSuspend -- wires AnomalyDetector events to the agent state machine.
 *
 * When an anomaly exceeds the configured severity threshold, this module
 * automatically calls the same suspend action that a human operator would
 * invoke via the dashboard (POST /api/v1/agents/:agentId/pause).
 *
 * Default thresholds:
 *   - Behavioral baseline deviation > 3 sigma -> suspend
 *   - Sudden permission escalation attempt     -> suspend immediately
 *   - Communication with known-bad endpoints   -> suspend
 *   - Unusual tool call burst (10x baseline within 60s) -> suspend
 *
 * Integration:
 *   The module subscribes to an AnomalyEventBus and calls the AgentStateMachine
 *   suspend() method on threshold breach. The state machine accepts the same
 *   payload as the dashboard hook, so human override via resume() is unchanged.
 *
 * Audit chain:
 *   Every auto-suspension produces a signed audit event (written to the
 *   provided WebhookDelivery or stderr if no delivery is configured).
 *
 * Onyx #8 gap closure: Anomaly Auto-Suspend Wiring.
 *
 * @connexum/ai-governance
 */
import type { Anomaly, AnomalyEventBus } from './anomaly-detector';
/**
 * Minimal agent state machine interface.
 * Matches the in-memory state map in packages/governance-server/src/index.ts:2185.
 */
export interface AgentStateMachine {
    /**
     * Suspend the agent. Sets status to 'paused' with the given reason.
     * This must be idempotent: suspending an already-suspended agent is a no-op.
     */
    suspend(agentId: string, reason: string): void;
    /**
     * Resume the agent. Sets status back to 'running'.
     */
    resume(agentId: string): void;
    /**
     * Get the current status of an agent.
     */
    getStatus(agentId: string): 'running' | 'paused' | 'stopped' | 'auto-suspended-pending-review';
    /**
     * Whether a new execute() call is permitted for this agent.
     */
    canExecute(agentId: string): boolean;
}
/**
 * Minimal SIEM delivery interface matching webhook-delivery.ts EventPayload.
 */
export interface SiemDelivery {
    deliver(event: {
        type: string;
        source: string;
        data: Record<string, unknown>;
        timestamp: string;
    }): Promise<unknown>;
}
export interface AutoSuspendThresholds {
    /**
     * Baseline deviation sigma multiplier triggering suspension.
     * Default: 3 (3 sigma above baseline = suspend).
     */
    baselineDeviationSigma?: number;
    /**
     * Whether permission escalation attempts immediately suspend (regardless of sigma).
     * Default: true.
     */
    suspendOnPermissionEscalation?: boolean;
    /**
     * Deny-listed endpoint patterns. If an anomaly toolName matches any of these
     * (case-insensitive substring), the agent is immediately suspended.
     * Default: [] (empty -- customer fills for their environment).
     */
    badEndpointPatterns?: string[];
    /**
     * Tool call burst multiplier triggering suspension.
     * If tool calls per 60s exceed baseline * burstMultiplier, suspend.
     * Default: 10.
     */
    toolCallBurstMultiplier?: number;
    /**
     * Burst detection window in milliseconds. Default: 60_000 (60s).
     */
    burstWindowMs?: number;
}
export interface AnomalyAutoSuspendConfig {
    /** The anomaly event bus to subscribe to. */
    eventBus: AnomalyEventBus;
    /** The agent state machine to call when suspension is triggered. */
    stateMachine: AgentStateMachine;
    /** Optional SIEM delivery for external alerting. */
    siemDelivery?: SiemDelivery;
    /** Threshold configuration. */
    thresholds?: AutoSuspendThresholds;
    /**
     * Minimum anomaly severity from AnomalyDetector to act on.
     * 'DEVIATION' is the only type from the built-in detector; future types possible.
     * By default all detected anomalies with any type trigger the check.
     */
    anomalyTypes?: string[];
}
export interface AutoSuspendEvent {
    eventId: string;
    agentId: string;
    triggeredBy: Anomaly;
    threshold: string;
    suspendedAt: string;
    contentHash: string;
}
export declare class AnomalyAutoSuspend {
    private readonly stateMachine;
    private readonly siemDelivery?;
    private readonly thresholds;
    private readonly anomalyTypes;
    /** Track recent tool call counts per agent for burst detection. */
    private burstCounters;
    /** Audit log of all auto-suspension events (capped at 1000). */
    private suspensionLog;
    constructor(config: AnomalyAutoSuspendConfig);
    /**
     * Subscribe the auto-suspend logic to an already-constructed event bus.
     *
     * Two wiring paths are registered (defense-in-depth):
     *
     * Path 1 -- interceptEmit (existing):
     *   Patches `bus.emit` so that any local emit() call on this pod triggers
     *   handleAnomaly synchronously. Works for both EventBus and RedisEventBus.
     *   Does NOT fire for cross-pod events that arrive via Redis subscriber
     *   (handleIncoming -> dispatch) because those bypass emit().
     *
     * Path 2 -- explicit on('anomaly:detected') (NEW):
     *   Registers a handler via the bus's `on()` method when the bus supports it.
     *   This fires for BOTH local dispatches AND cross-pod Redis events, because
     *   both code paths ultimately call dispatch() which invokes registered handlers.
     *
     * Double-fire protection:
     *   A local emit on this pod triggers both paths (interceptEmit first, then
     *   dispatch calls the on() handler). handleAnomaly() is idempotent: if the
     *   agent is already suspended after the first path fires, the second path's
     *   call returns early at the status check. No duplicate suspension, audit
     *   entry, or webhook fire results.
     *
     * Cross-pod behaviour (Option a -- chosen):
     *   Pod B receives an anomaly for an agent that doesn't run on Pod B. Pod B's
     *   on() handler fires, handleAnomaly() looks up the agent in Pod B's state
     *   machine, finds status='running' (default), evaluates thresholds, and
     *   suspends in Pod B's local state machine. If the agent does not exist on
     *   Pod B (getStatus returns 'running' which is the default), the suspension
     *   is a no-op at the state machine level and is logged at debug level only.
     *   This keeps the architecture compatible with a future federated state machine
     *   without further refactor.
     */
    subscribeToEventBus(eventBus: AnomalyEventBus): void;
    /**
     * Evaluate an anomaly and suspend the agent if any threshold is crossed.
     */
    handleAnomaly(anomaly: Anomaly): void;
    /**
     * Execute the suspension: update state machine, emit audit event, notify SIEM.
     */
    private suspend;
    /**
     * Get the suspension audit log.
     */
    getSuspensionLog(): AutoSuspendEvent[];
    /**
     * Update thresholds at runtime (without restarting the subscription).
     */
    updateThresholds(thresholds: Partial<AutoSuspendThresholds>): void;
    /**
     * Get current effective thresholds.
     */
    getThresholds(): Required<AutoSuspendThresholds>;
}
/**
 * Concrete AgentStateMachine backed by an in-memory Map.
 * Matches the shape of agentControlState in packages/governance-server/src/index.ts.
 *
 * Production: inject the real agentControlState Map via the adapter below.
 * Testing: use this standalone implementation.
 */
export declare class InMemoryAgentStateMachine implements AgentStateMachine {
    private readonly state;
    suspend(agentId: string, reason: string): void;
    resume(agentId: string): void;
    getStatus(agentId: string): 'running' | 'paused' | 'stopped' | 'auto-suspended-pending-review';
    canExecute(agentId: string): boolean;
    /** Expose the underlying map for governance server integration. */
    getStateMap(): Map<string, {
        status: string;
        updatedAt: string;
        reason?: string;
    }>;
}
/**
 * Adapt the governance server's existing agentControlState Map to the
 * AgentStateMachine interface without modifying the Map's existing shape.
 *
 * Usage (in packages/governance-server/src/index.ts):
 *
 *   const autoSuspendMachine = new GovernanceServerStateMachineAdapter(agentControlState);
 *   const autoSuspend = new AnomalyAutoSuspend({
 *     eventBus: anomalyEventBus,
 *     stateMachine: autoSuspendMachine,
 *     siemDelivery: webhookDelivery,
 *   });
 */
export declare class GovernanceServerStateMachineAdapter implements AgentStateMachine {
    private readonly agentControlState;
    private readonly onSuspend?;
    private readonly onResume?;
    constructor(agentControlState: Map<string, {
        status: 'running' | 'paused' | 'stopped';
        updatedAt: string;
        reason?: string;
    }>, onSuspend?: ((agentId: string, reason: string) => void) | undefined, onResume?: ((agentId: string) => void) | undefined);
    suspend(agentId: string, reason: string): void;
    resume(agentId: string): void;
    getStatus(agentId: string): 'running' | 'paused' | 'stopped' | 'auto-suspended-pending-review';
    canExecute(agentId: string): boolean;
}
//# sourceMappingURL=anomaly-auto-suspend.d.ts.map