hypersteeldb 0.5.4

A database that compiles questions instead of guessing answers: typed vocabulary discovered from your documents, queries type-checked before they run, roaring-bitmap set algebra over reified hyperedges, and Dempster-Shafer evidence with an explicit conflict guard.
Documentation
//! Layer-by-layer validation of the SteelDB pipeline. Deterministic layers always run; model layers
//! (tagger, SPLADE, projection) run when models are present. `cargo test --features onnx,agent --test layers -- --nocapture`.
use std::collections::HashMap;
use steeldb::index::InfonIndex;
use steeldb::{Postings, RoarPostings, TokenStore};

#[test]
fn layer4_linter() {
    let l = steeldb::linter::Linter::from_tokens(
        ["org/toyota","org/honda","artifact/battery_cell","powertrain/electric","powertrain/diesel"].into_iter().map(String::from));
    let r = l.lint("(and org/toyota (evidence artifact/battery_cel :min-bel 0.8) powertrain/*)");
    eprintln!("L4 LINTER: ok={} errors={:?} repaired={:?}", r.ok, r.errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>(), r.repaired);
    assert!(!r.ok);
    assert_eq!(r.errors[0].suggestions[0], "artifact/battery_cell");
}

#[test]
fn layer5_ds_polarity() {
    let mut ix: InfonIndex<RoarPostings> = InfonIndex::from_postings(HashMap::new(), 5);
    ix.add_infon_polar(0,"hazard/thermal",1.0);
    ix.add_infon_polar(1,"hazard/thermal",0.5);
    ix.add_infon_polar(2,"hazard/thermal",-0.5);
    ix.add_infon_polar(3,"hazard/thermal",-1.0);
    let scope = ix.universe();
    let mass = ix.signed_mass("hazard/thermal", &scope);
    let (bel,pl) = ix.belief_interval("hazard/thermal", &scope);
    eprintln!("L5 DS: signed_mass={mass:.2}  belief=[{bel:.2}, {pl:.2}]");
    assert!((mass-0.0).abs()<1e-9);
    assert!((bel-0.2).abs()<1e-9 && (pl-0.8).abs()<1e-9);
    assert_eq!(ix.evidence_set("hazard/thermal",0.8).len(), 1);
}

#[test]
fn layer6_ikl() {
    let raw = HashMap::from([("country/japan".to_string(),vec![0u32,1]),("country/usa".to_string(),vec![2,3]),("powertrain/electric".to_string(),vec![1,2])]);
    let ix: InfonIndex<RoarPostings> = InfonIndex::from_postings(raw, 4);
    let hit = steeldb::evaluate(&ix, "(and country/japan powertrain/electric)");
    let notq = steeldb::evaluate(&ix, "(and powertrain/electric (not country/japan))");
    eprintln!("L6 IKL: (and japan electric)={} (electric AND-NOT japan)={}", hit.len(), notq.len());
    assert_eq!(hit.len(),1); assert_eq!(notq.len(),1);
}

#[test]
fn layer7_programs() {
    let raw = HashMap::from([("country/japan".to_string(),vec![0u32,1]),("country/usa".to_string(),vec![2,3,4]),("powertrain/electric".to_string(),vec![1,2,4]),("powertrain/diesel".to_string(),vec![0,3])]);
    let ix: InfonIndex<RoarPostings> = InfonIndex::from_postings(raw, 5);
    let ct = steeldb::programs::crosstab(&ix, "*", "country", "powertrain", 6);
    eprintln!("L7 PROGRAMS crosstab:\n{}", serde_json::to_string_pretty(&ct).unwrap());
    assert_eq!(ct["row_facet"], "country");
}

#[cfg(feature="onnx")]
#[test]
fn layer1_tagger() {
    use steeldb::text::SpoTagger;
    let ml = std::path::PathBuf::from("models/step0_bundle_ml");
    if !ml.join("spo.onnx").exists() { eprintln!("L1: no models"); return; }
    let mut t = SpoTagger::load(&ml).unwrap();
    for s in ["Toyota supplies a battery cell under SAE J1100 specs in Q3 2026.","Hyundai recalled 82,000 electric SUVs over a coolant fault in Korea."] {
        let spans = t.tag(s).unwrap();
        eprintln!("L1 TAGGER | {s}\n   {}", spans.iter().map(|x| format!("{}:{:?}",x.kind,x.text.trim())).collect::<Vec<_>>().join("  "));
    }
}

#[cfg(feature="onnx")]
#[test]
fn layer3_projection() {
    use steeldb::projectors::TextEngine;
    let ml = std::path::PathBuf::from("models/step0_bundle_ml");
    let splade = std::path::PathBuf::from("models/splade");
    if !ml.join("spo.onnx").exists() { eprintln!("L3: no models"); return; }
    let sp = if splade.join("splade.onnx").exists() { Some(splade.as_path()) } else { None };
    let mut eng = TextEngine::load(&ml, sp).unwrap();
    let (tokens, numbers) = eng.project_sentence("Toyota supplies a battery cell under SAE J1100 specs in Q3 2026.");
    eprintln!("L3 PROJECTION tokens:\n   {}\n   numbers: {:?}", tokens.join("  "), numbers);
    assert!(!tokens.is_empty());
}