graph

package
v0.6.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 27, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package graph — store.go defines the pluggable storage interface for persisting and restoring projected graphs to/from remote backends.

The unit of persistence is a SQLite .db file (produced by SQLiteWriter or mache build). This keeps the abstraction simple: backends just need to store and retrieve opaque blobs keyed by repo identity + generation.

Implementations: local disk (default), Cloudflare R2, GCS, S3.

Index

Constants

View Source
const (
	ArenaHeaderSize = 4096
	ArenaMagic      = 0x4C455930
)
View Source
const (
	SchemaDotJSON  = "_schema.json"
	DiagnosticsDir = "_diagnostics"
	ContextFile    = "context"
	LocationFile   = "location"
	PromptFile     = "PROMPT.txt"
	CallersDir     = "callers"
	CalleesDir     = "callees"
	DiagLastWrite  = "last-write-status"
	DiagASTErrors  = "ast-errors"
	DiagLint       = "lint"
)

Well-known virtual directory and file names.

Variables

View Source
var ErrActNotSupported = errors.New("act not supported by this graph")

ErrActNotSupported is returned by Graph implementations that do not support actions.

View Source
var ErrNotFound = errors.New("node not found")

Functions

func ConnectedComponents added in v0.5.6

func ConnectedComponents(refs map[string][]string) [][]string

ConnectedComponents finds connected components in the refs graph projection. Simpler than Louvain — useful as a baseline or when modularity optimization is overkill (e.g., disconnected subgraphs).

func CreateArena added in v0.2.0

func CreateArena(dbPath, arenaPath string) error

CreateArena creates a fresh double-buffered arena file from a .db file. Layout: [Header (4KB)] [Buffer0 = dbBytes] [Buffer1 = zeros] Buffer size is the .db file size rounded up to the next 4KB page boundary.

func ExtractActiveDB added in v0.2.0

func ExtractActiveDB(arenaPath string) (string, error)

ExtractActiveDB extracts the active SQLite database from the arena to a temp file. Returns the path to the temp file.

func FilterTestRefs added in v0.6.2

func FilterTestRefs(refs map[string][]string) map[string][]string

FilterTestRefs returns a copy of refs with test-related content removed. Filters both test nodes (IDs containing "_test", "Test", "Benchmark") and test tokens (env vars with "TEST" in the name, tokens starting with "Test").

func FindSourceChild added in v0.2.0

func FindSourceChild(g Graph, dirID string) string

FindSourceChild finds the "source" file child of a directory node. Returns the full source ID or "" if not found. Used by callees/ to resolve a callee directory to its source content.

func IsCalleesPath added in v0.2.0

func IsCalleesPath(path string) bool

IsCalleesPath returns true if the path contains a /callees segment boundary.

func IsCallersPath added in v0.2.0

func IsCallersPath(path string) bool

IsCallersPath returns true if the path contains a /callers segment boundary.

func IsDiagPath added in v0.5.2

func IsDiagPath(path string) bool

IsDiagPath returns true if the path contains a /_diagnostics segment.

func ParseCalleesPath added in v0.2.0

func ParseCalleesPath(path string) (parentDir, entryName string)

ParseCalleesPath splits a callees path into (parentDir, entryName). E.g. "/funcs/Foo/callees/funcs_Bar_source" → ("/funcs/Foo", "funcs_Bar_source")

func ParseCallersPath added in v0.2.0

func ParseCallersPath(path string) (parentDir, entryName string)

ParseCallersPath splits a callers path into (parentDir, entryName). E.g. "/funcs/Foo/callers/funcs_Bar_source" → ("/funcs/Foo", "funcs_Bar_source") Returns ("", "") if not a valid callers path.

func ParseDiagPath added in v0.5.2

func ParseDiagPath(path string) (parentDir, fileName string)

ParseDiagPath splits a diagnostics path into (parentDir, fileName). E.g. "/vulns/func_a/_diagnostics/last-write-status" → ("/vulns/func_a", "last-write-status") Returns ("", "") if not a valid diagnostics path.

func VDirSymlinkTarget added in v0.2.0

func VDirSymlinkTarget(vdirParentDir, targetID string) string

VDirSymlinkTarget computes the relative symlink target from a virtual dir entry back to the target node in the graph. Works for both callers/ and callees/.

func WriteArenaHeader added in v0.2.0

func WriteArenaHeader(f *os.File, h *ArenaHeader) error

WriteArenaHeader serializes an ArenaHeader to the first 16 bytes at offset 0.

Types

type ActionResult added in v0.5.0

type ActionResult struct {
	NodeID  string `json:"node_id"`           // mache ID of the acted-upon node
	Action  string `json:"action"`            // "click", "type", "enter", "focus"
	Path    string `json:"path"`              // filesystem path
	Payload string `json:"payload,omitempty"` // optional (e.g., typed text)
}

