#![allow(dead_code)]
use std::path::Path;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::search::model_download::{ModelManifest, compute_sha256, model_file_path};
use crate::search::semantic_readiness::FallbackMode;
pub(crate) const VERIFIED_MARKER_NAME: &str = ".verified";
pub(crate) const QUARANTINE_MARKER_NAME: &str = ".quarantined";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum RuntimeLoadability {
NotProbed,
Loadable,
BaselineBuildNoSemantic,
IncompatibleCpu,
OnnxLoadFailed,
}
impl RuntimeLoadability {
pub(crate) fn probe_cheap(semantic_feature_built: bool, cpu_has_avx2: bool) -> Self {
if !semantic_feature_built {
Self::BaselineBuildNoSemantic
} else if !cpu_has_avx2 {
Self::IncompatibleCpu
} else {
Self::NotProbed
}
}
pub(crate) fn probe_cheap_host() -> Self {
Self::probe_cheap(true, true)
}
fn is_hard_host_block(self) -> bool {
matches!(self, Self::BaselineBuildNoSemantic | Self::IncompatibleCpu)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum ModelSource {
Registry,
Mirror,
FromFile,
Preseeded,
Unknown,
}
impl ModelSource {
fn marker_token(self) -> &'static str {
match self {
Self::Registry => "registry",
Self::Mirror => "mirror",
Self::FromFile => "from-file",
Self::Preseeded => "preseeded_local",
Self::Unknown => "unknown",
}
}
fn from_marker_value(value: &str) -> Self {
if value == "registry" {
Self::Registry
} else if value.starts_with("mirror:") || value == "mirror" {
Self::Mirror
} else if value == "from-file" {
Self::FromFile
} else if value == "preseeded_local" {
Self::Preseeded
} else {
Self::Unknown
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub(crate) struct ModelFingerprint {
pub revision: String,
pub content_digest: String,
}
impl ModelFingerprint {
pub(crate) fn from_manifest(manifest: &ModelManifest) -> Self {
let mut lines: Vec<String> = manifest
.files
.iter()
.map(|f| format!("{}={}", f.local_name(), f.sha256))
.collect();
lines.sort();
let mut hasher = Sha256::new();
hasher.update(manifest.revision.as_bytes());
hasher.update(b"\n");
for line in &lines {
hasher.update(line.as_bytes());
hasher.update(b"\n");
}
Self {
revision: manifest.revision.clone(),
content_digest: hex::encode(hasher.finalize()),
}
}
pub(crate) fn marker_token(&self) -> String {
let short = self
.content_digest
.get(..16)
.unwrap_or(self.content_digest.as_str());
format!("{}:{short}", self.revision)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct VerifiedMarker {
pub revision: String,
pub verified_at: Option<String>,
pub source: ModelSource,
pub source_path: Option<String>,
pub fingerprint: Option<String>,
}
impl VerifiedMarker {
pub(crate) fn for_from_file(
manifest: &ModelManifest,
source_path: &Path,
verified_at: String,
) -> Self {
Self {
revision: manifest.revision.clone(),
verified_at: Some(verified_at),
source: ModelSource::FromFile,
source_path: Some(source_path.display().to_string()),
fingerprint: Some(ModelFingerprint::from_manifest(manifest).marker_token()),
}
}
pub(crate) fn render(&self) -> String {
let mut out = format!("revision={}\n", self.revision);
if let Some(ts) = &self.verified_at {
out.push_str(&format!("verified_at={ts}\n"));
}
let source_value = match (self.source, self.source_path.as_deref()) {
(ModelSource::Mirror, Some(url)) => format!("mirror:{url}"),
(source, _) => source.marker_token().to_string(),
};
out.push_str(&format!("source={source_value}\n"));
if let Some(path) = &self.source_path
&& self.source != ModelSource::Mirror
{
out.push_str(&format!("source_path={path}\n"));
}
if let Some(fp) = &self.fingerprint {
out.push_str(&format!("fingerprint={fp}\n"));
}
out
}
pub(crate) fn parse(content: &str) -> Option<Self> {
let revision = field(content, "revision")?;
let raw_source = field(content, "source");
let source = raw_source
.as_deref()
.map(ModelSource::from_marker_value)
.unwrap_or(ModelSource::Unknown);
let mirror_url = raw_source
.as_deref()
.and_then(|v| v.strip_prefix("mirror:").map(str::to_string));
let source_path = field(content, "source_path").or(mirror_url);
Some(Self {
revision,
verified_at: field(content, "verified_at"),
source,
source_path,
fingerprint: field(content, "fingerprint"),
})
}
}
fn field(content: &str, key: &str) -> Option<String> {
let prefix = format!("{key}=");
content
.lines()
.find_map(|line| line.strip_prefix(&prefix))
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum DownloadCostClass {
None,
Small,
Medium,
Large,
}
impl DownloadCostClass {
const SMALL_MAX: u64 = 100 * 1024 * 1024;
const MEDIUM_MAX: u64 = 250 * 1024 * 1024;
pub(crate) fn from_bytes(bytes: u64) -> Self {
if bytes == 0 {
Self::None
} else if bytes <= Self::SMALL_MAX {
Self::Small
} else if bytes <= Self::MEDIUM_MAX {
Self::Medium
} else {
Self::Large
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum SkippedNetworkReason {
ExplicitInstallRequired,
OfflinePolicy,
DisabledByPolicy,
BudgetExceeded,
AlreadyAcquired,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum ModelAcquisitionState {
DisabledByPolicy,
BaselineNoSemantic,
IncompatibleRuntime,
QuarantinedCorrupt,
PartialDownload,
Absent,
OfflineBlocked,
BudgetBlocked,
ChecksumMismatch,
RuntimeLoadFailed,
Ready,
}
impl ModelAcquisitionState {
pub(crate) fn code(self) -> &'static str {
match self {
Self::DisabledByPolicy => "disabled_by_policy",
Self::BaselineNoSemantic => "baseline_no_semantic",
Self::IncompatibleRuntime => "incompatible_runtime",
Self::QuarantinedCorrupt => "quarantined_corrupt",
Self::PartialDownload => "partial_download",
Self::Absent => "absent",
Self::OfflineBlocked => "offline_blocked",
Self::BudgetBlocked => "budget_blocked",
Self::ChecksumMismatch => "checksum_mismatch",
Self::RuntimeLoadFailed => "runtime_load_failed",
Self::Ready => "ready",
}
}
pub(crate) fn is_usable(self) -> bool {
matches!(self, Self::Ready)
}
fn state_detail(self) -> &'static str {
match self {
Self::DisabledByPolicy => {
"semantic model acquisition disabled by policy; lexical search only"
}
Self::BaselineNoSemantic => {
"this is the pre-AVX2 baseline build (semantic compiled out); install the full \
artifact on an AVX2 host to enable semantic search"
}
Self::IncompatibleRuntime => {
"this host's CPU lacks AVX2; the semantic ONNX runtime cannot load here — use \
lexical search or run on an AVX2 host"
}
Self::QuarantinedCorrupt => {
"the model cache was found corrupt and quarantined; repair or reinstall it"
}
Self::PartialDownload => {
"a partial model acquisition is present; resume it with an explicit install"
}
Self::Absent => {
"no embedding model acquired; lexical search works, semantic is opt-in via \
explicit install"
}
Self::OfflineBlocked => {
"model is not acquired and the host is offline; install from local files"
}
Self::BudgetBlocked => {
"the model exceeds the configured byte budget; raise the budget or keep lexical"
}
Self::ChecksumMismatch => {
"model files failed checksum verification; repair or reinstall them"
}
Self::RuntimeLoadFailed => {
"model files are valid but the ONNX runtime failed to load them; reinstall or run \
on a compatible host"
}
Self::Ready => "embedding model acquired, checksum-valid, and loadable",
}
}
fn next_step(self) -> ModelAcquisitionNextStep {
use ModelAcquisitionNextStep as N;
match self {
Self::Ready => N::None,
Self::DisabledByPolicy => N::EnableSemanticPolicy,
Self::BaselineNoSemantic => N::UseFullBuildOnCompatibleHost,
Self::IncompatibleRuntime | Self::RuntimeLoadFailed => N::ReinstallOnCompatibleHost,
Self::QuarantinedCorrupt | Self::ChecksumMismatch => N::RepairOrReinstall,
Self::PartialDownload => N::ResumeInstall,
Self::Absent => N::InstallModel,
Self::OfflineBlocked => N::InstallFromFileOffline,
Self::BudgetBlocked => N::RaiseBudgetOrUseLexical,
}
}
fn skipped_network_reason(self) -> Option<SkippedNetworkReason> {
use SkippedNetworkReason as R;
match self {
Self::DisabledByPolicy => Some(R::DisabledByPolicy),
Self::Absent
| Self::PartialDownload
| Self::ChecksumMismatch
| Self::QuarantinedCorrupt => Some(R::ExplicitInstallRequired),
Self::OfflineBlocked => Some(R::OfflinePolicy),
Self::BudgetBlocked => Some(R::BudgetExceeded),
Self::Ready => Some(R::AlreadyAcquired),
Self::BaselineNoSemantic | Self::IncompatibleRuntime | Self::RuntimeLoadFailed => None,
}
}
fn rollback_guidance(self, model_name: &str) -> Option<String> {
match self {
Self::ChecksumMismatch | Self::QuarantinedCorrupt | Self::RuntimeLoadFailed => {
Some(format!(
"Safe to clear: `cass models remove --model {model_name}` removes only the \
derived model cache (lexical search keeps working); then reinstall with \
`cass models install --model {model_name}`."
))
}
Self::PartialDownload => Some(format!(
"The partial cache is resumable; re-run `cass models install --model {model_name}`, \
or clear it with `cass models remove --model {model_name}` and start fresh."
)),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum ModelAcquisitionNextStep {
None,
InstallModel,
ResumeInstall,
EnableSemanticPolicy,
UseFullBuildOnCompatibleHost,
ReinstallOnCompatibleHost,
InstallFromFileOffline,
RepairOrReinstall,
RaiseBudgetOrUseLexical,
}
impl ModelAcquisitionNextStep {
fn next_command(self, model_name: &str) -> Option<String> {
match self {
Self::None
| Self::EnableSemanticPolicy
| Self::UseFullBuildOnCompatibleHost
| Self::ReinstallOnCompatibleHost
| Self::RaiseBudgetOrUseLexical => None,
Self::InstallModel | Self::ResumeInstall => {
Some(format!("cass models install --model {model_name} --json"))
}
Self::InstallFromFileOffline => Some(format!(
"cass models install --model {model_name} --from-file <dir> --json"
)),
Self::RepairOrReinstall => Some("cass models verify --repair --json".to_string()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ModelAcquisitionSignals {
pub policy_enabled: bool,
pub runtime: RuntimeLoadability,
pub source: ModelSource,
pub files_present: bool,
pub partial_present: bool,
pub checksum_ok: bool,
pub quarantined: bool,
pub offline: bool,
pub budget_exceeded: bool,
pub expected_total_bytes: u64,
pub offline_install_available: bool,
}
impl ModelAcquisitionSignals {
pub(crate) fn state(&self) -> ModelAcquisitionState {
use ModelAcquisitionState as S;
if !self.policy_enabled {
return S::DisabledByPolicy;
}
match self.runtime {
RuntimeLoadability::BaselineBuildNoSemantic => return S::BaselineNoSemantic,
RuntimeLoadability::IncompatibleCpu => return S::IncompatibleRuntime,
_ => {}
}
if self.quarantined {
return S::QuarantinedCorrupt;
}
if !self.files_present {
if self.partial_present {
return S::PartialDownload;
}
if self.offline {
return S::OfflineBlocked;
}
if self.budget_exceeded {
return S::BudgetBlocked;
}
return S::Absent;
}
if !self.checksum_ok {
return S::ChecksumMismatch;
}
if self.runtime == RuntimeLoadability::OnnxLoadFailed {
return S::RuntimeLoadFailed;
}
S::Ready
}
pub(crate) fn report(&self, model_name: &str) -> ModelAcquisitionReport {
let state = self.state();
let next_step = state.next_step();
ModelAcquisitionReport {
state,
usable: state.is_usable(),
runtime: self.runtime,
source: self.source,
cost_class: DownloadCostClass::from_bytes(self.expected_total_bytes),
expected_download_bytes: self.expected_total_bytes,
offline_install_available: self.offline_install_available,
skipped_network_reason: state.skipped_network_reason(),
fallback_mode: if state.is_usable() {
FallbackMode::None
} else {
FallbackMode::Lexical
},
next_step,
next_command: next_step.next_command(model_name),
state_detail: state.state_detail().to_string(),
rollback_guidance: state.rollback_guidance(model_name),
}
}
pub(crate) fn semantic_model_inputs(&self) -> SemanticModelInputs {
SemanticModelInputs {
model_present: self.files_present || self.partial_present,
model_files_complete: self.files_present,
checksum_ok: self.files_present && self.checksum_ok,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct SemanticModelInputs {
pub model_present: bool,
pub model_files_complete: bool,
pub checksum_ok: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct ModelAcquisitionReport {
pub state: ModelAcquisitionState,
pub usable: bool,
pub runtime: RuntimeLoadability,
pub source: ModelSource,
pub cost_class: DownloadCostClass,
pub expected_download_bytes: u64,
pub offline_install_available: bool,
pub skipped_network_reason: Option<SkippedNetworkReason>,
pub fallback_mode: FallbackMode,
pub next_step: ModelAcquisitionNextStep,
pub next_command: Option<String>,
pub state_detail: String,
pub rollback_guidance: Option<String>,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct OnDiskPolicyInputs {
pub policy_enabled: bool,
pub offline: bool,
pub budget_max_bytes: Option<u64>,
}
pub(crate) fn probe_on_disk(
model_dir: &Path,
manifest: &ModelManifest,
runtime: RuntimeLoadability,
policy: OnDiskPolicyInputs,
) -> ModelAcquisitionSignals {
let total = manifest.total_size();
let mut present = 0usize;
let mut checksum_ok = true;
for file in &manifest.files {
if let Some(path) = model_file_path(model_dir, file) {
present += 1;
match compute_sha256(&path) {
Ok(actual) => {
if actual != file.sha256 {
checksum_ok = false;
}
}
Err(_) => checksum_ok = false,
}
}
}
let files_present = present == manifest.files.len() && !manifest.files.is_empty();
let partial_present = present > 0 && !files_present;
let source = std::fs::read_to_string(model_dir.join(VERIFIED_MARKER_NAME))
.ok()
.and_then(|c| VerifiedMarker::parse(&c))
.map(|m| m.source)
.unwrap_or(if files_present {
ModelSource::Preseeded
} else {
ModelSource::Unknown
});
let quarantined = model_dir.join(QUARANTINE_MARKER_NAME).is_file();
let budget_exceeded = policy.budget_max_bytes.is_some_and(|max| total > max);
ModelAcquisitionSignals {
policy_enabled: policy.policy_enabled,
runtime,
source,
files_present,
partial_present,
checksum_ok: files_present && checksum_ok,
quarantined,
offline: policy.offline,
budget_exceeded,
expected_total_bytes: total,
offline_install_available: !manifest.files.is_empty(),
}
}
pub(crate) fn live_acquisition_block(
model_dir: &Path,
manifest: &ModelManifest,
runtime: RuntimeLoadability,
policy: OnDiskPolicyInputs,
model_name: &str,
) -> serde_json::Value {
let report = probe_on_disk(model_dir, manifest, runtime, policy).report(model_name);
let fingerprint = ModelFingerprint::from_manifest(manifest);
let mut block = serde_json::to_value(&report).unwrap_or_else(|_| serde_json::json!({}));
if let Some(obj) = block.as_object_mut() {
obj.insert(
"fingerprint".to_string(),
serde_json::json!({
"revision": fingerprint.revision,
"content_digest": fingerprint.content_digest,
"marker_token": fingerprint.marker_token(),
}),
);
}
block
}
#[cfg(test)]
mod tests {
use super::*;
use crate::search::model_download::ModelFile;
use crate::search::semantic_readiness::{SemanticReadinessReason, SemanticSignals};
fn synthetic_manifest(files: &[(&str, &str)]) -> ModelManifest {
ModelManifest {
id: "test-model".to_string(),
repo: "test/model".to_string(),
revision: "rev-abc123".to_string(),
files: files
.iter()
.map(|(name, body)| ModelFile {
name: name.to_string(),
sha256: sha256_hex(body.as_bytes()),
size: body.len() as u64,
})
.collect(),
license: "Apache-2.0".to_string(),
}
}
fn sha256_hex(bytes: &[u8]) -> String {
let mut h = Sha256::new();
h.update(bytes);
hex::encode(h.finalize())
}
fn ready() -> ModelAcquisitionSignals {
ModelAcquisitionSignals {
policy_enabled: true,
runtime: RuntimeLoadability::Loadable,
source: ModelSource::Registry,
files_present: true,
partial_present: false,
checksum_ok: true,
quarantined: false,
offline: false,
budget_exceeded: false,
expected_total_bytes: 90 * 1024 * 1024,
offline_install_available: true,
}
}
fn policy(budget: Option<u64>) -> OnDiskPolicyInputs {
OnDiskPolicyInputs {
policy_enabled: true,
offline: false,
budget_max_bytes: budget,
}
}
#[test]
fn ready_state_is_usable_with_no_fallback() {
let r = ready().report("minilm");
assert_eq!(r.state, ModelAcquisitionState::Ready);
assert!(r.usable);
assert_eq!(r.fallback_mode, FallbackMode::None);
assert_eq!(r.next_step, ModelAcquisitionNextStep::None);
assert_eq!(
r.skipped_network_reason,
Some(SkippedNetworkReason::AlreadyAcquired)
);
assert!(r.rollback_guidance.is_none());
assert!(r.next_command.is_none());
}
#[test]
fn not_probed_runtime_is_still_ready_so_status_never_loads_onnx() {
let mut s = ready();
s.runtime = RuntimeLoadability::NotProbed;
assert_eq!(s.state(), ModelAcquisitionState::Ready);
}
#[test]
fn disabled_policy_dominates_everything() {
let mut s = ready();
s.policy_enabled = false;
let r = s.report("minilm");
assert_eq!(r.state, ModelAcquisitionState::DisabledByPolicy);
assert_eq!(r.fallback_mode, FallbackMode::Lexical);
assert_eq!(r.next_step, ModelAcquisitionNextStep::EnableSemanticPolicy);
assert_eq!(
r.skipped_network_reason,
Some(SkippedNetworkReason::DisabledByPolicy)
);
}
#[test]
fn baseline_build_blocks_even_with_valid_files() {
let mut s = ready();
s.runtime = RuntimeLoadability::BaselineBuildNoSemantic;
let r = s.report("minilm");
assert_eq!(r.state, ModelAcquisitionState::BaselineNoSemantic);
assert!(r.skipped_network_reason.is_none());
assert_eq!(
r.next_step,
ModelAcquisitionNextStep::UseFullBuildOnCompatibleHost
);
}
#[test]
fn incompatible_cpu_blocks_even_with_valid_files() {
let mut s = ready();
s.runtime = RuntimeLoadability::IncompatibleCpu;
let r = s.report("minilm");
assert_eq!(r.state, ModelAcquisitionState::IncompatibleRuntime);
assert!(r.skipped_network_reason.is_none());
assert_eq!(
r.next_step,
ModelAcquisitionNextStep::ReinstallOnCompatibleHost
);
}
#[test]
fn onnx_load_failure_only_when_files_valid() {
let mut s = ready();
s.runtime = RuntimeLoadability::OnnxLoadFailed;
assert_eq!(s.state(), ModelAcquisitionState::RuntimeLoadFailed);
let r = s.report("minilm");
assert!(r.rollback_guidance.is_some());
let mut s = ready();
s.runtime = RuntimeLoadability::OnnxLoadFailed;
s.checksum_ok = false;
assert_eq!(s.state(), ModelAcquisitionState::ChecksumMismatch);
}
#[test]
fn absent_reports_explicit_install_required_no_auto_download() {
let mut s = ready();
s.files_present = false;
s.checksum_ok = false;
let r = s.report("minilm");
assert_eq!(r.state, ModelAcquisitionState::Absent);
assert_eq!(
r.skipped_network_reason,
Some(SkippedNetworkReason::ExplicitInstallRequired)
);
assert_eq!(r.next_step, ModelAcquisitionNextStep::InstallModel);
assert_eq!(
r.next_command.as_deref(),
Some("cass models install --model minilm --json")
);
assert_eq!(r.fallback_mode, FallbackMode::Lexical);
}
#[test]
fn partial_offline_budget_are_distinct() {
let mut s = ready();
s.files_present = false;
s.partial_present = true;
assert_eq!(s.state(), ModelAcquisitionState::PartialDownload);
let mut s = ready();
s.files_present = false;
s.offline = true;
assert_eq!(s.state(), ModelAcquisitionState::OfflineBlocked);
assert_eq!(
s.report("minilm").next_step,
ModelAcquisitionNextStep::InstallFromFileOffline
);
let mut s = ready();
s.files_present = false;
s.budget_exceeded = true;
assert_eq!(s.state(), ModelAcquisitionState::BudgetBlocked);
}
#[test]
fn checksum_mismatch_offers_safe_rollback() {
let mut s = ready();
s.checksum_ok = false;
let r = s.report("snowflake-arctic-s");
assert_eq!(r.state, ModelAcquisitionState::ChecksumMismatch);
let guidance = r.rollback_guidance.expect("rollback guidance");
assert!(guidance.contains("cass models remove --model snowflake-arctic-s"));
assert!(guidance.contains("lexical search keeps working"));
assert_eq!(
r.next_command.as_deref(),
Some("cass models verify --repair --json")
);
}
#[test]
fn every_state_is_reachable_from_some_signal_set() {
use ModelAcquisitionState as S;
let reached: std::collections::BTreeSet<S> = [
{
let mut s = ready();
s.policy_enabled = false;
s.state()
},
{
let mut s = ready();
s.runtime = RuntimeLoadability::BaselineBuildNoSemantic;
s.state()
},
{
let mut s = ready();
s.runtime = RuntimeLoadability::IncompatibleCpu;
s.state()
},
{
let mut s = ready();
s.quarantined = true;
s.state()
},
{
let mut s = ready();
s.files_present = false;
s.partial_present = true;
s.state()
},
{
let mut s = ready();
s.files_present = false;
s.offline = true;
s.state()
},
{
let mut s = ready();
s.files_present = false;
s.budget_exceeded = true;
s.state()
},
{
let mut s = ready();
s.files_present = false;
s.state()
},
{
let mut s = ready();
s.checksum_ok = false;
s.state()
},
{
let mut s = ready();
s.runtime = RuntimeLoadability::OnnxLoadFailed;
s.state()
},
ready().state(),
]
.into_iter()
.collect();
assert_eq!(reached.len(), 11, "all eleven states must be reachable");
}
#[test]
fn report_round_trips_through_json_with_snake_case_codes() {
let r = ready().report("minilm");
let json = serde_json::to_string(&r).unwrap();
for needle in [
"\"state\":\"ready\"",
"\"usable\":true",
"\"runtime\":\"loadable\"",
"\"source\":\"registry\"",
"\"cost_class\":\"small\"",
"\"fallback_mode\":\"none\"",
"\"skipped_network_reason\":\"already_acquired\"",
] {
assert!(json.contains(needle), "missing {needle} in {json}");
}
let parsed: ModelAcquisitionReport = serde_json::from_str(&json).unwrap();
assert_eq!(parsed, r);
}
#[test]
fn state_code_matches_snake_case_serialization() {
for state in [
ModelAcquisitionState::Absent,
ModelAcquisitionState::ChecksumMismatch,
ModelAcquisitionState::Ready,
ModelAcquisitionState::BaselineNoSemantic,
ModelAcquisitionState::RuntimeLoadFailed,
] {
let serialized = serde_json::to_string(&state).unwrap();
assert_eq!(serialized, format!("\"{}\"", state.code()));
}
}
#[test]
fn cost_class_boundaries() {
assert_eq!(DownloadCostClass::from_bytes(0), DownloadCostClass::None);
assert_eq!(
DownloadCostClass::from_bytes(90 * 1024 * 1024),
DownloadCostClass::Small
);
assert_eq!(
DownloadCostClass::from_bytes(120 * 1024 * 1024),
DownloadCostClass::Medium
);
assert_eq!(
DownloadCostClass::from_bytes(270 * 1024 * 1024),
DownloadCostClass::Large
);
assert_eq!(
DownloadCostClass::from_bytes(100 * 1024 * 1024),
DownloadCostClass::Small
);
}
#[test]
fn cheap_probe_classifies_build_and_cpu() {
assert_eq!(
RuntimeLoadability::probe_cheap(false, true),
RuntimeLoadability::BaselineBuildNoSemantic
);
assert_eq!(
RuntimeLoadability::probe_cheap(true, false),
RuntimeLoadability::IncompatibleCpu
);
assert_eq!(
RuntimeLoadability::probe_cheap(true, true),
RuntimeLoadability::NotProbed
);
assert_eq!(
RuntimeLoadability::probe_cheap(false, false),
RuntimeLoadability::BaselineBuildNoSemantic
);
let _ = RuntimeLoadability::probe_cheap_host();
}
#[test]
fn fingerprint_is_deterministic_and_order_independent() {
let a = synthetic_manifest(&[("model.onnx", "weights"), ("tokenizer.json", "vocab")]);
let b = synthetic_manifest(&[("tokenizer.json", "vocab"), ("model.onnx", "weights")]);
let fa = ModelFingerprint::from_manifest(&a);
let fb = ModelFingerprint::from_manifest(&b);
assert_eq!(fa, fb, "fingerprint must not depend on file order");
assert_eq!(fa.revision, "rev-abc123");
assert!(fa.marker_token().starts_with("rev-abc123:"));
let c = synthetic_manifest(&[("model.onnx", "OTHER"), ("tokenizer.json", "vocab")]);
assert_ne!(
fa.content_digest,
ModelFingerprint::from_manifest(&c).content_digest
);
}
#[test]
fn from_file_marker_records_source_and_fingerprint_and_round_trips() {
let manifest = synthetic_manifest(&[("model.onnx", "weights")]);
let src = Path::new("/home/dev/models/minilm");
let marker = VerifiedMarker::for_from_file(&manifest, src, "2026-06-15T00:00:00Z".into());
let rendered = marker.render();
assert!(rendered.starts_with("revision=rev-abc123\n"));
assert!(rendered.contains("source=from-file\n"));
assert!(rendered.contains("source_path=/home/dev/models/minilm\n"));
assert!(rendered.contains("fingerprint=rev-abc123:"));
let parsed = VerifiedMarker::parse(&rendered).expect("parse");
assert_eq!(parsed, marker);
assert_eq!(parsed.source, ModelSource::FromFile);
}
#[test]
fn parser_is_compatible_with_legacy_markers() {
let legacy = "revision=rev-abc123\nverified_at=2026-01-01T00:00:00Z\nsource=registry\n";
let m = VerifiedMarker::parse(legacy).unwrap();
assert_eq!(m.source, ModelSource::Registry);
assert!(m.fingerprint.is_none());
let mirror = "revision=r\nsource=mirror:https://m.example/cache\n";
let m = VerifiedMarker::parse(mirror).unwrap();
assert_eq!(m.source, ModelSource::Mirror);
assert_eq!(m.source_path.as_deref(), Some("https://m.example/cache"));
let thin = "revision=r\n";
assert!(VerifiedMarker::parse(thin).is_some());
assert!(VerifiedMarker::parse("source=registry\n").is_none());
}
#[test]
fn mirror_marker_round_trips_without_duplicate_path_line() {
let marker = VerifiedMarker {
revision: "r".into(),
verified_at: None,
source: ModelSource::Mirror,
source_path: Some("https://m.example/cache".into()),
fingerprint: None,
};
let rendered = marker.render();
assert!(rendered.contains("source=mirror:https://m.example/cache\n"));
assert!(!rendered.contains("source_path="));
assert_eq!(VerifiedMarker::parse(&rendered).unwrap(), marker);
}
fn write(dir: &Path, name: &str, body: &str) {
std::fs::write(dir.join(name), body).unwrap();
}
fn temp_model_dir(tag: &str) -> std::path::PathBuf {
let base =
std::env::temp_dir().join(format!("cass-model-acq-{tag}-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&base);
std::fs::create_dir_all(&base).unwrap();
base
}
#[test]
fn probe_absent_model_dir() {
let manifest = synthetic_manifest(&[("model.onnx", "weights"), ("tokenizer.json", "v")]);
let dir = temp_model_dir("absent");
let signals = probe_on_disk(&dir, &manifest, RuntimeLoadability::NotProbed, policy(None));
assert!(!signals.files_present);
assert!(!signals.partial_present);
assert_eq!(signals.source, ModelSource::Unknown);
assert_eq!(signals.state(), ModelAcquisitionState::Absent);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn probe_partial_model_dir() {
let manifest = synthetic_manifest(&[("model.onnx", "weights"), ("tokenizer.json", "v")]);
let dir = temp_model_dir("partial");
write(&dir, "model.onnx", "weights"); let signals = probe_on_disk(&dir, &manifest, RuntimeLoadability::NotProbed, policy(None));
assert!(!signals.files_present);
assert!(signals.partial_present);
assert_eq!(signals.state(), ModelAcquisitionState::PartialDownload);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn probe_checksum_mismatch_model_dir() {
let manifest = synthetic_manifest(&[("model.onnx", "weights"), ("tokenizer.json", "v")]);
let dir = temp_model_dir("mismatch");
write(&dir, "model.onnx", "CORRUPT"); write(&dir, "tokenizer.json", "v");
let signals = probe_on_disk(&dir, &manifest, RuntimeLoadability::NotProbed, policy(None));
assert!(signals.files_present);
assert!(!signals.checksum_ok);
assert_eq!(signals.state(), ModelAcquisitionState::ChecksumMismatch);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn probe_from_file_install_is_ready_with_provenance() {
let manifest = synthetic_manifest(&[("model.onnx", "weights"), ("tokenizer.json", "v")]);
let dir = temp_model_dir("fromfile");
write(&dir, "model.onnx", "weights");
write(&dir, "tokenizer.json", "v");
let marker = VerifiedMarker::for_from_file(
&manifest,
Path::new("/srv/airgap"),
"2026-06-15T00:00:00Z".into(),
);
write(&dir, VERIFIED_MARKER_NAME, &marker.render());
let signals = probe_on_disk(&dir, &manifest, RuntimeLoadability::Loadable, policy(None));
assert!(signals.files_present);
assert!(signals.checksum_ok);
assert_eq!(signals.source, ModelSource::FromFile);
assert_eq!(signals.state(), ModelAcquisitionState::Ready);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn probe_quarantined_model_dir() {
let manifest = synthetic_manifest(&[("model.onnx", "weights")]);
let dir = temp_model_dir("quarantine");
write(&dir, "model.onnx", "weights");
write(&dir, QUARANTINE_MARKER_NAME, "corrupt graph at load");
let signals = probe_on_disk(&dir, &manifest, RuntimeLoadability::NotProbed, policy(None));
assert!(signals.quarantined);
assert_eq!(signals.state(), ModelAcquisitionState::QuarantinedCorrupt);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn probe_budget_blocked_when_over_cap() {
let manifest = synthetic_manifest(&[("model.onnx", "weights")]);
let dir = temp_model_dir("budget");
let signals = probe_on_disk(
&dir,
&manifest,
RuntimeLoadability::NotProbed,
policy(Some(1)),
);
assert!(signals.budget_exceeded);
assert_eq!(signals.state(), ModelAcquisitionState::BudgetBlocked);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn live_acquisition_block_carries_report_and_fingerprint() {
let manifest = synthetic_manifest(&[("model.onnx", "weights"), ("tokenizer.json", "v")]);
let dir = temp_model_dir("liveblock");
let block = live_acquisition_block(
&dir,
&manifest,
RuntimeLoadability::NotProbed,
policy(None),
"minilm",
);
assert_eq!(block["state"].as_str(), Some("absent"));
assert_eq!(
block["skipped_network_reason"].as_str(),
Some("explicit_install_required")
);
assert_eq!(block["fallback_mode"].as_str(), Some("lexical"));
assert_eq!(
block["next_command"].as_str(),
Some("cass models install --model minilm --json")
);
assert_eq!(
block["fingerprint"]["revision"].as_str(),
Some("rev-abc123")
);
assert!(
block["fingerprint"]["marker_token"]
.as_str()
.is_some_and(|t| t.starts_with("rev-abc123:")),
"marker_token should be <revision>:<digest16>; got {:?}",
block["fingerprint"]["marker_token"]
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn bridges_into_semantic_readiness_without_drift() {
let acq = ready();
let inputs = acq.semantic_model_inputs();
assert!(inputs.model_present && inputs.model_files_complete && inputs.checksum_ok);
let sem = SemanticSignals {
policy_enabled: true,
baseline_only: false,
model_present: inputs.model_present,
model_files_complete: inputs.model_files_complete,
checksum_ok: inputs.checksum_ok,
vector_index_present: true,
db_fingerprint_matches: Some(true),
backfill_in_progress: false,
fast_tier_ready: true,
quality_tier_ready: true,
};
assert_eq!(sem.reason(), SemanticReadinessReason::QualityTierReady);
let mut acq = ready();
acq.checksum_ok = false;
let inputs = acq.semantic_model_inputs();
let sem = SemanticSignals {
policy_enabled: true,
baseline_only: false,
model_present: inputs.model_present,
model_files_complete: inputs.model_files_complete,
checksum_ok: inputs.checksum_ok,
vector_index_present: false,
db_fingerprint_matches: None,
backfill_in_progress: false,
fast_tier_ready: false,
quality_tier_ready: false,
};
assert_eq!(sem.reason(), SemanticReadinessReason::ChecksumMismatch);
let mut acq = ready();
acq.files_present = false;
acq.partial_present = false;
let inputs = acq.semantic_model_inputs();
let sem = SemanticSignals {
policy_enabled: true,
baseline_only: false,
model_present: inputs.model_present,
model_files_complete: inputs.model_files_complete,
checksum_ok: inputs.checksum_ok,
vector_index_present: false,
db_fingerprint_matches: None,
backfill_in_progress: false,
fast_tier_ready: false,
quality_tier_ready: false,
};
assert_eq!(sem.reason(), SemanticReadinessReason::ModelNotAcquired);
}
}