diff --git a/src/model.rs b/src/model.rs index cde2811..96aea11 100644 --- a/src/model.rs +++ b/src/model.rs @@ -82,10 +82,10 @@ pub enum Mode { Lexical, Hybrid } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] pub enum IndexStatus { - Ok, // packed file present and structurally valid + Ok, // packed file present and matches the corpus + model #[default] Absent, // no usable index — intentional lexical-only - Mismatch(String), // packed file present but structurally invalid; reason carried + Mismatch(String), // packed file present but structurally or semantically invalid; reason carried } impl std::fmt::Display for IndexStatus { diff --git a/tests/pack_cli_tests.rs b/tests/pack_cli_tests.rs index fe2b84f..88ab410 100644 --- a/tests/pack_cli_tests.rs +++ b/tests/pack_cli_tests.rs @@ -120,3 +120,37 @@ fn cli_packed_file_loads_back_as_ok_index() { assert!(vector.is_some(), "packed file written by the CLI must yield an index"); assert_eq!(status, IndexStatus::Ok); } + +/// Positional alignment (spec § Testing strategy): the packed matrix stores one +/// row per corpus entry in corpus-load order, so row `i` is the embedding of +/// `entries[i].text`. The two entries carry order-revealing orthogonal vectors; +/// if packing did not preserve corpus order the rows would come back swapped. +#[test] +fn cli_packed_rows_are_in_corpus_order() { + use alpha_id::packed::read_packed; + let dir = tempfile::tempdir().unwrap(); + let corpus = dir.path().join("corpus.txt"); + // alpha is line 1 (corpus entry 0), beta is line 2 (corpus entry 1). + std::fs::write(&corpus, format!("{}\n{}\n", corpus_line("alpha"), corpus_line("beta"))).unwrap(); + let index_dir = dir.path().join("index"); + std::fs::create_dir_all(&index_dir).unwrap(); + + let store = alpha_id::embed::EmbeddingStore::open(index_dir.to_str().unwrap(), "test/model").unwrap(); + store.put("alpha", &[1.0f32, 0.0]).unwrap(); + store.put("beta", &[0.0f32, 1.0]).unwrap(); + + let config = write_config(dir.path(), &corpus, &index_dir); + let out = Command::new(env!("CARGO_BIN_EXE_alpha-id")) + .args(["--config", config.to_str().unwrap(), "index", "--pack"]) + .output() + .unwrap(); + assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr)); + + let (_header, rows) = read_packed(&index_dir.join("packed.test_model.bin")).unwrap(); + // Row i is the embedding of corpus entry i: alpha→[1,0] at row 0, beta→[0,1] at row 1. + assert_eq!( + rows, + vec![vec![1.0f32, 0.0], vec![0.0f32, 1.0]], + "packed rows must follow corpus-load order" + ); +}