holographic_memory/core/
schema.rs1use anyhow::{bail, Result};
5use serde::{Deserialize, Serialize};
6use std::path::Path;
7
8use super::config::HmsConfig;
9
10#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
11pub struct EmbeddingSpace {
12 pub model: String,
13 pub revision: String,
14 pub dimensions: usize,
15 pub normalization: String,
16 pub metric: String,
17}
18
19#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
20struct StoreSchema {
21 version: u32,
22 dimensions: usize,
23 text_encoder: String,
24 vector_encoder: String,
25 metric: String,
26 encrypted: bool,
27 meaning_enabled: bool,
28 embedding_space: Option<EmbeddingSpace>,
29}
30
31pub(crate) fn validate_store(path: &Path, dimensions: usize, config: &HmsConfig) -> Result<u32> {
34 let mut expected = StoreSchema {
35 version: super::format::STORE_SCHEMA_VERSION,
36 dimensions,
37 text_encoder: config.text_encoder.name().into(),
38 vector_encoder: "signed-projection-v2".into(),
39 metric: "jaccard".into(),
40 encrypted: config.security.encryption_enabled,
41 meaning_enabled: config.meaning.enabled,
42 embedding_space: config.embedding_space.clone(),
43 };
44 let schema_path = path.join("store.json");
45 if schema_path.exists() {
46 let bytes = std::fs::read(schema_path)?;
47 if let Some(version) = serde_json::from_slice::<serde_json::Value>(&bytes)
48 .ok()
49 .and_then(|v| v["version"].as_u64())
50 .filter(|&v| v > u64::from(super::format::STORE_SCHEMA_VERSION))
51 {
52 bail!(
53 "store schema version {version} is newer than the supported version {}; open it with a release that supports it",
54 super::format::STORE_SCHEMA_VERSION
55 );
56 }
57 let actual: StoreSchema = serde_json::from_slice(&bytes)?;
58 if (super::format::STORE_SCHEMA_OLDEST..=super::format::STORE_SCHEMA_VERSION)
61 .contains(&actual.version)
62 {
63 expected.version = actual.version;
64 }
65 if actual != expected {
66 bail!("incompatible store schema: dimensions, encoder, embedding model, encryption, or meaning configuration changed; reopen with the original configuration or re-encode source documents into a new store");
67 }
68 } else {
69 if path.join("vectors_data.bin").exists() {
70 bail!("legacy store has no embedding schema; preserve it and use hms-admin reencode with original source documents to create a new store");
71 }
72 super::durable_file::atomic_write(&schema_path, &serde_json::to_vec_pretty(&expected)?)?;
73 }
74 Ok(expected.version)
75}