hypersteeldb 0.3.2

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
//! Proves the SPO tagger + SPLADE ONNX stages run natively in Rust (via `ort`) against the real
//! exported models. Requires `--features onnx`.
#![cfg(feature = "onnx")]

use std::io::Write;
use std::path::PathBuf;
use steeldb::text::{SpladeProjector, SpoTagger};
use steeldb::Corpus;

// Set STEELDB_ML_BUNDLE (SPO tagger dir) and optionally STEELDB_SPLADE_DIR to run these; else skip.
fn ml_bundle() -> PathBuf {
    std::env::var("STEELDB_ML_BUNDLE").map(PathBuf::from).unwrap_or_default()
}
fn splade_dir() -> PathBuf {
    std::env::var("STEELDB_SPLADE_DIR").map(PathBuf::from).unwrap_or_default()
}

#[test]
fn incremental_text_ingest_hot_engine() {
    let dir = ml_bundle();
    if !dir.join("spo.onnx").exists() {
        eprintln!("skip: spo.onnx not present");
        return;
    }
    // hold the engine hot and project sentences into a growing corpus (the TUI's realtime path)
    let splade = splade_dir();
    let splade_opt = splade.join("splade.onnx").exists().then_some(splade.as_path());
    let mut eng = steeldb::projectors::TextEngine::load(&dir, splade_opt).expect("load engine");
    let mut c = Corpus::new_incremental("live", vec!["sentence".into()], steeldb::CorpusKind::Text);
    eng.project_text(
        "Toyota reinforced the concrete beam with rebar to meet the 2024 seismic standard in Osaka.",
        &mut |s| {
            c.add_situation(s.tokens, s.display);
        },
    );
    let before = c.stats().situations;
    assert!(before >= 1, "expected at least one projected situation");
    // add more live — the corpus grows and stays queryable
    eng.project_text("Hyundai tested the EV battery pack in Korea.", &mut |s| {
        c.add_situation(s.tokens, s.display);
    });
    let s = c.stats();
    assert!(s.situations > before, "corpus should grow on further ingest");
    assert!(s.vocab > 0, "expected a non-empty vocabulary");
}

#[test]
fn spo_tagger_multilingual() {
    let dir = ml_bundle();
    if !dir.join("spo.onnx").exists() {
        eprintln!("skip: spo.onnx not present");
        return;
    }
    let mut tagger = SpoTagger::load(&dir).expect("load tagger");
    let cases = [
        ("en", "Toyota reinforced the concrete beam with rebar to meet the 2024 seismic standard in Osaka."),
        ("ja", "トヨタは大阪で2024年の耐震基準を満たすため、鉄筋でコンクリート梁を補強した。"),
        ("ko", "도요타는 오사카에서 2024년 내진 기준을 충족하기 위해 철근으로 콘크리트 보를 보강했다."),
    ];
    for (lang, text) in cases {
        let spans = tagger.tag(text).expect("tag");
        eprintln!("[{lang}] {} spans:", spans.len());
        for s in &spans {
            eprintln!("   {:<5} {:?}", s.kind, s.text);
        }
        assert!(!spans.is_empty(), "{lang}: expected at least one span");
        assert!(spans.iter().all(|s| !s.text.trim().is_empty()));
    }
}

#[test]
fn splade_projects_english_facets() {
    let dir = splade_dir();
    if !dir.join("splade.onnx").exists() {
        eprintln!("skip: splade.onnx not present");
        return;
    }
    let mut splade = SpladeProjector::load(&dir, false).expect("load splade");
    let terms = splade
        .project(
            "engineers reinforced the concrete beam using high-strength rebar to meet seismic standards",
            8,
            0.3,
        )
        .expect("project");
    eprintln!("facets: {:?}", splade.facets());
    for t in &terms {
        eprintln!("   {:<24} w={:.3}", t.token, t.weight);
    }
    assert!(!terms.is_empty(), "expected facet activations");
    // tokens are facet-prefixed
    assert!(terms.iter().all(|t| t.token.contains('/')));
}

#[test]
fn text_projector_end_to_end() {
    let ml = ml_bundle();
    if !ml.join("spo.onnx").exists() {
        eprintln!("skip: tagger not present");
        return;
    }
    let p = std::env::temp_dir().join("steeldb_text_e2e.txt");
    let mut f = std::fs::File::create(&p).unwrap();
    f.write_all(
        "Toyota reinforced the concrete beam in Osaka. 도요타는 오사카에서 철근을 사용했다. トヨタは大阪で鉄筋を使用した。"
            .as_bytes(),
    )
    .unwrap();

    let splade = splade_dir();
    let splade_opt = if splade.join("splade.onnx").exists() { Some(splade.as_path()) } else { None };
    let corpus = Corpus::from_text(&p, &ml, splade_opt).expect("project text");
    let s = corpus.stats();
    eprintln!("text corpus: {} situations, {} tokens", s.situations, s.vocab);
    assert!(s.situations >= 3, "expected one situation per sentence");

    // a geo token from the tagger should retrieve the sentences mentioning Osaka
    let out = corpus.query("geo/*", 10);
    eprintln!("geo/* → {} hits", out.count);
    assert!(out.count >= 1, "expected a geo span to be queryable");
}