/** * E2 process first-class object (docs/plans/2026-05-29-e2-process-object.md). * * A `process` is a "living process map": a named, ordered list of steps that * evolves over time. Unlike `incident` (open->resolved->closed, no supersede), * `process` REUSES the `decision` supersede path as its delta mechanism: a * process evolves by being superseded by a NEW VERSION that records what * changed (`change_summary`) and the full new state (`steps`), carrying a * server-derived `version` counter. The version chain (walk `superseded_by`) * is the changelog. Computed structural step-diffing is a deferred v2 read-side * feature; the row stores enough to reconstruct any delta * (predecessor.steps + successor.steps + change_summary). * * The `processes` table is the source of truth: a process stays `active` * regardless of memory decay. A memory row mirrors the process for recall but * is NOT canonical — memory_id is NULLABLE with ON DELETE SET NULL so * forget/consolidate/archive gracefully orphans the process row. * * Lifecycle: active -> superseded (a newer version replaces it; superseded_by * points to the successor) or active -> closed (retired with no successor; * only an active head closes). * * Tenant scoping: every helper requires tenantId. BEFORE INSERT/UPDATE triggers * enforce processes.tenant_id == the referenced memory's tenant_id, and a * superseded_by same-tenant trigger makes cross-tenant supersession * unrepresentable. Mirrors the v30 decisions pattern (src/decisions.ts). * * Dual-write atomicity: `saveProcess` writes the memory + processes row (and, * when superseding, the predecessor's UPDATE) inside writeEntry's SAVEPOINT * 'write_entry' via the afterWrite hook, so a failure in any step rolls all of * them back. Pattern matches saveDecision (decisions.ts). */ export type ProcessStatus = 'active' | 'superseded' | 'closed'; export declare const VALID_PROCESS_STATES: ReadonlySet; /** Arbitrary JSON-shaped value; the domain type for untrusted input at the * steps I/O boundary (validateProcessSteps parses this into string[]). */ type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue; }; /** DoS / abuse caps on the steps body (untrusted at the HTTP/SDK boundary). */ export declare const MAX_PROCESS_STEPS = 200; export declare const MAX_PROCESS_STEP_LEN = 2000; export interface Process { id: number; /** Nullable: ON DELETE SET NULL lets memory deletion (forget / consolidate / * archive) proceed without breaking the process row. */ memoryId: string | null; tenantId: string; processName: string; description: string | null; /** Ordered step list (the process body). Stored as a JSON array of strings. */ steps: string[]; /** Server-derived: 1 on a fresh create, predecessor.version + 1 on supersede. */ version: number; status: ProcessStatus; /** Successor process id; set only when status === 'superseded'. */ supersededBy: number | null; supersededAt: string | null; /** The per-version delta note; set on a successor row only (NULL on a v1). */ changeSummary: string | null; closedAt: string | null; createdAt: string; } export interface SaveProcessOpts { processName: string; steps: string[]; description?: string; /** The delta note for a supersession; ignored (stored NULL) on a fresh create. */ changeSummary?: string; /** Table id of an ACTIVE process this new version supersedes. */ supersedesProcessId?: number; /** Extra memory tags merged after ['process']. */ extraTags?: string[]; } export interface ListProcessesOpts { status?: ProcessStatus; limit?: number; } /** * Validate + normalise the steps body. Returns the trimmed step strings * (trim-then-store, so ' x ' is stored as 'x'). Throws on a non-array, a * non-string / empty element, or a cap breach. Mirrors the incident DoS-cap * discipline. */ export declare function validateProcessSteps(steps: JsonValue): string[]; /** * Create a process (or a new version that supersedes an existing one). Writes * the memory mirror + the processes row atomically inside writeEntry's SAVEPOINT * 'write_entry'. When supersedesProcessId is given, the referenced ACTIVE row is * preflighted (status + version) BEFORE the INSERT, then UPDATEd -> superseded in * the SAME SAVEPOINT (CAS: WHERE status='active' AND id != ; throws on * changes===0 so a duplicate supersede aborts the whole write). The new row's * version = predecessor.version + 1 (server-derived); change_summary carries the * delta note. A fresh create has version 1 and change_summary NULL. */ export declare function saveProcess(hippoRoot: string, tenantId: string, opts: SaveProcessOpts, actor?: string): Process; /** * Close (retire) an active process with no successor. Updates the processes row * only; the memory mirror is not mutated. CAS guard: WHERE status='active'; 0 * changes distinguishes not-found from not-active. A superseded row is already * terminal in the chain and cannot be closed. */ export declare function closeProcess(hippoRoot: string, tenantId: string, id: number, actor?: string): Process; export declare function loadProcessById(hippoRoot: string, tenantId: string, id: number): Process | null; export declare function loadProcesses(hippoRoot: string, tenantId: string, opts?: ListProcessesOpts): Process[]; export declare function loadActiveProcesses(hippoRoot: string, tenantId: string, opts?: { limit?: number; }): Process[]; export {}; //# sourceMappingURL=processes.d.ts.map