Documentation
¶
Index ¶
- Constants
- Variables
- func ChunkText(text string, thresholdTokens, chunkTokens, overlapTokens int) []string
- func IsStructuralEdge(edgeType string) bool
- func MarshalEdge(e *Edge) ([]byte, error)
- func MarshalNode(n *Node) ([]byte, error)
- func NodeHashInCommit(s *storage.Store, commitHash, nodeID string) (string, bool, error)
- func NodeIDsInCommit(s *storage.Store, commitHash string) ([]string, error)
- type ActivationConfig
- type BboltEdgeStore
- func (s *BboltEdgeStore) ByType(edgeType string) []*Edge
- func (s *BboltEdgeStore) Clear()
- func (s *BboltEdgeStore) Count() int
- func (s *BboltEdgeStore) Delete(id string)
- func (s *BboltEdgeStore) DeleteTx(tx *bolt.Tx, batch *EdgeBatch, id string)
- func (s *BboltEdgeStore) FlushBatchTx(tx *bolt.Tx, batch *EdgeBatch)
- func (s *BboltEdgeStore) ForEach(fn func(e *Edge))
- func (s *BboltEdgeStore) From(nodeID string) []*Edge
- func (s *BboltEdgeStore) Get(id string) (*Edge, bool)
- func (s *BboltEdgeStore) Put(e *Edge)
- func (s *BboltEdgeStore) PutTx(tx *bolt.Tx, batch *EdgeBatch, e *Edge)
- func (s *BboltEdgeStore) To(nodeID string) []*Edge
- type Commit
- type CommitAction
- type DiffResult
- type Edge
- type EdgeBatch
- type EdgeStore
- type Graph
- func (g *Graph) AddEdge(sourceID, targetID, edgeType string, weight float64, props Properties) (*Edge, error)
- func (g *Graph) AddEdgeTx(tx *bolt.Tx, batch *EdgeBatch, sourceID, targetID, edgeType string, ...) (*Edge, error)
- func (g *Graph) AddNode(props Properties) *Node
- func (g *Graph) AddNodeWithIDForTest(id string, props Properties) *Node
- func (g *Graph) AllNodeIDs() []string
- func (g *Graph) ClearDirty()
- func (g *Graph) DeleteEdge(id string) error
- func (g *Graph) DeleteNode(id string) error
- func (g *Graph) EdgeCount() int
- func (g *Graph) EdgesByType(edgeType string) []*Edge
- func (g *Graph) EdgesFrom(nodeID string) []*Edge
- func (g *Graph) EdgesTo(nodeID string) []*Edge
- func (g *Graph) ForEachEdge(fn func(*Edge))
- func (g *Graph) GetEdge(id string) (*Edge, bool)
- func (g *Graph) GetNode(id string) (*Node, bool)
- func (g *Graph) IsDirty() bool
- func (g *Graph) IsStructuralChild(id string) bool
- func (g *Graph) Load(s *storage.Store, commitHash string) (*Commit, error)
- func (g *Graph) MarshalEdgeAdjacency() ([]byte, error)
- func (g *Graph) NodeCount() int
- func (g *Graph) NodeIDSet() map[string]struct{}
- func (g *Graph) NodeIterator() NodeIterator
- func (g *Graph) PrepareCommit(s *storage.Store, parent string, message string, actions []CommitAction, ...) (*Commit, error)
- func (g *Graph) RecordAccess(nodeID string, now time.Time, cfg ActivationConfig)
- func (g *Graph) RemoveEdgeProperty(id, key string) error
- func (g *Graph) RemoveNodeProperty(id, key string) error
- func (g *Graph) Save(s *storage.Store, parent string, message string, pCfg ...storage.ProllyConfig) (*Commit, error)
- func (g *Graph) SaveWithActions(s *storage.Store, parent string, message string, actions []CommitAction, ...) (*Commit, error)
- func (g *Graph) SemanticEdgeCount(id string) int
- func (g *Graph) SetEdgeProperty(id, key string, val Property) error
- func (g *Graph) SetEdgeWeight(id string, weight float64) error
- func (g *Graph) SetNodeProperty(id, key string, val Property) error
- func (g *Graph) Traverse(startID string, opts TraverseOptions) Subgraph
- func (g *Graph) UnmarshalEdgeAdjacency(data []byte) error
- func (g *Graph) WriteCommit(s *storage.Store, c *Commit) (*Commit, error)
- type GraphOption
- type MemoryEdgeStore
- func (s *MemoryEdgeStore) ByType(edgeType string) []*Edge
- func (s *MemoryEdgeStore) Clear()
- func (s *MemoryEdgeStore) Count() int
- func (s *MemoryEdgeStore) Delete(id string)
- func (s *MemoryEdgeStore) DeleteTx(_ *bolt.Tx, _ *EdgeBatch, id string)
- func (s *MemoryEdgeStore) ForEach(fn func(e *Edge))
- func (s *MemoryEdgeStore) From(nodeID string) []*Edge
- func (s *MemoryEdgeStore) Get(id string) (*Edge, bool)
- func (s *MemoryEdgeStore) InEdgeIDs() map[string]map[string]struct{}
- func (s *MemoryEdgeStore) OutEdgeIDs() map[string]map[string]struct{}
- func (s *MemoryEdgeStore) Put(e *Edge)
- func (s *MemoryEdgeStore) PutTx(_ *bolt.Tx, _ *EdgeBatch, e *Edge)
- func (s *MemoryEdgeStore) To(nodeID string) []*Edge
- func (s *MemoryEdgeStore) TypeEdgeIDs() map[string]map[string]struct{}
- type Node
- type NodeIterator
- type NodeReader
- type Properties
- func (ps Properties) Clone() Properties
- func (ps Properties) GetBool(key string) (bool, bool)
- func (ps Properties) GetBytes(key string) ([]byte, bool)
- func (ps Properties) GetFloat64(key string) (float64, bool)
- func (ps Properties) GetInt64(key string) (int64, bool)
- func (ps Properties) GetString(key string) (string, bool)
- func (ps Properties) GetStringList(key string) ([]string, bool)
- func (ps Properties) GetTimestamp(key string) (time.Time, bool)
- func (ps Properties) GetVector(key string) ([]float32, bool)
- func (ps Properties) MarshalBinary() ([]byte, error)
- type Property
- func BoolProperty(v bool) Property
- func BytesProperty(v []byte) Property
- func Float64Property(v float64) Property
- func Int64Property(v int64) Property
- func StringListProperty(v []string) Property
- func StringProperty(v string) Property
- func TimestampProperty(v time.Time) Property
- func UnmarshalProperty(data []byte) (Property, error)
- func VectorProperty(v []float32) Property
- func (p Property) Bool() bool
- func (p Property) Bytes() []byte
- func (p Property) Compare(other Property) int
- func (p Property) Equal(other Property) bool
- func (p Property) Float64() float64
- func (p Property) FormatValue() string
- func (p Property) Int64() int64
- func (p Property) MarshalBinary() ([]byte, error)
- func (p Property) String() string
- func (p Property) StringList() []string
- func (p Property) StringValue() string
- func (p Property) Timestamp() time.Time
- func (p Property) Vector() []float32
- type PropertyType
- type Section
- type Subgraph
- type SubgraphEdge
- type SubgraphNode
- type TSIndex
- func (idx *TSIndex) CommitAt(t time.Time) (string, bool)
- func (idx *TSIndex) CommitBefore(t time.Time) (string, bool)
- func (idx *TSIndex) CommitsBetween(start, end time.Time) []string
- func (idx *TSIndex) Count() int
- func (idx *TSIndex) Put(c *Commit) error
- func (idx *TSIndex) PutTx(tx *bolt.Tx, c *Commit)
- type TraverseOptions
Constants ¶
const ( // User-driven actions (api/ cluster). ActionCapture = "capture" ActionClassify = "classify" ActionUpdate = "update" ActionResolve = "resolve" ActionDelete = "delete" ActionLink = "link" ActionUnlink = "unlink" ActionMerge = "merge" ActionRevert = "revert" ActionIngest = "ingest" ActionImportCSV = "import_csv" ActionReembed = "reembed" ActionRepair = "repair" ActionSessionCreate = "session_create" ActionSessionCommit = "session_commit" ActionSessionArchive = "session_archive" ActionCollectionCreate = "collection_create" ActionCollectionAdd = "collection_add" ActionCollectionRemove = "collection_remove" ActionCollectionUpdate = "collection_update" ActionCollectionMove = "collection_move" ActionCollectionRename = "collection_rename" ActionCollectionRetire = "collection_retire" ActionCollectionUnretire = "collection_unretire" ActionCollectionSchemaUpdate = "collection_schema_update" ActionCollectionMigrate = "collection_migrate" ActionCurationStuckReset = "curation_stuck_reset" // Curation cycle actions (autonomous + deterministic passes). ActionCurationClassify = "curation:classify" ActionCurationSummary = "curation:summary" ActionCurationLink = "curation:link" // orphan linking (related_to edges) ActionCurationSupersede = "curation:supersede" ActionCurationContradictionCheck = "curation:contradiction_check" // covers contradict + no_contradict outcomes ActionCurationConceptEmerge = "curation:concept_emerge" // new concept + instance_of edges ActionCurationConceptEnrich = "curation:concept_enrich" // concept node enrichment (LLM synthesis or deterministic alias-merge / evidence-count update) ActionCurationSectionLink = "curation:section_link" ActionCurationObservationExtract = "curation:observation_extract" ActionCurationLifecycle = "curation:lifecycle" // valid_until set on stale ephemeral/temporal records ActionCurationQualityRepair = "curation:quality_repair" // deterministic content_short fix ActionCurationGC = "curation:gc" // hard-delete debris ActionCurationSelfHeal = "curation:self_heal" // self-heal repair_method/repair_input_hash recovery (curation/self_heal.go) )
Action kind canonical strings. Every emit site references one of these constants; the saveactions lint enforces it. Two namespaces:
- User-driven verbs (no prefix) -- one action per api/ operation. These are the kinds an operator sees in `gramaton_log` for their own write activity.
- Curation cycle verbs (`curation:` prefix) -- emitted by the autonomous + deterministic curation passes. Filterable separately so an operator asking "what did curation touch this week" doesn't have to scrape commit messages.
Adding a new kind: declare the constant here, reference it at the emit site. Renaming a kind is a breaking change for any persisted commit that carries the old string (commit.Actions is on-disk state); avoid unless there's a real reason.
const DefaultCacheCapacity = 10000
DefaultCacheCapacity is the default maximum number of nodes held in the in-memory cache. Nodes beyond this limit are evicted LRU. Set to 0 for unlimited (all accessed nodes stay cached). Dirty nodes are never evicted.
const DefaultEdgeCacheCapacity = 10000
DefaultEdgeCacheCapacity is the default max edges in the LRU cache.
Variables ¶
var ErrNotFound = errors.New("not found")
ErrNotFound is returned when a node or edge does not exist.
Functions ¶
func ChunkText ¶
ChunkText splits text into overlapping chunks based on a token budget. Uses a simple approximation of 1 token per 4 characters. Returns nil if the text is at or below the threshold, or if chunkTokens is non-positive (callers misconfiguring chunkSize=0 previously could trigger an infinite loop when nextStart didn't advance past start).
func IsStructuralEdge ¶
IsStructuralEdge returns true for edge types that represent structural relationships rather than semantic ones. Structural edges are excluded from semantic edge counts and graph-based scoring.
func MarshalEdge ¶
MarshalEdge encodes an edge to a deterministic byte representation. Format: [id][source_id][target_id][type][weight:8][properties_bytes]
func MarshalNode ¶
MarshalNode encodes a node to a deterministic byte representation. Format: [id_length:4][id][properties_bytes]
func NodeHashInCommit ¶
NodeHashInCommit returns the content hash for a specific node ID in a commit. Uses prolly tree lookup for v1 commits (O(log N)).
Types ¶
type ActivationConfig ¶
ActivationConfig controls spreading activation behavior.
type BboltEdgeStore ¶
type BboltEdgeStore struct {
// contains filtered or unexported fields
}
BboltEdgeStore is a disk-backed EdgeStore using bbolt (D25).
Bucket layout:
edges -> edge_id -> serialized Edge (MarshalEdge format) adj:out -> node_id -> encoded edge ID list adj:in -> node_id -> encoded edge ID list adj:type -> edge_type -> encoded edge ID list
An LRU cache holds recently accessed edges to avoid repeated bbolt reads for hot paths (graph traversal neighborhoods).
Concurrency: Put/Delete take no *bolt.Tx (open their own Update); PutTx/DeleteTx accept the caller's tx + an optional *EdgeBatch adjacency cache. Removes the stashed-pointer race class.
func NewBboltEdgeStore ¶
func NewBboltEdgeStore(db *bolt.DB, cacheCapacity int) (*BboltEdgeStore, error)
NewBboltEdgeStore opens or creates a bbolt-backed edge store.
func (*BboltEdgeStore) ByType ¶
func (s *BboltEdgeStore) ByType(edgeType string) []*Edge
func (*BboltEdgeStore) Clear ¶
func (s *BboltEdgeStore) Clear()
Clear deletes every edge bucket and empties the in-memory cache.
Caller is expected to hold the engine write lock so no concurrent Get/Put hits the cache during the swap. Even so, the cache is emptied in place via reset() instead of pointer-reassigning the cache field -- the latter would race with Get callers that snapshot the field before the swap.
func (*BboltEdgeStore) Count ¶
func (s *BboltEdgeStore) Count() int
func (*BboltEdgeStore) Delete ¶
func (s *BboltEdgeStore) Delete(id string)
Delete removes an edge via its own tx.
func (*BboltEdgeStore) DeleteTx ¶
func (s *BboltEdgeStore) DeleteTx(tx *bolt.Tx, batch *EdgeBatch, id string)
DeleteTx removes an edge via the caller's tx + optional *EdgeBatch.
func (*BboltEdgeStore) FlushBatchTx ¶
func (s *BboltEdgeStore) FlushBatchTx(tx *bolt.Tx, batch *EdgeBatch)
FlushBatchTx writes the *EdgeBatch's cached adjacency lists back to bbolt via tx. Safe with nil batch (no-op).
func (*BboltEdgeStore) ForEach ¶
func (s *BboltEdgeStore) ForEach(fn func(e *Edge))
func (*BboltEdgeStore) From ¶
func (s *BboltEdgeStore) From(nodeID string) []*Edge
func (*BboltEdgeStore) Put ¶
func (s *BboltEdgeStore) Put(e *Edge)
Put stores an edge via its own bbolt Update.
func (*BboltEdgeStore) PutTx ¶
func (s *BboltEdgeStore) PutTx(tx *bolt.Tx, batch *EdgeBatch, e *Edge)
PutTx stores an edge via the caller's tx + optional *EdgeBatch.
func (*BboltEdgeStore) To ¶
func (s *BboltEdgeStore) To(nodeID string) []*Edge
type Commit ¶
type Commit struct {
Version int `json:"version"`
Hash string `json:"hash"`
Parent string `json:"parent,omitempty"`
Timestamp time.Time `json:"timestamp"`
Message string `json:"message"`
NodeTreeRoot string `json:"node_tree_root,omitempty"`
EdgeTreeRoot string `json:"edge_tree_root,omitempty"`
// Persisted index roots (content-addressed chunks).
// Omitempty ensures backward compatibility with older commits.
BM25Root string `json:"bm25_root,omitempty"` // legacy single-index (read as bm25Full)
BM25FullRoot string `json:"bm25_full_root,omitempty"` // content_full BM25 index
BM25MediumRoot string `json:"bm25_medium_root,omitempty"` // content_medium BM25 index
BM25ShortRoot string `json:"bm25_short_root,omitempty"` // content_short BM25 index
VecRoot string `json:"vec_root,omitempty"`
PropRoot string `json:"prop_root,omitempty"`
EdgeAdjRoot string `json:"edge_adj_root,omitempty"`
// NodeHashes/EdgeHashes retained for reading v0 commits only.
NodeHashes []string `json:"node_hashes,omitempty"`
EdgeHashes []string `json:"edge_hashes,omitempty"`
// Structured per-commit actions (D3). Optional; old commits
// deserialize with Actions == nil. Omitempty on write keeps
// pre-D3 consumers readable and bounds commit JSON size.
Actions []CommitAction `json:"actions,omitempty"`
}
Commit is an immutable snapshot of the graph state.
func LoadCommitMeta ¶
LoadCommitMeta reads a commit's JSON from storage without mutating graph state. Used by callers that only need commit-level fields (parent, timestamp, index roots) -- chain traversal, timestamp backfill, history walkers -- and want to avoid the prolly-tree load that full (*Graph).Load performs.
type CommitAction ¶
type CommitAction struct {
Kind string `json:"kind"` // canonical Action* constant (see below)
RecordID string `json:"record_id,omitempty"` // target record when action is record-scoped
Field string `json:"field,omitempty"` // target property when action is field-scoped
}
CommitAction is a structured descriptor of an intent-level change carried by a commit. Unlike the free-form Commit.Message, actions are addressable per-record and filterable by Kind (D3). A single commit may carry many actions (e.g. a curation cycle touching multiple records, a batch collection add, a migration sweep).
Emission is loose: callers populate the slice at each `Save` site, the server trusts the contents, and a future CI lint enforces coverage. The field is omitempty so existing commits serialize unchanged and old-binary reads of new commits fall back to Message-based filtering.
type DiffResult ¶
type DiffResult struct {
// Added: entries in the new commit but not the old (key=node/edge ID, value=content hash).
Added []storage.ProllyEntry `json:"added,omitempty"`
// Removed: entries in the old commit but not the new.
Removed []storage.ProllyEntry `json:"removed,omitempty"`
}
DiffResult describes the structural differences between two commits.
func DiffCommits ¶
func DiffCommits(s *storage.Store, oldCommit, newCommit *Commit) (DiffResult, error)
DiffCommits computes the structural difference between two commits using prolly tree diff. For v1 commits, this efficiently skips unchanged subtrees. Falls back to flat list comparison for v0.
A nil oldCommit means "no prior state" -- every entry in newCommit is reported as Added. Callers diffing against chain-root (empty Since) rely on this.
type Edge ¶
type Edge struct {
ID string
SourceID string
TargetID string
Type string
Weight float64
Properties Properties
}
Edge is a directed relationship between two nodes. Edges are first-class objects with their own ID, type, weight, and optional properties.
func UnmarshalEdge ¶
UnmarshalEdge decodes an edge from bytes.
type EdgeBatch ¶
type EdgeBatch struct {
// contains filtered or unexported fields
}
EdgeBatch bundles the in-batch adjacency cache. addToEdgeIDList decoded, linear-scanned, sorted, and re-encoded the full edge ID list for each single-item write -- O(K log K) per edge with K being the node's current degree. Bulk-loading a node with K edges was O(K^2 log K). These maps buffer decoded adjacency lists per bucket; FlushBatchTx flushes each dirty key once.
Pass via PutTx/DeleteTx and flush via FlushBatchTx when done. A nil *EdgeBatch disables caching and falls back to per-call encode/ decode.
func NewEdgeBatch ¶
func NewEdgeBatch() *EdgeBatch
NewEdgeBatch creates an empty adjacency cache for use with a single shared bbolt transaction. The caller flushes via FlushBatchTx.
type EdgeStore ¶
type EdgeStore interface {
// Put stores an edge and updates adjacency indexes via its own tx.
Put(e *Edge)
// PutTx stores an edge via the caller's tx + optional *EdgeBatch.
// In-memory impls ignore tx and batch.
PutTx(tx *bolt.Tx, batch *EdgeBatch, e *Edge)
// Get retrieves an edge by ID.
Get(id string) (*Edge, bool)
// Delete removes an edge and updates adjacency indexes via its own tx.
Delete(id string)
// DeleteTx removes an edge via the caller's tx + optional *EdgeBatch.
DeleteTx(tx *bolt.Tx, batch *EdgeBatch, id string)
// From returns all outbound edges from a node.
From(nodeID string) []*Edge
// To returns all inbound edges to a node.
To(nodeID string) []*Edge
// ByType returns all edges of the given type.
ByType(edgeType string) []*Edge
// Count returns the total number of edges.
Count() int
// ForEach iterates all edges in unspecified order.
ForEach(fn func(e *Edge))
// Clear removes all edges and adjacency data. Used during Load
// to reset state before repopulating from the prolly tree.
Clear()
}
EdgeStore abstracts edge storage and adjacency index operations. The Graph delegates edge CRUD and traversal queries to this interface.
Implementations: MemoryEdgeStore (in-memory maps, current default), and BboltEdgeStore (bbolt-backed).
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is a property graph engine backed by a content-addressed store. Nodes are lazily loaded from a prolly tree on first access and cached in memory. Edges are loaded at startup (MemoryEdgeStore) or on demand (BboltEdgeStore).
The graph tracks which nodes and edges have been modified since the last save (dirty tracking), enabling incremental persistence. The nodeHashes/edgeHashes maps cache content hashes from the previous save, so only dirty items need re-marshaling.
The graph is not thread-safe. The server layer handles write serialization.
func NewWithCapacity ¶
func NewWithCapacity(cacheCapacity int, opts ...GraphOption) *Graph
NewWithCapacity creates a graph with a specific node cache capacity. 0 means unlimited.
func (*Graph) AddEdge ¶
func (g *Graph) AddEdge(sourceID, targetID, edgeType string, weight float64, props Properties) (*Edge, error)
AddEdge creates a new edge between two existing nodes via the edge store's own transaction. Both source and target nodes must exist. Weight should be in [0.0, 1.0]. Properties are cloned on creation.
func (*Graph) AddEdgeTx ¶
func (g *Graph) AddEdgeTx(tx *bolt.Tx, batch *EdgeBatch, sourceID, targetID, edgeType string, weight float64, props Properties) (*Edge, error)
AddEdgeTx is AddEdge via the caller's bbolt transaction + optional *EdgeBatch cache. When tx and batch are both nil, falls back to the edge store opening its own Update (non-batched path). When non-nil, writes go through the bbolt-backed store's PutTx so the shared tx is used and the adjacency cache amortizes re-encode cost. In-memory edge stores ignore tx/batch. See D40.
func (*Graph) AddNode ¶
func (g *Graph) AddNode(props Properties) *Node
AddNode creates a new node with the given properties and returns it. The node is assigned a new ULID. Properties are cloned on creation.
func (*Graph) AddNodeWithIDForTest ¶
func (g *Graph) AddNodeWithIDForTest(id string, props Properties) *Node
AddNodeWithIDForTest creates a node with a caller-chosen ID. Exists only to let tests construct the record-deleted-then-recreated-with- same-ID scenario (RC-4 regression) that no user-facing API path produces. Do not call from production code -- the ID collision risk defeats the ULID invariant.
func (*Graph) AllNodeIDs ¶
AllNodeIDs returns all node IDs in the graph. Order is not guaranteed. In lazy mode, iterates the prolly tree for IDs.
Prefer NodeIterator for new code -- it avoids the intermediate slice.
func (*Graph) ClearDirty ¶
func (g *Graph) ClearDirty()
ClearDirty resets all dirty tracking state. Called after a successful save.
func (*Graph) DeleteEdge ¶
DeleteEdge removes an edge and updates all indexes.
func (*Graph) DeleteNode ¶
DeleteNode removes a node and all its inbound and outbound edges (cascading deletion). Returns ErrNotFound if the node doesn't exist. Lazily loads the node if needed.
func (*Graph) EdgesByType ¶
EdgesByType returns all edges of the given type.
func (*Graph) ForEachEdge ¶
ForEachEdge iterates every edge in the store in unspecified order, calling fn for each. Avoids the per-node EdgesFrom/EdgesTo round trips when callers genuinely need every edge (e.g. Validate).
func (*Graph) GetNode ¶
GetNode returns the node with the given ID, or nil and false if not found. When the graph has a backing store (after Load), cache misses trigger a lazy load from the prolly tree. Accessed nodes are promoted in the LRU; eviction may remove a clean (non-dirty) node from the cache.
Lazy-load I/O happens outside the cache lock so concurrent cache hits aren't blocked on disk reads. After the load, we re-check under the lock in case another goroutine raced us to populate the same entry.
func (*Graph) IsDirty ¶
IsDirty reports whether any nodes or edges have been modified since the last save.
func (*Graph) IsStructuralChild ¶
IsStructuralChild returns true if a node has an outbound structural edge (chunk_of or section_of), meaning it is a chunk or section of another record.
func (*Graph) Load ¶
Load restores graph state from a commit. For v1 commits, nodes are NOT loaded eagerly -- they are lazily loaded from the prolly tree on first access via GetNode. Edges are fully loaded since they're lightweight and needed for adjacency indexes.
Handles both v0 (flat hash lists) and v1 (prolly tree) commit formats. v0 commits still load everything eagerly since they lack prolly tree support for single-key lookup.
func (*Graph) MarshalEdgeAdjacency ¶
MarshalEdgeAdjacency serializes the three edge adjacency maps (outEdges, inEdges, typeEdges) into a binary format. This allows EdgesFrom/EdgesTo to work at startup without loading all edges.
func (*Graph) NodeCount ¶
NodeCount returns the number of nodes in the graph. In lazy mode, this returns the count from the prolly tree (which includes nodes not yet loaded into the cache).
func (*Graph) NodeIDSet ¶
NodeIDSet returns a set of all node IDs without loading node data. Uses the in-memory nodeHashes map (populated at Load time) so this is O(n) in IDs only, no disk I/O.
func (*Graph) NodeIterator ¶
func (g *Graph) NodeIterator() NodeIterator
NodeIterator returns an iterator over all nodes in the graph. In lazy mode, iterates prolly tree entries and loads each node on demand. In eager mode (no backing store), iterates the in-memory map.
func (*Graph) PrepareCommit ¶
func (g *Graph) PrepareCommit(s *storage.Store, parent string, message string, actions []CommitAction, pCfg ...storage.ProllyConfig) (*Commit, error)
PrepareCommit persists all dirty/new graph state (nodes, edges, prolly trees) into the store and returns a *Commit with NodeTreeRoot and EdgeTreeRoot populated. The commit chunk itself is NOT yet written -- the caller may set additional fields (e.g. engine-managed index roots) on the returned commit, then call WriteCommit to persist.
PrepareCommit advances g.lastNodeTreeRoot and g.lastEdgeTreeRoot so subsequent saves apply incremental updates against the freshly persisted trees. ClearDirty runs in WriteCommit, after the commit chunk lands -- not here -- so dirty state is preserved if the caller fails between Prepare and Write.
func (*Graph) RecordAccess ¶
func (g *Graph) RecordAccess(nodeID string, now time.Time, cfg ActivationConfig)
RecordAccess updates a node's access metadata and spreads activation to its one-hop neighbors. Call this when a node is returned to a consumer (search result, inspect, etc.).
Direct access: increments access_count, sets last_accessed to now. Neighbor activation: for each edge from the accessed node, adds base_amount * edge_weight * attenuation_factor to the neighbor's activation_boost.
Lookups go through GetNode so the call works correctly in lazy mode (evicted neighbors are loaded back; previously they would silently be skipped). Mutations of n.Properties assume the engine write lock is held by the caller -- the engine convention for any code path that modifies node state.
func (*Graph) RemoveEdgeProperty ¶
RemoveEdgeProperty removes a property from an edge.
func (*Graph) RemoveNodeProperty ¶
RemoveNodeProperty removes a property from a node. No error if the property doesn't exist. Lazily loads the node if needed.
func (*Graph) Save ¶
func (g *Graph) Save(s *storage.Store, parent string, message string, pCfg ...storage.ProllyConfig) (*Commit, error)
Save persists the current graph state as a commit to the store. Uses dirty tracking to only marshal modified nodes/edges. The full entry maps (nodeHashes/edgeHashes) are rebuilt for the prolly tree, but unchanged chunks deduplicate via content-addressing.
Equivalent to SaveWithActions with no D3 action descriptors. Kept for source-compatibility with pre-Phase-3 tests and callers that don't carry structured actions.
func (*Graph) SaveWithActions ¶
func (g *Graph) SaveWithActions(s *storage.Store, parent string, message string, actions []CommitAction, pCfg ...storage.ProllyConfig) (*Commit, error)
SaveWithActions is Save extended with the optional D3 structured action descriptor list. Empty slice / nil = no structured actions (commit is filterable by Message prefix only). Callers that emit actions (api/ cluster, future curation/ cluster) invoke this directly; engine.Save routes here via its variadic actions arg.
SaveWithActions is the single-call form -- it composes PrepareCommit and WriteCommit with no fields set in between. Callers (e.g. core engine) that need to attach engine-managed index roots before the commit chunk lands call PrepareCommit + WriteCommit directly to avoid a per-save orphan commit chunk.
func (*Graph) SemanticEdgeCount ¶
SemanticEdgeCount returns the total edge count (in + out) excluding structural edges (chunk_of, section_of).
func (*Graph) SetEdgeProperty ¶
SetEdgeProperty sets a single property on an edge.
func (*Graph) SetEdgeWeight ¶
SetEdgeWeight updates an edge's weight.
func (*Graph) SetNodeProperty ¶
SetNodeProperty sets a single property on a node. Creates the property if absent, overwrites if present. Lazily loads the node if needed.
func (*Graph) Traverse ¶
func (g *Graph) Traverse(startID string, opts TraverseOptions) Subgraph
Traverse performs a breadth-first traversal from the given node, returning all reachable nodes and edges within the given depth. Follows both outbound and inbound edges.
func (*Graph) UnmarshalEdgeAdjacency ¶
UnmarshalEdgeAdjacency restores the edge adjacency maps from binary data. Clears existing adjacency state.
func (*Graph) WriteCommit ¶
WriteCommit serializes c, writes it as a content-addressed chunk, sets c.Hash, and clears dirty tracking on success. Pair with PrepareCommit -- typical flow is PrepareCommit, populate any engine-managed fields (index roots), then WriteCommit. Calling WriteCommit twice on the same commit writes two chunks and orphans the first; the engine path writes once.
type GraphOption ¶
type GraphOption func(*Graph)
GraphOption configures graph creation.
func WithEdgeStore ¶
func WithEdgeStore(es EdgeStore) GraphOption
WithEdgeStore injects an external EdgeStore. If not provided, a MemoryEdgeStore is used (the default for backward compatibility).
type MemoryEdgeStore ¶
type MemoryEdgeStore struct {
// contains filtered or unexported fields
}
MemoryEdgeStore is an in-memory EdgeStore using Go maps.
func NewMemoryEdgeStore ¶
func NewMemoryEdgeStore() *MemoryEdgeStore
NewMemoryEdgeStore creates an empty in-memory edge store.
func (*MemoryEdgeStore) ByType ¶
func (s *MemoryEdgeStore) ByType(edgeType string) []*Edge
func (*MemoryEdgeStore) Clear ¶
func (s *MemoryEdgeStore) Clear()
func (*MemoryEdgeStore) Count ¶
func (s *MemoryEdgeStore) Count() int
func (*MemoryEdgeStore) Delete ¶
func (s *MemoryEdgeStore) Delete(id string)
func (*MemoryEdgeStore) DeleteTx ¶
func (s *MemoryEdgeStore) DeleteTx(_ *bolt.Tx, _ *EdgeBatch, id string)
DeleteTx mirrors Delete; the in-memory impl ignores tx and batch.
func (*MemoryEdgeStore) ForEach ¶
func (s *MemoryEdgeStore) ForEach(fn func(e *Edge))
func (*MemoryEdgeStore) From ¶
func (s *MemoryEdgeStore) From(nodeID string) []*Edge
func (*MemoryEdgeStore) InEdgeIDs ¶
func (s *MemoryEdgeStore) InEdgeIDs() map[string]map[string]struct{}
InEdgeIDs returns the raw set of edge IDs to a target node.
func (*MemoryEdgeStore) OutEdgeIDs ¶
func (s *MemoryEdgeStore) OutEdgeIDs() map[string]map[string]struct{}
OutEdgeIDs returns the raw set of edge IDs from a source node. Used by MarshalEdgeAdjacency and other internal operations that need the adjacency index directly.
func (*MemoryEdgeStore) Put ¶
func (s *MemoryEdgeStore) Put(e *Edge)
func (*MemoryEdgeStore) PutTx ¶
func (s *MemoryEdgeStore) PutTx(_ *bolt.Tx, _ *EdgeBatch, e *Edge)
PutTx mirrors Put; the in-memory impl ignores tx and batch.
func (*MemoryEdgeStore) To ¶
func (s *MemoryEdgeStore) To(nodeID string) []*Edge
func (*MemoryEdgeStore) TypeEdgeIDs ¶
func (s *MemoryEdgeStore) TypeEdgeIDs() map[string]map[string]struct{}
TypeEdgeIDs returns the raw set of edge IDs by type.
type Node ¶
type Node struct {
ID string
Properties Properties
}
Node is a vertex in the property graph. It has a stable ULID and a set of typed properties. The graph engine treats all nodes identically -- "types" like knowledge record, concept node, and chunk node are conventions enforced by higher layers through property values.
func UnmarshalNode ¶
UnmarshalNode decodes a node from bytes.
type NodeIterator ¶
NodeIterator pages through nodes without full materialization. The current in-memory implementation wraps a slice. A future lazy implementation will cursor through the prolly tree.
Usage:
it := g.NodeIterator()
defer it.Close()
for it.Next() {
n := it.Node()
// use n
}
type NodeReader ¶
type NodeReader interface {
GetNode(id string) (*Node, bool)
NodeIterator() NodeIterator
NodeIDSet() map[string]struct{}
NodeCount() int
EdgeCount() int
EdgesFrom(nodeID string) []*Edge
EdgesTo(nodeID string) []*Edge
IsStructuralChild(id string) bool
SemanticEdgeCount(id string) int
}
NodeReader is the read interface for graph access. All read-side consumers should accept this interface rather than *Graph directly.
The graph loads nodes lazily from the prolly tree with LRU caching. Callers that go through NodeReader work with any implementation unchanged.
type Properties ¶
Properties is a map of named properties. A key is either present with a value or absent. No nulls.
func UnmarshalProperties ¶
func UnmarshalProperties(data []byte) (Properties, error)
UnmarshalProperties decodes a Properties map from bytes.
func (Properties) GetFloat64 ¶
func (ps Properties) GetFloat64(key string) (float64, bool)
func (Properties) GetStringList ¶
func (ps Properties) GetStringList(key string) ([]string, bool)
func (Properties) GetTimestamp ¶
func (ps Properties) GetTimestamp(key string) (time.Time, bool)
func (Properties) MarshalBinary ¶
func (ps Properties) MarshalBinary() ([]byte, error)
MarshalBinary encodes a Properties map to a deterministic byte representation. Keys are sorted lexicographically for deterministic output (required for content-addressed storage).
type Property ¶
type Property struct {
Type PropertyType
// contains filtered or unexported fields
}
Property is a typed value. Exactly one of the typed fields is valid, determined by Type. This is a value type -- copy freely.
func BoolProperty ¶
func BytesProperty ¶
func Float64Property ¶
func Int64Property ¶
func StringListProperty ¶
func StringProperty ¶
func TimestampProperty ¶
func UnmarshalProperty ¶
UnmarshalProperty decodes a Property from bytes produced by MarshalBinary.
func VectorProperty ¶
func (Property) Compare ¶
Compare returns -1, 0, or 1 for ordered types (String, Float64, Int64, Timestamp). Panics for unordered types (Bool, Vector, StringList, Bytes) or if the types don't match.
func (Property) FormatValue ¶
FormatValue returns a human-readable string representation of the property value.
func (Property) MarshalBinary ¶
MarshalBinary encodes a Property to a deterministic byte representation. Format: [type_byte] [type-specific payload]
func (Property) String ¶
String implements fmt.Stringer with a human-readable rendering of the property value. Never panics. Use StringValue for the typed accessor that asserts Type == TypeString.
func (Property) StringList ¶
func (Property) StringValue ¶
StringValue returns the underlying string. Panics if Type != TypeString. Use Properties.GetString for a safe accessor that returns (value, ok).
String (without Value) is the fmt.Stringer implementation and never panics; reaching for the panicking variant from a fmt/log site is the bug this rename was designed to prevent.
type PropertyType ¶
type PropertyType uint8
PropertyType identifies the type of a property value.
const ( TypeString PropertyType = 1 TypeFloat64 PropertyType = 2 TypeInt64 PropertyType = 3 TypeBool PropertyType = 4 TypeTimestamp PropertyType = 5 TypeVector PropertyType = 6 TypeStringList PropertyType = 7 TypeBytes PropertyType = 8 )
func (PropertyType) String ¶
func (t PropertyType) String() string
type Section ¶
type Section struct {
Heading string // section heading (empty if split by paragraphs)
Text string // full section content including heading line
}
Section is a semantically coherent portion of a document, split at structural boundaries (headings, numbered sections, paragraphs).
func SplitSections ¶
SplitSections splits text into semantically coherent sections based on structural cues. Detection priority: markdown headings, numbered sections, HTML headings, paragraph breaks. Sections are merged or sub-split to stay within [minChars, maxChars].
Returns nil if text is shorter than minChars (no splitting needed).
type Subgraph ¶
type Subgraph struct {
Nodes []SubgraphNode `json:"nodes"`
Edges []SubgraphEdge `json:"edges"`
}
Subgraph is the result of a graph traversal.
type SubgraphEdge ¶
type SubgraphEdge struct {
Source string `json:"source"`
Target string `json:"target"`
Type string `json:"type"`
Weight float64 `json:"weight"`
}
SubgraphEdge is an edge in a traversal result.
type SubgraphNode ¶
type SubgraphNode struct {
ID string `json:"id"`
Keywords []string `json:"keywords,omitempty"`
SummaryShort string `json:"summary_short,omitempty"`
}
SubgraphNode is a node in a traversal result.
type TSIndex ¶
type TSIndex struct {
// contains filtered or unexported fields
}
TSIndex is a bbolt-backed index mapping commit timestamps to commit hashes (D7). Used by temporal queries that need to find commits by wall-clock time instead of walking the parent chain from HEAD.
Bucket layout:
commit_timestamps -> tsKey(timestamp, hash[:12]) -> full commit hash commit_timestamps_meta -> reserved for future sentinels (unused in Phase 1)
The key encodes time as 8-byte big-endian unix nanoseconds + '#' + up-to-12 char hash prefix. Big-endian byte order guarantees that lexicographic key order equals chronological order, so bbolt cursor Seek gives O(log N) snap-to-prior lookups and range scans. RFC3339Nano string keys were considered and rejected because Go drops trailing zero fractional digits, which breaks the lexicographic==chronological invariant.
Concurrency: Put opens its own bbolt Update tx; PutTx accepts the caller's tx. CommitAt / CommitsBetween always open their own View; no tx argument.
func NewTSIndex ¶
NewTSIndex opens or creates the timestamp index buckets.
func (*TSIndex) CommitAt ¶
CommitAt returns the full hash of the commit at or strictly before t (snap-to-prior semantics, following Fluree's as-of-date contract). Returns ("", false) when the bucket is empty or t is before the earliest indexed commit.
func (*TSIndex) CommitBefore ¶
CommitBefore returns the full hash of the latest commit STRICTLY before t. Unlike CommitAt, a commit at exactly t is NOT returned. Useful for diff since-boundaries: a diff window "since X" should include commits at X, so sinceCommit must be before X.
func (*TSIndex) CommitsBetween ¶
CommitsBetween returns the full hashes of commits with timestamps in [start, end] (inclusive both ends), in chronological order. Returns nil for an empty range (end < start) or no matches.
func (*TSIndex) Count ¶
Count returns the number of entries in the timestamp index. Useful for diagnostics and the `gramaton migrate` progress log.
type TraverseOptions ¶
type TraverseOptions struct {
MaxDepth int
EdgeTypes []string // nil means all types
MinEdgeWeight float64
}
TraverseOptions controls graph traversal behavior.