use fathomdb_embedder_api::{Embedder, EmbedderError, EmbedderIdentity, Vector};
use fathomdb_engine::{
DenseReadiness, Engine, InitialState, PreparedWrite, ProjectionRole, ProjectionSpec,
ProjectionVector, SourceId,
};
use fathomdb_schema::SQLITE_SUFFIX;
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
use tempfile::TempDir;
#[derive(Clone, Debug)]
struct DelayEmbedder {
identity: EmbedderIdentity,
delay: Duration,
fail: bool,
}
impl DelayEmbedder {
fn new(delay: Duration) -> Self {
Self { identity: EmbedderIdentity::new("deterministic", "rev-a", 384), delay, fail: false }
}
fn failing() -> Self {
Self { fail: true, ..Self::new(Duration::ZERO) }
}
}
impl Embedder for DelayEmbedder {
fn identity(&self) -> EmbedderIdentity {
self.identity.clone()
}
fn embed(&self, _text: &str) -> Result<Vector, EmbedderError> {
if !self.delay.is_zero() {
thread::sleep(self.delay);
}
if self.fail {
return Err(EmbedderError::Failed { message: "deterministic failure".to_string() });
}
let mut v = vec![0.0_f32; self.identity.dimension as usize];
v[0] = 1.0;
Ok(v)
}
}
fn db_path(dir: &TempDir, name: &str) -> PathBuf {
dir.path().join(format!("{name}{SQLITE_SUFFIX}"))
}
fn roles(rs: &[ProjectionRole]) -> BTreeSet<ProjectionRole> {
rs.iter().copied().collect()
}
fn vector_spec(name: &str) -> ProjectionSpec {
ProjectionSpec {
name: name.to_string(),
roles: roles(&[ProjectionRole::Searchable]),
fts: None,
vector: Some(ProjectionVector { embedder: None, dense_readiness: None }),
source: None,
}
}
fn node(logical_id: &str, body_json: &str) -> PreparedWrite {
PreparedWrite::Node {
kind: "doc".to_string(),
body: body_json.to_string(),
source_id: SourceId::new("test:fixture").expect("source id"),
logical_id: Some(logical_id.to_string()),
state: InitialState::Active,
reason: None,
valid_from: None,
valid_until: None,
}
}
fn anon_node(body_json: &str) -> PreparedWrite {
PreparedWrite::Node {
kind: "doc".to_string(),
body: body_json.to_string(),
source_id: SourceId::new("test:fixture").expect("source id"),
logical_id: None,
state: InitialState::Active,
reason: None,
valid_from: None,
valid_until: None,
}
}
fn readiness(engine: &Engine, name: &str) -> Option<DenseReadiness> {
engine
.read_projections()
.expect("read_projections")
.into_iter()
.find(|s| s.name == name)
.and_then(|s| s.vector)
.and_then(|v| v.dense_readiness)
}
fn ro(path: &Path) -> rusqlite::Connection {
rusqlite::Connection::open_with_flags(
path,
rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY | rusqlite::OpenFlags::SQLITE_OPEN_URI,
)
.expect("open read-only")
}
fn vector_row_exists(conn: &rusqlite::Connection, cursor: i64) -> bool {
conn.query_row(
"SELECT COUNT(*) FROM _fathomdb_vector_rows WHERE write_cursor = ?1",
[cursor],
|r| r.get::<_, i64>(0),
)
.expect("vector row probe")
> 0
}
fn vec0_row_exists(conn: &rusqlite::Connection, cursor: i64) -> bool {
conn.query_row("SELECT COUNT(*) FROM vector_default WHERE rowid = ?1", [cursor], |r| {
r.get::<_, i64>(0)
})
.unwrap_or(0)
> 0
}
fn active_cursor(conn: &rusqlite::Connection, logical_id: &str) -> i64 {
conn.query_row(
"SELECT write_cursor FROM canonical_nodes
WHERE logical_id = ?1 AND superseded_at IS NULL",
[logical_id],
|r| r.get::<_, i64>(0),
)
.expect("active cursor")
}
fn terminals_missing_vectors(conn: &rusqlite::Connection) -> i64 {
conn.query_row(
"SELECT COUNT(*)
FROM _fathomdb_projection_terminal t
JOIN canonical_nodes n ON n.write_cursor = t.write_cursor
JOIN _fathomdb_vector_kinds k ON k.kind = n.kind
LEFT JOIN _fathomdb_vector_rows v ON v.write_cursor = t.write_cursor
WHERE t.state = 'up_to_date' AND v.write_cursor IS NULL",
[],
|r| r.get::<_, i64>(0),
)
.expect("torn-terminal probe")
}
fn any_terminal_missing_vectors(conn: &rusqlite::Connection) -> i64 {
conn.query_row(
"SELECT COUNT(*)
FROM _fathomdb_projection_terminal t
JOIN canonical_nodes n ON n.write_cursor = t.write_cursor
JOIN _fathomdb_vector_kinds k ON k.kind = n.kind
LEFT JOIN _fathomdb_vector_rows v ON v.write_cursor = t.write_cursor
WHERE v.write_cursor IS NULL",
[],
|r| r.get::<_, i64>(0),
)
.expect("any-terminal probe")
}
fn unembedded_at_or_below(conn: &rusqlite::Connection, max_cursor: i64) -> i64 {
conn.query_row(
"SELECT COUNT(*)
FROM canonical_nodes n
JOIN _fathomdb_vector_kinds k ON k.kind = n.kind
LEFT JOIN _fathomdb_vector_rows v ON v.write_cursor = n.write_cursor
WHERE n.write_cursor <= ?1 AND v.write_cursor IS NULL",
[max_cursor],
|r| r.get::<_, i64>(0),
)
.expect("unembedded probe")
}
fn max_node_cursor(conn: &rusqlite::Connection) -> i64 {
conn.query_row("SELECT COALESCE(MAX(write_cursor), 0) FROM canonical_nodes", [], |r| {
r.get::<_, i64>(0)
})
.expect("max cursor")
}
#[test]
fn readiness_reads_embedding_while_embeds_are_outstanding_then_flips_to_ready() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_p1");
let opened =
Engine::open_with_embedder_for_test(&path, Arc::new(DelayEmbedder::new(Duration::ZERO)))
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"an empty corpus has no outstanding embeds"
);
engine.set_projection_scheduler_frozen_for_test(true);
engine.write(&[node("N1", r#"{"summary":"a dense meaning"}"#)]).expect("write");
let conn = ro(&path);
let cursor = active_cursor(&conn, "N1");
assert!(
!vector_row_exists(&conn, cursor),
"precondition: the vector row must be absent while the scheduler is frozen"
);
assert!(!vec0_row_exists(&conn, cursor), "precondition: the vec0 row must be absent too");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Embedding),
"readiness must report `embedding` while an embed is outstanding, never `ready`"
);
engine.set_projection_scheduler_frozen_for_test(false);
engine.drain(30_000).expect("drain");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"readiness must flip to `ready` once the embed lands"
);
let conn = ro(&path);
assert!(vector_row_exists(&conn, cursor), "the vector row is at rest once readiness is ready");
assert!(vec0_row_exists(&conn, cursor), "the vec0 row is at rest once readiness is ready");
assert_eq!(terminals_missing_vectors(&conn), 0, "§4.1: no terminal without its vector");
opened.engine.close().unwrap();
}
#[test]
fn atomic_flip_never_exposes_ready_without_the_vector_under_concurrent_write() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_p2");
let opened = Engine::open_with_embedder_for_test(
&path,
Arc::new(DelayEmbedder::new(Duration::from_millis(1))),
)
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
const WRITES: usize = 300;
let writer_done = AtomicBool::new(false);
let saw_embedding = AtomicBool::new(false);
let saw_ready = AtomicBool::new(false);
thread::scope(|scope| {
scope.spawn(|| {
for i in 0..WRITES {
engine
.write(&[anon_node(&format!(r#"{{"summary":"meaning {i}"}}"#))])
.expect("concurrent write");
thread::sleep(Duration::from_millis(1));
}
writer_done.store(true, Ordering::SeqCst);
});
let conn = ro(&path);
let deadline = Instant::now() + Duration::from_secs(60);
let mut samples = 0_u32;
loop {
let max_cursor = max_node_cursor(&conn);
let observed = readiness(engine, "summary");
match observed {
Some(DenseReadiness::Ready) => {
saw_ready.store(true, Ordering::SeqCst);
assert_eq!(
unembedded_at_or_below(&conn, max_cursor),
0,
"FORBIDDEN TORN STATE: readiness read `ready` while a vector row \
at or below cursor {max_cursor} was absent"
);
}
Some(DenseReadiness::Embedding) => {
saw_embedding.store(true, Ordering::SeqCst);
}
Some(DenseReadiness::Unavailable) => {
panic!("the fixture has a usable dense runtime, so it cannot be unavailable")
}
None => panic!("a declared vector projection must always carry a readiness"),
}
assert_eq!(
terminals_missing_vectors(&conn),
0,
"FORBIDDEN TORN STATE: an `up_to_date` terminal exists without its vector row"
);
samples += 1;
if writer_done.load(Ordering::SeqCst)
&& samples > 200
&& saw_ready.load(Ordering::SeqCst)
{
break;
}
assert!(Instant::now() < deadline, "observer timed out");
thread::sleep(Duration::from_millis(1));
}
});
assert!(
saw_embedding.load(Ordering::SeqCst),
"non-vacuity: the tolerated torn state (`embedding`) must have been observed at least \
once, else the race window never opened"
);
assert!(
saw_ready.load(Ordering::SeqCst),
"non-vacuity: `ready` must have been observed at least once, else the branch carrying \
the forbidden-torn-state assertion never executed"
);
engine.drain(60_000).expect("drain");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"the corpus settles to ready once every embed lands"
);
let conn = ro(&path);
assert_eq!(unembedded_at_or_below(&conn, max_node_cursor(&conn)), 0);
assert_eq!(terminals_missing_vectors(&conn), 0);
opened.engine.close().unwrap();
}
#[test]
fn a_failed_embed_is_not_a_torn_write_and_the_detector_is_not_vacuous() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_failed");
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(DelayEmbedder::failing()))
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
engine.set_projection_retry_delays_for_test(&[0, 0, 0]);
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.write(&[anon_node(r#"{"summary":"will fail projection"}"#)]).expect("write");
engine.drain(30_000).expect("drain");
let conn = ro(&path);
assert!(
any_terminal_missing_vectors(&conn) > 0,
"non-vacuity: the terminal-without-vector detector MUST be able to fire"
);
assert_eq!(
terminals_missing_vectors(&conn),
0,
"a `failed` terminal is not a torn write — no `up_to_date` terminal lacks its vector"
);
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"a TERMINALLY-failed embed is not outstanding work; readiness returns to `ready`"
);
opened.engine.close().unwrap();
}
fn vector_kind_registered(conn: &rusqlite::Connection, kind: &str) -> bool {
conn.query_row("SELECT COUNT(*) FROM _fathomdb_vector_kinds WHERE kind = ?1", [kind], |r| {
r.get::<_, i64>(0)
})
.expect("vector kind probe")
> 0
}
#[test]
fn readiness_is_ready_when_a_live_edge_body_can_never_be_scheduled() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_unschedulable_edge");
let opened =
Engine::open_with_embedder_for_test(&path, Arc::new(DelayEmbedder::new(Duration::ZERO)))
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"precondition: an empty corpus has no outstanding embeds"
);
let raw = rusqlite::Connection::open(&path).expect("raw writer");
raw.execute(
"INSERT INTO canonical_edges(write_cursor, kind, from_id, to_id, body)
VALUES(9000001, 'mentions', 'a', 'b', 'an edge body nothing will embed')",
[],
)
.expect("insert a live edge body");
let conn = ro(&path);
assert!(
!vector_kind_registered(&conn, "edge_fact"),
"fixture: `edge_fact` must NOT be a registered vector kind"
);
assert_eq!(
conn.query_row(
"SELECT COUNT(*) FROM canonical_edges ce
LEFT JOIN _fathomdb_projection_terminal pt ON pt.write_cursor = ce.write_cursor
WHERE ce.body IS NOT NULL
AND ce.superseded_at IS NULL
AND ce.t_invalid IS NULL
AND pt.write_cursor IS NULL",
[],
|r| r.get::<_, i64>(0)
)
.expect("fixture probe"),
1,
"fixture: exactly one live, un-terminated edge body must exist"
);
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"readiness must NOT report `embedding` for an edge body the scheduler will never \
schedule — that is a permanent false `embedding`"
);
engine.drain(5_000).expect("drain must report idle when no schedulable embed is outstanding");
opened.engine.close().unwrap();
}
#[test]
fn readiness_still_reports_embedding_for_a_schedulable_edge_body() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_schedulable_edge");
let opened =
Engine::open_with_embedder_for_test(&path, Arc::new(DelayEmbedder::new(Duration::ZERO)))
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.configure_vector_kind_for_test("edge_fact").expect("edge vector kind");
engine.set_projection_scheduler_frozen_for_test(true);
let raw = rusqlite::Connection::open(&path).expect("raw writer");
raw.execute(
"INSERT INTO canonical_edges(write_cursor, kind, from_id, to_id, body)
VALUES(9000001, 'mentions', 'a', 'b', 'an edge body that WILL embed')",
[],
)
.expect("insert a live edge body");
let conn = ro(&path);
assert!(
vector_kind_registered(&conn, "edge_fact"),
"fixture: `edge_fact` must be a registered vector kind here"
);
assert!(
!vector_row_exists(&conn, 9_000_001),
"precondition: the edge vector must be absent while the scheduler is frozen"
);
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Embedding),
"readiness must still report `embedding` while a SCHEDULABLE edge embed is outstanding"
);
opened.engine.close().unwrap();
}
#[test]
fn caller_supplied_dense_readiness_is_inert_engine_reports_derived_truth() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_inert");
let opened =
Engine::open_with_embedder_for_test(&path, Arc::new(DelayEmbedder::new(Duration::ZERO)))
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
let mut lying = vector_spec("summary");
lying.vector =
Some(ProjectionVector { embedder: None, dense_readiness: Some(DenseReadiness::Ready) });
engine.configure_projections(&[lying.clone()], &[]).expect("configure accepts it inertly");
engine.set_projection_scheduler_frozen_for_test(true);
engine.write(&[node("N1", r#"{"summary":"a dense meaning"}"#)]).expect("write");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Embedding),
"the caller's `ready` must NOT be honoured — the engine reports the derived truth"
);
engine.set_projection_scheduler_frozen_for_test(false);
engine.drain(30_000).expect("drain");
let mut lying_other_way = vector_spec("summary");
lying_other_way.vector =
Some(ProjectionVector { embedder: None, dense_readiness: Some(DenseReadiness::Embedding) });
engine.configure_projections(&[lying_other_way], &[]).expect("configure");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"the caller's `embedding` must NOT be honoured either"
);
opened.engine.close().unwrap();
}
#[test]
fn readiness_is_not_part_of_the_declaration_reapply_is_a_no_op() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_noop");
let opened =
Engine::open_with_embedder_for_test(&path, Arc::new(DelayEmbedder::new(Duration::ZERO)))
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
let read_back = engine.read_projections().expect("read_projections");
assert_eq!(read_back.len(), 1);
assert_eq!(
read_back[0].vector.as_ref().and_then(|v| v.dense_readiness),
Some(DenseReadiness::Ready),
"read output carries the engine-set readiness"
);
let again = engine.configure_projections(&read_back, &[]).expect("re-apply read output");
assert!(again.unchanged, "read.projections output must re-apply as an idempotent no-op");
opened.engine.close().unwrap();
}
#[test]
fn default_path_is_unchanged_when_no_vector_projection_is_declared() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "readiness_default");
let opened =
Engine::open_with_embedder_for_test(&path, Arc::new(DelayEmbedder::new(Duration::ZERO)))
.expect("open");
let engine = &opened.engine;
engine.configure_vector_kind_for_test("doc").expect("vector kind");
engine.write(&[node("N1", r#"{"summary":"a dense meaning"}"#)]).expect("write");
engine.drain(30_000).expect("drain");
assert!(engine.read_projections().expect("read_projections").is_empty());
let conn = ro(&path);
let cursor = active_cursor(&conn, "N1");
assert!(vector_row_exists(&conn, cursor), "the default embed path still embeds");
assert_eq!(terminals_missing_vectors(&conn), 0);
engine
.configure_projections(
&[ProjectionSpec {
name: "status".to_string(),
roles: roles(&[ProjectionRole::Filterable]),
fts: None,
vector: None,
source: None,
}],
&[],
)
.expect("configure filterable");
let status = engine
.read_projections()
.expect("read_projections")
.into_iter()
.find(|s| s.name == "status")
.expect("status projection");
assert!(status.vector.is_none(), "a non-vector projection carries no readiness");
opened.engine.close().unwrap();
}