haematite-cli 0.21.7

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use std::sync::atomic::Ordering;

use serde_json::{Value, json};

use crate::serve::protocol::Operation;
use crate::serve::query::search_text_tests_support::{Fixture, QUERY, TestResult, request};

fn rows(answer: &Value) -> Result<Vec<Value>, Box<dyn std::error::Error>> {
    answer["rows"]
        .as_array()
        .ok_or_else(|| "no query rows".into())
        .map(|rows| {
            rows.iter()
                .map(|row| {
                    json!({"document_id": row["origin"]["id"], "score": row["origin"]["score"]})
                })
                .collect()
        })
}

#[test]
fn search_text_question_matches_vectors_search_text_at_the_same_moment() -> TestResult {
    let fixture = Fixture::new(true)?;
    let expected = fixture.search()?;
    let mut ask = request(QUERY, 10)?;
    ask.selection.version = Some(serde_json::from_value(
        expected["selection"]["version"].clone(),
    )?);
    let answer = fixture.query(ask)?;
    assert_eq!(
        rows(&answer)?,
        expected["hits"].as_array().ok_or("no search hits")?.clone()
    );
    assert_eq!(answer["search"]["compared"], expected["compared"]);
    assert_eq!(answer["search"]["compared"], 5);
    assert_eq!(answer["rows"][0]["origin"]["id"], "a");
    assert_eq!(answer["rows"][1]["origin"]["id"], "c");
    assert_eq!(fixture.worker.asked.load(Ordering::SeqCst), 2);
    Ok(())
}

#[test]
fn search_text_measure_mismatch_names_both_and_does_not_embed() -> TestResult {
    let fixture = Fixture::new(true)?;
    let failure = fixture
        .service
        .dispatch(Operation::QueryRun(request(
            "notes | similar(.body_vec; \"chest pain\"; dot) | limit(10)",
            10,
        )?))
        .err()
        .ok_or("mismatched measure was searched")?;
    assert_eq!(failure.code, "query_measure_mismatch");
    assert!(failure.message.contains("dot"), "{}", failure.message);
    assert!(failure.message.contains("cosine"), "{}", failure.message);
    assert!(failure.message.contains("body_vec"), "{}", failure.message);
    assert_eq!(fixture.worker.asked.load(Ordering::SeqCst), 0);
    Ok(())
}

#[test]
fn search_text_without_a_worker_refuses_before_reading_the_collection() -> TestResult {
    let fixture = Fixture::new(false)?;
    fixture.no_query_worker()?;
    let failure = fixture
        .service
        .dispatch(Operation::QueryRun(request(
            "absent | similar(.body_vec; \"chest pain\"; cosine) | limit(10)",
            10,
        )?))
        .err()
        .ok_or("unconfigured text search was answered")?;
    assert_eq!(failure.code, "embed_not_configured");
    assert_eq!(fixture.worker.asked.load(Ordering::SeqCst), 0);
    Ok(())
}

#[test]
fn search_text_pages_skip_exactly_the_hits_already_given() -> TestResult {
    let fixture = Fixture::new(true)?;
    let expected = fixture.search()?;
    let mut ask = request(QUERY, 2)?;
    ask.selection.version = Some(serde_json::from_value(
        expected["selection"]["version"].clone(),
    )?);
    let first = fixture.query(ask)?;
    assert_eq!(first["records_read"], 3);
    let mut second_ask = request(QUERY, 2)?;
    second_ask.continuation = Some(
        first["next"]
            .as_str()
            .ok_or("no first continuation")?
            .to_owned(),
    );
    let second = fixture.query(second_ask)?;
    assert_eq!(second["records_read"], 5);
    let mut third_ask = request(QUERY, 2)?;
    third_ask.continuation = Some(
        second["next"]
            .as_str()
            .ok_or("no second continuation")?
            .to_owned(),
    );
    let third = fixture.query(third_ask)?;
    assert_eq!(third["records_read"], 5);
    assert!(third["next"].is_null());
    let mut given = rows(&first)?;
    given.extend(rows(&second)?);
    given.extend(rows(&third)?);
    assert_eq!(
        given,
        expected["hits"].as_array().ok_or("no search hits")?.clone()
    );
    for page in [&first, &second, &third] {
        assert_eq!(page["search"], json!({"exact": true, "compared": 5}));
        assert_eq!(page["selection"], expected["selection"]);
    }
    Ok(())
}

#[test]
fn search_text_embedding_can_take_writer_admission() -> TestResult {
    let fixture = Fixture::new(true)?;
    let answer = fixture.query(request(QUERY, 10)?)?;
    assert_eq!(rows(&answer)?.len(), 5);
    assert_eq!(fixture.worker.asked.load(Ordering::SeqCst), 1);
    Ok(())
}

#[test]
fn search_text_refuses_a_scan_bound_below_the_field_size() -> TestResult {
    let fixture = Fixture::with_scan(true, 4)?;
    let failure = fixture
        .service
        .dispatch(Operation::QueryRun(request(QUERY, 10)?))
        .err()
        .ok_or("partial text search was answered")?;
    assert_eq!(failure.code, "query_scan_limit");
    assert!(failure.message.contains("body_vec"), "{}", failure.message);
    assert_eq!(fixture.worker.asked.load(Ordering::SeqCst), 1);
    Ok(())
}

#[test]
fn search_text_fixture_starts_without_asking_a_patient_question() -> TestResult {
    let fixture = Fixture::new(true)?;
    let driver = fixture
        .service
        .embedding()
        .ok_or("missing embedding driver")?;
    assert_eq!(driver.status()["worker"], "ready");
    assert!(driver.last_failure().is_none());
    assert_eq!(fixture.worker.asked.load(Ordering::SeqCst), 0);
    Ok(())
}