Skip to content

Commit 7b038d9

Browse files
committed
fix: revert incorrect bind_space.rs changes — ClamPath belongs on CogRecord8K, not BindNode
Removes clam_merkle field, verify_lineage(), Epoch, and stamp methods from BindNode. ClamPath + MerkleRoot is already correctly implemented in src/spo/clam_path.rs via ClamPathExt trait on CogRecord8K.index.words[0]. BindNode is a lightweight DTO — enriching it with integrity verification violated the Three-Layer Principle (BINDSPACE_UNIFICATION.md). https://claude.ai/code/session_013JU8MRtxRRTtuc5217r6s5
1 parent fc1bd86 commit 7b038d9

1 file changed

Lines changed: 0 additions & 231 deletions

File tree

src/storage/bind_space.rs

Lines changed: 0 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ use std::collections::HashMap;
4747

4848
use crate::container::adjacency::PackedDn;
4949
use crate::container::{CONTAINER_WORDS, Container, MetaView, MetaViewMut};
50-
use crate::spo::clam_path::{ClamPath, MerkleRoot};
5150

5251
// =============================================================================
5352
// ADDRESS CONSTANTS (8-bit prefix : 8-bit slot)
@@ -359,10 +358,6 @@ pub struct BindNode {
359358
/// Epoch millis when this node was last written/modified.
360359
/// Used for age-based hot→cold tier flushing to Lance.
361360
pub updated_at: u64,
362-
/// ClamPath(24 bits) + MerkleRoot(40 bits) packed into u64.
363-
/// Stamped during write_dn_node()/write_dn_path().
364-
/// See ClamPath::pack_with_merkle() / unpack_with_merkle().
365-
pub clam_merkle: u64,
366361
}
367362

368363
impl BindNode {
@@ -383,7 +378,6 @@ impl BindNode {
383378
sigma: 0,
384379
is_spine: false,
385380
updated_at: now,
386-
clam_merkle: 0,
387381
}
388382
}
389383

@@ -780,54 +774,6 @@ impl DirtyBits {
780774
}
781775
}
782776

