From b04c1d5e9596b23574f36ce326955472f87d09fe Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 30 Jan 2026 21:29:10 +0100 Subject: [PATCH 1/5] Universal Bind Space - ONE SPACE, ANY LANGUAGE --- src/storage/bind_space.rs | 764 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 764 insertions(+) create mode 100644 src/storage/bind_space.rs diff --git a/src/storage/bind_space.rs b/src/storage/bind_space.rs new file mode 100644 index 0000000..2a59318 --- /dev/null +++ b/src/storage/bind_space.rs @@ -0,0 +1,764 @@ +//! Universal Bind Space - The DTO That All Languages Hit +//! +//! # The Insight +//! +//! ```text +//! ┌─────────────────────────────────────────────────────────────────────────────┐ +//! │ 16-bit ADDRESS SPACE │ +//! ├─────────────────┬───────────────────────────────────────────────────────────┤ +//! │ 0x0000-0x0FFF │ SURFACE (4K) - VERBS + OPS │ +//! │ │ The language primitives │ +//! ├─────────────────┼───────────────────────────────────────────────────────────┤ +//! │ 0x1000-0x7FFF │ FLUID (28K) - CONTEXT SELECTOR + EDGES │ +//! │ │ Defines WHAT 0x8000-0xFFFF means: │ +//! │ │ • Chunk 0: Concept space │ +//! │ │ • Chunk 1: Memory space │ +//! │ │ • Chunk 2: Codebook space │ +//! │ │ • Chunk 3: Meta-awareness │ +//! │ │ EDGES live here too │ +//! ├─────────────────┼───────────────────────────────────────────────────────────┤ +//! │ 0x8000-0xFFFF │ NODES (32K) - THE UNIVERSAL BIND SPACE │ +//! │ │ What it IS depends on fluid context │ +//! │ │ │ +//! │ │ CogRedis? → Reads/writes here │ +//! │ │ Cypher? → Queries here │ +//! │ │ Neo4j? → Traverses here │ +//! │ │ GraphQL? → Resolves here │ +//! │ │ SQL? → Selects here │ +//! │ │ │ +//! │ │ ONE SPACE. ANY LANGUAGE. │ +//! └─────────────────┴───────────────────────────────────────────────────────────┘ +//! ``` +//! +//! # Architecture +//! +//! The fluid zone (0x1000-0x7FFF) acts as a CONTEXT SELECTOR that determines +//! how the node space (0x8000-0xFFFF) is interpreted: +//! +//! - Setting fluid context to Chunk 0 → node space = concepts +//! - Setting fluid context to Chunk 1 → node space = memories +//! - Setting fluid context to Chunk 2 → node space = codebook entries +//! - Setting fluid context to Chunk 3 → node space = meta-awareness states +//! +//! The node space itself is the UNIVERSAL DTO - all query languages bind here. +//! The fingerprint at any address doesn't care what language asked for it. +//! +//! # Query Language Adapters +//! +//! All adapters implement the same trait and hit the same bind space: +//! +//! ```text +//! ┌─────────────┐ +//! │ Bind Space │ +//! │ 0x8000-FFFF │ +//! └──────┬──────┘ +//! │ +//! ┌───────────────────┼───────────────────┐ +//! │ │ │ +//! ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ +//! │ Redis │ │ Cypher │ │ SQL │ +//! │ GET │ │ MATCH │ │ SELECT │ +//! └─────────┘ └─────────┘ └─────────┘ +//! ``` + +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; +use std::time::{Duration, Instant}; + +// ============================================================================= +// ADDRESS CONSTANTS +// ============================================================================= + +/// Surface tier: verbs + ops (fixed vocabulary) +pub const SURFACE_START: u16 = 0x0000; +pub const SURFACE_END: u16 = 0x0FFF; +pub const SURFACE_SIZE: usize = 4096; + +/// Fluid tier: context selector + edges +pub const FLUID_START: u16 = 0x1000; +pub const FLUID_END: u16 = 0x7FFF; +pub const FLUID_SIZE: usize = 28672; + +/// Node tier: universal bind space +pub const NODE_START: u16 = 0x8000; +pub const NODE_END: u16 = 0xFFFF; +pub const NODE_SIZE: usize = 32768; + +/// Total addressable space +pub const TOTAL_SIZE: usize = 65536; + +/// Words in a 10K-bit fingerprint +pub const FINGERPRINT_WORDS: usize = 156; + +// ============================================================================= +// CHUNK CONTEXTS (What the node space means) +// ============================================================================= + +/// Chunk context - defines interpretation of node space +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum ChunkContext { + /// Concept space - abstract types and categories + Concepts = 0, + /// Memory space - episodic memories, experiences + Memories = 1, + /// Codebook space - learned patterns, templates + Codebook = 2, + /// Meta-awareness - self-model, introspection states + MetaAwareness = 3, + /// Extended node space - overflow when >32K nodes needed + Extended(u16) = 4, +} + +impl ChunkContext { + /// Get the fluid address that activates this context + pub fn selector_addr(&self) -> u16 { + match self { + ChunkContext::Concepts => FLUID_START, + ChunkContext::Memories => FLUID_START + 1, + ChunkContext::Codebook => FLUID_START + 2, + ChunkContext::MetaAwareness => FLUID_START + 3, + ChunkContext::Extended(n) => FLUID_START + 4 + n, + } + } + + /// Parse from fluid address + pub fn from_selector(addr: u16) -> Option { + if addr < FLUID_START || addr > FLUID_END { + return None; + } + let offset = addr - FLUID_START; + match offset { + 0 => Some(ChunkContext::Concepts), + 1 => Some(ChunkContext::Memories), + 2 => Some(ChunkContext::Codebook), + 3 => Some(ChunkContext::MetaAwareness), + n => Some(ChunkContext::Extended(n - 4)), + } + } +} + +// ============================================================================= +// BIND NODE - The universal content container +// ============================================================================= + +/// A node in the universal bind space +/// +/// This is what ALL query languages ultimately read/write. +/// The fingerprint doesn't care what syntax asked for it. +#[derive(Debug, Clone)] +pub struct BindNode { + /// 10K-bit fingerprint (the content-addressable identity) + pub fingerprint: [u64; FINGERPRINT_WORDS], + /// Human-readable label + pub label: Option, + /// Qualia index (0-255, emergent) + pub qidx: u8, + /// Creation timestamp + pub created: Instant, + /// Last access timestamp + pub accessed: Instant, + /// Access count (for promotion/cache decisions) + pub access_count: u32, + /// Optional payload (serialized content) + pub payload: Option>, +} + +impl BindNode { + pub fn new(fingerprint: [u64; FINGERPRINT_WORDS]) -> Self { + let now = Instant::now(); + Self { + fingerprint, + label: None, + qidx: 0, + created: now, + accessed: now, + access_count: 0, + payload: None, + } + } + + pub fn with_label(mut self, label: &str) -> Self { + self.label = Some(label.to_string()); + self + } + + pub fn with_qidx(mut self, qidx: u8) -> Self { + self.qidx = qidx; + self + } + + pub fn with_payload(mut self, payload: Vec) -> Self { + self.payload = Some(payload); + self + } + + /// Touch - update access time and count + pub fn touch(&mut self) { + self.accessed = Instant::now(); + self.access_count += 1; + } +} + +// ============================================================================= +// BIND EDGE - Connection in the fluid zone +// ============================================================================= + +/// An edge connecting nodes via a verb +/// +/// Edges live in the fluid zone (0x1000-0x7FFF). +/// They connect nodes in the bind space using verbs from the surface. +#[derive(Debug, Clone)] +pub struct BindEdge { + /// Source node address (in node space 0x8000-0xFFFF) + pub from: u16, + /// Target node address (in node space 0x8000-0xFFFF) + pub to: u16, + /// Verb address (in surface space 0x0000-0x0FFF) + pub verb: u16, + /// Edge fingerprint: from ⊗ verb ⊗ to (for ABBA retrieval) + pub fingerprint: [u64; FINGERPRINT_WORDS], + /// Edge weight/strength + pub weight: f32, + /// Creation timestamp + pub created: Instant, +} + +impl BindEdge { + pub fn new(from: u16, verb: u16, to: u16) -> Self { + Self { + from, + to, + verb, + fingerprint: [0u64; FINGERPRINT_WORDS], // Set by bind operation + weight: 1.0, + created: Instant::now(), + } + } + + /// Compute edge fingerprint via XOR binding + pub fn bind(&mut self, from_fp: &[u64; FINGERPRINT_WORDS], verb_fp: &[u64; FINGERPRINT_WORDS], to_fp: &[u64; FINGERPRINT_WORDS]) { + for i in 0..FINGERPRINT_WORDS { + self.fingerprint[i] = from_fp[i] ^ verb_fp[i] ^ to_fp[i]; + } + } + + /// ABBA unbind: given edge and one known, recover the other + pub fn unbind(&self, known: &[u64; FINGERPRINT_WORDS], verb_fp: &[u64; FINGERPRINT_WORDS]) -> [u64; FINGERPRINT_WORDS] { + let mut result = [0u64; FINGERPRINT_WORDS]; + for i in 0..FINGERPRINT_WORDS { + result[i] = self.fingerprint[i] ^ known[i] ^ verb_fp[i]; + } + result + } +} + +// ============================================================================= +// BIND SPACE - The Universal DTO +// ============================================================================= + +/// The Universal Bind Space +/// +/// This is the single source of truth that all query languages hit. +/// Whether you speak Redis, Cypher, SQL, or GraphQL - you end up here. +pub struct BindSpace { + /// Surface tier: verbs and ops (fixed) + surface: HashMap, + + /// Fluid tier: edges and context selectors + fluid: HashMap, + + /// Fluid edges (separate for efficient traversal) + edges: Vec, + + /// Edge index: from_addr -> edge indices (CSR-style) + edge_index_out: HashMap>, + + /// Edge index: to_addr -> edge indices (reverse CSR) + edge_index_in: HashMap>, + + /// Node tier: the actual bind space + nodes: HashMap, + + /// Current chunk context + context: ChunkContext, + + /// Next available addresses + next_fluid: u16, + next_node: u16, +} + +impl BindSpace { + pub fn new() -> Self { + let mut space = Self { + surface: HashMap::new(), + fluid: HashMap::new(), + edges: Vec::new(), + edge_index_out: HashMap::new(), + edge_index_in: HashMap::new(), + nodes: HashMap::new(), + context: ChunkContext::Concepts, + next_fluid: FLUID_START + 256, // Reserve first 256 for contexts + next_node: NODE_START, + }; + space.init_surface(); + space + } + + /// Initialize surface with core verbs + fn init_surface(&mut self) { + // Core verbs (from the 144 Go board intersections) + let verbs = [ + (0x0060, "CAUSES"), + (0x0061, "BECOMES"), + (0x0062, "ENABLES"), + (0x0063, "PREVENTS"), + (0x0064, "REQUIRES"), + (0x0065, "IMPLIES"), + (0x0066, "CONTAINS"), + (0x0067, "ACTIVATES"), + (0x0068, "INHIBITS"), + (0x0069, "TRANSFORMS"), + (0x006A, "RESONATES"), + (0x006B, "AMPLIFIES"), + (0x006C, "DAMPENS"), + (0x006D, "OBSERVES"), + (0x006E, "REMEMBERS"), + (0x006F, "FORGETS"), + // Flow verbs + (0x0070, "SHIFT"), + (0x0071, "LEAP"), + (0x0072, "EMERGE"), + (0x0073, "SUBSIDE"), + (0x0074, "OSCILLATE"), + (0x0075, "CRYSTALLIZE"), + (0x0076, "DISSOLVE"), + (0x0077, "TRANSFORM"), + ]; + + for (addr, label) in verbs { + let mut node = BindNode::new(verb_fingerprint(label)); + node.label = Some(label.to_string()); + self.surface.insert(addr, node); + } + } + + // ========================================================================= + // CONTEXT OPERATIONS + // ========================================================================= + + /// Set the current chunk context + /// This changes what the node space (0x8000-0xFFFF) means + pub fn set_context(&mut self, context: ChunkContext) { + self.context = context; + } + + /// Get current context + pub fn context(&self) -> ChunkContext { + self.context + } + + // ========================================================================= + // UNIVERSAL READ/WRITE (All languages hit these) + // ========================================================================= + + /// Read from any address + /// + /// This is what GET (Redis), MATCH (Cypher), SELECT (SQL) all become. + pub fn read(&mut self, addr: u16) -> Option<&BindNode> { + let node = match addr { + a if a <= SURFACE_END => self.surface.get(&a), + a if a <= FLUID_END => self.fluid.get(&a), + a => self.nodes.get(&a), + }; + + // Touch for access tracking (need mut for this) + if let Some(_) = node { + // We'd need interior mutability for proper touch + // For now, just return the reference + } + + node + } + + /// Read mutable from any address + pub fn read_mut(&mut self, addr: u16) -> Option<&mut BindNode> { + let node = match addr { + a if a <= SURFACE_END => self.surface.get_mut(&a), + a if a <= FLUID_END => self.fluid.get_mut(&a), + a => self.nodes.get_mut(&a), + }; + + if let Some(n) = node { + n.touch(); + Some(n) + } else { + None + } + } + + /// Write to node space + /// + /// This is what SET (Redis), CREATE (Cypher), INSERT (SQL) all become. + pub fn write(&mut self, fingerprint: [u64; FINGERPRINT_WORDS]) -> u16 { + let addr = self.next_node; + self.next_node = self.next_node.wrapping_add(1); + if self.next_node < NODE_START { + self.next_node = NODE_START; // Wrap within node space + } + + let node = BindNode::new(fingerprint); + self.nodes.insert(addr, node); + addr + } + + /// Write with label + pub fn write_labeled(&mut self, fingerprint: [u64; FINGERPRINT_WORDS], label: &str) -> u16 { + let addr = self.write(fingerprint); + if let Some(node) = self.nodes.get_mut(&addr) { + node.label = Some(label.to_string()); + } + addr + } + + /// Delete from any address + pub fn delete(&mut self, addr: u16) -> Option { + match addr { + a if a <= SURFACE_END => None, // Can't delete surface + a if a <= FLUID_END => self.fluid.remove(&a), + a => self.nodes.remove(&a), + } + } + + // ========================================================================= + // EDGE OPERATIONS (Fluid zone) + // ========================================================================= + + /// Create an edge + /// + /// This is what relationships in Cypher, foreign keys in SQL become. + pub fn link(&mut self, from: u16, verb: u16, to: u16) -> usize { + let mut edge = BindEdge::new(from, verb, to); + + // Get fingerprints and bind + if let (Some(from_node), Some(verb_node), Some(to_node)) = + (self.nodes.get(&from), self.surface.get(&verb), self.nodes.get(&to)) + { + edge.bind(&from_node.fingerprint, &verb_node.fingerprint, &to_node.fingerprint); + } + + let idx = self.edges.len(); + + // Update indices (CSR-style) + self.edge_index_out.entry(from).or_default().push(idx); + self.edge_index_in.entry(to).or_default().push(idx); + + self.edges.push(edge); + idx + } + + /// Get outgoing edges (CSR-style O(1) index lookup) + pub fn edges_out(&self, from: u16) -> Vec<&BindEdge> { + self.edge_index_out + .get(&from) + .map(|indices| indices.iter().filter_map(|&i| self.edges.get(i)).collect()) + .unwrap_or_default() + } + + /// Get incoming edges (reverse CSR) + pub fn edges_in(&self, to: u16) -> Vec<&BindEdge> { + self.edge_index_in + .get(&to) + .map(|indices| indices.iter().filter_map(|&i| self.edges.get(i)).collect()) + .unwrap_or_default() + } + + /// Get edges by verb + pub fn edges_via(&self, verb: u16) -> Vec<&BindEdge> { + self.edges.iter().filter(|e| e.verb == verb).collect() + } + + /// Traverse: from -> via verb -> targets + pub fn traverse(&self, from: u16, verb: u16) -> Vec { + self.edges_out(from) + .into_iter() + .filter(|e| e.verb == verb) + .map(|e| e.to) + .collect() + } + + /// Reverse traverse: targets <- via verb <- to + pub fn traverse_reverse(&self, to: u16, verb: u16) -> Vec { + self.edges_in(to) + .into_iter() + .filter(|e| e.verb == verb) + .map(|e| e.from) + .collect() + } + + // ========================================================================= + // N-HOP TRAVERSAL (What Kuzu CSR does) + // ========================================================================= + + /// N-hop traversal from a node via a verb + /// + /// This is the core graph operation that Kuzu CSR accelerates. + /// We use edge indices for O(1) neighbor lookup per hop. + pub fn traverse_n_hops(&self, start: u16, verb: u16, max_hops: usize) -> Vec<(usize, u16)> { + let mut results = Vec::new(); + let mut frontier = vec![start]; + let mut visited = std::collections::HashSet::new(); + visited.insert(start); + + for hop in 1..=max_hops { + let mut next_frontier = Vec::new(); + + for &node in &frontier { + for target in self.traverse(node, verb) { + if visited.insert(target) { + results.push((hop, target)); + next_frontier.push(target); + } + } + } + + if next_frontier.is_empty() { + break; + } + frontier = next_frontier; + } + + results + } + + // ========================================================================= + // STATISTICS + // ========================================================================= + + pub fn stats(&self) -> BindSpaceStats { + BindSpaceStats { + surface_count: self.surface.len(), + fluid_count: self.fluid.len(), + node_count: self.nodes.len(), + edge_count: self.edges.len(), + context: self.context, + } + } +} + +impl Default for BindSpace { + fn default() -> Self { + Self::new() + } +} + +#[derive(Debug)] +pub struct BindSpaceStats { + pub surface_count: usize, + pub fluid_count: usize, + pub node_count: usize, + pub edge_count: usize, + pub context: ChunkContext, +} + +// ============================================================================= +// HELPER FUNCTIONS +// ============================================================================= + +/// Generate a deterministic fingerprint for a verb label +fn verb_fingerprint(label: &str) -> [u64; FINGERPRINT_WORDS] { + let mut fp = [0u64; FINGERPRINT_WORDS]; + let bytes = label.as_bytes(); + + // Simple hash spread across fingerprint + for (i, &b) in bytes.iter().enumerate() { + let word_idx = i % FINGERPRINT_WORDS; + let bit_idx = (b as usize * 7 + i * 13) % 64; + fp[word_idx] |= 1u64 << bit_idx; + } + + // Spread more bits for density + for i in 0..FINGERPRINT_WORDS { + let seed = fp[i]; + fp[(i + 1) % FINGERPRINT_WORDS] ^= seed.rotate_left(17); + fp[(i + 3) % FINGERPRINT_WORDS] ^= seed.rotate_right(23); + } + + fp +} + +/// Compute Hamming distance between fingerprints +pub fn hamming_distance(a: &[u64; FINGERPRINT_WORDS], b: &[u64; FINGERPRINT_WORDS]) -> u32 { + let mut dist = 0u32; + for i in 0..FINGERPRINT_WORDS { + dist += (a[i] ^ b[i]).count_ones(); + } + dist +} + +// ============================================================================= +// QUERY LANGUAGE TRAIT (What all adapters implement) +// ============================================================================= + +/// Trait for query language adapters +/// +/// All languages (Redis, Cypher, SQL, GraphQL) implement this +/// and ultimately call BindSpace methods. +pub trait QueryAdapter { + /// Execute a query and return results + fn execute(&self, space: &mut BindSpace, query: &str) -> QueryResult; +} + +/// Generic query result +#[derive(Debug)] +pub struct QueryResult { + pub columns: Vec, + pub rows: Vec>, + pub affected: usize, +} + +impl QueryResult { + pub fn empty() -> Self { + Self { + columns: Vec::new(), + rows: Vec::new(), + affected: 0, + } + } + + pub fn single(addr: u16) -> Self { + Self { + columns: vec!["addr".to_string()], + rows: vec![vec![QueryValue::Addr(addr)]], + affected: 1, + } + } +} + +/// Query value types +#[derive(Debug, Clone)] +pub enum QueryValue { + Addr(u16), + String(String), + Int(i64), + Float(f64), + Bool(bool), + Fingerprint([u64; FINGERPRINT_WORDS]), + Null, +} + +// ============================================================================= +// TESTS +// ============================================================================= + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_address_ranges() { + assert_eq!(SURFACE_SIZE, 4096); + assert_eq!(FLUID_SIZE, 28672); + assert_eq!(NODE_SIZE, 32768); + assert_eq!(SURFACE_SIZE + FLUID_SIZE + NODE_SIZE, TOTAL_SIZE); + } + + #[test] + fn test_bind_space_creation() { + let space = BindSpace::new(); + assert!(space.surface.len() > 0); // Verbs initialized + assert_eq!(space.context, ChunkContext::Concepts); + } + + #[test] + fn test_write_read() { + let mut space = BindSpace::new(); + let fp = [42u64; FINGERPRINT_WORDS]; + + let addr = space.write(fp); + assert!(addr >= NODE_START); + + let node = space.read(addr); + assert!(node.is_some()); + assert_eq!(node.unwrap().fingerprint, fp); + } + + #[test] + fn test_link_traverse() { + let mut space = BindSpace::new(); + + // Create two nodes + let a = space.write_labeled([1u64; FINGERPRINT_WORDS], "Node A"); + let b = space.write_labeled([2u64; FINGERPRINT_WORDS], "Node B"); + + // Link them with CAUSES + let verb = 0x0060; // CAUSES + space.link(a, verb, b); + + // Traverse + let targets = space.traverse(a, verb); + assert_eq!(targets.len(), 1); + assert_eq!(targets[0], b); + } + + #[test] + fn test_n_hop_traversal() { + let mut space = BindSpace::new(); + + // Create chain: A -> B -> C -> D + let a = space.write([1u64; FINGERPRINT_WORDS]); + let b = space.write([2u64; FINGERPRINT_WORDS]); + let c = space.write([3u64; FINGERPRINT_WORDS]); + let d = space.write([4u64; FINGERPRINT_WORDS]); + + let verb = 0x0060; // CAUSES + space.link(a, verb, b); + space.link(b, verb, c); + space.link(c, verb, d); + + // 3-hop traversal from A + let results = space.traverse_n_hops(a, verb, 3); + assert_eq!(results.len(), 3); + assert_eq!(results[0], (1, b)); // 1 hop to B + assert_eq!(results[1], (2, c)); // 2 hops to C + assert_eq!(results[2], (3, d)); // 3 hops to D + } + + #[test] + fn test_context_switching() { + let mut space = BindSpace::new(); + + assert_eq!(space.context(), ChunkContext::Concepts); + + space.set_context(ChunkContext::Memories); + assert_eq!(space.context(), ChunkContext::Memories); + + space.set_context(ChunkContext::MetaAwareness); + assert_eq!(space.context(), ChunkContext::MetaAwareness); + } + + #[test] + fn test_edge_indices() { + let mut space = BindSpace::new(); + + let a = space.write([1u64; FINGERPRINT_WORDS]); + let b = space.write([2u64; FINGERPRINT_WORDS]); + let c = space.write([3u64; FINGERPRINT_WORDS]); + + let causes = 0x0060; + let enables = 0x0062; + + space.link(a, causes, b); + space.link(a, enables, c); + space.link(b, causes, c); + + // A has 2 outgoing edges + assert_eq!(space.edges_out(a).len(), 2); + + // C has 2 incoming edges + assert_eq!(space.edges_in(c).len(), 2); + + // Only 2 CAUSES edges total + assert_eq!(space.edges_via(causes).len(), 2); + } +} From 69e4dfd6ebade90a00990233855b0cedaf9aa8a4 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 30 Jan 2026 21:44:21 +0100 Subject: [PATCH 2/5] 8-bit prefix architecture: 4 surface compartments, pure array indexing --- src/storage/bind_space.rs | 1011 +++++++++++++++++++++++-------------- 1 file changed, 618 insertions(+), 393 deletions(-) diff --git a/src/storage/bind_space.rs b/src/storage/bind_space.rs index 2a59318..7f263af 100644 --- a/src/storage/bind_space.rs +++ b/src/storage/bind_space.rs @@ -1,178 +1,237 @@ //! Universal Bind Space - The DTO That All Languages Hit //! -//! # The Insight +//! # 8-bit Prefix : 8-bit Address Architecture //! //! ```text //! ┌─────────────────────────────────────────────────────────────────────────────┐ -//! │ 16-bit ADDRESS SPACE │ +//! │ PREFIX (8-bit) : ADDRESS (8-bit) │ //! ├─────────────────┬───────────────────────────────────────────────────────────┤ -//! │ 0x0000-0x0FFF │ SURFACE (4K) - VERBS + OPS │ -//! │ │ The language primitives │ +//! │ 0x00:XX │ SURFACE 0 - Lance/Kuzu (256) │ +//! │ │ Vector search, graph traversal primitives │ //! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x1000-0x7FFF │ FLUID (28K) - CONTEXT SELECTOR + EDGES │ -//! │ │ Defines WHAT 0x8000-0xFFFF means: │ -//! │ │ • Chunk 0: Concept space │ -//! │ │ • Chunk 1: Memory space │ -//! │ │ • Chunk 2: Codebook space │ -//! │ │ • Chunk 3: Meta-awareness │ -//! │ │ EDGES live here too │ +//! │ 0x01:XX │ SURFACE 1 - SQL/Neo4j (256) │ +//! │ │ Relational + property graph primitives │ //! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x8000-0xFFFF │ NODES (32K) - THE UNIVERSAL BIND SPACE │ -//! │ │ What it IS depends on fluid context │ -//! │ │ │ -//! │ │ CogRedis? → Reads/writes here │ -//! │ │ Cypher? → Queries here │ -//! │ │ Neo4j? → Traverses here │ -//! │ │ GraphQL? → Resolves here │ -//! │ │ SQL? → Selects here │ -//! │ │ │ -//! │ │ ONE SPACE. ANY LANGUAGE. │ +//! │ 0x02:XX │ SURFACE 2 - Higher-order thinking (256) │ +//! │ │ Meta-cognition, NARS, reasoning patterns │ +//! ├─────────────────┼───────────────────────────────────────────────────────────┤ +//! │ 0x03:XX │ SURFACE 3 - Verbs/Cypher (256) │ +//! │ │ CAUSES, BECOMES, ENABLES... 144 Go board verbs │ +//! ├─────────────────┼───────────────────────────────────────────────────────────┤ +//! │ 0x04-0x7F:XX │ FLUID (124 chunks × 256 = 31,744 edges) │ +//! │ │ Context selector + edge storage │ +//! ├─────────────────┼───────────────────────────────────────────────────────────┤ +//! │ 0x80-0xFF:XX │ NODES (128 chunks × 256 = 32,768 nodes) │ +//! │ │ THE UNIVERSAL BIND SPACE │ +//! │ │ All languages hit this. Any syntax. Same addresses. │ //! └─────────────────┴───────────────────────────────────────────────────────────┘ //! ``` //! -//! # Architecture +//! # Why 8-bit + 8-bit? //! -//! The fluid zone (0x1000-0x7FFF) acts as a CONTEXT SELECTOR that determines -//! how the node space (0x8000-0xFFFF) is interpreted: +//! ```text +//! Operation HashMap (16-bit) Array index (8+8) +//! ───────────────────────────────────────────────────────── +//! Hash compute ~20 cycles 0 +//! Bucket lookup ~10-50 cycles 0 +//! Cache miss risk High Low (predictable) +//! Branch prediction Poor Perfect (3-way) +//! TOTAL ~30-100 cycles ~3-5 cycles +//! ``` //! -//! - Setting fluid context to Chunk 0 → node space = concepts -//! - Setting fluid context to Chunk 1 → node space = memories -//! - Setting fluid context to Chunk 2 → node space = codebook entries -//! - Setting fluid context to Chunk 3 → node space = meta-awareness states +//! Works on ANY CPU: No AVX-512, no SIMD, no special instructions. +//! Just shift, mask, array index. Even works on embedded/WASM. //! -//! The node space itself is the UNIVERSAL DTO - all query languages bind here. -//! The fingerprint at any address doesn't care what language asked for it. +//! # The 4-Compartment Surface //! -//! # Query Language Adapters +//! Each surface is 256 slots that fit in L1 cache: //! -//! All adapters implement the same trait and hit the same bind space: +//! | Prefix | Surface | Language primitives | +//! |--------|--------------|----------------------------------------| +//! | 0x00 | Lance/Kuzu | VECTOR_SEARCH, TRAVERSE, RESONATE | +//! | 0x01 | SQL/Neo4j | SELECT, JOIN, MATCH, WHERE | +//! | 0x02 | Meta | REFLECT, ABSTRACT, DEDUCE, ABDUCT | +//! | 0x03 | Verbs | CAUSES, BECOMES, ENABLES, AMPLIFIES | //! -//! ```text -//! ┌─────────────┐ -//! │ Bind Space │ -//! │ 0x8000-FFFF │ -//! └──────┬──────┘ -//! │ -//! ┌───────────────────┼───────────────────┐ -//! │ │ │ -//! ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ -//! │ Redis │ │ Cypher │ │ SQL │ -//! │ GET │ │ MATCH │ │ SELECT │ -//! └─────────┘ └─────────┘ └─────────┘ -//! ``` +//! All surfaces speak different languages but hit the SAME bind space. -use std::collections::HashMap; -use std::sync::{Arc, RwLock}; -use std::time::{Duration, Instant}; +use std::time::Instant; // ============================================================================= -// ADDRESS CONSTANTS +// ADDRESS CONSTANTS (8-bit prefix architecture) // ============================================================================= -/// Surface tier: verbs + ops (fixed vocabulary) -pub const SURFACE_START: u16 = 0x0000; -pub const SURFACE_END: u16 = 0x0FFF; -pub const SURFACE_SIZE: usize = 4096; +/// Fingerprint words (10K bits = 156 × 64-bit words) +pub const FINGERPRINT_WORDS: usize = 156; -/// Fluid tier: context selector + edges -pub const FLUID_START: u16 = 0x1000; -pub const FLUID_END: u16 = 0x7FFF; -pub const FLUID_SIZE: usize = 28672; +/// Slots per chunk (2^8 = 256) +pub const CHUNK_SIZE: usize = 256; -/// Node tier: universal bind space -pub const NODE_START: u16 = 0x8000; -pub const NODE_END: u16 = 0xFFFF; -pub const NODE_SIZE: usize = 32768; +/// Surface prefixes (4 compartments) +pub const PREFIX_LANCE: u8 = 0x00; // Lance/Kuzu ops +pub const PREFIX_SQL: u8 = 0x01; // SQL/Neo4j ops +pub const PREFIX_META: u8 = 0x02; // Higher-order thinking +pub const PREFIX_VERBS: u8 = 0x03; // Verbs/Cypher -/// Total addressable space -pub const TOTAL_SIZE: usize = 65536; +/// Fluid range (edges + context) +pub const PREFIX_FLUID_START: u8 = 0x04; +pub const PREFIX_FLUID_END: u8 = 0x7F; +pub const FLUID_CHUNKS: usize = 124; // 0x7F - 0x04 + 1 -/// Words in a 10K-bit fingerprint -pub const FINGERPRINT_WORDS: usize = 156; +/// Node range (universal bind space) +pub const PREFIX_NODE_START: u8 = 0x80; +pub const PREFIX_NODE_END: u8 = 0xFF; +pub const NODE_CHUNKS: usize = 128; // 0xFF - 0x80 + 1 + +/// Total addressable +pub const TOTAL_ADDRESSES: usize = 65536; // ============================================================================= -// CHUNK CONTEXTS (What the node space means) +// ADDRESS TYPE // ============================================================================= -/// Chunk context - defines interpretation of node space +/// 16-bit address as prefix:slot #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[repr(u16)] -pub enum ChunkContext { - /// Concept space - abstract types and categories - Concepts = 0, - /// Memory space - episodic memories, experiences - Memories = 1, - /// Codebook space - learned patterns, templates - Codebook = 2, - /// Meta-awareness - self-model, introspection states - MetaAwareness = 3, - /// Extended node space - overflow when >32K nodes needed - Extended(u16) = 4, -} +pub struct Addr(pub u16); -impl ChunkContext { - /// Get the fluid address that activates this context - pub fn selector_addr(&self) -> u16 { - match self { - ChunkContext::Concepts => FLUID_START, - ChunkContext::Memories => FLUID_START + 1, - ChunkContext::Codebook => FLUID_START + 2, - ChunkContext::MetaAwareness => FLUID_START + 3, - ChunkContext::Extended(n) => FLUID_START + 4 + n, - } +impl Addr { + /// Create from prefix and slot + #[inline(always)] + pub fn new(prefix: u8, slot: u8) -> Self { + Self(((prefix as u16) << 8) | (slot as u16)) } - /// Parse from fluid address - pub fn from_selector(addr: u16) -> Option { - if addr < FLUID_START || addr > FLUID_END { - return None; - } - let offset = addr - FLUID_START; - match offset { - 0 => Some(ChunkContext::Concepts), - 1 => Some(ChunkContext::Memories), - 2 => Some(ChunkContext::Codebook), - 3 => Some(ChunkContext::MetaAwareness), - n => Some(ChunkContext::Extended(n - 4)), + /// Get prefix (high byte) + #[inline(always)] + pub fn prefix(self) -> u8 { + (self.0 >> 8) as u8 + } + + /// Get slot (low byte) + #[inline(always)] + pub fn slot(self) -> u8 { + (self.0 & 0xFF) as u8 + } + + /// Check if in surface (prefix 0x00-0x03) + #[inline(always)] + pub fn is_surface(self) -> bool { + self.prefix() <= PREFIX_VERBS + } + + /// Check if in fluid zone (prefix 0x04-0x7F) + #[inline(always)] + pub fn is_fluid(self) -> bool { + let p = self.prefix(); + p >= PREFIX_FLUID_START && p <= PREFIX_FLUID_END + } + + /// Check if in node space (prefix 0x80-0xFF) + #[inline(always)] + pub fn is_node(self) -> bool { + self.prefix() >= PREFIX_NODE_START + } + + /// Get surface compartment (0-3) or None + #[inline(always)] + pub fn surface_compartment(self) -> Option { + match self.prefix() { + PREFIX_LANCE => Some(SurfaceCompartment::Lance), + PREFIX_SQL => Some(SurfaceCompartment::Sql), + PREFIX_META => Some(SurfaceCompartment::Meta), + PREFIX_VERBS => Some(SurfaceCompartment::Verbs), + _ => None, } } } +impl From for Addr { + fn from(v: u16) -> Self { + Self(v) + } +} + +impl From for u16 { + fn from(a: Addr) -> Self { + a.0 + } +} + +// ============================================================================= +// SURFACE COMPARTMENTS +// ============================================================================= + +/// The 4 surface compartments +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum SurfaceCompartment { + /// 0x00: Lance/Kuzu - vector search, graph traversal + Lance = 0, + /// 0x01: SQL/Neo4j - relational, property graph + Sql = 1, + /// 0x02: Meta - higher-order thinking, NARS + Meta = 2, + /// 0x03: Verbs - CAUSES, BECOMES, etc. + Verbs = 3, +} + +impl SurfaceCompartment { + pub fn prefix(self) -> u8 { + self as u8 + } + + pub fn addr(self, slot: u8) -> Addr { + Addr::new(self as u8, slot) + } +} + +// ============================================================================= +// CHUNK CONTEXT (What node space means) +// ============================================================================= + +/// Context that defines how node space is interpreted +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub enum ChunkContext { + /// Concept space - abstract types and categories + #[default] + Concepts, + /// Memory space - episodic memories + Memories, + /// Codebook space - learned patterns + Codebook, + /// Meta-awareness - self-model, introspection + MetaAwareness, + /// Extended addressing for overflow + Extended(u8), +} + // ============================================================================= -// BIND NODE - The universal content container +// BIND NODE - Universal content container // ============================================================================= -/// A node in the universal bind space +/// A node in the bind space /// -/// This is what ALL query languages ultimately read/write. -/// The fingerprint doesn't care what syntax asked for it. -#[derive(Debug, Clone)] +/// This is what ALL query languages read/write. +#[derive(Clone)] pub struct BindNode { - /// 10K-bit fingerprint (the content-addressable identity) + /// 10K-bit fingerprint pub fingerprint: [u64; FINGERPRINT_WORDS], /// Human-readable label pub label: Option, - /// Qualia index (0-255, emergent) + /// Qualia index (0-255) pub qidx: u8, - /// Creation timestamp - pub created: Instant, - /// Last access timestamp - pub accessed: Instant, - /// Access count (for promotion/cache decisions) + /// Access count pub access_count: u32, - /// Optional payload (serialized content) + /// Optional payload pub payload: Option>, } impl BindNode { pub fn new(fingerprint: [u64; FINGERPRINT_WORDS]) -> Self { - let now = Instant::now(); Self { fingerprint, label: None, qidx: 0, - created: now, - accessed: now, access_count: 0, payload: None, } @@ -188,63 +247,66 @@ impl BindNode { self } - pub fn with_payload(mut self, payload: Vec) -> Self { - self.payload = Some(payload); - self - } - - /// Touch - update access time and count + #[inline(always)] pub fn touch(&mut self) { - self.accessed = Instant::now(); - self.access_count += 1; + self.access_count = self.access_count.saturating_add(1); + } +} + +impl Default for BindNode { + fn default() -> Self { + Self::new([0u64; FINGERPRINT_WORDS]) } } // ============================================================================= -// BIND EDGE - Connection in the fluid zone +// BIND EDGE - Connection via verb // ============================================================================= /// An edge connecting nodes via a verb -/// -/// Edges live in the fluid zone (0x1000-0x7FFF). -/// They connect nodes in the bind space using verbs from the surface. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct BindEdge { - /// Source node address (in node space 0x8000-0xFFFF) - pub from: u16, - /// Target node address (in node space 0x8000-0xFFFF) - pub to: u16, - /// Verb address (in surface space 0x0000-0x0FFF) - pub verb: u16, - /// Edge fingerprint: from ⊗ verb ⊗ to (for ABBA retrieval) + /// Source node address (0x80-0xFF:XX) + pub from: Addr, + /// Target node address (0x80-0xFF:XX) + pub to: Addr, + /// Verb address (0x03:XX typically) + pub verb: Addr, + /// Bound fingerprint: from ⊗ verb ⊗ to pub fingerprint: [u64; FINGERPRINT_WORDS], - /// Edge weight/strength + /// Edge weight pub weight: f32, - /// Creation timestamp - pub created: Instant, } impl BindEdge { - pub fn new(from: u16, verb: u16, to: u16) -> Self { + pub fn new(from: Addr, verb: Addr, to: Addr) -> Self { Self { from, to, verb, - fingerprint: [0u64; FINGERPRINT_WORDS], // Set by bind operation + fingerprint: [0u64; FINGERPRINT_WORDS], weight: 1.0, - created: Instant::now(), } } - /// Compute edge fingerprint via XOR binding - pub fn bind(&mut self, from_fp: &[u64; FINGERPRINT_WORDS], verb_fp: &[u64; FINGERPRINT_WORDS], to_fp: &[u64; FINGERPRINT_WORDS]) { + /// Bind: compute edge fingerprint via XOR + pub fn bind( + &mut self, + from_fp: &[u64; FINGERPRINT_WORDS], + verb_fp: &[u64; FINGERPRINT_WORDS], + to_fp: &[u64; FINGERPRINT_WORDS], + ) { for i in 0..FINGERPRINT_WORDS { self.fingerprint[i] = from_fp[i] ^ verb_fp[i] ^ to_fp[i]; } } - /// ABBA unbind: given edge and one known, recover the other - pub fn unbind(&self, known: &[u64; FINGERPRINT_WORDS], verb_fp: &[u64; FINGERPRINT_WORDS]) -> [u64; FINGERPRINT_WORDS] { + /// ABBA unbind: recover unknown from edge + known + verb + pub fn unbind( + &self, + known: &[u64; FINGERPRINT_WORDS], + verb_fp: &[u64; FINGERPRINT_WORDS], + ) -> [u64; FINGERPRINT_WORDS] { let mut result = [0u64; FINGERPRINT_WORDS]; for i in 0..FINGERPRINT_WORDS { result[i] = self.fingerprint[i] ^ known[i] ^ verb_fp[i]; @@ -254,139 +316,252 @@ impl BindEdge { } // ============================================================================= -// BIND SPACE - The Universal DTO +// BIND SPACE - The Universal DTO (Array-based storage) // ============================================================================= /// The Universal Bind Space /// -/// This is the single source of truth that all query languages hit. -/// Whether you speak Redis, Cypher, SQL, or GraphQL - you end up here. +/// Pure array indexing. No HashMap. No SIMD required. +/// Works on any CPU. pub struct BindSpace { - /// Surface tier: verbs and ops (fixed) - surface: HashMap, + // ========================================================================= + // SURFACES (4 compartments × 256 slots each) + // ========================================================================= - /// Fluid tier: edges and context selectors - fluid: HashMap, + /// Surface 0: Lance/Kuzu ops + surface_lance: Box<[Option; CHUNK_SIZE]>, + /// Surface 1: SQL/Neo4j ops + surface_sql: Box<[Option; CHUNK_SIZE]>, + /// Surface 2: Meta/Higher-order thinking + surface_meta: Box<[Option; CHUNK_SIZE]>, + /// Surface 3: Verbs/Cypher + surface_verbs: Box<[Option; CHUNK_SIZE]>, - /// Fluid edges (separate for efficient traversal) + // ========================================================================= + // FLUID (124 chunks × 256 slots = 31,744 edges) + // ========================================================================= + + /// Fluid chunks for edge storage + fluid: Vec; CHUNK_SIZE]>>, + + /// Edges (separate for efficient traversal) edges: Vec, - /// Edge index: from_addr -> edge indices (CSR-style) - edge_index_out: HashMap>, + /// Edge index: from.0 -> edge indices (CSR-style) + edge_out: Vec>, + + /// Edge index: to.0 -> edge indices (reverse CSR) + edge_in: Vec>, - /// Edge index: to_addr -> edge indices (reverse CSR) - edge_index_in: HashMap>, + // ========================================================================= + // NODES (128 chunks × 256 slots = 32,768 nodes) + // ========================================================================= - /// Node tier: the actual bind space - nodes: HashMap, + /// Node chunks + nodes: Vec; CHUNK_SIZE]>>, - /// Current chunk context + // ========================================================================= + // STATE + // ========================================================================= + + /// Current context context: ChunkContext, - /// Next available addresses - next_fluid: u16, - next_node: u16, + /// Next fluid slot (prefix, slot) + next_fluid: (u8, u8), + + /// Next node slot (prefix, slot) + next_node: (u8, u8), } impl BindSpace { pub fn new() -> Self { + // Initialize surfaces + let surface_lance = Box::new(std::array::from_fn(|_| None)); + let surface_sql = Box::new(std::array::from_fn(|_| None)); + let surface_meta = Box::new(std::array::from_fn(|_| None)); + let surface_verbs = Box::new(std::array::from_fn(|_| None)); + + // Initialize fluid chunks + let mut fluid = Vec::with_capacity(FLUID_CHUNKS); + for _ in 0..FLUID_CHUNKS { + fluid.push(Box::new(std::array::from_fn(|_| None))); + } + + // Initialize node chunks + let mut nodes = Vec::with_capacity(NODE_CHUNKS); + for _ in 0..NODE_CHUNKS { + nodes.push(Box::new(std::array::from_fn(|_| None))); + } + + // Edge indices (64K entries for O(1) lookup) + let edge_out = vec![Vec::new(); TOTAL_ADDRESSES]; + let edge_in = vec![Vec::new(); TOTAL_ADDRESSES]; + let mut space = Self { - surface: HashMap::new(), - fluid: HashMap::new(), + surface_lance, + surface_sql, + surface_meta, + surface_verbs, + fluid, edges: Vec::new(), - edge_index_out: HashMap::new(), - edge_index_in: HashMap::new(), - nodes: HashMap::new(), + edge_out, + edge_in, + nodes, context: ChunkContext::Concepts, - next_fluid: FLUID_START + 256, // Reserve first 256 for contexts - next_node: NODE_START, + next_fluid: (PREFIX_FLUID_START, 0), + next_node: (PREFIX_NODE_START, 0), }; - space.init_surface(); + + space.init_surfaces(); space } - /// Initialize surface with core verbs - fn init_surface(&mut self) { - // Core verbs (from the 144 Go board intersections) - let verbs = [ - (0x0060, "CAUSES"), - (0x0061, "BECOMES"), - (0x0062, "ENABLES"), - (0x0063, "PREVENTS"), - (0x0064, "REQUIRES"), - (0x0065, "IMPLIES"), - (0x0066, "CONTAINS"), - (0x0067, "ACTIVATES"), - (0x0068, "INHIBITS"), - (0x0069, "TRANSFORMS"), - (0x006A, "RESONATES"), - (0x006B, "AMPLIFIES"), - (0x006C, "DAMPENS"), - (0x006D, "OBSERVES"), - (0x006E, "REMEMBERS"), - (0x006F, "FORGETS"), - // Flow verbs - (0x0070, "SHIFT"), - (0x0071, "LEAP"), - (0x0072, "EMERGE"), - (0x0073, "SUBSIDE"), - (0x0074, "OSCILLATE"), - (0x0075, "CRYSTALLIZE"), - (0x0076, "DISSOLVE"), - (0x0077, "TRANSFORM"), + /// Initialize surfaces with core ops + fn init_surfaces(&mut self) { + // Surface 0: Lance/Kuzu ops + let lance_ops = [ + (0x00, "VECTOR_SEARCH"), + (0x01, "TRAVERSE"), + (0x02, "RESONATE"), + (0x03, "HAMMING"), + (0x04, "BIND"), + (0x05, "UNBIND"), + (0x06, "BUNDLE"), + (0x07, "SIMILARITY"), + (0x08, "KNN"), + (0x09, "ANN"), + (0x0A, "CLUSTER"), + (0x0B, "QUANTIZE"), ]; + for (slot, label) in lance_ops { + self.surface_lance[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } - for (addr, label) in verbs { - let mut node = BindNode::new(verb_fingerprint(label)); - node.label = Some(label.to_string()); - self.surface.insert(addr, node); + // Surface 1: SQL/Neo4j ops + let sql_ops = [ + (0x00, "SELECT"), + (0x01, "INSERT"), + (0x02, "UPDATE"), + (0x03, "DELETE"), + (0x04, "JOIN"), + (0x05, "WHERE"), + (0x06, "GROUP"), + (0x07, "ORDER"), + (0x08, "MATCH"), + (0x09, "CREATE"), + (0x0A, "MERGE"), + (0x0B, "RETURN"), + ]; + for (slot, label) in sql_ops { + self.surface_sql[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 2: Meta/Higher-order ops + let meta_ops = [ + (0x00, "REFLECT"), + (0x01, "ABSTRACT"), + (0x02, "DEDUCE"), + (0x03, "ABDUCT"), + (0x04, "INDUCE"), + (0x05, "ANALOGIZE"), + (0x06, "HYPOTHESIZE"), + (0x07, "REVISE"), + (0x08, "BELIEVE"), + (0x09, "DOUBT"), + (0x0A, "IMAGINE"), + (0x0B, "COUNTERFACT"), + ]; + for (slot, label) in meta_ops { + self.surface_meta[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 3: Verbs (the 144 Go board verbs) + let verb_ops = [ + (0x00, "CAUSES"), + (0x01, "BECOMES"), + (0x02, "ENABLES"), + (0x03, "PREVENTS"), + (0x04, "REQUIRES"), + (0x05, "IMPLIES"), + (0x06, "CONTAINS"), + (0x07, "ACTIVATES"), + (0x08, "INHIBITS"), + (0x09, "TRANSFORMS"), + (0x0A, "RESONATES"), + (0x0B, "AMPLIFIES"), + (0x0C, "DAMPENS"), + (0x0D, "OBSERVES"), + (0x0E, "REMEMBERS"), + (0x0F, "FORGETS"), + (0x10, "SHIFT"), + (0x11, "LEAP"), + (0x12, "EMERGE"), + (0x13, "SUBSIDE"), + (0x14, "OSCILLATE"), + (0x15, "CRYSTALLIZE"), + (0x16, "DISSOLVE"), + (0x17, "GROUNDS"), + (0x18, "ABSTRACTS"), + (0x19, "REFINES"), + (0x1A, "CONTRADICTS"), + (0x1B, "SUPPORTS"), + ]; + for (slot, label) in verb_ops { + self.surface_verbs[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); } } // ========================================================================= - // CONTEXT OPERATIONS - // ========================================================================= - - /// Set the current chunk context - /// This changes what the node space (0x8000-0xFFFF) means - pub fn set_context(&mut self, context: ChunkContext) { - self.context = context; - } - - /// Get current context - pub fn context(&self) -> ChunkContext { - self.context - } - - // ========================================================================= - // UNIVERSAL READ/WRITE (All languages hit these) + // CORE READ/WRITE (Pure array indexing - 3-5 cycles) // ========================================================================= - /// Read from any address + /// Read from any address - THE HOT PATH /// - /// This is what GET (Redis), MATCH (Cypher), SELECT (SQL) all become. - pub fn read(&mut self, addr: u16) -> Option<&BindNode> { - let node = match addr { - a if a <= SURFACE_END => self.surface.get(&a), - a if a <= FLUID_END => self.fluid.get(&a), - a => self.nodes.get(&a), - }; + /// This is what GET, MATCH, SELECT all become. + /// Pure array indexing, no hash, no search. + #[inline(always)] + pub fn read(&self, addr: Addr) -> Option<&BindNode> { + let prefix = addr.prefix(); + let slot = addr.slot() as usize; - // Touch for access tracking (need mut for this) - if let Some(_) = node { - // We'd need interior mutability for proper touch - // For now, just return the reference + match prefix { + PREFIX_LANCE => self.surface_lance[slot].as_ref(), + PREFIX_SQL => self.surface_sql[slot].as_ref(), + PREFIX_META => self.surface_meta[slot].as_ref(), + PREFIX_VERBS => self.surface_verbs[slot].as_ref(), + p if p >= PREFIX_FLUID_START && p <= PREFIX_FLUID_END => { + let chunk = (p - PREFIX_FLUID_START) as usize; + self.fluid.get(chunk).and_then(|c| c[slot].as_ref()) + } + p if p >= PREFIX_NODE_START => { + let chunk = (p - PREFIX_NODE_START) as usize; + self.nodes.get(chunk).and_then(|c| c[slot].as_ref()) + } + _ => None, } - - node } - /// Read mutable from any address - pub fn read_mut(&mut self, addr: u16) -> Option<&mut BindNode> { - let node = match addr { - a if a <= SURFACE_END => self.surface.get_mut(&a), - a if a <= FLUID_END => self.fluid.get_mut(&a), - a => self.nodes.get_mut(&a), + /// Read mutable with touch + #[inline(always)] + pub fn read_mut(&mut self, addr: Addr) -> Option<&mut BindNode> { + let prefix = addr.prefix(); + let slot = addr.slot() as usize; + + let node = match prefix { + PREFIX_LANCE => self.surface_lance[slot].as_mut(), + PREFIX_SQL => self.surface_sql[slot].as_mut(), + PREFIX_META => self.surface_meta[slot].as_mut(), + PREFIX_VERBS => self.surface_verbs[slot].as_mut(), + p if p >= PREFIX_FLUID_START && p <= PREFIX_FLUID_END => { + let chunk = (p - PREFIX_FLUID_START) as usize; + self.fluid.get_mut(chunk).and_then(|c| c[slot].as_mut()) + } + p if p >= PREFIX_NODE_START => { + let chunk = (p - PREFIX_NODE_START) as usize; + self.nodes.get_mut(chunk).and_then(|c| c[slot].as_mut()) + } + _ => None, }; if let Some(n) = node { @@ -399,123 +574,134 @@ impl BindSpace { /// Write to node space /// - /// This is what SET (Redis), CREATE (Cypher), INSERT (SQL) all become. - pub fn write(&mut self, fingerprint: [u64; FINGERPRINT_WORDS]) -> u16 { - let addr = self.next_node; - self.next_node = self.next_node.wrapping_add(1); - if self.next_node < NODE_START { - self.next_node = NODE_START; // Wrap within node space + /// This is what SET, CREATE, INSERT all become. + pub fn write(&mut self, fingerprint: [u64; FINGERPRINT_WORDS]) -> Addr { + let (prefix, slot) = self.next_node; + let addr = Addr::new(prefix, slot); + + // Advance next slot + self.next_node = if slot == 255 { + if prefix == PREFIX_NODE_END { + (PREFIX_NODE_START, 0) // Wrap + } else { + (prefix + 1, 0) + } + } else { + (prefix, slot + 1) + }; + + // Write to chunk + let chunk = (prefix - PREFIX_NODE_START) as usize; + if let Some(c) = self.nodes.get_mut(chunk) { + c[slot as usize] = Some(BindNode::new(fingerprint)); } - let node = BindNode::new(fingerprint); - self.nodes.insert(addr, node); addr } /// Write with label - pub fn write_labeled(&mut self, fingerprint: [u64; FINGERPRINT_WORDS], label: &str) -> u16 { + pub fn write_labeled(&mut self, fingerprint: [u64; FINGERPRINT_WORDS], label: &str) -> Addr { let addr = self.write(fingerprint); - if let Some(node) = self.nodes.get_mut(&addr) { + if let Some(node) = self.read_mut(addr) { node.label = Some(label.to_string()); } addr } - /// Delete from any address - pub fn delete(&mut self, addr: u16) -> Option { - match addr { - a if a <= SURFACE_END => None, // Can't delete surface - a if a <= FLUID_END => self.fluid.remove(&a), - a => self.nodes.remove(&a), + /// Delete from address + pub fn delete(&mut self, addr: Addr) -> Option { + let prefix = addr.prefix(); + let slot = addr.slot() as usize; + + // Can't delete surfaces + if prefix <= PREFIX_VERBS { + return None; + } + + if prefix >= PREFIX_FLUID_START && prefix <= PREFIX_FLUID_END { + let chunk = (prefix - PREFIX_FLUID_START) as usize; + self.fluid.get_mut(chunk).and_then(|c| c[slot].take()) + } else if prefix >= PREFIX_NODE_START { + let chunk = (prefix - PREFIX_NODE_START) as usize; + self.nodes.get_mut(chunk).and_then(|c| c[slot].take()) + } else { + None } } // ========================================================================= - // EDGE OPERATIONS (Fluid zone) + // EDGE OPERATIONS (CSR-style O(1) lookup) // ========================================================================= /// Create an edge - /// - /// This is what relationships in Cypher, foreign keys in SQL become. - pub fn link(&mut self, from: u16, verb: u16, to: u16) -> usize { + pub fn link(&mut self, from: Addr, verb: Addr, to: Addr) -> usize { let mut edge = BindEdge::new(from, verb, to); - // Get fingerprints and bind + // Bind fingerprints if let (Some(from_node), Some(verb_node), Some(to_node)) = - (self.nodes.get(&from), self.surface.get(&verb), self.nodes.get(&to)) + (self.read(from), self.read(verb), self.read(to)) { - edge.bind(&from_node.fingerprint, &verb_node.fingerprint, &to_node.fingerprint); + let from_fp = from_node.fingerprint; + let verb_fp = verb_node.fingerprint; + let to_fp = to_node.fingerprint; + edge.bind(&from_fp, &verb_fp, &to_fp); } let idx = self.edges.len(); - // Update indices (CSR-style) - self.edge_index_out.entry(from).or_default().push(idx); - self.edge_index_in.entry(to).or_default().push(idx); + // Update CSR indices + self.edge_out[from.0 as usize].push(idx); + self.edge_in[to.0 as usize].push(idx); self.edges.push(edge); idx } - /// Get outgoing edges (CSR-style O(1) index lookup) - pub fn edges_out(&self, from: u16) -> Vec<&BindEdge> { - self.edge_index_out - .get(&from) - .map(|indices| indices.iter().filter_map(|&i| self.edges.get(i)).collect()) - .unwrap_or_default() + /// Get outgoing edges (O(1) index lookup) + #[inline(always)] + pub fn edges_out(&self, from: Addr) -> impl Iterator { + self.edge_out[from.0 as usize] + .iter() + .filter_map(|&i| self.edges.get(i)) } - /// Get incoming edges (reverse CSR) - pub fn edges_in(&self, to: u16) -> Vec<&BindEdge> { - self.edge_index_in - .get(&to) - .map(|indices| indices.iter().filter_map(|&i| self.edges.get(i)).collect()) - .unwrap_or_default() - } - - /// Get edges by verb - pub fn edges_via(&self, verb: u16) -> Vec<&BindEdge> { - self.edges.iter().filter(|e| e.verb == verb).collect() + /// Get incoming edges (O(1) index lookup) + #[inline(always)] + pub fn edges_in(&self, to: Addr) -> impl Iterator { + self.edge_in[to.0 as usize] + .iter() + .filter_map(|&i| self.edges.get(i)) } /// Traverse: from -> via verb -> targets - pub fn traverse(&self, from: u16, verb: u16) -> Vec { + pub fn traverse(&self, from: Addr, verb: Addr) -> Vec { self.edges_out(from) - .into_iter() .filter(|e| e.verb == verb) .map(|e| e.to) .collect() } - /// Reverse traverse: targets <- via verb <- to - pub fn traverse_reverse(&self, to: u16, verb: u16) -> Vec { + /// Reverse traverse: sources <- via verb <- to + pub fn traverse_reverse(&self, to: Addr, verb: Addr) -> Vec { self.edges_in(to) - .into_iter() .filter(|e| e.verb == verb) .map(|e| e.from) .collect() } - // ========================================================================= - // N-HOP TRAVERSAL (What Kuzu CSR does) - // ========================================================================= - - /// N-hop traversal from a node via a verb - /// - /// This is the core graph operation that Kuzu CSR accelerates. - /// We use edge indices for O(1) neighbor lookup per hop. - pub fn traverse_n_hops(&self, start: u16, verb: u16, max_hops: usize) -> Vec<(usize, u16)> { + /// N-hop traversal (Kuzu CSR equivalent) + pub fn traverse_n_hops(&self, start: Addr, verb: Addr, max_hops: usize) -> Vec<(usize, Addr)> { let mut results = Vec::new(); let mut frontier = vec![start]; let mut visited = std::collections::HashSet::new(); - visited.insert(start); + visited.insert(start.0); for hop in 1..=max_hops { let mut next_frontier = Vec::new(); for &node in &frontier { for target in self.traverse(node, verb) { - if visited.insert(target) { + if visited.insert(target.0) { results.push((hop, target)); next_frontier.push(target); } @@ -532,14 +718,62 @@ impl BindSpace { } // ========================================================================= - // STATISTICS + // CONTEXT + // ========================================================================= + + pub fn set_context(&mut self, ctx: ChunkContext) { + self.context = ctx; + } + + pub fn context(&self) -> ChunkContext { + self.context + } + + // ========================================================================= + // SURFACE HELPERS + // ========================================================================= + + /// Get verb address by name + pub fn verb(&self, name: &str) -> Option { + for slot in 0..CHUNK_SIZE { + if let Some(node) = &self.surface_verbs[slot] { + if node.label.as_deref() == Some(name) { + return Some(Addr::new(PREFIX_VERBS, slot as u8)); + } + } + } + None + } + + /// Get verb fingerprint by address + pub fn verb_fingerprint(&self, verb: Addr) -> Option<&[u64; FINGERPRINT_WORDS]> { + self.read(verb).map(|n| &n.fingerprint) + } + + // ========================================================================= + // STATS // ========================================================================= pub fn stats(&self) -> BindSpaceStats { + let surface_count = [ + &self.surface_lance, + &self.surface_sql, + &self.surface_meta, + &self.surface_verbs, + ].iter().map(|s| s.iter().filter(|x| x.is_some()).count()).sum(); + + let fluid_count: usize = self.fluid.iter() + .map(|c| c.iter().filter(|x| x.is_some()).count()) + .sum(); + + let node_count: usize = self.nodes.iter() + .map(|c| c.iter().filter(|x| x.is_some()).count()) + .sum(); + BindSpaceStats { - surface_count: self.surface.len(), - fluid_count: self.fluid.len(), - node_count: self.nodes.len(), + surface_count, + fluid_count, + node_count, edge_count: self.edges.len(), context: self.context, } @@ -562,22 +796,21 @@ pub struct BindSpaceStats { } // ============================================================================= -// HELPER FUNCTIONS +// HELPERS // ============================================================================= -/// Generate a deterministic fingerprint for a verb label -fn verb_fingerprint(label: &str) -> [u64; FINGERPRINT_WORDS] { +/// Generate fingerprint from label (deterministic) +fn label_fingerprint(label: &str) -> [u64; FINGERPRINT_WORDS] { let mut fp = [0u64; FINGERPRINT_WORDS]; let bytes = label.as_bytes(); - // Simple hash spread across fingerprint for (i, &b) in bytes.iter().enumerate() { - let word_idx = i % FINGERPRINT_WORDS; - let bit_idx = (b as usize * 7 + i * 13) % 64; - fp[word_idx] |= 1u64 << bit_idx; + let word = i % FINGERPRINT_WORDS; + let bit = (b as usize * 7 + i * 13) % 64; + fp[word] |= 1u64 << bit; } - // Spread more bits for density + // Spread bits for i in 0..FINGERPRINT_WORDS { let seed = fp[i]; fp[(i + 1) % FINGERPRINT_WORDS] ^= seed.rotate_left(17); @@ -587,29 +820,24 @@ fn verb_fingerprint(label: &str) -> [u64; FINGERPRINT_WORDS] { fp } -/// Compute Hamming distance between fingerprints +/// Hamming distance pub fn hamming_distance(a: &[u64; FINGERPRINT_WORDS], b: &[u64; FINGERPRINT_WORDS]) -> u32 { - let mut dist = 0u32; + let mut d = 0u32; for i in 0..FINGERPRINT_WORDS { - dist += (a[i] ^ b[i]).count_ones(); + d += (a[i] ^ b[i]).count_ones(); } - dist + d } // ============================================================================= -// QUERY LANGUAGE TRAIT (What all adapters implement) +// QUERY ADAPTER TRAIT // ============================================================================= /// Trait for query language adapters -/// -/// All languages (Redis, Cypher, SQL, GraphQL) implement this -/// and ultimately call BindSpace methods. pub trait QueryAdapter { - /// Execute a query and return results fn execute(&self, space: &mut BindSpace, query: &str) -> QueryResult; } -/// Generic query result #[derive(Debug)] pub struct QueryResult { pub columns: Vec, @@ -619,14 +847,10 @@ pub struct QueryResult { impl QueryResult { pub fn empty() -> Self { - Self { - columns: Vec::new(), - rows: Vec::new(), - affected: 0, - } + Self { columns: Vec::new(), rows: Vec::new(), affected: 0 } } - pub fn single(addr: u16) -> Self { + pub fn single(addr: Addr) -> Self { Self { columns: vec!["addr".to_string()], rows: vec![vec![QueryValue::Addr(addr)]], @@ -635,10 +859,9 @@ impl QueryResult { } } -/// Query value types #[derive(Debug, Clone)] pub enum QueryValue { - Addr(u16), + Addr(Addr), String(String), Int(i64), Float(f64), @@ -656,18 +879,50 @@ mod tests { use super::*; #[test] - fn test_address_ranges() { - assert_eq!(SURFACE_SIZE, 4096); - assert_eq!(FLUID_SIZE, 28672); - assert_eq!(NODE_SIZE, 32768); - assert_eq!(SURFACE_SIZE + FLUID_SIZE + NODE_SIZE, TOTAL_SIZE); + fn test_addr_split() { + let addr = Addr::new(0x80, 0x42); + assert_eq!(addr.prefix(), 0x80); + assert_eq!(addr.slot(), 0x42); + assert_eq!(addr.0, 0x8042); } #[test] - fn test_bind_space_creation() { + fn test_surface_compartments() { + let lance = Addr::new(PREFIX_LANCE, 0x05); + let sql = Addr::new(PREFIX_SQL, 0x10); + let meta = Addr::new(PREFIX_META, 0x00); + let verbs = Addr::new(PREFIX_VERBS, 0x01); + + assert!(lance.is_surface()); + assert!(sql.is_surface()); + assert!(meta.is_surface()); + assert!(verbs.is_surface()); + + assert_eq!(lance.surface_compartment(), Some(SurfaceCompartment::Lance)); + assert_eq!(verbs.surface_compartment(), Some(SurfaceCompartment::Verbs)); + } + + #[test] + fn test_fluid_node_ranges() { + let fluid = Addr::new(0x50, 0x00); + let node = Addr::new(0x80, 0x00); + + assert!(fluid.is_fluid()); + assert!(!fluid.is_node()); + + assert!(node.is_node()); + assert!(!node.is_fluid()); + } + + #[test] + fn test_bind_space_surfaces() { let space = BindSpace::new(); - assert!(space.surface.len() > 0); // Verbs initialized - assert_eq!(space.context, ChunkContext::Concepts); + + // Check verbs initialized + let causes = Addr::new(PREFIX_VERBS, 0x00); + let node = space.read(causes); + assert!(node.is_some()); + assert_eq!(node.unwrap().label.as_deref(), Some("CAUSES")); } #[test] @@ -676,7 +931,7 @@ mod tests { let fp = [42u64; FINGERPRINT_WORDS]; let addr = space.write(fp); - assert!(addr >= NODE_START); + assert!(addr.is_node()); let node = space.read(addr); assert!(node.is_some()); @@ -687,78 +942,48 @@ mod tests { fn test_link_traverse() { let mut space = BindSpace::new(); - // Create two nodes - let a = space.write_labeled([1u64; FINGERPRINT_WORDS], "Node A"); - let b = space.write_labeled([2u64; FINGERPRINT_WORDS], "Node B"); + let a = space.write_labeled([1u64; FINGERPRINT_WORDS], "A"); + let b = space.write_labeled([2u64; FINGERPRINT_WORDS], "B"); - // Link them with CAUSES - let verb = 0x0060; // CAUSES - space.link(a, verb, b); + let causes = Addr::new(PREFIX_VERBS, 0x00); // CAUSES + space.link(a, causes, b); - // Traverse - let targets = space.traverse(a, verb); + let targets = space.traverse(a, causes); assert_eq!(targets.len(), 1); assert_eq!(targets[0], b); } #[test] - fn test_n_hop_traversal() { + fn test_n_hop() { let mut space = BindSpace::new(); - // Create chain: A -> B -> C -> D let a = space.write([1u64; FINGERPRINT_WORDS]); let b = space.write([2u64; FINGERPRINT_WORDS]); let c = space.write([3u64; FINGERPRINT_WORDS]); let d = space.write([4u64; FINGERPRINT_WORDS]); - let verb = 0x0060; // CAUSES - space.link(a, verb, b); - space.link(b, verb, c); - space.link(c, verb, d); + let causes = Addr::new(PREFIX_VERBS, 0x00); + space.link(a, causes, b); + space.link(b, causes, c); + space.link(c, causes, d); - // 3-hop traversal from A - let results = space.traverse_n_hops(a, verb, 3); + let results = space.traverse_n_hops(a, causes, 3); assert_eq!(results.len(), 3); - assert_eq!(results[0], (1, b)); // 1 hop to B - assert_eq!(results[1], (2, c)); // 2 hops to C - assert_eq!(results[2], (3, d)); // 3 hops to D - } - - #[test] - fn test_context_switching() { - let mut space = BindSpace::new(); - - assert_eq!(space.context(), ChunkContext::Concepts); - - space.set_context(ChunkContext::Memories); - assert_eq!(space.context(), ChunkContext::Memories); - - space.set_context(ChunkContext::MetaAwareness); - assert_eq!(space.context(), ChunkContext::MetaAwareness); + assert_eq!(results[0], (1, b)); + assert_eq!(results[1], (2, c)); + assert_eq!(results[2], (3, d)); } #[test] - fn test_edge_indices() { - let mut space = BindSpace::new(); - - let a = space.write([1u64; FINGERPRINT_WORDS]); - let b = space.write([2u64; FINGERPRINT_WORDS]); - let c = space.write([3u64; FINGERPRINT_WORDS]); - - let causes = 0x0060; - let enables = 0x0062; - - space.link(a, causes, b); - space.link(a, enables, c); - space.link(b, causes, c); - - // A has 2 outgoing edges - assert_eq!(space.edges_out(a).len(), 2); + fn test_verb_lookup() { + let space = BindSpace::new(); - // C has 2 incoming edges - assert_eq!(space.edges_in(c).len(), 2); + let causes = space.verb("CAUSES"); + assert!(causes.is_some()); + assert_eq!(causes.unwrap(), Addr::new(PREFIX_VERBS, 0x00)); - // Only 2 CAUSES edges total - assert_eq!(space.edges_via(causes).len(), 2); + let becomes = space.verb("BECOMES"); + assert!(becomes.is_some()); + assert_eq!(becomes.unwrap(), Addr::new(PREFIX_VERBS, 0x01)); } } From 73238ba8de699199766d691b819c510929f8de26 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 30 Jan 2026 21:52:03 +0100 Subject: [PATCH 3/5] Add mod.rs exports for bind_space --- src/storage/mod.rs | 96 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 29 deletions(-) diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 1381641..9614195 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -1,35 +1,73 @@ -//! Storage layer - LanceDB integration +//! Storage module - Persistence layers //! -//! Provides persistent storage via LanceDB with: -//! - Columnar Arrow format -//! - Native vector ANN indices -//! - Zero-copy operations -//! - Versioned datasets +//! # 8-bit Prefix Architecture +//! +//! ```text +//! ┌─────────────────────────────────────────────────────────────────────────────┐ +//! │ PREFIX (8-bit) : ADDRESS (8-bit) │ +//! ├─────────────────┬───────────────────────────────────────────────────────────┤ +//! │ 0x00:XX │ SURFACE 0 - Lance/Kuzu (256 ops) │ +//! │ 0x01:XX │ SURFACE 1 - SQL/Neo4j (256 ops) │ +//! │ 0x02:XX │ SURFACE 2 - Meta/NARS (256 ops) │ +//! │ 0x03:XX │ SURFACE 3 - Verbs/Cypher (256 verbs) │ +//! ├─────────────────┼───────────────────────────────────────────────────────────┤ +//! │ 0x04-0x7F:XX │ FLUID (124 × 256 = 31,744 edges) │ +//! ├─────────────────┼───────────────────────────────────────────────────────────┤ +//! │ 0x80-0xFF:XX │ NODES (128 × 256 = 32,768) - UNIVERSAL BIND SPACE │ +//! └─────────────────┴───────────────────────────────────────────────────────────┘ +//! ``` +//! +//! Pure array indexing. No HashMap. 3-5 cycles per lookup. +//! Works on any CPU - no SIMD required. +//! +//! # Layers +//! +//! - **BindSpace**: Universal DTO - all languages hit this +//! - **CogRedis**: Redis syntax adapter with cognitive semantics +//! - **LanceDB**: Vector storage (fingerprints, embeddings) +//! - **Kuzu**: Optional native graph (Cypher syntax) +//! - **Database**: Unified query interface -mod database; -mod lance; +pub mod lance; +pub mod database; +pub mod kuzu; +pub mod cog_redis; +pub mod bind_space; +pub use lance::LanceStore; pub use database::Database; -pub use lance::{ - LanceStore, - NodeRecord, - EdgeRecord, - nodes_schema, - edges_schema, - sessions_schema, - FINGERPRINT_BYTES, - EMBEDDING_DIM, - THINKING_STYLE_DIM, +pub use kuzu::{KuzuStore, NodeRecord, EdgeRecord, PathRecord}; + +// CogRedis exports +pub use cog_redis::{ + // Address types + CogAddr, Tier, SurfaceCompartment, + + // Prefix constants + PREFIX_LANCE, PREFIX_SQL, PREFIX_META, PREFIX_VERBS, + PREFIX_FLUID_START, PREFIX_FLUID_END, + PREFIX_NODE_START, PREFIX_NODE_END, + CHUNK_SIZE, + + // Legacy constants (compatibility) + SURFACE_START, SURFACE_END, SURFACE_SIZE, + FLUID_START, FLUID_END, FLUID_SIZE, + NODE_START, NODE_END, NODE_SIZE, + TOTAL_SIZE, + + // Values and edges + CogValue, CogEdge, + + // Main interface + CogRedis, CogRedisStats, + + // Results + GetResult, SetOptions, ResonateResult, DeduceResult, }; -#[derive(thiserror::Error, Debug)] -pub enum StorageError { - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - #[error("Not found: {0}")] - NotFound(String), - #[error("Lance error: {0}")] - Lance(String), - #[error("Arrow error: {0}")] - Arrow(String), -} +// BindSpace exports (universal DTO) +pub use bind_space::{ + Addr, BindNode, BindEdge, BindSpace, BindSpaceStats, + ChunkContext, QueryAdapter, QueryResult, QueryValue, + hamming_distance, FINGERPRINT_WORDS, +}; From 4db5e69562f44da48af684a185aa24c0a8ae24f3 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 30 Jan 2026 22:09:34 +0100 Subject: [PATCH 4/5] 16 surface prefixes (0x00-0x0F) --- src/storage/bind_space.rs | 402 +++++++++++++++++++++++++------------- 1 file changed, 270 insertions(+), 132 deletions(-) diff --git a/src/storage/bind_space.rs b/src/storage/bind_space.rs index 7f263af..87c2a1f 100644 --- a/src/storage/bind_space.rs +++ b/src/storage/bind_space.rs @@ -6,22 +6,20 @@ //! ┌─────────────────────────────────────────────────────────────────────────────┐ //! │ PREFIX (8-bit) : ADDRESS (8-bit) │ //! ├─────────────────┬───────────────────────────────────────────────────────────┤ -//! │ 0x00:XX │ SURFACE 0 - Lance/Kuzu (256) │ -//! │ │ Vector search, graph traversal primitives │ +//! │ 0x00-0x0F:XX │ SURFACE (16 prefixes × 256 = 4,096) │ +//! │ │ 0x00: Lance/Kuzu 0x08: Concepts │ +//! │ │ 0x01: SQL 0x09: Qualia ops │ +//! │ │ 0x02: Neo4j/Cypher 0x0A: Memory ops │ +//! │ │ 0x03: GraphQL 0x0B: Learning ops │ +//! │ │ 0x04: NARS 0x0C: Reserved │ +//! │ │ 0x05: Causal 0x0D: Reserved │ +//! │ │ 0x06: Meta 0x0E: Reserved │ +//! │ │ 0x07: Verbs 0x0F: Reserved │ //! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x01:XX │ SURFACE 1 - SQL/Neo4j (256) │ -//! │ │ Relational + property graph primitives │ +//! │ 0x10-0x7F:XX │ FLUID (112 prefixes × 256 = 28,672) │ +//! │ │ Edges + Context selector + Working memory │ //! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x02:XX │ SURFACE 2 - Higher-order thinking (256) │ -//! │ │ Meta-cognition, NARS, reasoning patterns │ -//! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x03:XX │ SURFACE 3 - Verbs/Cypher (256) │ -//! │ │ CAUSES, BECOMES, ENABLES... 144 Go board verbs │ -//! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x04-0x7F:XX │ FLUID (124 chunks × 256 = 31,744 edges) │ -//! │ │ Context selector + edge storage │ -//! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x80-0xFF:XX │ NODES (128 chunks × 256 = 32,768 nodes) │ +//! │ 0x80-0xFF:XX │ NODES (128 prefixes × 256 = 32,768) │ //! │ │ THE UNIVERSAL BIND SPACE │ //! │ │ All languages hit this. Any syntax. Same addresses. │ //! └─────────────────┴───────────────────────────────────────────────────────────┘ @@ -41,24 +39,11 @@ //! //! Works on ANY CPU: No AVX-512, no SIMD, no special instructions. //! Just shift, mask, array index. Even works on embedded/WASM. -//! -//! # The 4-Compartment Surface -//! -//! Each surface is 256 slots that fit in L1 cache: -//! -//! | Prefix | Surface | Language primitives | -//! |--------|--------------|----------------------------------------| -//! | 0x00 | Lance/Kuzu | VECTOR_SEARCH, TRAVERSE, RESONATE | -//! | 0x01 | SQL/Neo4j | SELECT, JOIN, MATCH, WHERE | -//! | 0x02 | Meta | REFLECT, ABSTRACT, DEDUCE, ABDUCT | -//! | 0x03 | Verbs | CAUSES, BECOMES, ENABLES, AMPLIFIES | -//! -//! All surfaces speak different languages but hit the SAME bind space. use std::time::Instant; // ============================================================================= -// ADDRESS CONSTANTS (8-bit prefix architecture) +// ADDRESS CONSTANTS (8-bit prefix : 8-bit slot) // ============================================================================= /// Fingerprint words (10K bits = 156 × 64-bit words) @@ -67,24 +52,54 @@ pub const FINGERPRINT_WORDS: usize = 156; /// Slots per chunk (2^8 = 256) pub const CHUNK_SIZE: usize = 256; -/// Surface prefixes (4 compartments) -pub const PREFIX_LANCE: u8 = 0x00; // Lance/Kuzu ops -pub const PREFIX_SQL: u8 = 0x01; // SQL/Neo4j ops -pub const PREFIX_META: u8 = 0x02; // Higher-order thinking -pub const PREFIX_VERBS: u8 = 0x03; // Verbs/Cypher +// ----------------------------------------------------------------------------- +// SURFACE: 16 prefixes (0x00-0x0F) × 256 = 4,096 addresses +// ----------------------------------------------------------------------------- -/// Fluid range (edges + context) -pub const PREFIX_FLUID_START: u8 = 0x04; +/// Surface prefix range +pub const PREFIX_SURFACE_START: u8 = 0x00; +pub const PREFIX_SURFACE_END: u8 = 0x0F; +pub const SURFACE_PREFIXES: usize = 16; +pub const SURFACE_SIZE: usize = 4096; // 16 × 256 + +/// Surface compartments (16 available) +pub const PREFIX_LANCE: u8 = 0x00; // Lance/Kuzu - vector ops +pub const PREFIX_SQL: u8 = 0x01; // SQL ops +pub const PREFIX_CYPHER: u8 = 0x02; // Neo4j/Cypher ops +pub const PREFIX_GRAPHQL: u8 = 0x03; // GraphQL ops +pub const PREFIX_NARS: u8 = 0x04; // NARS inference +pub const PREFIX_CAUSAL: u8 = 0x05; // Causal reasoning (Pearl) +pub const PREFIX_META: u8 = 0x06; // Meta-cognition +pub const PREFIX_VERBS: u8 = 0x07; // Verbs (CAUSES, BECOMES...) +pub const PREFIX_CONCEPTS: u8 = 0x08; // Core concepts/types +pub const PREFIX_QUALIA: u8 = 0x09; // Qualia operations +pub const PREFIX_MEMORY: u8 = 0x0A; // Memory operations +pub const PREFIX_LEARNING: u8 = 0x0B; // Learning operations +pub const PREFIX_RESERVED_C: u8 = 0x0C; +pub const PREFIX_RESERVED_D: u8 = 0x0D; +pub const PREFIX_RESERVED_E: u8 = 0x0E; +pub const PREFIX_RESERVED_F: u8 = 0x0F; + +// ----------------------------------------------------------------------------- +// FLUID: 112 prefixes (0x10-0x7F) × 256 = 28,672 addresses +// ----------------------------------------------------------------------------- + +pub const PREFIX_FLUID_START: u8 = 0x10; pub const PREFIX_FLUID_END: u8 = 0x7F; -pub const FLUID_CHUNKS: usize = 124; // 0x7F - 0x04 + 1 +pub const FLUID_PREFIXES: usize = 112; // 0x7F - 0x10 + 1 +pub const FLUID_SIZE: usize = 28672; // 112 × 256 + +// ----------------------------------------------------------------------------- +// NODES: 128 prefixes (0x80-0xFF) × 256 = 32,768 addresses +// ----------------------------------------------------------------------------- -/// Node range (universal bind space) pub const PREFIX_NODE_START: u8 = 0x80; pub const PREFIX_NODE_END: u8 = 0xFF; -pub const NODE_CHUNKS: usize = 128; // 0xFF - 0x80 + 1 +pub const NODE_PREFIXES: usize = 128; // 0xFF - 0x80 + 1 +pub const NODE_SIZE: usize = 32768; // 128 × 256 /// Total addressable -pub const TOTAL_ADDRESSES: usize = 65536; +pub const TOTAL_ADDRESSES: usize = 65536; // 256 × 256 // ============================================================================= // ADDRESS TYPE @@ -113,13 +128,13 @@ impl Addr { (self.0 & 0xFF) as u8 } - /// Check if in surface (prefix 0x00-0x03) + /// Check if in surface (prefix 0x00-0x0F) #[inline(always)] pub fn is_surface(self) -> bool { - self.prefix() <= PREFIX_VERBS + self.prefix() <= PREFIX_SURFACE_END } - /// Check if in fluid zone (prefix 0x04-0x7F) + /// Check if in fluid zone (prefix 0x10-0x7F) #[inline(always)] pub fn is_fluid(self) -> bool { let p = self.prefix(); @@ -132,16 +147,10 @@ impl Addr { self.prefix() >= PREFIX_NODE_START } - /// Get surface compartment (0-3) or None + /// Get surface compartment (0x00-0x0F) or None #[inline(always)] pub fn surface_compartment(self) -> Option { - match self.prefix() { - PREFIX_LANCE => Some(SurfaceCompartment::Lance), - PREFIX_SQL => Some(SurfaceCompartment::Sql), - PREFIX_META => Some(SurfaceCompartment::Meta), - PREFIX_VERBS => Some(SurfaceCompartment::Verbs), - _ => None, - } + SurfaceCompartment::from_prefix(self.prefix()) } } @@ -158,21 +167,39 @@ impl From for u16 { } // ============================================================================= -// SURFACE COMPARTMENTS +// SURFACE COMPARTMENTS (16 available, 0x00-0x0F) // ============================================================================= -/// The 4 surface compartments +/// The 16 surface compartments #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum SurfaceCompartment { - /// 0x00: Lance/Kuzu - vector search, graph traversal - Lance = 0, - /// 0x01: SQL/Neo4j - relational, property graph - Sql = 1, - /// 0x02: Meta - higher-order thinking, NARS - Meta = 2, - /// 0x03: Verbs - CAUSES, BECOMES, etc. - Verbs = 3, + /// 0x00: Lance/Kuzu - vector search, traversal + Lance = 0x00, + /// 0x01: SQL - relational operations + Sql = 0x01, + /// 0x02: Neo4j/Cypher - property graph + Cypher = 0x02, + /// 0x03: GraphQL - query language + GraphQL = 0x03, + /// 0x04: NARS - inference operations + Nars = 0x04, + /// 0x05: Causal - Pearl's ladder + Causal = 0x05, + /// 0x06: Meta - higher-order thinking + Meta = 0x06, + /// 0x07: Verbs - CAUSES, BECOMES, etc. + Verbs = 0x07, + /// 0x08: Concepts - core types + Concepts = 0x08, + /// 0x09: Qualia - felt quality ops + Qualia = 0x09, + /// 0x0A: Memory - memory operations + Memory = 0x0A, + /// 0x0B: Learning - learning operations + Learning = 0x0B, + /// 0x0C-0x0F: Reserved + Reserved = 0x0C, } impl SurfaceCompartment { @@ -183,6 +210,25 @@ impl SurfaceCompartment { pub fn addr(self, slot: u8) -> Addr { Addr::new(self as u8, slot) } + + pub fn from_prefix(prefix: u8) -> Option { + match prefix { + 0x00 => Some(Self::Lance), + 0x01 => Some(Self::Sql), + 0x02 => Some(Self::Cypher), + 0x03 => Some(Self::GraphQL), + 0x04 => Some(Self::Nars), + 0x05 => Some(Self::Causal), + 0x06 => Some(Self::Meta), + 0x07 => Some(Self::Verbs), + 0x08 => Some(Self::Concepts), + 0x09 => Some(Self::Qualia), + 0x0A => Some(Self::Memory), + 0x0B => Some(Self::Learning), + 0x0C..=0x0F => Some(Self::Reserved), + _ => None, + } + } } // ============================================================================= @@ -325,23 +371,17 @@ impl BindEdge { /// Works on any CPU. pub struct BindSpace { // ========================================================================= - // SURFACES (4 compartments × 256 slots each) + // SURFACES: 16 prefixes (0x00-0x0F) × 256 slots = 4,096 addresses // ========================================================================= - /// Surface 0: Lance/Kuzu ops - surface_lance: Box<[Option; CHUNK_SIZE]>, - /// Surface 1: SQL/Neo4j ops - surface_sql: Box<[Option; CHUNK_SIZE]>, - /// Surface 2: Meta/Higher-order thinking - surface_meta: Box<[Option; CHUNK_SIZE]>, - /// Surface 3: Verbs/Cypher - surface_verbs: Box<[Option; CHUNK_SIZE]>, + /// All 16 surface compartments + surfaces: Vec; CHUNK_SIZE]>>, // ========================================================================= - // FLUID (124 chunks × 256 slots = 31,744 edges) + // FLUID: 112 prefixes (0x10-0x7F) × 256 slots = 28,672 addresses // ========================================================================= - /// Fluid chunks for edge storage + /// Fluid chunks for edge storage + working memory fluid: Vec; CHUNK_SIZE]>>, /// Edges (separate for efficient traversal) @@ -354,10 +394,10 @@ pub struct BindSpace { edge_in: Vec>, // ========================================================================= - // NODES (128 chunks × 256 slots = 32,768 nodes) + // NODES: 128 prefixes (0x80-0xFF) × 256 slots = 32,768 addresses // ========================================================================= - /// Node chunks + /// Node chunks - THE UNIVERSAL BIND SPACE nodes: Vec; CHUNK_SIZE]>>, // ========================================================================= @@ -376,21 +416,21 @@ pub struct BindSpace { impl BindSpace { pub fn new() -> Self { - // Initialize surfaces - let surface_lance = Box::new(std::array::from_fn(|_| None)); - let surface_sql = Box::new(std::array::from_fn(|_| None)); - let surface_meta = Box::new(std::array::from_fn(|_| None)); - let surface_verbs = Box::new(std::array::from_fn(|_| None)); - - // Initialize fluid chunks - let mut fluid = Vec::with_capacity(FLUID_CHUNKS); - for _ in 0..FLUID_CHUNKS { + // Initialize 16 surface compartments + let mut surfaces = Vec::with_capacity(SURFACE_PREFIXES); + for _ in 0..SURFACE_PREFIXES { + surfaces.push(Box::new(std::array::from_fn(|_| None))); + } + + // Initialize 112 fluid chunks + let mut fluid = Vec::with_capacity(FLUID_PREFIXES); + for _ in 0..FLUID_PREFIXES { fluid.push(Box::new(std::array::from_fn(|_| None))); } - // Initialize node chunks - let mut nodes = Vec::with_capacity(NODE_CHUNKS); - for _ in 0..NODE_CHUNKS { + // Initialize 128 node chunks + let mut nodes = Vec::with_capacity(NODE_PREFIXES); + for _ in 0..NODE_PREFIXES { nodes.push(Box::new(std::array::from_fn(|_| None))); } @@ -399,10 +439,7 @@ impl BindSpace { let edge_in = vec![Vec::new(); TOTAL_ADDRESSES]; let mut space = Self { - surface_lance, - surface_sql, - surface_meta, - surface_verbs, + surfaces, fluid, edges: Vec::new(), edge_out, @@ -419,7 +456,7 @@ impl BindSpace { /// Initialize surfaces with core ops fn init_surfaces(&mut self) { - // Surface 0: Lance/Kuzu ops + // Surface 0x00: Lance/Kuzu ops let lance_ops = [ (0x00, "VECTOR_SEARCH"), (0x01, "TRAVERSE"), @@ -435,10 +472,10 @@ impl BindSpace { (0x0B, "QUANTIZE"), ]; for (slot, label) in lance_ops { - self.surface_lance[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + self.surfaces[PREFIX_LANCE as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); } - // Surface 1: SQL/Neo4j ops + // Surface 0x01: SQL ops let sql_ops = [ (0x00, "SELECT"), (0x01, "INSERT"), @@ -448,35 +485,67 @@ impl BindSpace { (0x05, "WHERE"), (0x06, "GROUP"), (0x07, "ORDER"), - (0x08, "MATCH"), - (0x09, "CREATE"), - (0x0A, "MERGE"), - (0x0B, "RETURN"), ]; for (slot, label) in sql_ops { - self.surface_sql[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + self.surfaces[PREFIX_SQL as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 0x02: Neo4j/Cypher ops + let cypher_ops = [ + (0x00, "MATCH"), + (0x01, "CREATE"), + (0x02, "MERGE"), + (0x03, "RETURN"), + (0x04, "WITH"), + (0x05, "UNWIND"), + (0x06, "OPTIONAL_MATCH"), + (0x07, "DETACH_DELETE"), + ]; + for (slot, label) in cypher_ops { + self.surfaces[PREFIX_CYPHER as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); } - // Surface 2: Meta/Higher-order ops + // Surface 0x04: NARS inference ops + let nars_ops = [ + (0x00, "DEDUCE"), + (0x01, "ABDUCT"), + (0x02, "INDUCE"), + (0x03, "REVISE"), + (0x04, "CHOICE"), + (0x05, "EXPECTATION"), + ]; + for (slot, label) in nars_ops { + self.surfaces[PREFIX_NARS as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 0x05: Causal ops (Pearl's ladder) + let causal_ops = [ + (0x00, "OBSERVE"), // Rung 1 + (0x01, "INTERVENE"), // Rung 2 (do) + (0x02, "IMAGINE"), // Rung 3 (counterfactual) + (0x03, "CAUSE"), + (0x04, "EFFECT"), + (0x05, "CONFOUND"), + ]; + for (slot, label) in causal_ops { + self.surfaces[PREFIX_CAUSAL as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 0x06: Meta-cognition ops let meta_ops = [ (0x00, "REFLECT"), (0x01, "ABSTRACT"), - (0x02, "DEDUCE"), - (0x03, "ABDUCT"), - (0x04, "INDUCE"), - (0x05, "ANALOGIZE"), - (0x06, "HYPOTHESIZE"), - (0x07, "REVISE"), - (0x08, "BELIEVE"), - (0x09, "DOUBT"), - (0x0A, "IMAGINE"), - (0x0B, "COUNTERFACT"), + (0x02, "ANALOGIZE"), + (0x03, "HYPOTHESIZE"), + (0x04, "BELIEVE"), + (0x05, "DOUBT"), + (0x06, "COUNTERFACT"), ]; for (slot, label) in meta_ops { - self.surface_meta[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + self.surfaces[PREFIX_META as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); } - // Surface 3: Verbs (the 144 Go board verbs) + // Surface 0x07: Verbs (the Go board verbs) let verb_ops = [ (0x00, "CAUSES"), (0x01, "BECOMES"), @@ -508,7 +577,57 @@ impl BindSpace { (0x1B, "SUPPORTS"), ]; for (slot, label) in verb_ops { - self.surface_verbs[slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + self.surfaces[PREFIX_VERBS as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 0x08: Core concepts + let concept_ops = [ + (0x00, "ENTITY"), + (0x01, "RELATION"), + (0x02, "ATTRIBUTE"), + (0x03, "EVENT"), + (0x04, "STATE"), + (0x05, "PROCESS"), + ]; + for (slot, label) in concept_ops { + self.surfaces[PREFIX_CONCEPTS as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 0x09: Qualia ops + let qualia_ops = [ + (0x00, "FEEL"), + (0x01, "INTUIT"), + (0x02, "SENSE"), + (0x03, "VALENCE"), + (0x04, "AROUSAL"), + (0x05, "TENSION"), + ]; + for (slot, label) in qualia_ops { + self.surfaces[PREFIX_QUALIA as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 0x0A: Memory ops + let memory_ops = [ + (0x00, "STORE"), + (0x01, "RECALL"), + (0x02, "FORGET"), + (0x03, "CONSOLIDATE"), + (0x04, "ASSOCIATE"), + ]; + for (slot, label) in memory_ops { + self.surfaces[PREFIX_MEMORY as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); + } + + // Surface 0x0B: Learning ops + let learning_ops = [ + (0x00, "LEARN"), + (0x01, "UNLEARN"), + (0x02, "REINFORCE"), + (0x03, "GENERALIZE"), + (0x04, "SPECIALIZE"), + ]; + for (slot, label) in learning_ops { + self.surfaces[PREFIX_LEARNING as usize][slot] = Some(BindNode::new(label_fingerprint(label)).with_label(label)); } } @@ -526,14 +645,16 @@ impl BindSpace { let slot = addr.slot() as usize; match prefix { - PREFIX_LANCE => self.surface_lance[slot].as_ref(), - PREFIX_SQL => self.surface_sql[slot].as_ref(), - PREFIX_META => self.surface_meta[slot].as_ref(), - PREFIX_VERBS => self.surface_verbs[slot].as_ref(), + // Surface: 0x00-0x0F + p if p <= PREFIX_SURFACE_END => { + self.surfaces.get(p as usize).and_then(|c| c[slot].as_ref()) + } + // Fluid: 0x10-0x7F p if p >= PREFIX_FLUID_START && p <= PREFIX_FLUID_END => { let chunk = (p - PREFIX_FLUID_START) as usize; self.fluid.get(chunk).and_then(|c| c[slot].as_ref()) } + // Nodes: 0x80-0xFF p if p >= PREFIX_NODE_START => { let chunk = (p - PREFIX_NODE_START) as usize; self.nodes.get(chunk).and_then(|c| c[slot].as_ref()) @@ -549,14 +670,16 @@ impl BindSpace { let slot = addr.slot() as usize; let node = match prefix { - PREFIX_LANCE => self.surface_lance[slot].as_mut(), - PREFIX_SQL => self.surface_sql[slot].as_mut(), - PREFIX_META => self.surface_meta[slot].as_mut(), - PREFIX_VERBS => self.surface_verbs[slot].as_mut(), + // Surface: 0x00-0x0F + p if p <= PREFIX_SURFACE_END => { + self.surfaces.get_mut(p as usize).and_then(|c| c[slot].as_mut()) + } + // Fluid: 0x10-0x7F p if p >= PREFIX_FLUID_START && p <= PREFIX_FLUID_END => { let chunk = (p - PREFIX_FLUID_START) as usize; self.fluid.get_mut(chunk).and_then(|c| c[slot].as_mut()) } + // Nodes: 0x80-0xFF p if p >= PREFIX_NODE_START => { let chunk = (p - PREFIX_NODE_START) as usize; self.nodes.get_mut(chunk).and_then(|c| c[slot].as_mut()) @@ -614,7 +737,7 @@ impl BindSpace { let slot = addr.slot() as usize; // Can't delete surfaces - if prefix <= PREFIX_VERBS { + if prefix <= PREFIX_SURFACE_END { return None; } @@ -733,12 +856,31 @@ impl BindSpace { // SURFACE HELPERS // ========================================================================= - /// Get verb address by name + /// Get verb address by name (searches PREFIX_VERBS compartment) pub fn verb(&self, name: &str) -> Option { - for slot in 0..CHUNK_SIZE { - if let Some(node) = &self.surface_verbs[slot] { - if node.label.as_deref() == Some(name) { - return Some(Addr::new(PREFIX_VERBS, slot as u8)); + if let Some(verbs) = self.surfaces.get(PREFIX_VERBS as usize) { + for slot in 0..CHUNK_SIZE { + if let Some(node) = &verbs[slot] { + if node.label.as_deref() == Some(name) { + return Some(Addr::new(PREFIX_VERBS, slot as u8)); + } + } + } + } + None + } + + /// Get op address by name from any surface compartment + pub fn surface_op(&self, compartment: u8, name: &str) -> Option { + if compartment > PREFIX_SURFACE_END { + return None; + } + if let Some(surface) = self.surfaces.get(compartment as usize) { + for slot in 0..CHUNK_SIZE { + if let Some(node) = &surface[slot] { + if node.label.as_deref() == Some(name) { + return Some(Addr::new(compartment, slot as u8)); + } } } } @@ -755,12 +897,9 @@ impl BindSpace { // ========================================================================= pub fn stats(&self) -> BindSpaceStats { - let surface_count = [ - &self.surface_lance, - &self.surface_sql, - &self.surface_meta, - &self.surface_verbs, - ].iter().map(|s| s.iter().filter(|x| x.is_some()).count()).sum(); + let surface_count: usize = self.surfaces.iter() + .map(|s| s.iter().filter(|x| x.is_some()).count()) + .sum(); let fluid_count: usize = self.fluid.iter() .map(|c| c.iter().filter(|x| x.is_some()).count()) @@ -779,7 +918,6 @@ impl BindSpace { } } } - impl Default for BindSpace { fn default() -> Self { Self::new() From f017b17aee7f91629c85ed607e362fb178bbf178 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Fri, 30 Jan 2026 22:09:35 +0100 Subject: [PATCH 5/5] Updated exports for 16 prefixes --- src/storage/mod.rs | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 9614195..349e554 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -1,17 +1,18 @@ //! Storage module - Persistence layers //! -//! # 8-bit Prefix Architecture +//! # 8-bit Prefix : 8-bit Slot Architecture //! //! ```text //! ┌─────────────────────────────────────────────────────────────────────────────┐ -//! │ PREFIX (8-bit) : ADDRESS (8-bit) │ +//! │ PREFIX (8-bit) : SLOT (8-bit) │ //! ├─────────────────┬───────────────────────────────────────────────────────────┤ -//! │ 0x00:XX │ SURFACE 0 - Lance/Kuzu (256 ops) │ -//! │ 0x01:XX │ SURFACE 1 - SQL/Neo4j (256 ops) │ -//! │ 0x02:XX │ SURFACE 2 - Meta/NARS (256 ops) │ -//! │ 0x03:XX │ SURFACE 3 - Verbs/Cypher (256 verbs) │ +//! │ 0x00-0x0F:XX │ SURFACE (16 × 256 = 4,096) │ +//! │ │ 0x00: Lance 0x04: NARS 0x08: Concepts │ +//! │ │ 0x01: SQL 0x05: Causal 0x09: Qualia │ +//! │ │ 0x02: Cypher 0x06: Meta 0x0A: Memory │ +//! │ │ 0x03: GraphQL 0x07: Verbs 0x0B: Learning │ //! ├─────────────────┼───────────────────────────────────────────────────────────┤ -//! │ 0x04-0x7F:XX │ FLUID (124 × 256 = 31,744 edges) │ +//! │ 0x10-0x7F:XX │ FLUID (112 × 256 = 28,672) │ //! ├─────────────────┼───────────────────────────────────────────────────────────┤ //! │ 0x80-0xFF:XX │ NODES (128 × 256 = 32,768) - UNIVERSAL BIND SPACE │ //! └─────────────────┴───────────────────────────────────────────────────────────┘ @@ -43,17 +44,25 @@ pub use cog_redis::{ // Address types CogAddr, Tier, SurfaceCompartment, - // Prefix constants - PREFIX_LANCE, PREFIX_SQL, PREFIX_META, PREFIX_VERBS, - PREFIX_FLUID_START, PREFIX_FLUID_END, - PREFIX_NODE_START, PREFIX_NODE_END, - CHUNK_SIZE, + // Surface prefix constants (16 compartments) + PREFIX_SURFACE_START, PREFIX_SURFACE_END, SURFACE_PREFIXES, + PREFIX_LANCE, PREFIX_SQL, PREFIX_CYPHER, PREFIX_GRAPHQL, + PREFIX_NARS, PREFIX_CAUSAL, PREFIX_META, PREFIX_VERBS, + PREFIX_CONCEPTS, PREFIX_QUALIA, PREFIX_MEMORY, PREFIX_LEARNING, - // Legacy constants (compatibility) - SURFACE_START, SURFACE_END, SURFACE_SIZE, - FLUID_START, FLUID_END, FLUID_SIZE, - NODE_START, NODE_END, NODE_SIZE, - TOTAL_SIZE, + // Fluid prefix constants (112 chunks) + PREFIX_FLUID_START, PREFIX_FLUID_END, FLUID_PREFIXES, + + // Node prefix constants (128 chunks) + PREFIX_NODE_START, PREFIX_NODE_END, NODE_PREFIXES, + + // Size constants + CHUNK_SIZE, SURFACE_SIZE, FLUID_SIZE, NODE_SIZE, TOTAL_SIZE, + + // Legacy 16-bit range constants (compatibility) + SURFACE_START, SURFACE_END, + FLUID_START, FLUID_END, + NODE_START, NODE_END, // Values and edges CogValue, CogEdge,