ActionResult is returned when an action is performed on a graph node. Used by interactive graphs (browser DOM, iTerm2 sessions, macOS AX elements).

type ArenaFlusher added in v0.2.0

type ArenaFlusher struct {
	// contains filtered or unexported fields
}

ArenaFlusher writes a serialized .db file into the double-buffered arena and atomically flips the header so readers see the new version.

Flush is O(N) where N = DB size — the entire .db is copied to the inactive buffer on every flush. To amortize this cost, callers should use RequestFlush (coalesced) instead of FlushNow (synchronous) for writes. The coalescing goroutine batches rapid writes into a single flush per tick interval (default 100ms), so N concurrent agent writes within a tick produce 1 flush instead of N.

Benchmarked on M3 Max (BenchmarkArenaFlush):

108 KB  → ~4ms  (fsync-dominated floor)
  1 MB  → ~5ms
 10 MB  → ~10-25ms

Flush uses page-level diff: only changed SQLite pages are written to the inactive buffer, avoiding a full-DB copy on every swap.

func NewArenaFlusher added in v0.2.0

func NewArenaFlusher(arenaPath, masterDBPath string, ctrl *control.Controller) *ArenaFlusher

NewArenaFlusher creates a flusher that targets the given arena file and updates the control block on each flush. The masterDBPath is the writable temp file that WritableGraph mutates.

Call Start() to begin the coalescing goroutine, and Close() to stop it and perform a final flush.

func (*ArenaFlusher) Close added in v0.2.0

func (f *ArenaFlusher) Close() error

Close stops the coalescing goroutine and performs a final synchronous flush if dirty.

func (*ArenaFlusher) FlushNow added in v0.2.0

func (f *ArenaFlusher) FlushNow() error

FlushNow performs a synchronous flush. Use for final flush on unmount or when the caller needs to guarantee the arena is up-to-date.

func (*ArenaFlusher) LastError added in v0.2.0

func (f *ArenaFlusher) LastError() error

LastError returns the last error from the coalescing goroutine.

func (*ArenaFlusher) RequestFlush added in v0.2.0

func (f *ArenaFlusher) RequestFlush()

RequestFlush marks the flusher as dirty. The coalescing goroutine will perform the actual flush on the next tick. Non-blocking, O(1).

func (*ArenaFlusher) Start added in v0.2.0

func (f *ArenaFlusher) Start(interval time.Duration)

Start begins the coalescing goroutine that flushes at most once per interval when dirty. Safe to call multiple times (idempotent).

type ArenaHeader added in v0.2.0

type ArenaHeader struct {
	Magic        uint32
	Version      uint8
	ActiveBuffer uint8
	Padding      [2]byte
	Sequence     uint64
}

func ReadArenaHeader added in v0.2.0

func ReadArenaHeader(f *os.File) (*ArenaHeader, error)

ReadArenaHeader reads the 4KB header from the file.

func (*ArenaHeader) CalculateActiveOffset added in v0.2.0

func (h *ArenaHeader) CalculateActiveOffset(fileSize int64) (int64, error)

CalculateArenaOffset returns the byte offset of the active buffer.

type CallExtractor added in v0.2.0

type CallExtractor func(content []byte, path, langName string) ([]QualifiedCall, error)

CallExtractor parses source code and returns qualified function call tokens. Used for on-demand "callees/" resolution. langName is the tree-sitter language identifier (e.g. "go", "python").

type Class added in v0.6.2

type Class struct {
	ID        int
	Label     string   // emergent: most-referenced token among members
	Members   []string // constituent node IDs
	InternalW float64  // total internal edge weight (density measure)
}

Class is an equivalence class of nodes (a community collapsed into one unit).

type Community added in v0.5.6

type Community struct {
	ID      int      // Community identifier
	Members []string // Node IDs belonging to this community
}

Community represents a cluster of densely-connected nodes detected by Louvain.

type CommunityResult added in v0.5.6

type CommunityResult struct {
	Communities []Community    // Detected communities, sorted by size descending
	Membership  map[string]int // Node ID → community ID
	Modularity  float64        // Final modularity score (0 to 1, higher = better partition)
	NumNodes    int            // Total nodes in the graph
	NumEdges    int            // Total edges (undirected)
}

CommunityResult holds the output of community detection.

func DetectCommunities added in v0.5.6

func DetectCommunities(refs map[string][]string, minCommunitySize int) *CommunityResult

DetectCommunities runs Louvain community detection on a bipartite refs graph. Input: refs maps token → []nodeID (which nodes reference that token). The algorithm projects this into a unipartite graph where two nodes are connected if they share at least one token, with edge weight = number of shared tokens. Returns communities of nodes that are densely co-referencing.

minCommunitySize filters out communities smaller than this (default 2 if 0).

type CompositeGraph added in v0.5.0

type CompositeGraph struct {
	// contains filtered or unexported fields
}