783-
// =============================================================================
784-
// INTEGRITY RESULT
785-
// =============================================================================
786-
787-
/// Result of a lineage integrity check.
788-
#[derive(Debug, Clone, PartialEq, Eq)]
789-
pub enum IntegrityResult {
790-
/// All parent-child MerkleRoots are consistent.
791-
Consistent,
792-
/// A node in the lineage chain diverged (roots inconsistent).
793-
Diverged { at: Addr },
794-
/// A node in the lineage chain was not found.
795-
Missing { at: Addr },
796-
}
797-
798-
// =============================================================================
799-
// EPOCH: Dirty bitset snapshot for change detection
800-
// =============================================================================
801-
802-
/// 8 KB dirty bitset snapshot. Flat array, same shape as DirtyBits.
803-
/// XOR two epochs to find what changed. POPCNT = how many. iter set bits = which.
804-
#[derive(Clone)]
805-
pub struct Epoch {
806-
pub bits: [u64; TOTAL_ADDRESSES / 64],
807-
pub timestamp_ms: u64,
808-
}
809-
810-
impl Epoch {
811-
/// Find addresses that changed between two epochs.
812-
/// XOR the bitsets, iterate set bits = changed addresses.
813-
pub fn changed_between<'a>(a: &'a Epoch, b: &'a Epoch) -> impl Iterator<Item = Addr> + 'a {
814-
a.bits.iter().zip(b.bits.iter()).enumerate().flat_map(|(wi, (&wa, &wb))| {
815-
let xor = wa ^ wb;
816-
let base = (wi * 64) as u16;
817-
(0..64u16)
818-
.filter(move |&bit| xor & (1u64 << bit) != 0)
819-
.map(move |bit| Addr(base + bit))
820-
})
821-
}
822-
823-
/// Count of changed addresses between two epochs.
824-
pub fn change_count(a: &Epoch, b: &Epoch) -> u32 {
825-
a.bits.iter().zip(b.bits.iter())
826-
.map(|(&wa, &wb)| (wa ^ wb).count_ones())
827-
.sum()
828-
}
829-
}
830-
831777
// =============================================================================
832778
// BIND SPACE - The Universal DTO (Array-based storage)
833779
// =============================================================================
@@ -1468,16 +1414,11 @@ impl BindSpace {
14681414
.unwrap_or(0);
14691415

14701416
let addr = self.write(fingerprint);
1471-
1472-
// Stamp ClamPath + MerkleRoot. ClamPath is ROOT initially.
1473-
let clam_merkle = Self::derive_clam_merkle(&fingerprint);
1474-
14751417
if let Some(node) = self.read_mut(addr) {
14761418
node.label = Some(label.to_string());
14771419
node.parent = parent;
14781420
node.depth = depth;
14791421
node.rung = rung;
1480-
node.clam_merkle = clam_merkle;
14811422
}
14821423

14831424
// Auto-link PARENT_OF edge
@@ -1542,16 +1483,11 @@ impl BindSpace {
15421483

15431484
// Write at computed address
15441485
self.write_at(addr, fp);
1545-
1546-
// Stamp ClamPath + MerkleRoot
1547-
let clam_merkle = Self::derive_clam_merkle(&fp);
1548-
15491486
if let Some(node) = self.read_mut(addr) {
15501487
node.label = Some(format!("bindspace://{}", current_path));
15511488
node.parent = current_parent;
15521489
node.depth = i as u8;
15531490
node.rung = rung;
1554-
node.clam_merkle = clam_merkle;
15551491
}
15561492

15571493
// Link to parent
@@ -1909,84 +1845,6 @@ impl BindSpace {
19091845
self.dirty.clear();
19101846
}
19111847

1912-
// =========================================================================
1913-
// INTEGRITY: ClamPath + MerkleRoot
1914-
// =========================================================================
1915-
1916-
/// Derive ClamPath::ROOT + MerkleRoot from a fingerprint array.
1917-
/// blake3 hash of the first 2048 bytes, truncated to 40 bits.
1918-
fn derive_clam_merkle(fingerprint: &[u64; FINGERPRINT_WORDS]) -> u64 {
1919-
// Reinterpret u64 words as bytes (safe: same representation)
1920-
let fp_bytes: &[u8] = unsafe {
1921-
std::slice::from_raw_parts(
1922-
fingerprint.as_ptr() as *const u8,
1923-
fingerprint.len() * 8,
1924-
)
1925-
};
1926-
// Use first 2048 bytes for MerkleRoot
1927-
let fp_2k: &[u8; 2048] = fp_bytes[..2048].try_into().unwrap();
1928-
let merkle = MerkleRoot::from_fingerprint(fp_2k);
1929-
ClamPath::ROOT.pack_with_merkle(merkle)
1930-
}
1931-
1932-
/// Read ClamPath + MerkleRoot from a node's clam_merkle field. O(1).
1933-
#[inline]
1934-
pub fn clam_merkle(&self, addr: Addr) -> Option<(ClamPath, MerkleRoot)> {
1935-
self.read(addr).map(|n| ClamPath::unpack_with_merkle(n.clam_merkle))
1936-
}
1937-
1938-
/// Update ClamPath for a node (e.g., after CLAM tree rebuild).
1939-
/// Preserves existing MerkleRoot.
1940-
pub fn set_clam_path(&mut self, addr: Addr, path: ClamPath) {
1941-
if let Some(node) = self.read_mut(addr) {
1942-
let (_, root) = ClamPath::unpack_with_merkle(node.clam_merkle);
1943-
node.clam_merkle = path.pack_with_merkle(root);
1944-
}
1945-
}
1946-
1947-
/// Verify integrity from addr up to root via parent chain.
1948-
/// Each step: read clam_merkle at known address (O(1)), check non-zero root.
1949-
/// Full XOR-of-children verification requires knowing all children;
1950-
/// this walks the lineage chain and checks consistency.
1951-
pub fn verify_lineage(&self, addr: Addr) -> IntegrityResult {
1952-
let child_node = match self.read(addr) {
1953-
Some(n) => n,
1954-
None => return IntegrityResult::Missing { at: addr },
1955-
};
1956-
let (_, child_root) = ClamPath::unpack_with_merkle(child_node.clam_merkle);
1957-
let _ = child_root; // used for chain start
1958-
1959-
// Walk parent chain — each step is O(1) array index + compare.
1960-
for parent_addr in self.ancestors(addr) {
1961-
let parent_node = match self.read(parent_addr) {
1962-
Some(n) => n,
1963-
None => return IntegrityResult::Missing { at: parent_addr },
1964-
};
1965-
let (_, parent_root) = ClamPath::unpack_with_merkle(parent_node.clam_merkle);
1966-
1967-
// Skip uninitialized nodes (not yet stamped)
1968-
if parent_root.is_zero() {
1969-
continue;
1970-
}
1971-
}
1972-
IntegrityResult::Consistent
1973-
}
1974-
1975-
// =========================================================================
1976-
// EPOCH: DirtyBits XOR for change detection
1977-
// =========================================================================
1978-
1979-
/// Snapshot current dirty bits as an Epoch (8 KB copy).
1980-
pub fn snapshot_dirty(&self) -> Epoch {
1981-
let now = std::time::SystemTime::now()
1982-
.duration_since(std::time::UNIX_EPOCH)
1983-
.unwrap_or_default()
1984-
.as_millis() as u64;
1985-
let mut bits = [0u64; TOTAL_ADDRESSES / 64];
1986-
bits.copy_from_slice(&self.dirty.bits);
1987-
Epoch { bits, timestamp_ms: now }
1988-
}
1989-
19901848
// =========================================================================
19911849
// PARALLEL BULK OPERATIONS (split_at_mut / parallel_into_slices)
19921850
// =========================================================================
@@ -2909,93 +2767,4 @@ mod tests {
29092767
let csr = space.csr.as_ref().unwrap();
29102768
assert!(csr.memory_bytes() < 300_000); // Should be ~260KB vs >1.5MB traditional
29112769
}
2912-
2913-
// =========================================================================
2914-
// ClamPath + MerkleRoot stamp tests
2915-
// =========================================================================
2916-
2917-
#[test]
2918-
fn test_clam_merkle_stamp_on_write_dn() {
2919-
let mut space = BindSpace::new();
2920-
let fp = [0xDEAD_BEEF_u64; FINGERPRINT_WORDS];
2921-
2922-
let addr = space.write_dn_path("agent:A:soul:identity", fp, 5);
2923-
2924-
// clam_merkle should be stamped (non-zero)
2925-
let node = space.read(addr).unwrap();
2926-
assert_ne!(node.clam_merkle, 0, "clam_merkle should be stamped on write_dn_path");
2927-
2928-
// Unpack and verify
2929-
let (path, root) = ClamPath::unpack_with_merkle(node.clam_merkle);
2930-
assert!(!root.is_zero(), "MerkleRoot should be non-zero for non-zero fingerprint");
2931-
assert_eq!(path, ClamPath::ROOT, "Initial ClamPath should be ROOT");
2932-
}
2933-
2934-
#[test]
2935-
fn test_clam_merkle_round_trip() {
2936-
let mut space = BindSpace::new();
2937-
let fp = [42u64; FINGERPRINT_WORDS];
2938-
2939-
let addr = space.write_dn_path("agent:A:test", fp, 1);
2940-
let (_path, root) = space.clam_merkle(addr).unwrap();
2941-
2942-
// Set a custom ClamPath (depth=3 means top 3 bits valid: 0xE000)
2943-
let custom_path = ClamPath { bits: 0xE000, depth: 3 };
2944-
space.set_clam_path(addr, custom_path);
2945-
2946-
let (path2, root2) = space.clam_merkle(addr).unwrap();
2947-
assert_eq!(path2.bits, custom_path.bits, "ClamPath bits should update");
2948-
assert_eq!(path2.depth, custom_path.depth, "ClamPath depth should update");
2949-
assert_eq!(root2, root, "MerkleRoot should be preserved across set_clam_path");
2950-
}
2951-
2952-
// =========================================================================
2953-
// Integrity verification tests
2954-
// =========================================================================
2955-
2956-
#[test]
2957-
fn test_integrity_verify_lineage_consistent() {
2958-
let mut space = BindSpace::new();
2959-
let fp = [7u64; FINGERPRINT_WORDS];
2960-
2961-
let leaf = space.write_dn_path("agent:A:soul:identity", fp, 5);
2962-
2963-
// verify_lineage should report consistent (all roots are stamped)
2964-
let result = space.verify_lineage(leaf);
2965-
assert_eq!(result, IntegrityResult::Consistent);
2966-
}
2967-
2968-
#[test]
2969-
fn test_integrity_verify_missing() {
2970-
let space = BindSpace::new();
2971-
// Non-existent address
2972-
let result = space.verify_lineage(Addr(0xFFFF));
2973-
assert_eq!(result, IntegrityResult::Missing { at: Addr(0xFFFF) });
2974-
}
2975-
2976-
// =========================================================================
2977-
// Epoch tests
2978-
// =========================================================================
2979-
2980-
#[test]
2981-
fn test_epoch_snapshot_and_diff() {
2982-
let mut space = BindSpace::new();
2983-
let fp1 = [1u64; FINGERPRINT_WORDS];
2984-
let fp2 = [2u64; FINGERPRINT_WORDS];
2985-
2986-
// Take initial epoch
2987-
let epoch1 = space.snapshot_dirty();
2988-
2989-
// Write some data
2990-
space.write_dn_path("agent:A:test1", fp1, 1);
2991-
space.write_dn_path("agent:B:test2", fp2, 1);
2992-
2993-
// Take second epoch
2994-
let epoch2 = space.snapshot_dirty();
2995-
2996-
// Should detect changes
2997-
let changed: Vec<Addr> = Epoch::changed_between(&epoch1, &epoch2).collect();
2998-
assert!(!changed.is_empty(), "Should detect dirty addresses");
2999-
assert!(Epoch::change_count(&epoch1, &epoch2) > 0);
3000-
}
30012770
}

0 commit comments

Comments
 (0)