/** * Observe-mode validation — the accuracy gate for the agent behavioral governance layer. * * Deterministic, read-only analysis over panic telemetry (`panic.jsonl`). It produces the * evidence a maintainer needs to decide whether the panic SIGNAL is accurate enough to act on, * BEFORE any interventional posture (default advisory injection, experimental_blocking, * auto-installed hooks) is turned on by default. * * The `verdict` is a MECHANICAL read of the criteria, never an activation: it is CLEARED only when * every gate criterion is met, REVIEW_REQUIRED when there is enough data but a criterion is unmet, * and INSUFFICIENT_DATA below the episode floor. CLEARED does NOT turn anything on — activating an * interventional posture is still a human decision (`setup --panic …`, which consults this verdict * and requires an explicit acknowledgement to proceed when it is not CLEARED). * * No LLM, no heuristics beyond counting — the north-star determinism constraint holds. */ /** A panic.jsonl record (subset of fields this analysis reads). */ export interface PanicTelemetryEvent { ts: string; event: string; from_level?: number; to_level?: number; delta?: number; outcome?: string; /** panic_score_delta carries per-trigger provenance under `triggers`. */ triggers?: Array<{ name: string; delta: number; }>; /** panic_level_change carries it under `provenance`. */ provenance?: Array<{ name: string; delta: number; }>; } /** Gate thresholds — single source of truth, referenced by tests and the report. */ export declare const PANIC_GATE: { /** Minimum completed episodes before the gate is even evaluable. */ readonly MIN_EPISODES: 20; /** False-positive proxy at/below this is acceptable (lower is better). */ readonly FP_PROXY_TARGET: 0.2; /** Intervention follow-through at/above this is acceptable (higher is better). */ readonly FOLLOW_THROUGH_TARGET: 0.5; /** A single trigger firing in at/above this share of false positives is "noisy". */ readonly NOISY_TRIGGER_FP_SHARE: 0.5; }; export type PanicGateVerdict = 'INSUFFICIENT_DATA' | 'REVIEW_REQUIRED' | 'CLEARED'; export interface PanicGateReport { /** CLEARED only when every criterion is met — a mechanical read, never an activation. */ verdict: PanicGateVerdict; min_episodes: number; episodes: { total: number; completed: number; open: number; }; peak_level_histogram: Record<'L1' | 'L2' | 'L3' | 'L4', number>; false_positive: { /** * UPPER BOUND, not a true false-positive rate: the share of completed episodes that resolved * WITHOUT the agent re-orienting (resolved-by-decay). Some of those were genuine panics the * agent worked through without an explicit orient() — so this over-counts false positives by * construction. Presented as a proxy everywhere it surfaces; never labeled a true FP rate. */ proxy_rate: number | null; resolved_via_orient: number; resolved_via_decay: number; /** false-positive episodes that peaked at L3+ (the worst kind). */ high_level_count: number; /** per-trigger: how often it appears in false-positive episodes vs all episodes. */ by_trigger: Array<{ trigger: string; fp_episodes: number; all_episodes: number; fp_share: number; }>; }; intervention: { hook_intercepts: number; responses: number; follow_through_rate: number | null; avg_response_lag_ms: number | null; }; resolution: { completed_rate: number | null; /** episodes that re-opened within 60s of a prior episode ending (thrash). */ recurrence_count: number; avg_recovery_ms: number | null; }; /** Which gate criteria are met right now (verdict stays REVIEW_REQUIRED regardless). */ criteria: { data_sufficient: boolean; fp_ok: boolean | null; follow_through_ok: boolean | null; }; /** Human-readable, actionable reasons — what blocks the gate and why. */ recommendations: string[]; } /** * Compute the panic-signal accuracy gate from panic.jsonl events. */ export declare function validatePanicSignal(events: PanicTelemetryEvent[]): PanicGateReport; /** * Read all panic telemetry for a project, spanning the live file AND its rotated archives. * * Telemetry rotates the live `panic.jsonl` into numbered archives (`panic.1.jsonl` … up to * `panic..jsonl`) once it exceeds the size threshold. Reading only the live file * silently discards episodes on a long-running observation loop, so the gate's MIN_EPISODES floor * could stay unreachable forever. This reads the oldest archive first through the live file last, so * events arrive roughly in order (validatePanicSignal re-sorts by ts regardless). Malformed lines * are skipped; a missing file contributes nothing. Never throws. */ export declare function readPanicTelemetry(directory: string): PanicTelemetryEvent[]; //# sourceMappingURL=panic-validation.d.ts.map