haematite 0.6.1

Content-addressed, branchable, actor-native storage engine
Documentation
//! Lens Q2, the work-list half (Sol r2 fold): candidate storage for M3
//! roots is O(1) per root — pinned structurally on `group_snapshot_roots`.

use std::path::PathBuf;

use crate::branch::SnapshotEntry;
use crate::tree::Hash;

use super::super::consult::{MetadataPass, RegistrySource};
use super::super::report::MarkTallies;
use super::{SnapshotCandidates, group_snapshot_roots};

fn entry(name: &str) -> SnapshotEntry {
    SnapshotEntry {
        name: name.to_owned(),
        root_hash: Hash::from_bytes([0x77; 32]),
        timestamp: 1,
    }
}

fn pass_with(registries: Vec<RegistrySource>) -> MetadataPass {
    MetadataPass {
        manifest_report: None,
        sources: Vec::new(),
        refs_scans: Vec::new(),
        registries,
        supplied_missing: Vec::new(),
        blockers: Vec::new(),
        listed_paths: Vec::new(),
    }
}

/// Lens Q2, the work-list half (Sol r2): candidate storage is O(1) per
/// root — unbound roots carry NO shard list, and every root of a bound
/// registry SHARES the registry's single Arc (pointer-equal), so R
/// roots × S shards never materialises.
#[test]
fn candidate_storage_is_shared_not_per_root() -> Result<(), Box<dyn std::error::Error>> {
    let metadata = pass_with(vec![
        RegistrySource {
            path: PathBuf::from("/unbound.hsr"),
            entries: (0..50).map(|index| entry(&format!("u{index}"))).collect(),
            declared_shards: None,
        },
        RegistrySource {
            path: PathBuf::from("/bound.hsr"),
            entries: (0..50).map(|index| entry(&format!("b{index}"))).collect(),
            declared_shards: Some(vec![0, 2]),
        },
    ]);
    let mut tallies = MarkTallies::default();
    let work = group_snapshot_roots(&metadata, 4096, &mut tallies)?;
    assert_eq!(work.len(), 100);
    assert_eq!(tallies.snapshot_roots, 100);

    let mut shared: Option<&std::sync::Arc<[usize]>> = None;
    for item in &work {
        match &item.candidates {
            SnapshotCandidates::AllShards => {}
            SnapshotCandidates::Declared(ids) => match shared {
                None => shared = Some(ids),
                Some(first) => assert!(
                    std::sync::Arc::ptr_eq(first, ids),
                    "bound roots must SHARE one Arc, never clone the list"
                ),
            },
        }
    }
    let unbound = work
        .iter()
        .filter(|item| matches!(item.candidates, SnapshotCandidates::AllShards))
        .count();
    assert_eq!(unbound, 50, "unbound roots carry no list at all");
    assert!(shared.is_some(), "bound roots present");
    Ok(())
}