CompositeGraph multiplexes multiple Graph backends under path prefixes. Mount "browser" → paths under /browser/ route to that sub-graph. Mount "iterm" → paths under /iterm/ route to that sub-graph. Root ListChildren returns the list of mount point names.

func NewCompositeGraph added in v0.5.0

func NewCompositeGraph() *CompositeGraph

NewCompositeGraph creates an empty composite graph.

func (*CompositeGraph) Act added in v0.5.0

func (c *CompositeGraph) Act(id, action, payload string) (*ActionResult, error)

Act implements Graph. Routes to the appropriate sub-graph.

func (*CompositeGraph) GetCallees added in v0.5.0

func (c *CompositeGraph) GetCallees(id string) ([]*Node, error)

GetCallees implements Graph.

func (*CompositeGraph) GetCallers added in v0.5.0

func (c *CompositeGraph) GetCallers(token string) ([]*Node, error)

GetCallers implements Graph. Searches all mounted sub-graphs.

func (*CompositeGraph) GetNode added in v0.5.0

func (c *CompositeGraph) GetNode(id string) (*Node, error)

GetNode implements Graph.

func (*CompositeGraph) Invalidate added in v0.5.0

func (c *CompositeGraph) Invalidate(id string)

Invalidate implements Graph.

func (*CompositeGraph) ListChildren added in v0.5.0

func (c *CompositeGraph) ListChildren(id string) ([]string, error)

ListChildren implements Graph.

func (*CompositeGraph) Mount added in v0.5.0

func (c *CompositeGraph) Mount(prefix string, g Graph) error

Mount registers a sub-graph under the given prefix. Paths like "/<prefix>/..." are routed to this graph with the prefix stripped.

func (*CompositeGraph) ReadContent added in v0.5.0

func (c *CompositeGraph) ReadContent(id string, buf []byte, offset int64) (int, error)

ReadContent implements Graph.

func (*CompositeGraph) Unmount added in v0.5.0

func (c *CompositeGraph) Unmount(prefix string) error

Unmount removes a previously mounted sub-graph.

type ContentRef

type ContentRef struct {
	DBPath     string // Path to the SQLite database
	RecordID   string // Row ID in the results table
	Template   string // Content template to re-render
	ContentLen int64  // Pre-computed rendered byte length
}

ContentRef is a recipe for lazily resolving file content from a backing store. Instead of storing the full byte content in RAM, we store enough info to re-fetch it on demand.

type ContentResolverFunc

type ContentResolverFunc func(ref *ContentRef) ([]byte, error)

ContentResolverFunc resolves a ContentRef into byte content.

type ErrGraphNotCached added in v0.6.1

type ErrGraphNotCached struct {
	Repo string
}

ErrGraphNotCached is returned by Get/Head when no graph exists for the repo.

func (*ErrGraphNotCached) Error added in v0.6.1

func (e *ErrGraphNotCached) Error() string

type Graph

type Graph interface {
	GetNode(id string) (*Node, error)
	ListChildren(id string) ([]string, error)
	ReadContent(id string, buf []byte, offset int64) (int, error)
	GetCallers(token string) ([]*Node, error)
	GetCallees(id string) ([]*Node, error)
	// Invalidate evicts cached data for a node (size, content).
	// Called after write-back to force re-render on next access.
	Invalidate(id string)
	// Act performs an action on the node at the given path.
	// Interactive graphs (browser DOM, terminal sessions, macOS AX elements)
	// implement real actions. Passive graphs (code, data) return ErrActNotSupported.
	Act(id, action, payload string) (*ActionResult, error)
}

Graph is the interface for the FUSE layer. This allows us to swap the backend later (Memory -> SQLite -> Mmap).

type GraphMeta added in v0.6.1

type GraphMeta struct {
	Repo       string    // e.g., "github.com/org/repo"
	Generation uint64    // monotonic version counter
	Size       int64     // .db file size in bytes
	ModTime    time.Time // last update time
	ETag       string    // content hash for conditional gets (optional)
}

GraphMeta is metadata about a persisted graph.

type GraphStore added in v0.6.1

type GraphStore interface {
	// Put persists a graph database for the given repo.
	// The reader provides the SQLite .db bytes. Generation is an
	// opaque version counter (monotonically increasing).
	Put(ctx context.Context, repo string, generation uint64, r io.Reader) error

	// Get retrieves the latest graph database for the given repo.
	// Returns the reader, generation, and modification time.
	// Returns ErrGraphNotCached if no graph exists for this repo.
	Get(ctx context.Context, repo string) (io.ReadCloser, uint64, error)

	// Head returns metadata without fetching the full database.
	// Used for cache validation (is my local copy still current?).
	Head(ctx context.Context, repo string) (*GraphMeta, error)

	// Delete removes a persisted graph for the given repo.
	Delete(ctx context.Context, repo string) error

	// List returns all repos with persisted graphs.
	// Use for garbage collection and admin tooling.
	List(ctx context.Context) ([]GraphMeta, error)
}

