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::{AtomicU64, AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tempfile::TempDir;
#[derive(Clone, Debug)]
struct CountingEmbedder {
identity: EmbedderIdentity,
calls: Arc<AtomicUsize>,
delay_ms: Arc<AtomicU64>,
}
impl CountingEmbedder {
fn new() -> Self {
Self::with_identity(EmbedderIdentity::new("deterministic", "rev-a", 384))
}
fn with_identity(identity: EmbedderIdentity) -> Self {
Self {
identity,
calls: Arc::new(AtomicUsize::new(0)),
delay_ms: Arc::new(AtomicU64::new(0)),
}
}
}
impl Embedder for CountingEmbedder {
fn identity(&self) -> EmbedderIdentity {
self.identity.clone()
}
fn embed(&self, _text: &str) -> Result<Vector, EmbedderError> {
self.calls.fetch_add(1, Ordering::SeqCst);
let delay = self.delay_ms.load(Ordering::SeqCst);
if delay > 0 {
std::thread::sleep(Duration::from_millis(delay));
}
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 edge(logical_id: &str, from: &str, to: &str, body: &str) -> PreparedWrite {
PreparedWrite::Edge {
kind: "link".to_string(),
from: from.to_string(),
to: to.to_string(),
source_id: SourceId::new("test:fixture").expect("source id"),
logical_id: Some(logical_id.to_string()),
body: Some(body.to_string()),
t_valid: None,
t_invalid: None,
confidence: None,
extractor_model_id: None,
temporal_fallback: None,
}
}
fn node(kind: &str, logical_id: &str, body_json: &str) -> PreparedWrite {
PreparedWrite::Node {
kind: kind.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 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 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 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 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
}
fn projection_cursor(conn: &rusqlite::Connection) -> i64 {
conn.query_row(
"SELECT CAST(value AS INTEGER) FROM _fathomdb_open_state WHERE key = 'projection_cursor'",
[],
|r| r.get::<_, i64>(0),
)
.unwrap_or(0)
}
fn leaf_rows_without_vectors(conn: &rusqlite::Connection) -> i64 {
conn.query_row(
"SELECT COUNT(*)
FROM canonical_nodes n
LEFT JOIN _fathomdb_vector_rows v ON v.write_cursor = n.write_cursor
WHERE n.row_kind IN ('leaf', 'coverage') AND v.write_cursor IS NULL",
[],
|r| r.get::<_, i64>(0),
)
.expect("unembedded probe")
}
fn leaf_rows_of_kind_without_vectors(conn: &rusqlite::Connection, kind: &str) -> i64 {
conn.query_row(
"SELECT COUNT(*)
FROM canonical_nodes n
LEFT JOIN _fathomdb_vector_rows v ON v.write_cursor = n.write_cursor
WHERE n.row_kind IN ('leaf', 'coverage')
AND n.kind = ?1
AND v.write_cursor IS NULL",
[kind],
|r| r.get::<_, i64>(0),
)
.expect("per-kind unembedded probe")
}
#[test]
fn declaring_a_vector_projection_backfills_pre_existing_rows_and_drain_flushes_to_ready() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_backfill");
let embedder = CountingEmbedder::new();
let calls = Arc::clone(&embedder.calls);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.write(&[node("doc", "N1", r#"{"summary":"a dense meaning"}"#)]).expect("write N1");
engine.write(&[node("doc", "N2", r#"{"summary":"another meaning"}"#)]).expect("write N2");
engine.drain(30_000).expect("baseline drain");
let conn = ro(&path);
let c1 = active_cursor(&conn, "N1");
let c2 = active_cursor(&conn, "N2");
assert!(!vector_kind_registered(&conn, "doc"), "fixture: `doc` is not yet a vector kind");
assert!(!vector_row_exists(&conn, c1), "fixture: N1 has no vector yet");
assert!(!vector_row_exists(&conn, c2), "fixture: N2 has no vector yet");
assert_eq!(calls.load(Ordering::SeqCst), 0, "fixture: nothing has been embedded");
let delta = engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
assert!(
delta.deferred.contains(&"summary".to_string()),
"the vector sub-target is reported as deferred work"
);
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Embedding),
"FALSE-READY BARRIER: declaring `searchable→vector` over a corpus with un-embedded rows \
must report `embedding` — the deferred backfill is outstanding work"
);
engine.drain(30_000).expect("drain must flush the declared backfill");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"after `drain()` returns Ok the dense arm is caught up"
);
let conn = ro(&path);
assert!(vector_kind_registered(&conn, "doc"), "the declaration registered the vector kind");
assert!(vector_row_exists(&conn, c1), "N1's vector must exist at rest once readiness is ready");
assert!(vec0_row_exists(&conn, c1), "N1's vec0 row must exist at rest");
assert!(vector_row_exists(&conn, c2), "N2's vector must exist at rest once readiness is ready");
assert!(vec0_row_exists(&conn, c2), "N2's vec0 row must exist at rest");
assert_eq!(
leaf_rows_without_vectors(&conn),
0,
"no vector-eligible row may remain un-embedded once readiness reads ready"
);
assert_eq!(calls.load(Ordering::SeqCst), 2, "exactly the two backfilled rows were embedded");
opened.engine.close().unwrap();
}
#[test]
fn reapplying_a_satisfied_vector_declaration_does_not_rewind_or_re_embed() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_idempotent");
let embedder = CountingEmbedder::new();
let calls = Arc::clone(&embedder.calls);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.write(&[node("doc", "N1", r#"{"summary":"a dense meaning"}"#)]).expect("write N1");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("first configure");
engine.drain(30_000).expect("drain");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
let cursor_before = projection_cursor(&conn);
let calls_before = calls.load(Ordering::SeqCst);
assert_eq!(calls_before, 1, "exactly one backfill embed happened");
assert!(cursor_before > 0, "the readiness watermark advanced past the backfilled row");
let again = engine.configure_projections(&[vector_spec("summary")], &[]).expect("re-apply");
assert!(again.unchanged, "an identical re-apply diffs to a no-op");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"an idempotent re-apply must not re-open the backfill"
);
let conn = ro(&path);
assert_eq!(
projection_cursor(&conn),
cursor_before,
"an idempotent re-apply must NOT rewind the readiness watermark"
);
engine.drain(30_000).expect("drain");
assert_eq!(
calls.load(Ordering::SeqCst),
calls_before,
"an idempotent re-apply must NOT re-embed an already-embedded row"
);
opened.engine.close().unwrap();
}
fn projection_failure_rows(conn: &rusqlite::Connection) -> i64 {
conn.query_row(
"SELECT COUNT(*) FROM operational_mutations
WHERE collection_name = 'projection_failures'",
[],
|r| r.get::<_, i64>(0),
)
.unwrap_or(0)
}
#[test]
fn a_declaration_without_a_live_embedder_defers_then_boot_grafts() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_no_embedder");
{
let opened = Engine::open(path.clone()).expect("open without embedder");
let engine = &opened.engine;
engine.write(&[node("doc", "N1", r#"{"summary":"a dense meaning"}"#)]).expect("write");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Unavailable),
"with no live embedder the dense arm is unavailable even when no work is outstanding"
);
engine.drain(5_000).expect("drain must not burn its timeout on a dead dense arm");
let conn = ro(&path);
assert!(
!vector_kind_registered(&conn, "doc"),
"a declaration with no live embedder must NOT enrol the kind"
);
assert_eq!(
projection_failure_rows(&conn),
0,
"no doomed embeds may be queued, so no projection_failures audit rows"
);
opened.engine.close().unwrap();
}
let stored_identity = {
let conn = ro(&path);
conn.query_row(
"SELECT name, revision, dimension FROM _fathomdb_embedder_profiles
WHERE profile = 'default'",
[],
|r| {
Ok(EmbedderIdentity::new(
r.get::<_, String>(0)?,
r.get::<_, String>(1)?,
r.get::<_, u32>(2)?,
))
},
)
.expect("stored default embedder identity")
};
let embedder = CountingEmbedder::with_identity(stored_identity);
let calls = Arc::clone(&embedder.calls);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("reopen");
let engine = &opened.engine;
engine.configure_projections(&[vector_spec("summary")], &[]).expect("re-apply");
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"the boot graft settles before an idempotent re-apply"
);
engine.drain(30_000).expect("drain confirms the boot-grafted backfill");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
let cursor = active_cursor(&conn, "N1");
assert!(vector_row_exists(&conn, cursor), "the grafted backfill landed at rest");
assert!(vec0_row_exists(&conn, cursor), "…including the vec0 row");
assert_eq!(
calls.load(Ordering::SeqCst),
91,
"90 prospective-arm probe calls plus exactly one deferred row"
);
opened.engine.close().unwrap();
}
#[test]
fn drain_ok_implies_dense_readiness_ready_across_mutation_shapes() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_invariant");
let embedder = CountingEmbedder::new();
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
let check = |label: &str| {
engine.drain(30_000).unwrap_or_else(|e| panic!("{label}: drain must return Ok, got {e:?}"));
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"{label}: `drain()` returned Ok, so readiness MUST be `ready`"
);
let conn = ro(&path);
assert_eq!(
leaf_rows_without_vectors(&conn),
0,
"{label}: `drain()` returned Ok and readiness is `ready`, so no vector-eligible row \
may lack its vector at rest"
);
};
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
check("declare-on-empty");
engine.write(&[node("doc", "N1", r#"{"summary":"written after declaring"}"#)]).expect("write");
check("write-after-declare");
opened.engine.close().unwrap();
let path2 = db_path(&dir, "flush_barrier_invariant_2");
let embedder2 = CountingEmbedder::new();
let opened2 = Engine::open_with_embedder_for_test(&path2, Arc::new(embedder2)).expect("open 2");
let engine2 = &opened2.engine;
engine2.write(&[node("doc", "N1", r#"{"summary":"pre-existing"}"#)]).expect("write");
engine2.drain(30_000).expect("pre-declaration drain");
engine2.configure_projections(&[vector_spec("summary")], &[]).expect("configure 2");
engine2.drain(30_000).expect("post-declaration drain must return Ok");
assert_eq!(
readiness(engine2, "summary"),
Some(DenseReadiness::Ready),
"declare-after-write: `drain()` returned Ok, so readiness MUST be `ready`"
);
let conn = ro(&path2);
assert_eq!(
leaf_rows_without_vectors(&conn),
0,
"declare-after-write: FALSE-READY — `drain()` returned Ok and readiness reads `ready`, \
but a vector-eligible row has no vector at rest"
);
opened2.engine.close().unwrap();
}
fn vector_kind_count(conn: &rusqlite::Connection) -> i64 {
conn.query_row("SELECT COUNT(*) FROM _fathomdb_vector_kinds", [], |r| r.get::<_, i64>(0))
.expect("vector kind count")
}
#[test]
fn dropping_the_last_vector_projection_un_enrols_the_kind_and_stops_embedding() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_drop_inverse");
let embedder = CountingEmbedder::new();
let calls = Arc::clone(&embedder.calls);
let delay_ms = Arc::clone(&embedder.delay_ms);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.write(&[node("doc", "N1", r#"{"summary":"a dense meaning"}"#)]).expect("write N1");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.drain(30_000).expect("drain");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
let c1 = active_cursor(&conn, "N1");
assert!(vector_kind_registered(&conn, "doc"), "fixture: the declaration enrolled `doc`");
assert!(vector_row_exists(&conn, c1), "fixture: N1 is embedded");
assert!(vec0_row_exists(&conn, c1), "fixture: N1's vec0 row exists");
assert_eq!(calls.load(Ordering::SeqCst), 1, "fixture: exactly one embed so far");
let delta = engine
.configure_projections(&[], &["summary".to_string()])
.expect("drop the vector projection");
assert!(delta.dropped.contains(&"summary".to_string()), "the drop is reported");
assert!(
engine.read_projections().expect("read_projections").is_empty(),
"the registry no longer declares any projection"
);
let conn = ro(&path);
assert!(
!vector_kind_registered(&conn, "doc"),
"ONE-WAY ENROLMENT: dropping the last `searchable→vector` declaration must un-enrol the \
node kind it enrolled, or the write path keeps embedding for a projection the registry \
no longer declares"
);
assert!(
vector_row_exists(&conn, c1),
"un-enrolment must NOT delete embeddings — the shipped `drop` arm leaves vectors at rest"
);
assert!(vec0_row_exists(&conn, c1), "…including the vec0 row");
delay_ms.store(8_000, Ordering::SeqCst);
engine.write(&[node("doc", "N2", r#"{"summary":"written after the drop"}"#)]).expect("N2");
engine.drain(2_000).expect(
"drain must not wait on work for a DROPPED projection — with the embedder at 8s a 2s \
barrier can only return Ok if nothing was enqueued",
);
assert_eq!(
calls.load(Ordering::SeqCst),
1,
"a write after the drop must not be embedded — the dense arm is no longer declared"
);
engine.write(&[node("note", "M1", r#"{"summary":"a new kind after the drop"}"#)]).expect("M1");
engine.drain(2_000).expect("drain: still nothing enqueued");
let conn = ro(&path);
assert!(
!vector_kind_registered(&conn, "note"),
"late enrolment must be gated on an ACTIVE declaration, not merely on 'kind unseen'"
);
assert!(!vector_kind_registered(&conn, "doc"), "…and must not re-enrol `doc` either");
let c2 = active_cursor(&conn, "N2");
assert!(!vector_row_exists(&conn, c2), "N2 has no vector: nothing was ever enqueued for it");
assert!(!vec0_row_exists(&conn, c2), "…and no vec0 row");
assert!(vector_row_exists(&conn, c1), "N1's pre-drop vector is still at rest");
assert_eq!(calls.load(Ordering::SeqCst), 1, "still exactly the one pre-drop embed");
let again = engine.configure_projections(&[], &["summary".to_string()]).expect("re-drop");
assert!(again.dropped.is_empty(), "dropping an absent projection is a no-op, not an error");
let conn = ro(&path);
assert!(!vector_kind_registered(&conn, "doc"), "re-drop keeps the kind un-enrolled");
assert!(vector_row_exists(&conn, c1), "re-drop still deletes no embedding");
assert_eq!(calls.load(Ordering::SeqCst), 1, "re-drop embeds nothing");
delay_ms.store(0, Ordering::SeqCst);
engine.configure_projections(&[vector_spec("summary")], &[]).expect("re-declare");
engine.drain(30_000).expect("drain the re-declared backfill");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
assert!(vector_kind_registered(&conn, "doc"), "re-declaring re-enrols the kind");
assert!(vector_row_exists(&conn, c2), "the row written while the arm was off is backfilled");
assert_eq!(
leaf_rows_without_vectors(&conn),
0,
"after the re-declared backfill drains, no vector-eligible row lacks its vector"
);
opened.engine.close().unwrap();
}
#[test]
fn dropping_a_vector_projection_leaves_edge_fact_enrolled() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_drop_edge_fact");
let embedder = CountingEmbedder::new();
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.write(&[node("doc", "N1", r#"{"summary":"a dense meaning"}"#)]).expect("write N1");
engine.write(&[node("doc", "N2", r#"{"summary":"another meaning"}"#)]).expect("write N2");
engine.write(&[edge("E1", "N1", "N2", "N1 elaborates N2")]).expect("write E1");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.drain(30_000).expect("drain");
let conn = ro(&path);
assert!(vector_kind_registered(&conn, "doc"), "fixture: `doc` enrolled by the declaration");
assert!(vector_kind_registered(&conn, "edge_fact"), "fixture: `edge_fact` enrolled by G11");
assert_eq!(vector_kind_count(&conn), 2, "fixture: exactly `doc` + `edge_fact`");
engine.configure_projections(&[], &["summary".to_string()]).expect("drop");
let conn = ro(&path);
assert!(!vector_kind_registered(&conn, "doc"), "the node kind is un-enrolled");
assert!(
vector_kind_registered(&conn, "edge_fact"),
"`edge_fact` is auto-registered off edge BODIES by `project_canonical_edge_row`, not off \
the projection registry — dropping a node projection must not end its lifecycle"
);
assert_eq!(vector_kind_count(&conn), 1, "exactly the node kind was removed");
engine.write(&[edge("E2", "N2", "N1", "N2 is elaborated by N1")]).expect("write E2");
engine.drain(30_000).expect("drain the edge body");
let conn = ro(&path);
assert!(vector_kind_registered(&conn, "edge_fact"), "the edge dense arm survived the drop");
opened.engine.close().unwrap();
}
#[test]
fn a_kind_the_vector_writer_cannot_commit_is_not_enrolled_at_declaration_time() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_uncommittable_declare");
let embedder = CountingEmbedder::new();
let calls = Arc::clone(&embedder.calls);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.write(&[node("doc", "N1", r#"{"summary":"a dense meaning"}"#)]).expect("write N1");
engine
.write(&[node("invoice", "I1", r#"{"summary":"payable in 30 days"}"#)])
.expect("write I1");
engine.drain(30_000).expect("baseline drain");
let conn = ro(&path);
let c_doc = active_cursor(&conn, "N1");
let c_invoice = active_cursor(&conn, "I1");
assert!(!vector_kind_registered(&conn, "doc"), "fixture: nothing enrolled yet");
assert!(!vector_kind_registered(&conn, "invoice"), "fixture: nothing enrolled yet");
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.drain(30_000).expect(
"WEDGED: enrolling a node kind the vector writer cannot commit leaves the row pending \
forever — no terminal is ever recorded, so `drain` burns its whole timeout",
);
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"a kind the vector writer cannot commit must not hold the corpus in `embedding` forever"
);
let conn = ro(&path);
assert!(vector_kind_registered(&conn, "doc"), "the commit-able kind still gets its dense arm");
assert!(vector_row_exists(&conn, c_doc), "…and its vector is at rest");
assert!(vec0_row_exists(&conn, c_doc), "…including the vec0 row");
assert_eq!(
leaf_rows_of_kind_without_vectors(&conn, "doc"),
0,
"every `doc` row is embedded once readiness reads ready"
);
assert!(
!vector_kind_registered(&conn, "invoice"),
"ENROLMENT MUST BE RESTRICTED TO COMMIT-ABLE KINDS: `resolve_source_type(\"invoice\")` is \
`Err`, so an enrolled `invoice` row can never record a terminal"
);
assert!(!vector_row_exists(&conn, c_invoice), "the un-enrolled kind has no vector");
assert_eq!(calls.load(Ordering::SeqCst), 1, "exactly the one commit-able row was embedded");
assert_eq!(
projection_failure_rows(&conn),
0,
"a kind with no dense arm is not a FAILURE — it must not pollute the failure audit"
);
opened.engine.close().unwrap();
}
#[test]
fn a_kind_the_vector_writer_cannot_commit_is_not_late_enrolled_on_write() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_uncommittable_late");
let embedder = CountingEmbedder::new();
let calls = Arc::clone(&embedder.calls);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.drain(30_000).expect("declare-on-empty drain");
engine
.write(&[node("invoice", "I1", r#"{"summary":"payable in 30 days"}"#)])
.expect("write I1");
engine.drain(30_000).expect(
"WEDGED: late-enrolling a node kind the vector writer cannot commit leaves the row pending \
forever",
);
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Ready),
"a post-declaration write of an unmappable kind must not hold readiness in `embedding`"
);
let conn = ro(&path);
let c_invoice = active_cursor(&conn, "I1");
assert!(
!vector_kind_registered(&conn, "invoice"),
"LATE ENROLMENT MUST BE RESTRICTED TOO: the write path enrols off the batch's kinds, so it \
needs the same commit-ability filter as the declare-time backfill"
);
assert!(!vector_row_exists(&conn, c_invoice), "the un-enrolled kind has no vector");
assert_eq!(calls.load(Ordering::SeqCst), 0, "nothing was embedded");
engine.write(&[node("doc", "N1", r#"{"summary":"a dense meaning"}"#)]).expect("write N1");
engine.drain(30_000).expect("drain the commit-able write");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
let c_doc = active_cursor(&conn, "N1");
assert!(vector_kind_registered(&conn, "doc"), "the commit-able kind still late-enrols");
assert!(vector_row_exists(&conn, c_doc), "…and its vector is at rest");
assert_eq!(calls.load(Ordering::SeqCst), 1, "exactly the one commit-able row was embedded");
opened.engine.close().unwrap();
}
fn stored_default_identity(path: &Path) -> EmbedderIdentity {
let conn = ro(path);
conn.query_row(
"SELECT name, revision, dimension FROM _fathomdb_embedder_profiles
WHERE profile = 'default'",
[],
|r| {
Ok(EmbedderIdentity::new(
r.get::<_, String>(0)?,
r.get::<_, String>(1)?,
r.get::<_, u32>(2)?,
))
},
)
.expect("stored default embedder identity")
}
#[test]
fn a_first_write_after_an_empty_declaration_late_enrols_once() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_late_enrol_empty");
let embedder = CountingEmbedder::new();
let calls = Arc::clone(&embedder.calls);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
assert!(engine.read_projections().expect("read empty registry").is_empty());
engine.configure_projections(&[vector_spec("summary")], &[]).expect("declare on empty corpus");
let conn = ro(&path);
assert!(
!vector_kind_registered(&conn, "doc"),
"fixture: an empty declaration has no kind to enrol or backfill"
);
assert_eq!(calls.load(Ordering::SeqCst), 0, "fixture: empty declaration embeds nothing");
engine.write(&[node("doc", "N1", r#"{"summary":"first late-enrolled row"}"#)]).expect("write");
assert!(vector_kind_registered(&ro(&path), "doc"), "the first write late-enrols its kind");
engine.drain(30_000).expect("drain flushes the first late-enrolled row");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
let cursor = active_cursor(&conn, "N1");
assert_eq!(
leaf_rows_without_vectors(&conn),
0,
"the first late-enrolled row must have its vector at rest once readiness is ready"
);
assert!(vector_row_exists(&conn, cursor), "the first write has a vector row at rest");
assert!(vec0_row_exists(&conn, cursor), "the first write has a vec0 row at rest");
assert_eq!(calls.load(Ordering::SeqCst), 1, "exactly the first written row was embedded");
opened.engine.close().unwrap();
}
fn terminal_state(conn: &rusqlite::Connection, cursor: i64) -> Option<String> {
conn.query_row(
"SELECT state FROM _fathomdb_projection_terminal WHERE write_cursor = ?1",
[cursor],
|r| r.get::<_, String>(0),
)
.ok()
}
fn fts_row_exists(conn: &rusqlite::Connection, cursor: i64) -> bool {
conn.query_row("SELECT COUNT(*) FROM search_index WHERE write_cursor = ?1", [cursor], |r| {
r.get::<_, i64>(0)
})
.expect("fts row probe")
> 0
}
#[test]
fn a_no_embedder_session_leaves_an_enrolled_kinds_write_recoverable() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_no_embedder_recoverable");
Engine::open(path.clone()).expect("create").engine.close().unwrap();
let identity = stored_default_identity(&path);
{
let embedder = CountingEmbedder::with_identity(identity.clone());
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine
.write(&[node("doc", "N1", r#"{"summary":"embedded in session one"}"#)])
.expect("write N1");
engine.drain(30_000).expect("session 1 drain");
let conn = ro(&path);
assert!(vector_kind_registered(&conn, "doc"), "fixture: session 1 enrolled `doc`");
assert_eq!(leaf_rows_without_vectors(&conn), 0, "fixture: session 1's row is embedded");
opened.engine.close().unwrap();
}
let c1 = active_cursor(&ro(&path), "N1");
let c2 = {
let opened = Engine::open(path.clone()).expect("reopen without embedder");
let engine = &opened.engine;
engine.set_projection_retry_delays_for_test(&[]);
assert!(
vector_kind_registered(&ro(&path), "doc"),
"fixture: the kind stays enrolled across the reopen — that is the whole finding"
);
engine
.write(&[node("doc", "N2", r#"{"summary":"written with no dense arm"}"#)])
.expect("write N2");
let drained = engine.drain(3_000);
assert!(
matches!(drained, Err(fathomdb_engine::EngineError::Scheduler)),
"NO-EMBEDDER SESSION: an enrolled row with no vector is outstanding and this session \
cannot satisfy it, so `drain` must burn its timeout into `Scheduler` rather than \
clear the barrier by terminating the row. Got: {drained:?}"
);
assert_eq!(
readiness(engine, "summary"),
Some(DenseReadiness::Unavailable),
"an absent runtime remains unavailable even when durable work is pending"
);
let conn = ro(&path);
let c2 = active_cursor(&conn, "N2");
assert!(fts_row_exists(&conn, c2), "the write is accepted and still lexically searchable");
assert_eq!(
projection_failure_rows(&conn),
0,
"an ABSENT embedder is an ENVIRONMENT fact, not an embed failure — it must not \
pollute the `projection_failures` audit"
);
assert_eq!(
terminal_state(&conn, c2),
None,
"PERMANENTLY LOST WRITE: an `EmbedderNotConfiguredError` must record NO terminal. A \
`'failed'` terminal is permanent by design (nothing reopens one, and nothing should \
— that would loop a genuinely-failing row forever), so terminating here loses the \
write. Leaving the row PENDING is what lets the next live-embedder session's \
ORDINARY scheduler pick it up"
);
assert!(!vector_row_exists(&conn, c2), "fixture: no dense arm ⇒ no vector yet");
assert!(vector_row_exists(&conn, c1), "session 1's vector is untouched");
opened.engine.close().unwrap();
c2
};
let embedder = CountingEmbedder::with_identity(identity);
let calls = Arc::clone(&embedder.calls);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("reopen");
let engine = &opened.engine;
let calls_at_open = calls.load(Ordering::SeqCst);
engine.drain(30_000).expect("drain flushes the row the no-embedder session left pending");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
assert_eq!(
leaf_rows_without_vectors(&conn),
0,
"PERMANENTLY LOST WRITE: `drain()` returned Ok and readiness reads `ready`, but the row \
written in the no-embedder session still has no vector at rest"
);
assert!(vector_row_exists(&conn, c2), "the recovered row's vector must exist at rest");
assert!(vec0_row_exists(&conn, c2), "…including its vec0 row");
assert_eq!(
calls.load(Ordering::SeqCst) - calls_at_open,
1,
"exactly the ONE outstanding row was embedded — the recovery must not re-embed session \
1's row"
);
assert_eq!(
projection_failure_rows(&conn),
0,
"the recovery leaves no failure audit behind either"
);
opened.engine.close().unwrap();
}
const PROJECTION_SCAN_FETCH: usize = 32;
fn active_edge_cursor(conn: &rusqlite::Connection, logical_id: &str) -> i64 {
conn.query_row(
"SELECT write_cursor FROM canonical_edges
WHERE logical_id = ?1 AND superseded_at IS NULL",
[logical_id],
|r| r.get::<_, i64>(0),
)
.expect("active edge cursor")
}
fn pending_node_rows_below(conn: &rusqlite::Connection, 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_projection_terminal t ON t.write_cursor = n.write_cursor
WHERE n.row_kind IN ('leaf', 'coverage')
AND n.superseded_at IS NULL
AND t.write_cursor IS NULL
AND n.write_cursor < ?1",
[cursor],
|r| r.get::<_, i64>(0),
)
.expect("pending node rows below cursor")
}
fn poll_until(timeout: Duration, mut probe: impl FnMut() -> bool) -> bool {
let deadline = Instant::now() + timeout;
loop {
if probe() {
return true;
}
if Instant::now() >= deadline {
return false;
}
std::thread::sleep(Duration::from_millis(25));
}
}
#[test]
fn a_pending_edge_body_survives_a_full_scan_window_of_no_embedder_node_rows() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_scan_window_starvation");
Engine::open(path.clone()).expect("create").engine.close().unwrap();
let identity = stored_default_identity(&path);
{
let embedder = CountingEmbedder::with_identity(identity);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("open");
let engine = &opened.engine;
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.write(&[node("doc", "SEED", r#"{"summary":"enrols the kind"}"#)]).expect("seed");
engine.drain(30_000).expect("session 1 drain");
assert!(vector_kind_registered(&ro(&path), "doc"), "fixture: session 1 enrolled `doc`");
opened.engine.close().unwrap();
}
let opened = Engine::open(path.clone()).expect("reopen without embedder");
let engine = &opened.engine;
engine.set_projection_retry_delays_for_test(&[]);
let node_rows = PROJECTION_SCAN_FETCH + 8;
let batch: Vec<PreparedWrite> = (0..node_rows)
.map(|i| node("doc", &format!("N{i}"), &format!(r#"{{"summary":"row {i}"}}"#)))
.collect();
engine.write(&batch).expect("write the node rows");
engine
.write(&[edge("E1", "N0", "N1", "the edge body that must not be starved")])
.expect("edge");
let conn = ro(&path);
let edge_cursor = active_edge_cursor(&conn, "E1");
assert!(
vector_kind_registered(&conn, "edge_fact"),
"fixture: an edge body auto-registers `'edge_fact'` (G11), so it IS schedulable work"
);
let pending_before = pending_node_rows_below(&conn, edge_cursor);
assert!(
pending_before > PROJECTION_SCAN_FETCH as i64,
"fixture: the scan window must be over-subscribed by node rows ordered BEFORE the edge \
body — that is the whole scenario. Pending node rows below the edge: {pending_before}, \
scan window: {PROJECTION_SCAN_FETCH}"
);
let scheduled =
poll_until(Duration::from_secs(20), || terminal_state(&ro(&path), edge_cursor).is_some());
assert!(
scheduled,
"SCAN-WINDOW STARVATION: with more than PROJECTION_SCAN_FETCH ({PROJECTION_SCAN_FETCH}) \
pending node rows ordered before it, the pending edge body at cursor {edge_cursor} was \
NEVER scheduled. The no-embedder node exclusion must happen INSIDE \
`next_pending_projection_jobs`' SQL so the `LIMIT` applies to the ALREADY-FILTERED set; \
filtering after the fetch lets one full window of node rows hide every later job, and \
`drain` then times out on that edge workload indefinitely"
);
assert_eq!(
terminal_state(&ro(&path), edge_cursor),
Some("failed".to_string()),
"edges keep their shipped no-embedder behaviour (OOS-13): the retry ladder exhausts into \
a `'failed'` terminal. fix-5 changes WHICH rows the scan returns, not what happens to \
an edge once it is dispatched"
);
let conn = ro(&path);
assert_eq!(
pending_node_rows_below(&conn, edge_cursor),
pending_before,
"fix-4 stands: an absent embedder records NO terminal for a NODE row, so every one of \
them is still pending and still recoverable by the next live-embedder session"
);
opened.engine.close().unwrap();
}
fn rw(path: &Path) -> rusqlite::Connection {
let conn = rusqlite::Connection::open(path).expect("open read-write");
conn.busy_timeout(Duration::from_secs(10)).expect("busy_timeout");
conn
}
#[test]
fn a_boot_graft_whose_repair_fails_registers_nothing() {
let dir = TempDir::new().unwrap();
let path = db_path(&dir, "flush_barrier_enrolment_atomicity");
{
let opened = Engine::open(path.clone()).expect("create without embedder");
let engine = &opened.engine;
engine.configure_projections(&[vector_spec("summary")], &[]).expect("configure");
engine.write(&[node("doc", "N1", r#"{"summary":"stranded one"}"#)]).expect("N1");
engine.write(&[node("doc", "N2", r#"{"summary":"stranded two"}"#)]).expect("N2");
engine.drain(5_000).expect("no dense arm ⇒ nothing outstanding");
opened.engine.close().unwrap();
}
let identity = stored_default_identity(&path);
{
let conn = ro(&path);
assert!(
!vector_kind_registered(&conn, "doc"),
"fixture: a no-embedder session enrols nothing"
);
for id in ["N1", "N2"] {
let cursor = active_cursor(&conn, id);
assert_eq!(
terminal_state(&conn, cursor),
Some("up_to_date".to_string()),
"fixture: {id} holds the permanent terminal that makes it STRANDABLE"
);
assert!(!vector_row_exists(&conn, cursor), "fixture: {id} has no vector");
}
}
rw(&path)
.execute_batch(
"CREATE TRIGGER fix5_repair_fails
BEFORE DELETE ON _fathomdb_projection_terminal
BEGIN SELECT RAISE(ABORT, 'fix-5: the un-stranding repair failed'); END",
)
.expect("install the repair-failure injection");
let failed_open = Engine::open_with_embedder_for_test(
&path,
Arc::new(CountingEmbedder::with_identity(identity.clone())),
);
assert!(
failed_open.is_err(),
"the faulted boot graft must fail open rather than expose half-repaired durable state"
);
assert!(
!vector_kind_registered(&ro(&path), "doc"),
"TORN BOOT GRAFT: the registry INSERT must roll back with the terminal/cursor repair"
);
rw(&path).execute_batch("DROP TRIGGER fix5_repair_fails").expect("remove the injection");
let embedder = CountingEmbedder::with_identity(identity);
let opened = Engine::open_with_embedder_for_test(&path, Arc::new(embedder)).expect("reopen");
let engine = &opened.engine;
engine.drain(30_000).expect("drain flushes the boot-grafted backfill");
assert_eq!(readiness(engine, "summary"), Some(DenseReadiness::Ready));
let conn = ro(&path);
assert_eq!(
leaf_rows_without_vectors(&conn),
0,
"SELF-SEALED FALSE READY: `drain()` returned Ok and readiness reads `ready`, but rows \
stranded by the torn boot graft still have no vector at rest. The torn state is invisible to \
every later write precisely BECAUSE the kind is already registered — which is why the \
two statements have to be atomic"
);
for id in ["N1", "N2"] {
let cursor = active_cursor(&conn, id);
assert!(vector_row_exists(&conn, cursor), "{id}'s vector must exist at rest");
assert!(vec0_row_exists(&conn, cursor), "{id}'s vec0 row must exist at rest");
}
opened.engine.close().unwrap();
}