1use crate::package::Package;
8use crate::tier::checksum_hex;
9use anyhow::{Result, bail};
10
11pub fn verify_package(pack: &Package) -> Result<VerifyReport> {
13 let mut report = VerifyReport::default();
14 let Some(idx) = pack.weights_index() else {
15 return Ok(report);
16 };
17 for t in &idx.tensors {
18 report.tensors_checked += 1;
19 let raw = pack.tensor_bytes(&t.name)?;
20 let got = checksum_hex(&raw);
21 match &t.checksum {
22 Some(expect) if expect == &got => report.tensors_ok += 1,
23 Some(expect) => {
24 report.tensors_mismatch += 1;
25 report.failures.push(format!(
26 "tensor {}: checksum mismatch (toc={expect} got={got})",
27 t.name
28 ));
29 }
30 None => {
31 report.tensors_unchecked += 1;
32 }
33 }
34 }
35 for sc in &pack.manifest().sidecars {
36 report.sidecars_checked += 1;
37 let _ = pack.sidecar(&sc.id)?; report.sidecars_ok += 1;
39 }
40 if !report.failures.is_empty() {
41 bail!("{} checksum failure(s)", report.failures.len());
42 }
43 Ok(report)
44}
45
46#[derive(Debug, Default, Clone)]
47pub struct VerifyReport {
48 pub tensors_checked: usize,
49 pub tensors_ok: usize,
50 pub tensors_unchecked: usize,
51 pub tensors_mismatch: usize,
52 pub sidecars_checked: usize,
53 pub sidecars_ok: usize,
54 pub failures: Vec<String>,
55}