GraphStore persists and retrieves projected graph databases. The key is a repo identifier (e.g., "github.com/org/repo") and the value is a SQLite .db file containing the nodes/refs/defs tables.

type HotSwapGraph added in v0.2.0

type HotSwapGraph struct {
	// contains filtered or unexported fields
}

HotSwapGraph is a thread-safe wrapper that allows swapping the underlying graph instance.

func NewHotSwapGraph added in v0.2.0

func NewHotSwapGraph(initial Graph) *HotSwapGraph

func (*HotSwapGraph) Act added in v0.5.0

func (h *HotSwapGraph) Act(id, action, payload string) (*ActionResult, error)

Act delegates to current graph.

func (*HotSwapGraph) GetCallees added in v0.2.0

func (h *HotSwapGraph) GetCallees(id string) ([]*Node, error)

GetCallees delegates to current graph.

func (*HotSwapGraph) GetCallers added in v0.2.0

func (h *HotSwapGraph) GetCallers(token string) ([]*Node, error)

GetCallers delegates to current graph.

func (*HotSwapGraph) GetNode added in v0.2.0

func (h *HotSwapGraph) GetNode(id string) (*Node, error)

GetNode delegates to current graph.

func (*HotSwapGraph) Invalidate added in v0.2.0

func (h *HotSwapGraph) Invalidate(id string)

Invalidate delegates to current graph.

func (*HotSwapGraph) ListChildren added in v0.2.0

func (h *HotSwapGraph) ListChildren(id string) ([]string, error)

ListChildren delegates to current graph.

func (*HotSwapGraph) ReadContent added in v0.2.0

func (h *HotSwapGraph) ReadContent(id string, buf []byte, offset int64) (int, error)

ReadContent delegates to current graph.

func (*HotSwapGraph) Swap added in v0.2.0

func (h *HotSwapGraph) Swap(newGraph Graph)

