/** * Brain-page-nodes sentience layer — universal semantic graph SDK surface. * * This module is THE canonical sentience layer for brain_page_nodes: * * - `getRelated` — 1-hop neighbour traversal with edge-type filtering * - `getImpact` — upstream/downstream impact analysis (BFS with depth) * - `getContext` — 360-degree node context view (in-edges, out-edges, neighbours) * - `materializeXfkEdges` — promote cross-DB soft-FK references (XFKB-001..005) * to hard graph edges in brain_page_nodes / brain_page_edges * * Auto-population hooks (`ensureTaskNode`, `ensureMessageNode`, etc.) live in * `graph-auto-populate.ts` and are invoked by the CLEO write paths. This module * provides the read surface that Studio and the SDK expose externally. * * Design principles: * - All reads are BEST-EFFORT: failures return empty results, never throw. * - `materializeXfkEdges` runs as a best-effort migration; it is idempotent * and safe to call multiple times. * - Types imported from `@cleocode/contracts` where possible; local types * defined only for raw DB rows. * * @task T945 * @epic T1056 */ import type { BrainEdgeType, BrainNodeType } from '../store/schema/memory-schema.js'; import type { NodeContext, RelatedNode, TraceNode } from './graph-queries.js'; export type { NodeContext, RelatedNode, TraceNode }; /** * Node types that form the sentience layer. * Maps directly to `BRAIN_NODE_TYPES` entries that the graph surface exposes. * * Note: "conduit_message" in API responses corresponds to the internal `msg` * node type to keep the external interface self-documenting. */ export type SentienceNodeType = 'task' | 'decision' | 'observation' | 'symbol' | 'conduit_message' | 'llmtxt'; /** * Mapping from internal BRAIN_NODE_TYPES to the API-facing SentienceNodeType. * `msg` → `conduit_message` for clarity; all others pass through unchanged. */ export declare const INTERNAL_TO_SENTIENCE_TYPE: Partial>; /** * Canonical edge types for the sentience layer traversal surface. * * Source: BRAIN_EDGE_TYPES in memory-schema.ts (T945 Stage A). * These are the types that `cleo nexus query` must return without error. */ export declare const CANONICAL_SENTIENCE_EDGE_TYPES: readonly ["documents", "applies_to", "blocks", "derived_from", "touches_code", "discusses", "cites", "supersedes"]; export type CanonicalSentienceEdgeType = (typeof CANONICAL_SENTIENCE_EDGE_TYPES)[number]; /** * Parameters for {@link getRelated}. */ export interface GetRelatedParams { /** * Optional edge-type filter. When provided, only edges of this type are * followed. Accepts any `BrainEdgeType` from the canonical vocabulary. */ edgeType?: BrainEdgeType; /** * Maximum number of results to return. Defaults to 50. */ limit?: number; } /** * Return the immediate (1-hop) neighbours of a brain graph node. * * Follows edges in both directions (outgoing and incoming). Results are * sorted by edge weight descending, then quality score descending. When * `edgeType` is supplied only edges of that type are traversed. * * This is the primary SDK entry point for "what is related to X?" queries. * * @param projectRoot - Absolute path to the project root (locates brain.db). * @param nodeId - Node ID to query (format: `':'`). * @param params - Optional filter parameters. * @returns Array of neighbour nodes with edge metadata. * * @example * ```typescript * const neighbours = await getRelated('/project', 'task:T945', { edgeType: 'discusses' }); * for (const { node, edgeType, direction, weight } of neighbours) { * console.log(direction, edgeType, node.label, weight); * } * ``` * * @task T945 */ export declare function getRelated(projectRoot: string, nodeId: string, params?: GetRelatedParams): Promise; /** * Parameters for {@link getImpact}. */ export interface GetImpactParams { /** * Traversal direction. * - `'upstream'` — follow edges where this node is the **target** (what depends on it?) * - `'downstream'` — follow edges where this node is the **source** (what does it affect?) * - `'both'` — bidirectional BFS (default) */ direction?: 'upstream' | 'downstream' | 'both'; /** * Maximum BFS depth. Defaults to 3. */ maxDepth?: number; } /** * Return the transitive impact set for a brain graph node using BFS. * * The impact set is the set of all nodes reachable from `nodeId` within * `maxDepth` hops. Nodes are annotated with their discovery depth (0 = seed). * * This is the primary SDK entry point for "what does X affect?" queries — * the brain-layer equivalent of `gitnexus_impact` for code symbols. * * @param projectRoot - Absolute path to the project root (locates brain.db). * @param nodeId - Node ID to start from (format: `':'`). * @param params - Optional traversal parameters. * @returns Array of impacted nodes sorted by depth ascending, quality descending. * * @example * ```typescript * const impacted = await getImpact('/project', 'decision:D-abc123', { * direction: 'downstream', * maxDepth: 2, * }); * console.log(impacted.length, 'nodes impacted at depth ≤ 2'); * ``` * * @task T945 */ export declare function getImpact(projectRoot: string, nodeId: string, params?: GetImpactParams): Promise; /** * Return a 360-degree context view for a single brain graph node. * * Provides the node itself, all its incoming edges, all its outgoing edges, * and the full set of direct neighbour nodes with relationship metadata. * * This is the primary SDK entry point for "tell me everything about X" queries. * * @param projectRoot - Absolute path to the project root (locates brain.db). * @param nodeId - Node ID to inspect (format: `':'`). * @returns Full context record, or `null` if the node does not exist. * * @example * ```typescript * const ctx = await getContext('/project', 'task:T945'); * if (ctx) { * console.log(ctx.node.label, ctx.outEdges.length, 'outgoing edges'); * for (const n of ctx.neighbors) { * console.log(' →', n.edgeType, n.node.label); * } * } * ``` * * @task T945 */ export declare function getContext(projectRoot: string, nodeId: string): Promise; /** * Return the set of all edge type strings that appear in brain_page_edges. * * Used by `cleo nexus query` and the /api/v1/graph endpoint to verify * canonicalization. Returns the de-duplicated sorted list. * * @param projectRoot - Absolute path to the project root (locates brain.db). * @returns Array of edge type strings present in the graph. * * @task T945 */ export declare function listEdgeTypes(projectRoot: string): Promise; /** * Validate that all edge types present in brain_page_edges are members of * the canonical `BRAIN_EDGE_TYPES` array. * * Returns a list of unrecognized edge type strings (empty = fully canonical). * * @param projectRoot - Absolute path to the project root (locates brain.db). * @returns Array of non-canonical edge type strings found in the graph. * * @task T945 */ export declare function validateEdgeTypes(projectRoot: string): Promise; /** * Result summary from {@link materializeXfkEdges}. */ export interface MaterializeXfkResult { /** Number of new `part_of` edges created (task → epic). */ taskToEpic: number; /** Number of new `produced_by` edges created (observation → session). */ observationToSession: number; /** Number of new `applies_to` edges created (decision → task). */ decisionToTask: number; /** Number of new `applies_to` edges created (decision → epic). */ decisionToEpic: number; /** Number of new `informed_by` edges created (memory-link → task). */ memoryLinkToTask: number; /** Total new edges created across all XFK categories. */ total: number; } /** * Materialize cross-database soft-FK references as hard graph edges in brain.db. * * SQLite does not support FK constraints across database connections. Brain.db * stores "soft FKs" as text IDs referencing tasks.db rows. This function * promotes those soft-FK fields to explicit `brain_page_nodes` nodes and * `brain_page_edges` edges — making them first-class citizens of the graph * that can be traversed without cross-DB joins. * * ## XFKB mappings (T033 audit, ADR per cross-db-cleanup.ts) * * | XFKB | Source field | Target | Edge type | * |------|-------------|--------|-----------| * | XFKB-001 | brain_decisions.context_epic_id | task: | applies_to | * | XFKB-002 | brain_decisions.context_task_id | task: | applies_to | * | XFKB-003 | brain_memory_links.task_id | task: | informed_by | * | XFKB-004 | brain_observations.source_session_id | session: | produced_by | * | XFKB-005 | brain_page_nodes (task: prefix) existence | — | already a hard node | * * This function is idempotent: duplicate edges are silently skipped via * `INSERT OR IGNORE` on the composite PK (fromId, toId, edgeType). * * Task and session nodes are upserted in `brain_page_nodes` with * quality_score = 0.7 (provisional) if they do not already exist. * * @param projectRoot - Absolute path to the project root (locates brain.db). * @returns Summary counts of edges created by category. * * @task T945 */ export declare function materializeXfkEdges(projectRoot: string): Promise; /** * A single node row returned by the sentience layer graph query. */ export interface SentienceGraphNode { /** Stable composite ID: `':'`. */ id: string; /** * API-facing node type. * `msg` is exposed as `conduit_message`; all others pass through unchanged. */ type: SentienceNodeType; /** Human-readable label. */ label: string; /** Quality score 0.0–1.0. */ qualityScore: number; /** Optional type-specific metadata JSON string. */ metadataJson: string | null; /** ISO timestamp of creation. */ createdAt: string; } /** * A single edge row returned by the sentience layer graph query. */ export interface SentienceGraphEdge { /** Source node ID. */ fromId: string; /** Target node ID. */ toId: string; /** Edge type from BRAIN_EDGE_TYPES. */ edgeType: BrainEdgeType; /** Edge weight 0.0–1.0. */ weight: number; /** ISO timestamp of creation. */ createdAt: string; } /** * Response shape for the `/api/v1/graph` endpoint. */ export interface SentienceGraphResponse { /** Nodes of the requested types. */ nodes: SentienceGraphNode[]; /** Edges where both endpoints are within the returned node set. */ edges: SentienceGraphEdge[]; /** Total node count (before the limit was applied). */ totalNodes: number; /** Total edge count (before filtering). */ totalEdges: number; } /** * Fetch brain_page_nodes of the sentience node types and the edges between them. * * Used by `GET /api/v1/graph`. Limits to `limit` nodes (highest quality first) * and includes only edges where both endpoints are in the returned node set. * * @param projectRoot - Absolute path to the project root (locates brain.db). * @param limit - Maximum number of nodes to return. Defaults to 500. * @returns Nodes, edges, and total counts. * * @task T945 */ export declare function queryGraphNodes(projectRoot: string, limit?: number): Promise; /** * Run `PRAGMA foreign_key_check` on nexus.db and return the violation count. * * Returns 0 when all FK constraints pass or when nexus.db is unavailable. * A non-zero result means FK violations exist that must be fixed. * * Note: nexus.db uses its own FK schema. This function checks for violations * in the nexus graph (nexus_nodes / nexus_relations), not brain.db. * * @returns Number of FK violations found in nexus.db (0 = clean). * * @task T945 */ export declare function checkNexusForeignKeys(): Promise; //# sourceMappingURL=brain-page-nodes.d.ts.map