/** * Brain graph back-fill — populates brain_page_nodes and brain_page_edges from * existing typed table rows (decisions, patterns, learnings, observations, * sticky notes). * * Each row in a typed table gets a corresponding node in brain_page_nodes. * Relationship edges are derived from: * - decision.contextTaskId / contextEpicId → applies_to edges * - observation.sourceSessionId → produced_by edge * - observation text referencing task IDs → applies_to edges * - pattern entries → derived_from stubs * * Stub nodes (task:, session:, epic:) are created for referenced * external entities so edges have valid targets. * * Duplicate nodes are silently skipped (INSERT OR IGNORE semantics via * Drizzle onConflictDoNothing). * * T1003: Staged backfill functions (stagedBackfillRun, approveBackfillRun, * rollbackBackfillRun, listBackfillRuns) are appended below the graph * back-fill core. Staged runs capture exact source/version and incident-edge * preconditions in brain_backfill_runs; approval reconstructs only those missing * nodes, without synthesizing edges or invoking the broad graph back-fill. * * @task T530 * @epic T523 */ import type { KnowledgeBackfillOptions } from '@cleocode/contracts'; import type { BrainBackfillRunRow } from '../store/schema/memory-schema.js'; /** Result returned by backfillBrainGraph. */ export interface BrainBackfillResult { /** Counts before the back-fill ran. */ before: { nodes: number; edges: number; decisions: number; patterns: number; learnings: number; observations: number; stickyNotes: number; }; /** Counts after the back-fill ran. */ after: { nodes: number; edges: number; }; /** Number of nodes inserted during this run. */ nodesInserted: number; /** Number of edges inserted during this run. */ edgesInserted: number; /** Number of stub nodes created for external references (tasks, sessions, epics). */ stubsCreated: number; /** Node counts broken down by type. */ byType: Record; } /** * Back-fill brain_page_nodes and brain_page_edges from all existing typed rows * in brain.db. * * Safe to run multiple times — duplicate nodes and edges are silently ignored * via INSERT OR IGNORE semantics. * * @param projectRoot - Absolute path to the project root (contains .cleo/). * @returns BackfillResult with before/after counts and insertion stats. */ export declare function backfillBrainGraph(projectRoot: string): Promise; /** * Result of a staged backfill run creation. * * A staged run does NOT commit any rows to live tables. The caller must call * `approveBackfillRun` to commit or `rollbackBackfillRun` to discard. * * @task T1003 */ export interface StagedBackfillRunResult { /** The new run record. */ run: BrainBackfillRunRow; /** * True when no rows matched the source (run was staged with rowsAffected=0). * Callers may still approve or rollback a zero-row run. */ empty: boolean; } /** * Stage a graph backfill run against brain_page_nodes / brain_page_edges. * * Discovers all candidate node IDs from typed tables (decisions, patterns, * learnings, observations, sticky notes) that are NOT yet in brain_page_nodes. * Captures exact nodes, source hashes, incident-edge fingerprints and project binding in * `rollback_snapshot_json`, and creates a `brain_backfill_runs` * row with status='staged'. The ledger is written, but derived graph rows are unchanged. * * Pass `source` as a human-readable descriptor (e.g. a file path or session ID). * Pass `kind` as the backfill kind (e.g. 'graph-backfill', 'observation-promotion'). * * @param projectRoot - Absolute path to the project root. * @param opts - Optional overrides for source, kind, and target table. * @returns StagedBackfillRunResult with the staged run record. * * @task T1003 * @remarks The snapshot captures exact source and relationship preconditions without mutating derived nodes. * @example * ```ts * const staged = await stagedBackfillRun(projectRoot, undefined); * ``` */ export declare function stagedBackfillRun(projectRoot: string, opts?: KnowledgeBackfillOptions): Promise; /** * Approve a staged backfill run, committing its rows to live brain tables. * * Reads the staged run under a writer transaction, validates its exact source * and graph preconditions, then inserts only its reviewed derived nodes. The * same transaction records created-row hashes and approval metadata for recovery. * Historical edges remain unchanged. * * Double-approve is idempotent: returns `{ alreadySettled: true }` if the run * is already approved or rolled-back. * * @param projectRoot - Absolute path to the project root. * @param runId - The brain_backfill_runs.id to approve. * @param approvedBy - Optional identity of the approver (defaults to 'owner'). * @returns Result with the updated run record and graph backfill stats. * * @task T1003 * @remarks Approval inserts only the reviewed nodes and records recovery hashes atomically; stale source or graph state is rejected. * @example * ```ts * const applied = await approveBackfillRun(projectRoot, runId, 'calling-agent'); * ``` */ export declare function approveBackfillRun(projectRoot: string, runId: string, approvedBy?: string): Promise<{ run: BrainBackfillRunRow; alreadySettled: boolean; backfillResult?: BrainBackfillResult; }>; /** * Rollback a staged backfill run, discarding staged rows. * * If the run is still 'staged', marks it as 'rolled-back' (no rows were ever * committed, so no DELETE is required). * * If the run is 'approved', reads `rollback_snapshot_json` and DELETEs the * committed rows from the target table, then marks the run as 'rolled-back'. * * Idempotent: rolling back an already-rolled-back run returns * `{ alreadySettled: true }` without error. * * @param projectRoot - Absolute path to the project root. * @param runId - The brain_backfill_runs.id to roll back. * @returns Result with the updated run record and optional delete count. * * @task T1003 * @remarks Recovery removes only unchanged nodes created by this run and refuses concurrent node or edge edits. * @example * ```ts * const restored = await rollbackBackfillRun(projectRoot, runId); * ``` */ export declare function rollbackBackfillRun(projectRoot: string, runId: string): Promise<{ run: BrainBackfillRunRow; alreadySettled: boolean; deletedRows: number; }>; /** * List backfill runs, optionally filtered by status. * * @param projectRoot - Absolute path to the project root. * @param opts - Optional status filter and limit. * @returns Array of run records, ordered by created_at DESC. * * @task T1003 */ export declare function listBackfillRuns(projectRoot: string, opts?: { status?: string; limit?: number; }): Promise; //# sourceMappingURL=brain-backfill.d.ts.map