Preserve explicit code candidates and expose verified model asset milestones

This commit is contained in:
karl committed 2026-10-13 08:47:41 +02:00
1 parent 6e05227f53
commit e28e20af38
9 files changed
+475 -16

No files matched your search

+304 -6
View File
@@ -17,6 +17,31 @@ use std::{
/// Exact bytes of the pinned text model plus its multimedia projection.
pub const TOTAL_BYTES: u64 = 864_676_480;
const ATTEMPTS: usize = 3;
const BACKBONE_FILE: &str = "embeddinggemma-2-Q8_0.gguf";
const PROJECTOR_FILE: &str = "mmproj-embeddinggemma-2-Q8_0.gguf";
/// One verified pinned artifact. This does not imply the full bundle or an
/// inference session is ready; a later artifact can still fail provisioning.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerifiedAsset {
TextBackbone,
MediaProjector,
}
fn verified_asset(artifact: &Artifact) -> Option<VerifiedAsset> {
match artifact.path.as_str() {
BACKBONE_FILE => Some(VerifiedAsset::TextBackbone),
PROJECTOR_FILE => Some(VerifiedAsset::MediaProjector),
_ => None, // Private HTTP fixtures may use arbitrary artifact names.
}
}
fn validate_artifact_order(files: &[Artifact]) -> Result<()> {
if files.len() != 2 || files[0].path != BACKBONE_FILE || files[1].path != PROJECTOR_FILE {
bail!("bundled model manifest must provision the text backbone before the media projector");
}
Ok(())
}
#[derive(Deserialize)]
struct Manifest {
@@ -66,6 +91,7 @@ fn manifest() -> Result<Manifest> {
if manifest.files[0].path == manifest.files[1].path {
bail!("duplicate model manifest artifact");
}
validate_artifact_order(&manifest.files)?;
Ok(manifest)
}
@@ -158,28 +184,60 @@ fn verified(path: &Path, artifact: &Artifact) -> Result<bool> {
/// is completed verified bytes plus bytes of the current attempt. On failure it
/// resets to verified completed bytes; cached files never trigger network access.
pub fn provision(directory: &Path, progress: &AtomicU64) -> Result<()> {
provision_with_verified_assets(directory, progress, |_| {})
}
/// Provision the complete pinned pair, notifying after each artifact's exact
/// cached SHA verification or successful verified atomic installation. The
/// callback is synchronous and has no error return: callers must keep their
/// inference/setup errors separate from download errors. Byte progress alone
/// never triggers a notification. Success still requires both artifacts.
pub fn provision_with_verified_assets(
directory: &Path,
progress: &AtomicU64,
on_verified: impl FnMut(VerifiedAsset),
) -> Result<()> {
let manifest = manifest()?;
let client = Client::builder()
.connect_timeout(Duration::from_secs(20))
.timeout(Duration::from_secs(900))
.user_agent(concat!("Searchi/", env!("CARGO_PKG_VERSION")))
.build()?;
provision_with(directory, progress, &manifest, &client, |artifact| {
format!(
"https://huggingface.co/{}/resolve/{}/{}",
manifest.export_repository, manifest.revision, artifact.path
)
})
provision_with_callback(
directory,
progress,
&manifest,
&client,
|artifact| {
format!(
"https://huggingface.co/{}/resolve/{}/{}",
manifest.export_repository, manifest.revision, artifact.path
)
},
on_verified,
)
}
// URL injection is private so tests can use a local HTTP fixture. Production
// exposes no arbitrary download source or unverified executable provisioner.
#[cfg(test)]
fn provision_with(
directory: &Path,
progress: &AtomicU64,
manifest: &Manifest,
client: &Client,
url: impl Fn(&Artifact) -> String,
) -> Result<()> {
provision_with_callback(directory, progress, manifest, client, url, |_| {})
}
fn provision_with_callback(
directory: &Path,
progress: &AtomicU64,
manifest: &Manifest,
client: &Client,
url: impl Fn(&Artifact) -> String,
mut on_verified: impl FnMut(VerifiedAsset),
) -> Result<()> {
fs::create_dir_all(directory).context("create model cache directory")?;
progress.store(0, Ordering::Release);
@@ -190,6 +248,9 @@ fn provision_with(
if verified(&destination, artifact)? {
completed += artifact.bytes;
progress.store(completed, Ordering::Release);
if let Some(asset) = verified_asset(artifact) {
on_verified(asset);
}
continue;
}
let mut last_error = None;
@@ -225,6 +286,9 @@ fn provision_with(
}
completed += artifact.bytes;
progress.store(completed, Ordering::Release);
if let Some(asset) = verified_asset(artifact) {
on_verified(asset);
}
}
Ok(())
}
@@ -564,4 +628,238 @@ mod tests {
.unwrap()
.ends_with("models/embeddinggemma2"));
}
#[test]
fn pinned_backbone_must_precede_projector() {
let mut files = manifest().unwrap().files;
validate_artifact_order(&files).unwrap();
files.swap(0, 1);
assert!(validate_artifact_order(&files).is_err());
}
#[test]
fn cached_pair_emits_verified_callbacks_without_network() {
let directory = tempfile::tempdir().unwrap();
let manifest = test_manifest(vec![
artifact(BACKBONE_FILE, b"backbone"),
artifact(PROJECTOR_FILE, b"projection"),
]);
fs::write(directory.path().join(BACKBONE_FILE), b"backbone").unwrap();
fs::write(directory.path().join(PROJECTOR_FILE), b"projection").unwrap();
let progress = AtomicU64::new(0);
let mut observed = Vec::new();
provision_with_callback(
directory.path(),
&progress,
&manifest,
&client(),
|_| panic!("Cached pair attempted network"),
|asset| {
observed.push(asset);
let bytes = match asset {
VerifiedAsset::TextBackbone => 8,
VerifiedAsset::MediaProjector => 18,
};
assert_eq!(progress.load(Ordering::Acquire), bytes);
},
)
.unwrap();
assert_eq!(
observed,
[VerifiedAsset::TextBackbone, VerifiedAsset::MediaProjector]
);
assert_eq!(progress.load(Ordering::Acquire), 18);
}
#[test]
fn failed_projector_retains_verified_text_callback_and_progress() {
let directory = tempfile::tempdir().unwrap();
fs::write(directory.path().join(PROJECTOR_FILE), b"oldproject").unwrap();
let manifest = test_manifest(vec![
artifact(BACKBONE_FILE, b"backbone"),
artifact(PROJECTOR_FILE, b"projection"),
]);
let mut responses = vec![response(b"backbone", Some(8))];
responses.extend(vec![response(b"corrupted!", Some(10)); ATTEMPTS]);
let (url, server) = server(responses);
let progress = AtomicU64::new(0);
let mut observed = Vec::new();
let result = provision_with_callback(
directory.path(),
&progress,
&manifest,
&client(),
|_| url.clone(),
|asset| {
assert_eq!(asset, VerifiedAsset::TextBackbone);
assert_eq!(
fs::read(directory.path().join(BACKBONE_FILE)).unwrap(),
b"backbone"
);
observed.push(asset);
},
);
assert!(
result.is_err(),
"The incomplete bundle must not be successful"
);
assert_eq!(server.join().unwrap(), ATTEMPTS + 1);
assert_eq!(observed, [VerifiedAsset::TextBackbone]);
assert_eq!(progress.load(Ordering::Acquire), 8);
assert_eq!(
fs::read(directory.path().join(PROJECTOR_FILE)).unwrap(),
b"oldproject"
);
assert!(!verified(&directory.path().join(PROJECTOR_FILE), &manifest.files[1]).unwrap());
assert_no_part_files(directory.path());
}
#[test]
fn corrupt_backbone_never_emits_a_verified_callback() {
let directory = tempfile::tempdir().unwrap();
fs::write(directory.path().join(BACKBONE_FILE), b"corrupt!").unwrap();
let manifest = test_manifest(vec![
artifact(BACKBONE_FILE, b"backbone"),
artifact(PROJECTOR_FILE, b"projection"),
]);
let (url, server) = server(vec![response(b"corrupt!", Some(8)); ATTEMPTS]);
let progress = AtomicU64::new(0);
let mut observed = Vec::new();
assert!(provision_with_callback(
directory.path(),
&progress,
&manifest,
&client(),
|_| url.clone(),
|asset| observed.push(asset)
)
.is_err());
assert_eq!(server.join().unwrap(), ATTEMPTS);
assert!(observed.is_empty());
assert_eq!(progress.load(Ordering::Acquire), 0);
assert!(!directory.path().join(PROJECTOR_FILE).exists());
assert_no_part_files(directory.path());
}
#[test]
fn partial_backbone_download_never_emits_a_verified_callback() {
let directory = tempfile::tempdir().unwrap();
let manifest = test_manifest(vec![
artifact(BACKBONE_FILE, b"backbone"),
artifact(PROJECTOR_FILE, b"projection"),
]);
let (url, server) = server(vec![response(b"back", Some(8)); ATTEMPTS]);
let progress = AtomicU64::new(0);
let mut observed = Vec::new();
assert!(provision_with_callback(
directory.path(),
&progress,
&manifest,
&client(),
|_| url.clone(),
|asset| observed.push(asset)
)
.is_err());
assert_eq!(server.join().unwrap(), ATTEMPTS);
assert!(observed.is_empty());
assert_eq!(progress.load(Ordering::Acquire), 0);
assert!(!directory.path().join(BACKBONE_FILE).exists());
assert_no_part_files(directory.path());
}
#[test]
fn text_callback_precedes_gated_projector_and_full_completion() {
use std::sync::mpsc;
let directory = tempfile::tempdir().unwrap();
fs::write(directory.path().join(BACKBONE_FILE), b"backbone").unwrap();
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let url = format!("http://{}/fixture", listener.local_addr().unwrap());
let (release, wait) = mpsc::channel();
let (headers_sent, headers) = mpsc::channel();
listener.set_nonblocking(true).unwrap();
let server = thread::spawn(move || {
let deadline = Instant::now() + Duration::from_secs(5);
let mut stream = loop {
match listener.accept() {
Ok((stream, _)) => break stream,
Err(error)
if error.kind() == std::io::ErrorKind::WouldBlock
&& Instant::now() < deadline =>
{
thread::sleep(Duration::from_millis(2))
}
Err(error) => panic!("Gated local fixture accept failed: {error}"),
}
};
stream.set_nonblocking(false).unwrap();
stream
.set_read_timeout(Some(Duration::from_secs(2)))
.unwrap();
let mut request = Vec::new();
let mut buffer = [0u8; 1024];
while !request.windows(4).any(|w| w == b"\r\n\r\n") {
let n = stream.read(&mut buffer).unwrap();
assert!(n > 0);
request.extend_from_slice(&buffer[..n]);
assert!(request.len() <= 8192);
}
stream
.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 10\r\nConnection: close\r\n\r\n")
.unwrap();
headers_sent.send(()).unwrap();
wait.recv_timeout(Duration::from_secs(2)).unwrap();
stream.write_all(b"projection").unwrap();
});
let (events, observed) = mpsc::channel();
let (done, completion) = mpsc::channel();
let path = directory.path().to_path_buf();
let provisioning = thread::spawn(move || {
let manifest = test_manifest(vec![
artifact(BACKBONE_FILE, b"backbone"),
artifact(PROJECTOR_FILE, b"projection"),
]);
let progress = AtomicU64::new(0);
let result = provision_with_callback(
&path,
&progress,
&manifest,
&client(),
|_| url.clone(),
|asset| {
let artifact = match asset {
VerifiedAsset::TextBackbone => &manifest.files[0],
VerifiedAsset::MediaProjector => &manifest.files[1],
};
assert!(verified(&path.join(&artifact.path), artifact).unwrap());
events.send(asset).unwrap();
},
);
done.send(result).unwrap();
});
assert_eq!(
observed.recv_timeout(Duration::from_secs(2)).unwrap(),
VerifiedAsset::TextBackbone
);
headers.recv_timeout(Duration::from_secs(2)).unwrap();
assert!(
observed.try_recv().is_err(),
"Projector is not yet verified"
);
assert!(
completion.try_recv().is_err(),
"Bundle must remain incomplete"
);
assert!(!directory.path().join(PROJECTOR_FILE).exists());
release.send(()).unwrap();
assert_eq!(
observed.recv_timeout(Duration::from_secs(2)).unwrap(),
VerifiedAsset::MediaProjector
);
completion
.recv_timeout(Duration::from_secs(2))
.unwrap()
.unwrap();
provisioning.join().unwrap();
server.join().unwrap();
assert_no_part_files(directory.path());
}
}