@@ -47,7 +47,6 @@ use std::collections::HashMap;
4747
4848use crate :: container:: adjacency:: PackedDn ;
4949use 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
368363impl 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