import type { CompiledDefinition, ConceptIR, Inventory, IR } from '../core/types.js'; import { type TypedTable } from './schema.js'; export interface GraphNode { /** concept path, or artifact URI — identity is what the vault already uses */ id: string; kind: 'concept' | 'artifact'; label: string; /** concept type, or artifact kind */ type: string; /** concept domain, or artifact namespace */ domain: string; } export interface GraphEdge { src: string; dst: string; /** `link` · `meta:` · `has_row` · `cites` · `rel:` */ rel: string; label: string; } export interface GraphRow { /** `##` */ id: string; node: string; block: string; key: string; state: string; /** every cell of the row, joined — the full-text body */ text: string; } export interface GraphCite { row: string; uri: string; resolved: 0 | 1; } /** * A row identity that appeared more than once, and was therefore projected NOT * AT ALL — see `buildGraph`. Carries what a reader needs to fix it: which * document, which block, which key, and how many rows claimed it. */ export interface GraphDropped { node: string; block: string; key: string; /** how many rows claimed this identity — always 2 or more */ count: number; } /** E28 t6 — one typed table's worth of data: the spec it was derived from, and * a values array per record in `spec.columns` order. Built here rather than in * the driver so `applyGraph` stays a dumb executor with no view of the format. */ export interface TypedRows { spec: TypedTable; values: (string | number | null)[][]; } /** E38 t3 (rulings P8/P12) — a relation target the projection could not * resolve to a projected row: the address is authored (the cell says it), * the resolution is a state (the target may be archived, or live in a tier * this IR does not carry). NO edge is emitted for it — a dangling edge would * join nothing — and the miss is reported here instead of silently dropped. */ export interface GraphUnresolvedRelation { node: string; block: string; /** the declaring row's key (its display id) */ key: string; /** the relation name (the column's declared binding) */ relation: string; /** the uuid the cell points at */ target: string; } /** E38 t3 (P12) — the relation map `buildGraph` accepts: block → (column key * → relation name), exactly `relationColumnsOf(def)`'s answer. Only DECLARED * bindings emit edges: an undeclared literal rel-ish column in a markdown * table emits nothing at all. */ export type GraphRelations = ReadonlyMap>; export interface Graph { nodes: GraphNode[]; edges: GraphEdge[]; rows: GraphRow[]; cites: GraphCite[]; /** * Row identities refused for being ambiguous. Empty for every vault that * lints clean, since a duplicate id is already an error at parse time. */ dropped: GraphDropped[]; /** E28 t6 — the typed tables, when a definition was supplied. Absent when * buildGraph was called without one: the graph half needs no format. */ typed?: TypedRows[]; /** E38 t3 — relation targets that resolved to no projected row. CONDITIONAL * like `typed`: present only when a non-empty relation map was supplied, so * a relation-less projection is deep-equal to yesterday's, key and all. */ unresolvedRelations?: GraphUnresolvedRelation[]; } /** Row identity, shared with anything that wants to point back at a row. */ export declare function rowId(path: string, block: string, key: string): string; /** * Project an IR (and, when supplied, the artifact inventory) into nodes and * edges. Deterministic and order-stable: concepts in IR order, each concept's * edges in document order, artifacts last. */ export declare function buildGraph(ir: IR, inventory?: Inventory | null, def?: CompiledDefinition | null, relations?: GraphRelations | null): Graph; /** Shape of the projection, for a CLI summary or a golden test. */ export declare function graphStats(g: Graph): { nodes: number; concepts: number; artifacts: number; edges: number; rows: number; cites: number; byRel: Record; }; /** Concepts nothing links TO — the reverse of a broken link. */ export declare function orphans(g: Graph): string[]; /** Everything within `depth` hops of a node, following edges in both * directions. The deduped-frontier walk, in TypeScript — the same shape the * shipped SQL uses, and for the same reason: a walk that re-expands a node it * has already reached costs exponentially more for identical results. */ export declare function neighbourhood(g: Graph, start: string, depth: number, rels?: string[]): string[]; export type { ConceptIR };