Swap atomically replaces the current graph with a new one. It closes the old graph (if it implements Closer, though Graph interface doesn't enforce it). Ideally, Graph implementations should be safe to close.

type LocalStore added in v0.6.1

type LocalStore struct {
	BaseDir string
}

LocalStore persists graphs to a local directory. Each repo gets a subdirectory: {base}/{repo-hash}/graph.db

func NewLocalStore added in v0.6.1

func NewLocalStore(baseDir string) *LocalStore

NewLocalStore creates a LocalStore backed by the given directory.

func (*LocalStore) Delete added in v0.6.1

func (s *LocalStore) Delete(_ context.Context, repo string) error

Delete removes a persisted graph from local disk.

func (*LocalStore) Get added in v0.6.1

func (s *LocalStore) Get(_ context.Context, repo string) (io.ReadCloser, uint64, error)

Get retrieves the graph database from local disk.

func (*LocalStore) Head added in v0.6.1

func (s *LocalStore) Head(_ context.Context, repo string) (*GraphMeta, error)

Head returns metadata without reading the full database.

func (*LocalStore) List added in v0.6.1

func (s *LocalStore) List(_ context.Context) ([]GraphMeta, error)

List returns all repos with persisted graphs.

func (*LocalStore) Put added in v0.6.1

func (s *LocalStore) Put(_ context.Context, repo string, generation uint64, r io.Reader) error

Put persists a graph database to local disk.

type MemoryStore

type MemoryStore struct {

	// Diagnostics: last write status per node path (for _diagnostics/ virtual dir).
	WriteStatus sync.Map // node path (string) → error message (string)
	// contains filtered or unexported fields
}

func NewMemoryStore

func NewMemoryStore() *MemoryStore

func (*MemoryStore) Act added in v0.5.0

func (s *MemoryStore) Act(id, action, payload string) (*ActionResult, error)

Act returns ErrActNotSupported — MemoryStore is a passive code graph.

func (*MemoryStore) AddDef added in v0.2.0

func (s *MemoryStore) AddDef(token, dirID string) error

AddDef records that a construct (dirID) defines the given token. Used by callees/ resolution: token → where it is defined. Uses copy-on-write: creates a new slice instead of appending to the existing one, so concurrent readers (GetCallees holds RLock) never see a partially-updated slice.

func (*MemoryStore) AddNode

func (s *MemoryStore) AddNode(n *Node)

AddNode adds a non-root node to the store.

func (*MemoryStore) AddRef

func (s *MemoryStore) AddRef(token, nodeID string) error

AddRef records a reference from a file (nodeID) to a token.

func (*MemoryStore) AddRoot

func (s *MemoryStore) AddRoot(n *Node)

AddRoot registers a node as a top-level root and adds it to the store. Callers must explicitly declare roots — there is no heuristic.

func (*MemoryStore) Close

func (s *MemoryStore) Close() error

Close closes the refs database and removes the temp file.

func (*MemoryStore) DefsMap added in v0.6.0

func (s *MemoryStore) DefsMap() map[string][]string

DefsMap returns a snapshot of the token→dirIDs definition map. Used by find_definition to locate where symbols are defined.

func (*MemoryStore) DeleteFileNodes added in v0.2.0

func (s *MemoryStore) DeleteFileNodes(filePath string)

DeleteFileNodes removes all nodes that originated from the given source file. Uses the roaring bitmap index for O(k) lookup instead of O(N) full scan.

func (*MemoryStore) FileMtime added in v0.6.0

func (s *MemoryStore) FileMtime(filePath string) time.Time

FileMtime returns the tracked mtime for a source file. Returns zero time if the file is not tracked.

func (*MemoryStore) FlushRefs

func (s *MemoryStore) FlushRefs() error

FlushRefs writes all accumulated refs (from AddRef) into the in-memory SQLite sidecar as roaring bitmaps. Guarded by sync.Once — safe to call multiple times; only the first call performs the flush.

func (*MemoryStore) GetCallees added in v0.2.0

func (s *MemoryStore) GetCallees(id string) ([]*Node, error)

GetCallees implements Graph. It parses the node's source to find calls, then looks up those tokens in the defs index to find definitions.

func (*MemoryStore) GetCallers

func (s *MemoryStore) GetCallers(token string) ([]*Node, error)

GetCallers implements Graph.

func (*MemoryStore) GetNode

func (s *MemoryStore) GetNode(id string) (*Node, error)

GetNode implements Graph.

func (*MemoryStore) InitRefsDB

func (s *MemoryStore) InitRefsDB() error

InitRefsDB opens an in-memory SQLite database with the same schema as SQLiteGraph's sidecar (node_refs + file_ids + mache_refs vtab). Must be called before FlushRefs. Safe to call multiple times (idempotent).

func (*MemoryStore) Invalidate

func (s *MemoryStore) Invalidate(id string)

Invalidate is a no-op for MemoryStore — nodes are updated in-place.

func (*MemoryStore) IsFileStale added in v0.6.0

func (s *MemoryStore) IsFileStale(filePath string) bool

IsFileStale returns true if the source file's current mtime differs from the tracked mtime (i.e., the file has been modified since indexing).

func (*MemoryStore) ListChildren

func (s *MemoryStore) ListChildren(id string) ([]string, error)

ListChildren implements Graph.

func (*MemoryStore) QueryRefs

func (s *MemoryStore) QueryRefs(query string, args ...any) (*sql.Rows, error)

QueryRefs executes a SQL query against the in-memory refs database, which includes the mache_refs virtual table.

func (*MemoryStore) ReadContent

func (s *MemoryStore) ReadContent(id string, buf []byte, offset int64) (int, error)

ReadContent implements Graph. It handles both inline and lazy content. If the node has a SourceOrigin and the source file's mtime has changed, the refresher callback is invoked to re-ingest the file before reading.

func (*MemoryStore) RecordFileMtime added in v0.6.0

func (s *MemoryStore) RecordFileMtime(filePath string, mtime time.Time)

RecordFileMtime explicitly records the mtime for a source file. Called after re-ingestion to update the tracked mtime.

func (*MemoryStore) RefsMap added in v0.5.6

func (s *MemoryStore) RefsMap() map[string][]string

RefsMap returns a snapshot of the token→nodeIDs reference map. Used by community detection to build the co-reference graph.

func (*MemoryStore) ReplaceFileNodes added in v0.2.0

func (s *MemoryStore) ReplaceFileNodes(filePath string, newNodes []*Node)

ReplaceFileNodes atomically replaces all nodes from a file with a new set. This prevents race conditions where files disappear during re-ingestion.

func (*MemoryStore) RootIDs added in v0.4.0

func (s *MemoryStore) RootIDs() []string

RootIDs returns a copy of the top-level root node IDs.

func (*MemoryStore) SetCallExtractor added in v0.2.0

func (s *MemoryStore) SetCallExtractor(fn CallExtractor)

SetCallExtractor configures the parser for on-demand callee resolution.

func (*MemoryStore) SetRefresher added in v0.6.0

func (s *MemoryStore) SetRefresher(fn func(filePath string) error)

SetRefresher configures a callback invoked when a source file is stale. The callback should re-ingest the file and update the store.

func (*MemoryStore) SetResolver

func (s *MemoryStore) SetResolver(fn ContentResolverFunc)

SetResolver configures lazy content resolution for nodes with ContentRef. Cache size scales with node count: 25% of nodes, floor 1024, ceiling 16384.

func (*MemoryStore) ShiftOrigins added in v0.2.0

func (s *MemoryStore) ShiftOrigins(filePath string, afterByte uint32, delta int32)

ShiftOrigins adjusts StartByte/EndByte for all nodes from filePath whose origin starts at or after afterByte. delta is the signed byte count change (positive = content grew, negative = content shrank). Called after splice, BEFORE re-ingest, to keep sibling offsets correct.

func (*MemoryStore) UpdateNodeContent added in v0.2.0

func (s *MemoryStore) UpdateNodeContent(id string, data []byte, origin *SourceOrigin, modTime time.Time) error

UpdateNodeContent surgically updates a node's content and origin in-place. Preserves Children, Context, Properties, and Ref. Clears DraftData on success.

func (*MemoryStore) UpdateNodeContext added in v0.2.0

func (s *MemoryStore) UpdateNodeContext(id string, ctx []byte) error

UpdateNodeContext updates the Context field on a node (e.g., imports/package).

type MermaidOpts added in v0.6.2

type MermaidOpts struct {
	Layout  string // "TD", "LR", "BT", "RL" (default "TD")
	Compact bool   // omit member listings inside subgraphs
}

MermaidOpts controls diagram rendering.

type Node

type Node struct {
	ID         string
	Mode       fs.FileMode       // fs.ModeDir for directories, 0 for regular files
	ModTime    time.Time         // Modification time
	Data       []byte            // Inline content (small files, nil for lazy nodes)
	Context    []byte            // Context content (imports/globals, for virtual 'context' file)
	DraftData  []byte            // Draft content (uncommitted/invalid edits)
	Ref        *ContentRef       // Lazy content reference (large files, nil for inline nodes)
	Properties map[string][]byte // Metadata / extended attributes
	Children   []string          // Child node IDs (directories only)
	Origin     *SourceOrigin     // Source byte range (nil for dirs, JSON, SQLite nodes)
}

Node is the universal primitive. The Mode field explicitly declares whether this is a file or directory.

func (*Node) ContentSize

func (n *Node) ContentSize() int64

ContentSize returns the byte length of this node's content, regardless of whether it is inline or lazy.

type QualifiedCall added in v0.2.0

type QualifiedCall struct {
	Token     string // Function/method name (e.g., "Validate")
	Qualifier string // Package qualifier (e.g., "auth"); empty for unqualified calls
}

QualifiedCall represents a function call with optional package qualifier.

type QuotientEdge added in v0.6.2

type QuotientEdge struct {
	From         int                // class index (invariant: From < To)
	To           int                // class index
	Weight       float64            // aggregated cross-class coupling
	Tokens       []string           // boundary tokens creating this edge
	TokenWeights map[string]float64 // per-token contribution to Weight
}

QuotientEdge is an aggregated edge between two classes.

type QuotientGraph added in v0.6.2

type QuotientGraph struct {
	Classes []Class
	Edges   []QuotientEdge
	ClassOf map[string]int // node ID → class index
}

QuotientGraph compresses a full node graph into a diagram-scale object by collapsing nodes into equivalence classes (communities) and aggregating inter-class edges. The quotient G/P is uniquely determined by the partition P.

func ComputeQuotient added in v0.6.2

func ComputeQuotient(cr *CommunityResult, refs map[string][]string) *QuotientGraph

ComputeQuotient builds a QuotientGraph from a community partition and refs.

The algorithm mirrors buildRestrictions in sheaf.go: for each ref token referenced by nodes in multiple communities, create an inter-class edge with weight = product of member counts (bipartite projection weight).

Class labels are derived from the most-referenced token among class members. Ties are broken lexicographically for determinism.

func (*QuotientGraph) Mermaid added in v0.6.2

func (q *QuotientGraph) Mermaid(layout string) string

Mermaid renders the quotient graph as mermaid syntax.

Each Class becomes a subgraph (or a plain node if it has a single member). Each QuotientEdge becomes an arrow. Edge annotations show boundary tokens that contribute above the mean weight for that edge.

func (*QuotientGraph) MermaidWithOpts added in v0.6.2

func (q *QuotientGraph) MermaidWithOpts(opts MermaidOpts) string

MermaidWithOpts renders the quotient graph with full control over output.

type R2Store added in v0.6.1

type R2Store struct {
	Bucket    string
	AccountID string
	AccessKey string
	SecretKey string
}

R2Store persists graphs to Cloudflare R2. Key format: graphs/{repo-hash}/graph.db Debounce writes to avoid thrashing (caller's responsibility).

type SQLiteGraph

type SQLiteGraph struct {
	// contains filtered or unexported fields
}

SQLiteGraph implements Graph by querying the source SQLite database directly. No index copy, no ingestion step — the source DB's B+ tree IS the index.

Design: directory structure is derived lazily from schema + DB on first access, then cached in sync.Maps for lock-free concurrent reads from FUSE callbacks.

The scan is single-threaded and streaming: one sequential pass over all records, rendering name templates to build parent→child path relationships. This avoids the deadlock risk and channel overhead of a worker pool — SQLite sequential reads are I/O-bound and template rendering for name fields is cheap.

Memory model after scan:

  • dirChildren: sorted []string slices (one per directory), read-only post-scan
  • recordIDs: leaf dir path → DB row ID, for on-demand content resolution
  • contentCache: FIFO-bounded rendered content (avoids re-fetching hot files)

Content is never loaded during scan — only on FUSE read via resolveContent, which does a primary key lookup + template render + FIFO cache.

Cross-references (token → file bitmap) are stored in a sidecar database (<dbpath>.refs.db) to keep the source DB immutable. Refs are accumulated in-memory during ingestion and flushed once via FlushRefs.

func OpenSQLiteGraph

func OpenSQLiteGraph(dbPath string, schema *api.Topology, render TemplateRenderer) (*SQLiteGraph, error)

OpenSQLiteGraph opens a connection to the source DB and compiles the schema.

func (*SQLiteGraph) Act added in v0.5.0

func (g *SQLiteGraph) Act(id, action, payload string) (*ActionResult, error)

Act returns ErrActNotSupported — SQLiteGraph is a passive data graph.

func (*SQLiteGraph) AddDef added in v0.2.0

func (g *SQLiteGraph) AddDef(token, dirID string) error

AddDef records that a construct (dirID) defines the given token.

func (*SQLiteGraph) AddRef

func (g *SQLiteGraph) AddRef(token, nodeID string) error

AddRef accumulates a reference in-memory. No SQL is issued until FlushRefs. This eliminates the read-modify-write cycle per call — all bitmap mutations happen in RAM, and FlushRefs writes them in a single transaction. Not used for nodes-table path (refs already in main DB from mache build).

func (*SQLiteGraph) Close

func (g *SQLiteGraph) Close() error

Close closes both the source and sidecar database connections.

func (*SQLiteGraph) DefsMap added in v0.6.0

func (g *SQLiteGraph) DefsMap() map[string][]string

DefsMap returns a snapshot of the token→dirIDs definition map.

func (*SQLiteGraph) EagerScan

func (g *SQLiteGraph) EagerScan() error

EagerScan pre-scans all root nodes so no FUSE callback ever blocks on a scan. Call this before mounting — fuse-t's NFS transport times out if a callback takes >2s.

func (*SQLiteGraph) FlushRefs

func (g *SQLiteGraph) FlushRefs() error

FlushRefs writes all accumulated refs to the sidecar database in a single transaction. Call once after ingestion is complete. Batches all inserts (len(fileIDMap) + len(pendingRefs)) into one transaction.

Guarded by sync.Once — safe to call multiple times; only the first call performs the flush. This prevents the double-call bug where a second flush would reset nextFileID to 0, causing ID collisions in file_ids.

func (*SQLiteGraph) GetCallees added in v0.2.0

func (g *SQLiteGraph) GetCallees(id string) ([]*Node, error)

GetCallees implements Graph.

func (*SQLiteGraph) GetCallers

func (g *SQLiteGraph) GetCallers(token string) ([]*Node, error)

GetCallers returns the list of files (nodes) that reference the given token. For nodes-table path: queries main DB's node_refs (token, node_id) directly. For legacy path: reads roaring bitmaps from the sidecar refs database.

func (*SQLiteGraph) GetNode

func (g *SQLiteGraph) GetNode(id string) (*Node, error)

func (*SQLiteGraph) Invalidate

func (g *SQLiteGraph) Invalidate(id string)

Invalidate evicts cached size and content for a node. Must be called after write-back modifies a file's content to prevent stale size/data from being served on the next Getattr or Read.

func (*SQLiteGraph) ListChildren

func (g *SQLiteGraph) ListChildren(id string) ([]string, error)

func (*SQLiteGraph) QueryRefs

func (g *SQLiteGraph) QueryRefs(query string, args ...any) (*sql.Rows, error)

QueryRefs executes a SQL query against the refs database. For nodes-table path: queries the main DB (node_refs has (token, node_id)). For legacy path: queries the sidecar (includes mache_refs virtual table).

func (*SQLiteGraph) ReadContent

func (g *SQLiteGraph) ReadContent(id string, buf []byte, offset int64) (int, error)

func (*SQLiteGraph) RefsMap added in v0.5.6

func (g *SQLiteGraph) RefsMap() map[string][]string

RefsMap returns a token→nodeIDs map for community detection. For the nodes-table path, queries node_refs (token, node_id). For the legacy bitmap path, decodes bitmaps and resolves file IDs.

func (*SQLiteGraph) SetCallExtractor added in v0.2.0

func (g *SQLiteGraph) SetCallExtractor(fn CallExtractor)

SetCallExtractor configures the parser for on-demand callee resolution.

type SheafBackend added in v0.6.1

type SheafBackend interface {
	Invalidate(regionID int) ([]int, error)
}

SheafBackend is the subset of SheafClient that SheafInvalidator needs. Defined as an interface to allow testing without a real daemon.

type SheafInvalidator added in v0.6.1

type SheafInvalidator struct {
	// contains filtered or unexported fields
}

SheafInvalidator wraps a Graph with sheaf-aware cascading invalidation. When a node is invalidated, it looks up the node's community (region), asks the ley-line daemon which regions are transitively affected, then invalidates all nodes in those affected regions.

If the SheafClient is nil or the daemon is unavailable, it falls back to plain Graph.Invalidate on the single node.

func NewSheafInvalidator added in v0.6.1

func NewSheafInvalidator(graph Graph, sheaf SheafBackend, result *CommunityResult) *SheafInvalidator

NewSheafInvalidator creates a SheafInvalidator. All parameters are optional:

  • graph may be nil (all operations become no-ops)
  • sheaf may be nil (falls back to single-node invalidation)
  • result may be nil (falls back to single-node invalidation)

func (*SheafInvalidator) InvalidateWithCascade added in v0.6.1

func (si *SheafInvalidator) InvalidateWithCascade(id string, membership map[string]int) int

InvalidateWithCascade invalidates a node and, if sheaf is available, cascades the invalidation to all nodes in transitively affected regions.

The membership map is used to look up which community the node belongs to. If membership is nil, si.result.Membership is used.

Returns the number of nodes invalidated.

func (*SheafInvalidator) SetCommunityResult added in v0.6.1

func (si *SheafInvalidator) SetCommunityResult(cr *CommunityResult)

SetCommunityResult updates the community detection result used for lookups. Call this after re-running community detection.

type SourceOrigin

type SourceOrigin struct {
	FilePath  string `json:"file"`
	StartByte uint32 `json:"start_byte"`
	EndByte   uint32 `json:"end_byte"`
}

SourceOrigin tracks the byte range of a construct in its source file. Used by write-back to splice edits into the original source.

type TemplateRenderer

type TemplateRenderer func(tmpl string, values map[string]any) (string, error)

TemplateRenderer renders a Go text/template string with the given values map.

type WritableGraph added in v0.2.0

type WritableGraph struct {
	// contains filtered or unexported fields
}

WritableGraph is a read-write SQLite backend for arena-mode mounts. It opens the master .db in read-write mode and supports mutations that are flushed back to the arena via ArenaFlusher.

Read methods use the same nodes-table queries as SQLiteGraph's fast path. Write methods mutate the nodes table directly (UPDATE/INSERT/DELETE). Flush serializes the entire .db back to the double-buffered arena.

func OpenWritableGraph added in v0.2.0

func OpenWritableGraph(masterDBPath string, schema *api.Topology, render TemplateRenderer, flusher *ArenaFlusher) (*WritableGraph, error)

OpenWritableGraph opens a writable connection to the master .db. The DB must have a nodes table (created by mache build).

func (*WritableGraph) Act added in v0.5.0

func (g *WritableGraph) Act(id, action, payload string) (*ActionResult, error)

Act returns ErrActNotSupported — WritableGraph is a code-editing graph, not an interactive UI.

func (*WritableGraph) Close added in v0.2.0

func (g *WritableGraph) Close() error

Close closes the database connection.

func (*WritableGraph) DBPath added in v0.2.0

func (g *WritableGraph) DBPath() string

DBPath returns the path to the writable master database.

func (*WritableGraph) Flush added in v0.2.0

func (g *WritableGraph) Flush()

Flush requests a coalesced arena flush. Non-blocking — the actual I/O happens on the flusher's background tick. Use FlushNow for synchronous.

func (*WritableGraph) FlushNow added in v0.2.0

func (g *WritableGraph) FlushNow() error

FlushNow performs a synchronous arena flush. Use on unmount.

func (*WritableGraph) GetCallees added in v0.2.0

func (g *WritableGraph) GetCallees(id string) ([]*Node, error)

func (*WritableGraph) GetCallers added in v0.2.0

func (g *WritableGraph) GetCallers(token string) ([]*Node, error)

func (*WritableGraph) GetNode added in v0.2.0

func (g *WritableGraph) GetNode(id string) (*Node, error)

func (*WritableGraph) Invalidate added in v0.2.0

func (g *WritableGraph) Invalidate(id string)

func (*WritableGraph) ListChildren added in v0.2.0

func (g *WritableGraph) ListChildren(id string) ([]string, error)

func (*WritableGraph) ReadContent added in v0.2.0

func (g *WritableGraph) ReadContent(id string, buf []byte, offset int64) (int, error)

func (*WritableGraph) UpdateRecord added in v0.2.0

func (g *WritableGraph) UpdateRecord(id string, content []byte) error

UpdateRecord updates a file node's content in the nodes table. The content is stored as an opaque blob in the record column.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL