/** * E2 incident first-class object (docs/plans/2026-05-29-e2-incident-object.md). * * An incident is a postmortem capsule: a recorded operational event with a * lifecycle and optional linked receipts (the memories that are its evidence). * The `incidents` table is the source of truth: an incident stays `open` * regardless of memory decay. A memory row still mirrors the incident for * recall surfaces but is NOT canonical — memory_id is NULLABLE with ON DELETE * SET NULL so forget/consolidate/archive gracefully orphans the incident row. * * Lifecycle: open -> resolved (a resolution was recorded; the incident stays on * record with resolution_text + resolved_at) or open|resolved -> closed * (retired with closed_at). This is NOT decision's supersede: there is no * superseded_by self-FK, no supersede CAS, and no supersede trigger. * * Tenant scoping: every helper requires tenantId. BEFORE INSERT/UPDATE triggers * enforce incidents.tenant_id == the referenced memory's tenant_id. Mirrors the * v30 decisions pattern (src/decisions.ts). * * Dual-write atomicity: `saveIncident` writes the memory + incidents row inside * writeEntry's SAVEPOINT 'write_entry' (store.ts) via the afterWrite hook, so a * failure in any step rolls all of them back. Pattern matches saveDecision. * * linked_memory_ids ("linked receipts"): a JSON-encoded array of memory ids on * the row, default `[]`. On save, every id must exist in the SAME tenant; a * cross-tenant or nonexistent id is rejected (throw) before the insert. */ export type IncidentStatus = 'open' | 'resolved' | 'closed'; export declare const VALID_INCIDENT_STATES: ReadonlySet; export interface Incident { id: number; /** Nullable: ON DELETE SET NULL lets memory deletion (forget / consolidate / * archive) proceed without breaking the incident row. */ memoryId: string | null; tenantId: string; incidentText: string; context: string | null; status: IncidentStatus; /** Set only when status === 'resolved'. */ resolutionText: string | null; resolvedAt: string | null; closedAt: string | null; /** Linked receipts: memory ids that are this incident's evidence. */ linkedMemoryIds: string[]; createdAt: string; } export interface SaveIncidentOpts { incidentText: string; context?: string; /** Memory ids (linked receipts) that are this incident's evidence. Each must * exist in the same tenant; cross-tenant/nonexistent ids are rejected. */ linkedMemoryIds?: string[]; /** Extra memory tags merged after ['incident'] (the CLI passes path-context * tags; HTTP/SDK pass none). */ extraTags?: string[]; } export interface ListIncidentsOpts { status?: IncidentStatus; limit?: number; } /** * Create an incident. Writes the memory mirror + the incidents row atomically * inside writeEntry's SAVEPOINT 'write_entry'. * * The memory mirror: tags ['incident', ...extraTags], source 'incident', * confidence 'verified', half_life INCIDENT_HALF_LIFE_DAYS, content = * "\n\nContext: " when context is given. * * linked_memory_ids are validated BEFORE insert: each must exist in the SAME * tenant. A cross-tenant or nonexistent id throws and rolls back the whole * write. The validated ids are stored as JSON.stringify(validated). */ export declare function saveIncident(hippoRoot: string, tenantId: string, opts: SaveIncidentOpts, actor?: string): Incident; /** * Resolve an open incident (open -> resolved). Records resolution_text + * resolved_at; the incident stays on record. CAS guard: WHERE status='open'; * 0 changes distinguishes not-found from not-open so callers surface the right * error. Emits incident_resolve. */ export declare function resolveIncident(hippoRoot: string, tenantId: string, id: number, resolutionText: string, actor?: string): Incident; /** * Close (retire) an incident from open or resolved (open|resolved -> closed). * Updates closed_at only; the memory mirror is not mutated. CAS guard: WHERE * status IN ('open','resolved'); 0 changes distinguishes not-found from * wrong-state. Emits incident_close. */ export declare function closeIncident(hippoRoot: string, tenantId: string, id: number, actor?: string): Incident; export declare function loadIncidentById(hippoRoot: string, tenantId: string, id: number): Incident | null; export declare function loadIncidents(hippoRoot: string, tenantId: string, opts?: ListIncidentsOpts): Incident[]; export declare function loadOpenIncidents(hippoRoot: string, tenantId: string, opts?: { limit?: number; }): Incident[]; /** * Resolve a memory id to the table id of the OPEN incident backed by that * memory, or null when the memory has no open incident row. Extracted so a * memory-id-based lookup is unit-testable at the store layer (mirror of * resolveActiveDecisionIdByMemory). */ export declare function resolveActiveIncidentIdByMemory(hippoRoot: string, tenantId: string, memoryId: string): number | null; //# sourceMappingURL=incidents.d.ts.map