haematite-cli 0.21.3

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::{
    self as support, Fixture, TestResult, request,
};

#[test]
fn rerank_words_uses_the_question_worker_and_declared_metric() -> TestResult {
    let fixture = Fixture::new(true)?;
    let expected = fixture.search()?;
    let baseline = fixture.query(request(support::QUERY, 10)?)?;
    let answer = fixture.query(request(
        "notes | rerank(.body_vec; \"chest pain\"; cosine)",
        10,
    )?)?;
    assert_eq!(answer.get("rows"), baseline.get("rows"));
    assert_eq!(
        answer["rows"][0]["origin"]["score"],
        expected["hits"][0]["score"]
    );
    let rows = answer
        .get("rows")
        .and_then(Value::as_array)
        .ok_or("missing rows")?;
    let ids = rows
        .iter()
        .map(|row| {
            row.get("origin")
                .and_then(|origin| origin.get("id"))
                .and_then(Value::as_str)
                .ok_or("missing id")
        })
        .collect::<Result<Vec<_>, _>>()?;
    assert_eq!(ids, ["a", "c", "b", "d", "e"]);
    assert_eq!(answer.get("unscored"), Some(&json!(0)));
    assert_eq!(answer.get("next"), Some(&Value::Null));
    assert_eq!(fixture.worker.asked.load(Ordering::SeqCst), 3);
    Ok(())
}

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

#[test]
fn rerank_words_names_missing_embedding_before_query_worker_start() -> TestResult {
    let fixture = Fixture::new(false)?;
    fixture.no_query_worker()?;
    let error = fixture
        .service
        .dispatch(Operation::QueryRun(request(
            "absent | rerank(.body_vec; \"chest pain\"; cosine)",
            10,
        )?))
        .err()
        .ok_or("unconfigured rerank was accepted")?;
    assert_eq!(error.code, "embed_not_configured");
    Ok(())
}

#[test]
fn rerank_words_counts_a_stale_candidate_as_unscored_and_keeps_it_last() -> TestResult {
    use crate::serve::protocol::{Change, DocumentWrite, Mutation, StoreRead};

    let fixture = Fixture::new(true)?;
    let stats = fixture.service.dispatch(Operation::StoreStats(StoreRead {
        selection: support::selection(),
    }))?;
    let expected = serde_json::from_value(stats["selection"]["version"].clone())?;
    fixture.service.dispatch(Operation::Mutate(Mutation {
        request_id: "stale-rerank".to_owned(),
        branch: "main".to_owned(),
        expected,
        change: Change::Put(DocumentWrite {
            collection: "notes".to_owned(),
            document_id: "a".to_owned(),
            document: serde_json::value::to_raw_value(&json!({"body":"side"}))?,
        }),
    }))?;
    let answer = fixture.query(request(
        "notes | rerank(.body_vec; \"chest pain\"; cosine)",
        10,
    )?)?;
    assert_eq!(answer.get("unscored"), Some(&json!(1)));
    let last = answer
        .get("rows")
        .and_then(Value::as_array)
        .and_then(|rows| rows.last())
        .ok_or("missing last row")?;
    assert_eq!(
        last.get("origin").and_then(|origin| origin.get("id")),
        Some(&json!("a"))
    );
    assert_eq!(
        last.get("origin").and_then(|origin| origin.get("score")),
        Some(&Value::Null)
    );
    Ok(())
}