/** * Audit-finding classifier โ€” the deterministic half of the PM audit. * * ยง3.1: the LLM gathers facts; THIS code classifies. The agent never authors a * category, so a category-vs-evidence mislabel is structurally impossible. These * are the "When to Persist" thresholds as code, not prose the LLM applies. * * Pure functions, no I/O, no LLM โ€” domain logic (what *is* a ghost closure?), * which is why it lives in @ido4/core. Exposed to agents via the * `persist_audit_findings` MCP tool so the agent has no write path at all. */ export type FindingCategory = 'ghost_closure' | 'rubber_stamp' | 'shallow_pr' | 'silent_closure' | 'spec_orphan' | 'bypass_pattern' | 'suitability_drift' | 'actor_fragmentation'; export type FindingSeverity = 'error' | 'warning' | 'info'; export interface ClosureObservation { kind: 'closure'; issue?: number; actor_id?: string; terminal?: boolean; pr_found?: boolean; pr_number?: number; approving_reviews?: number; pr_body_len?: number; pr_ref_count?: number; comment_count?: number; lineage_ref?: string | null; ai_suitability?: string; ai_did_work_then_marked_human_only?: boolean; note?: string; scope?: string; epic?: string; } export interface BypassObservation { kind: 'bypass'; actor_id?: string; attempts?: number; executed?: number; note?: string; scope?: string; } export interface EpicObservation { kind: 'epic'; epic?: string; distinct_ai_actors?: number; note?: string; actor_id?: string; scope?: string; } export type Observation = ClosureObservation | BypassObservation | EpicObservation; export interface Classification { category: FindingCategory; severity: FindingSeverity; } /** Classify ONE observation โ†’ applicable findings (empty = clean; silence is the default). */ export declare function classifyObservation(obs: Observation): Classification[]; /** * Authoritative per-actor bypass observations derived from the deterministic * gate record (state.bypass_attempts written by the PreToolUse G1 rule), NOT * from agent-submitted counts. The audit classifies THESE, so an agent that * under-gathers cannot suppress a bypass_pattern finding. * * synthetic-005 OBS-01/OBS-02: the agent reported attempts:2 for agent-alpha * while the gate record held 3 (a plan_task bypass it didn't reconcile), * silently dropping a threshold-crossing finding. Deriving from the record * removes the agent's count from the trust path entirely. */ export interface GateBypassEntry { actor_id?: string; [k: string]: unknown; } export declare function bypassObservationsFromRecord(record: GateBypassEntry[] | undefined): BypassObservation[]; /** spec_orphan is rate-based (a single off-spec closure is normal). One finding or null. */ export declare function classifySpecOrphanRate(observations: Observation[], opts?: { minClosures?: number; threshold?: number; }): { category: 'spec_orphan'; severity: 'info'; rate: number; } | null; export declare const VALID_FINDING_CATEGORIES: FindingCategory[]; //# sourceMappingURL=finding-classifier.d.ts.map