Skip to main content

memra_cli/
lib.rs

1use memra_gguf::config::{HfConfig, ModelConfig};
2use memra_gguf::model_packs::{self, Gate, ModelPack, TokenizerSource};
3use memra_gguf::safetensors::{StInfo, StModel, parse_header_json, parse_index_weight_map_json};
4use memra_gguf::tensor_contract::{
5    CheckpointDialect, ContractOptions, FloatType, IntegerType, OutputHead, QuantLayout,
6    StorageLayout, TensorCensusEntry,
7};
8use memra_gguf::{GgmlType, GgufFile};
9use memra_reference::{deterministic_fixture, execute, execute_multimodal, execute_vision};
10use sha2::{Digest, Sha256};
11use std::collections::{BTreeMap, BTreeSet};
12use std::fmt::Write as _;
13use std::io::Write as _;
14use std::path::{Path, PathBuf};
15use std::process::{Command, Output, Stdio};
16
17const MAX_TEXT_BYTES: usize = 100_000_000;
18
19pub struct InspectRequest {
20    pub source: String,
21    pub against: String,
22    pub out_dir: PathBuf,
23}
24
25pub struct InspectSummary {
26    pub family: &'static str,
27    pub tensor_count: usize,
28    pub out_dir: PathBuf,
29}
30
31pub struct ScaffoldRequest {
32    pub family: String,
33    pub out_dir: PathBuf,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum VerifyStage {
38    Config,
39    Tiny,
40    Checkpoint,
41    Rewrite,
42    Serve,
43}
44
45pub struct VerifyRequest {
46    pub stage: VerifyStage,
47    pub source: String,
48    pub against: String,
49    pub out_dir: Option<PathBuf>,
50    pub oracle: Option<PathBuf>,
51    pub native_runner: Option<PathBuf>,
52}
53
54pub struct VerifySummary {
55    pub family: &'static str,
56    pub stage: VerifyStage,
57}
58
59pub fn verify_model(request: VerifyRequest) -> Result<VerifySummary, Box<dyn std::error::Error>> {
60    match request.stage {
61        VerifyStage::Config => {
62            let pack = model_packs::by_alias(&request.against)
63                .ok_or_else(|| format!("unknown model pack {:?}", request.against))?;
64            let config = load_config_only(&request.source)?;
65            pack.compile_plan(&config)?;
66            Ok(VerifySummary {
67                family: pack.family,
68                stage: VerifyStage::Config,
69            })
70        }
71        VerifyStage::Checkpoint => {
72            let pack = model_packs::by_alias(&request.against)
73                .ok_or_else(|| format!("unknown model pack {:?}", request.against))?;
74            let out_dir = request.out_dir.ok_or("verify checkpoint requires --out")?;
75            let summary = inspect_model(InspectRequest {
76                source: request.source.clone(),
77                against: request.against.clone(),
78                out_dir: out_dir.clone(),
79            })?;
80            write_hf_oracle_bundle(&request.source, &out_dir)?;
81            let gate = pack.checkpoint_parity.ok_or_else(|| {
82                format!(
83                    "model pack {} has no checkpoint parity threshold; capture bundle written to {} and no fallback is allowed",
84                    pack.family,
85                    out_dir.display()
86                )
87            })?;
88            let oracle_path = request.oracle.ok_or_else(|| {
89                format!(
90                    "checkpoint tensor contract passed; run {} offline, then repeat with --oracle <hf-oracle.tsv>; no fallback is allowed",
91                    out_dir.join("capture-hf-oracle.py").display()
92                )
93            })?;
94            let runner = request
95                .native_runner
96                .or_else(|| std::env::var_os("MEMRA_NATIVE_CHECKPOINT_RUNNER").map(PathBuf::from))
97                .ok_or("checkpoint parity requires --native-runner or MEMRA_NATIVE_CHECKPOINT_RUNNER; no fallback is allowed")?;
98            let native_path = out_dir.join("native-oracle.tsv");
99            run_native_checkpoint(&runner, &request.source, &native_path)?;
100            let runner_hash = hex_sha256(&std::fs::read(&runner)?);
101            let expected = parse_checkpoint_oracle(&std::fs::read_to_string(&oracle_path)?)?;
102            let actual = parse_checkpoint_oracle(&std::fs::read_to_string(&native_path)?)?;
103            let receipt = match compare_checkpoint_oracles(&expected, &actual, gate) {
104                Ok(receipt) => receipt,
105                Err(error) => {
106                    write_atomic(
107                        &out_dir.join("checkpoint-parity.tsv"),
108                        format!(
109                            "status\tfailed\nerror\t{}\n",
110                            lock_value(&error.to_string())
111                        )
112                        .as_bytes(),
113                    )?;
114                    write_atomic(
115                        &out_dir.join("gates.txt"),
116                        format_gate_results_with_receipts(
117                            pack,
118                            &out_dir,
119                            &[Gate::Config, Gate::TokenizerTemplate, Gate::TensorCensus],
120                            &[Gate::CheckpointParity],
121                        )
122                        .as_bytes(),
123                    )?;
124                    return Err(error);
125                }
126            };
127            let artifact_lock = std::fs::read(out_dir.join("artifact.lock"))?;
128            let receipt = format!(
129                "{receipt}artifact_lock_sha256\t{}\nnative_runner_sha256\t{runner_hash}\n",
130                hex_sha256(&artifact_lock)
131            );
132            write_atomic(&out_dir.join("checkpoint-parity.tsv"), receipt.as_bytes())?;
133            write_atomic(
134                &out_dir.join("gates.txt"),
135                format_gate_results_with_receipts(
136                    pack,
137                    &out_dir,
138                    &[
139                        Gate::Config,
140                        Gate::TokenizerTemplate,
141                        Gate::TensorCensus,
142                        Gate::CheckpointParity,
143                    ],
144                    &[],
145                )
146                .as_bytes(),
147            )?;
148            Ok(VerifySummary {
149                family: summary.family,
150                stage: VerifyStage::Checkpoint,
151            })
152        }
153        VerifyStage::Tiny => {
154            let pack = model_packs::by_alias(&request.against)
155                .ok_or_else(|| format!("unknown model pack {:?}", request.against))?;
156            if pack.support.is_none() {
157                return Err(format!(
158                    "model pack {} is inspect-only and has no native support state",
159                    pack.family
160                )
161                .into());
162            }
163            let out_dir = request.out_dir.ok_or("verify tiny requires --out")?;
164            let plan = pack.compile_tiny_plan()?;
165            let fixture = deterministic_fixture(&plan)?;
166            let first = execute(&plan, &fixture.weights, &fixture.token_ids)?;
167            let second = execute(&plan, &fixture.weights, &fixture.token_ids)?;
168            if first != second {
169                return Err("native reference fixture is not bit-deterministic".into());
170            }
171            let vision = fixture
172                .vision
173                .as_ref()
174                .map(|input| {
175                    let first = execute_vision(&plan, &fixture.weights, input)?;
176                    let second = execute_vision(&plan, &fixture.weights, input)?;
177                    if first != second {
178                        return Err(ReferenceVisionError::Nondeterministic);
179                    }
180                    Ok(first)
181                })
182                .transpose()
183                .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
184            let multimodal = match (
185                fixture.multimodal_token_ids.as_ref(),
186                fixture.vision.as_ref(),
187            ) {
188                (Some(token_ids), Some(input)) => {
189                    let first = execute_multimodal(&plan, &fixture.weights, token_ids, input)?;
190                    let second = execute_multimodal(&plan, &fixture.weights, token_ids, input)?;
191                    if first != second {
192                        return Err(
193                            "native multimodal reference fixture is not bit-deterministic".into(),
194                        );
195                    }
196                    Some(first)
197                }
198                (None, None) | (None, Some(_)) if plan.multimodal.is_none() => None,
199                _ => {
200                    return Err(
201                        "multimodal plan is missing its combined tiny fixture inputs".into(),
202                    );
203                }
204            };
205            std::fs::create_dir_all(&out_dir)?;
206            write_atomic(
207                &out_dir.join("tiny-fixture.txt"),
208                format_tiny_fixture(&plan, &fixture).as_bytes(),
209            )?;
210            write_atomic(
211                &out_dir.join("reference-oracle.tsv"),
212                format_reference_oracle(&first).as_bytes(),
213            )?;
214            if let Some(vision) = vision.as_ref() {
215                write_atomic(
216                    &out_dir.join("reference-vision-oracle.tsv"),
217                    format_reference_vision_oracle(vision).as_bytes(),
218                )?;
219            }
220            if let Some(multimodal) = multimodal.as_ref() {
221                write_atomic(
222                    &out_dir.join("reference-multimodal-oracle.tsv"),
223                    format_reference_oracle(&multimodal.language).as_bytes(),
224                )?;
225            }
226            write_atomic(
227                &out_dir.join("tiny-gate.tsv"),
228                format!("status\tpassed\nfamily\t{}\n", pack.family).as_bytes(),
229            )?;
230            write_atomic(
231                &out_dir.join("gates.txt"),
232                format_gate_results_with_receipts(
233                    pack,
234                    &out_dir,
235                    &[Gate::Config, Gate::TinyParity],
236                    &[],
237                )
238                .as_bytes(),
239            )?;
240            Ok(VerifySummary {
241                family: pack.family,
242                stage: VerifyStage::Tiny,
243            })
244        }
245        VerifyStage::Rewrite => {
246            let pack = model_packs::by_alias(&request.against)
247                .ok_or_else(|| format!("unknown model pack {:?}", request.against))?;
248            let out_dir = request
249                .out_dir
250                .ok_or("verify rewrite requires --out; no fallback is allowed")?;
251            verify_rewrite_receipt(pack, Path::new(&request.source), &out_dir)?;
252            Ok(VerifySummary {
253                family: pack.family,
254                stage: VerifyStage::Rewrite,
255            })
256        }
257        VerifyStage::Serve => {
258            let pack = model_packs::by_alias(&request.against)
259                .ok_or_else(|| format!("unknown model pack {:?}", request.against))?;
260            let out_dir = request
261                .out_dir
262                .ok_or("verify serve requires --out; no fallback is allowed")?;
263            let runner = request
264                .native_runner
265                .or_else(|| std::env::var_os("MEMRA_NATIVE_SERVE_RUNNER").map(PathBuf::from))
266                .ok_or("verify serve requires --native-runner or MEMRA_NATIVE_SERVE_RUNNER; no fallback is allowed")?;
267            verify_native_serve(pack, &request.source, &out_dir, &runner)?;
268            Ok(VerifySummary {
269                family: pack.family,
270                stage: VerifyStage::Serve,
271            })
272        }
273    }
274}
275
276fn verify_rewrite_receipt(
277    pack: &ModelPack,
278    receipt_path: &Path,
279    out_dir: &Path,
280) -> Result<(), Box<dyn std::error::Error>> {
281    let artifact_lock = std::fs::read_to_string(out_dir.join("artifact.lock"))?;
282    let artifact_lock_sha256 = hex_sha256(artifact_lock.as_bytes());
283    if !artifact_lock
284        .lines()
285        .any(|line| line == format!("family={}", pack.family))
286    {
287        return Err("rewrite receipt family does not match artifact.lock".into());
288    }
289    let manifest = std::fs::read_to_string(out_dir.join("execution-rewrites.tsv"))?;
290    let receipt = std::fs::read_to_string(receipt_path)?;
291    let mut fields = BTreeMap::new();
292    for line in receipt.lines() {
293        let Some((key, value)) = line.split_once('\t') else {
294            return Err(format!("malformed rewrite receipt line {line:?}").into());
295        };
296        if fields.insert(key, value).is_some() {
297            return Err(format!("duplicate rewrite receipt field {key}").into());
298        }
299    }
300    for (key, expected) in [
301        ("format", "memra-rewrite-parity-v1"),
302        ("status", "passed"),
303        ("first_violation", "none"),
304    ] {
305        if fields.get(key).copied() != Some(expected) {
306            return Err(format!("rewrite receipt requires {key}={expected}").into());
307        }
308    }
309    match fields.get("value_kind").copied() {
310        Some("logits-f32") if fields.get("require_argmax").copied() == Some("true") => {}
311        Some("token-ids-u32") if fields.get("require_argmax").copied() == Some("false") => {}
312        _ => return Err("rewrite receipt has an invalid value_kind/argmax policy".into()),
313    }
314    let rewrite_id = *fields.get("rewrite").ok_or("rewrite receipt has no id")?;
315    let row = manifest
316        .lines()
317        .skip(1)
318        .find(|line| line.split('\t').next() == Some(rewrite_id))
319        .ok_or_else(|| format!("rewrite {rewrite_id} is absent from execution manifest"))?;
320    let columns: Vec<_> = row.split('\t').collect();
321    if columns.len() != 8 || columns[4] != "true" {
322        return Err(format!("rewrite {rewrite_id} is not eligible in this artifact").into());
323    }
324    for (field, expected) in [
325        ("surface", columns[1]),
326        ("implementation", columns[2]),
327        ("plan_sha256", columns[3]),
328    ] {
329        if fields.get(field).copied() != Some(expected) {
330            return Err(format!("rewrite receipt {field} does not match manifest").into());
331        }
332    }
333    if fields.get("artifact_lock_sha256").copied() != Some(artifact_lock_sha256.as_str()) {
334        return Err("rewrite receipt does not match artifact.lock".into());
335    }
336    let reference = fields
337        .get("reference_sha256")
338        .ok_or("rewrite receipt has no reference hash")?;
339    let candidate = fields
340        .get("candidate_sha256")
341        .ok_or("rewrite receipt has no candidate hash")?;
342    let parse_nonnegative = |field: &str| -> Result<f32, Box<dyn std::error::Error>> {
343        let value = fields
344            .get(field)
345            .ok_or_else(|| format!("rewrite receipt has no {field}"))?
346            .parse::<f32>()?;
347        if !value.is_finite() || value < 0.0 {
348            return Err(format!("rewrite receipt {field} is not finite and nonnegative").into());
349        }
350        Ok(value)
351    };
352    let atol = parse_nonnegative("atol")?;
353    let rtol = parse_nonnegative("rtol")?;
354    let max_abs = parse_nonnegative("max_abs")?;
355    let _max_rel = parse_nonnegative("max_rel")?;
356    if atol == 0.0 && rtol == 0.0 && (max_abs != 0.0 || reference != candidate) {
357        return Err("exact rewrite receipt has nonzero error or different stream hashes".into());
358    }
359    for field in [
360        "implementation_sha256",
361        "reference_sha256",
362        "candidate_sha256",
363    ] {
364        let value = fields[field];
365        if value.len() != 64
366            || !value
367                .bytes()
368                .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
369        {
370            return Err(format!("rewrite receipt {field} is not a lowercase SHA-256").into());
371        }
372    }
373    if fields
374        .get("values")
375        .and_then(|value| value.parse::<usize>().ok())
376        .is_none_or(|values| values == 0)
377    {
378        return Err("rewrite receipt compared no values".into());
379    }
380    let receipt_hash = hex_sha256(receipt.as_bytes());
381    let receipt_dir = out_dir.join("rewrite-receipts");
382    std::fs::create_dir_all(&receipt_dir)?;
383    write_atomic(
384        &receipt_dir.join(format!("{rewrite_id}.tsv")),
385        receipt.as_bytes(),
386    )?;
387    let index_path = out_dir.join("rewrite-receipts.tsv");
388    let mut index = BTreeMap::new();
389    if let Ok(existing) = std::fs::read_to_string(&index_path) {
390        for line in existing.lines().skip(1) {
391            let columns: Vec<_> = line.split('\t').collect();
392            if columns.len() == 4 {
393                index.insert(
394                    columns[0].to_string(),
395                    (
396                        columns[1].to_string(),
397                        columns[2].to_string(),
398                        columns[3].to_string(),
399                    ),
400                );
401            }
402        }
403    }
404    index.insert(
405        rewrite_id.to_string(),
406        (columns[3].to_string(), receipt_hash, "passed".to_string()),
407    );
408    let mut index_text = String::from("rewrite\tplan_sha256\treceipt_sha256\tstatus\n");
409    for (rewrite, (plan, hash, status)) in index {
410        writeln!(index_text, "{rewrite}\t{plan}\t{hash}\t{status}").unwrap();
411    }
412    write_atomic(&index_path, index_text.as_bytes())?;
413    write_atomic(
414        &out_dir.join("gates.txt"),
415        format_gate_results_with_receipts(pack, out_dir, &[], &[]).as_bytes(),
416    )?;
417    Ok(())
418}
419
420fn verify_native_serve(
421    pack: &ModelPack,
422    source: &str,
423    out_dir: &Path,
424    runner: &Path,
425) -> Result<(), Box<dyn std::error::Error>> {
426    if !Path::new(source).exists() {
427        return Err("verify serve requires a local model artifact; no fallback is allowed".into());
428    }
429    let checkpoint_receipt = out_dir.join("checkpoint-parity.tsv");
430    let artifact_lock_path = out_dir.join("artifact.lock");
431    let artifact_lock = std::fs::read_to_string(&artifact_lock_path).map_err(|error| {
432        format!(
433            "verify serve requires {} from inspect/checkpoint first: {error}; no fallback is allowed",
434            artifact_lock_path.display()
435        )
436    })?;
437    if !artifact_lock
438        .lines()
439        .any(|line| line == format!("source={}", lock_value(source)))
440        || !artifact_lock.lines().any(|line| line == "binding=passed")
441        || !artifact_lock.lines().any(|line| line == "tokenizer=passed")
442    {
443        return Err(
444            "verify serve artifact.lock does not match this source with binding/tokenizer passed; no fallback is allowed"
445                .into(),
446        );
447    }
448    let checkpoint = std::fs::read_to_string(&checkpoint_receipt).map_err(|error| {
449        format!(
450            "verify serve requires a passed {} first: {error}; no fallback is allowed",
451            checkpoint_receipt.display()
452        )
453    })?;
454    if !checkpoint.lines().any(|line| line == "status\tpassed") {
455        return Err(
456            "verify serve requires status=passed checkpoint parity; no fallback is allowed".into(),
457        );
458    }
459    let lock_hash = hex_sha256(artifact_lock.as_bytes());
460    if !checkpoint
461        .lines()
462        .any(|line| line == format!("artifact_lock_sha256\t{lock_hash}"))
463    {
464        return Err(
465            "verify serve checkpoint receipt does not match artifact.lock; no fallback is allowed"
466                .into(),
467        );
468    }
469    std::fs::create_dir_all(out_dir)?;
470    let listener = std::net::TcpListener::bind("127.0.0.1:0")?;
471    let port = listener.local_addr()?.port();
472    drop(listener);
473    let address = format!("127.0.0.1:{port}");
474    let api_key = "memra-onboarding-verify";
475    let log_path = out_dir.join("serve.log");
476    let log = std::fs::File::create(&log_path)?;
477    let mut child = Command::new(runner)
478        .env("MEMRA_MODELS", format!("verify={source}"))
479        .env("MEMRA_REWRITE_BUNDLE", out_dir)
480        .env("MEMRA_ADDR", &address)
481        .env("MEMRA_API_KEY", api_key)
482        .stdin(Stdio::null())
483        .stdout(Stdio::from(log.try_clone()?))
484        .stderr(Stdio::from(log))
485        .spawn()?;
486    let result = (|| -> Result<String, Box<dyn std::error::Error>> {
487        let timeout = std::env::var("MEMRA_SERVE_VERIFY_TIMEOUT_S")
488            .ok()
489            .and_then(|value| value.parse::<u64>().ok())
490            .unwrap_or(180);
491        let started = std::time::Instant::now();
492        loop {
493            if let Some(status) = child.try_wait()? {
494                return Err(format!(
495                    "native server exited before readiness with {status}; inspect {}",
496                    log_path.display()
497                )
498                .into());
499            }
500            let ready = Command::new("curl")
501                .args([
502                    "--fail",
503                    "--silent",
504                    "--output",
505                    "/dev/null",
506                    &format!("http://{address}/readyz"),
507                ])
508                .status();
509            if ready.is_ok_and(|status| status.success()) {
510                break;
511            }
512            if started.elapsed() >= std::time::Duration::from_secs(timeout) {
513                return Err(format!(
514                    "native server did not become ready within {timeout}s; inspect {}",
515                    log_path.display()
516                )
517                .into());
518            }
519            std::thread::sleep(std::time::Duration::from_millis(250));
520        }
521        let response = Command::new("curl")
522            .args([
523                "--fail",
524                "--silent",
525                "--show-error",
526                "--header",
527                &format!("Authorization: Bearer {api_key}"),
528                "--header",
529                "Content-Type: application/json",
530                "--data",
531                r#"{"model":"verify","prompt":"Hello","max_tokens":1,"temperature":0}"#,
532                &format!("http://{address}/v1/completions"),
533            ])
534            .output()?;
535        if !response.status.success() {
536            return Err(format!(
537                "native completion failed with {}: {}",
538                response.status,
539                String::from_utf8_lossy(&response.stderr)
540            )
541            .into());
542        }
543        let response = String::from_utf8(response.stdout)?;
544        if !response.contains("\"choices\"") || response.contains("\"error\"") {
545            return Err(format!("native completion response is not successful: {response}").into());
546        }
547        Ok(response)
548    })();
549    let _ = child.kill();
550    let _ = child.wait();
551    let response = result?;
552    let runner_hash = hex_sha256(&std::fs::read(runner)?);
553    write_atomic(&out_dir.join("serve-response.json"), response.as_bytes())?;
554    write_atomic(
555        &out_dir.join("serve-gate.tsv"),
556        format!(
557            "status\tpassed\nfamily\t{}\nmodel\tverify\nendpoint\t/v1/completions\nartifact_lock_sha256\t{lock_hash}\nnative_runner_sha256\t{runner_hash}\n",
558            pack.family,
559        )
560        .as_bytes(),
561    )?;
562    write_atomic(
563        &out_dir.join("gates.txt"),
564        format_gate_results_with_receipts(
565            pack,
566            out_dir,
567            &[
568                Gate::Config,
569                Gate::TokenizerTemplate,
570                Gate::TensorCensus,
571                Gate::CheckpointParity,
572                Gate::Serve,
573            ],
574            &[],
575        )
576        .as_bytes(),
577    )?;
578    Ok(())
579}
580
581#[derive(Debug, Clone, PartialEq)]
582struct CheckpointOracle {
583    engine: String,
584    numeric_class: String,
585    tokens: Vec<u32>,
586    vocab: usize,
587    logits: Vec<f32>,
588}
589
590fn write_hf_oracle_bundle(source: &str, out_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
591    let tokens = [1u32, 2, 3, 4];
592    let (model, revision) = if Path::new(source).exists() {
593        (source.to_string(), None)
594    } else {
595        let (model, revision) = parse_pinned_hf_source(source)?;
596        (model.to_string(), Some(revision.to_string()))
597    };
598    let request = format!(
599        "format\tmemra-checkpoint-request-v1\nsource\t{}\nrevision\t{}\nnumeric_class\tsource-weights-float32-accumulation\ntokens\t{}\n",
600        lock_value(&model),
601        revision.as_deref().unwrap_or("local"),
602        tokens
603            .iter()
604            .map(u32::to_string)
605            .collect::<Vec<_>>()
606            .join(",")
607    );
608    write_atomic(&out_dir.join("oracle-request.tsv"), request.as_bytes())?;
609    let model_literal = format!("{model:?}");
610    let revision_literal = revision
611        .as_ref()
612        .map(|revision| format!("{revision:?}"))
613        .unwrap_or_else(|| "None".to_string());
614    let script = format!(
615        r#"#!/usr/bin/env python3
616import argparse
617import struct
618import torch
619import transformers
620from transformers import AutoModelForCausalLM
621
622MODEL = {model_literal}
623REVISION = {revision_literal}
624TOKENS = [1, 2, 3, 4]
625
626parser = argparse.ArgumentParser(description="Offline HF correctness oracle for Memra onboarding")
627parser.add_argument("--out", default="hf-oracle.tsv")
628args = parser.parse_args()
629
630model = AutoModelForCausalLM.from_pretrained(
631    MODEL,
632    revision=REVISION,
633    dtype=torch.float32,
634    trust_remote_code=False,
635)
636device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
637model = model.to(device).eval()
638with torch.no_grad():
639    logits = model(input_ids=torch.tensor([TOKENS], device=device)).logits[0, -1].float().cpu()
640
641with open(args.out, "w", encoding="utf-8") as f:
642    f.write("format\tmemra-checkpoint-oracle-v1\n")
643    f.write("engine\thf-transformers-fp32\n")
644    f.write("numeric_class\tsource-weights-float32-accumulation\n")
645    f.write(f"transformers_version\t{{transformers.__version__}}\n")
646    f.write(f"torch_version\t{{torch.__version__}}\n")
647    f.write("tokens\t" + ",".join(map(str, TOKENS)) + "\n")
648    f.write(f"vocab\t{{logits.numel()}}\n")
649    for index, value in enumerate(logits.tolist()):
650        bits = struct.unpack("<I", struct.pack("<f", value))[0]
651        f.write(f"logit\t{{index}}\t{{bits:08x}}\n")
652"#
653    );
654    write_atomic(&out_dir.join("capture-hf-oracle.py"), script.as_bytes())?;
655    Ok(())
656}
657
658fn run_native_checkpoint(
659    runner: &Path,
660    source: &str,
661    output: &Path,
662) -> Result<(), Box<dyn std::error::Error>> {
663    if !Path::new(source).is_dir() {
664        return Err(
665            "native checkpoint parity requires a local safetensors directory; inspect may use a pinned remote header, execution may not"
666                .into(),
667        );
668    }
669    let result = Command::new(runner)
670        .arg(source)
671        .args(["1", "2", "3", "4"])
672        .env("MEMRA_FULL_PREC", "1")
673        .env("MEMRA_ORACLE_OUT", output)
674        .output()?;
675    if !result.status.success() {
676        return Err(format!(
677            "native checkpoint runner failed ({}): stdout={} stderr={}",
678            result.status,
679            String::from_utf8_lossy(&result.stdout),
680            String::from_utf8_lossy(&result.stderr)
681        )
682        .into());
683    }
684    if !output.is_file() {
685        return Err(format!(
686            "native checkpoint runner did not create {}",
687            output.display()
688        )
689        .into());
690    }
691    Ok(())
692}
693
694fn parse_checkpoint_oracle(text: &str) -> Result<CheckpointOracle, Box<dyn std::error::Error>> {
695    let mut format_ok = false;
696    let mut engine = None;
697    let mut numeric_class = None;
698    let mut tokens = None;
699    let mut vocab = None;
700    let mut logits = BTreeMap::new();
701    for line in text.lines() {
702        let fields: Vec<_> = line.split('\t').collect();
703        match fields.as_slice() {
704            ["format", "memra-checkpoint-oracle-v1"] => format_ok = true,
705            ["engine", value] => engine = Some((*value).to_string()),
706            ["numeric_class", value] => numeric_class = Some((*value).to_string()),
707            ["tokens", value] => {
708                tokens = Some(
709                    value
710                        .split(',')
711                        .map(str::parse)
712                        .collect::<Result<Vec<u32>, _>>()?,
713                )
714            }
715            ["vocab", value] => vocab = Some(value.parse::<usize>()?),
716            ["logit", index, bits] => {
717                let index = index.parse::<usize>()?;
718                let bits = u32::from_str_radix(bits, 16)?;
719                if logits.insert(index, f32::from_bits(bits)).is_some() {
720                    return Err(format!("duplicate oracle logit index {index}").into());
721                }
722            }
723            _ => {}
724        }
725    }
726    if !format_ok {
727        return Err("oracle is missing format=memra-checkpoint-oracle-v1".into());
728    }
729    let vocab = vocab.ok_or("oracle is missing vocab")?;
730    if logits.len() != vocab || (0..vocab).any(|index| !logits.contains_key(&index)) {
731        return Err(format!(
732            "oracle has {} logits, expected contiguous {vocab}",
733            logits.len()
734        )
735        .into());
736    }
737    Ok(CheckpointOracle {
738        engine: engine.ok_or("oracle is missing engine")?,
739        numeric_class: numeric_class.ok_or("oracle is missing numeric_class")?,
740        tokens: tokens.ok_or("oracle is missing tokens")?,
741        vocab,
742        logits: (0..vocab).map(|index| logits[&index]).collect(),
743    })
744}
745
746fn compare_checkpoint_oracles(
747    expected: &CheckpointOracle,
748    actual: &CheckpointOracle,
749    gate: model_packs::CheckpointParityGate,
750) -> Result<String, Box<dyn std::error::Error>> {
751    if expected.numeric_class != actual.numeric_class {
752        return Err(format!(
753            "oracle numeric class mismatch: expected={} native={}",
754            expected.numeric_class, actual.numeric_class
755        )
756        .into());
757    }
758    if expected.tokens != actual.tokens || expected.vocab != actual.vocab {
759        return Err(format!(
760            "oracle identity mismatch: expected tokens={:?} vocab={}, native tokens={:?} vocab={}",
761            expected.tokens, expected.vocab, actual.tokens, actual.vocab
762        )
763        .into());
764    }
765    let mut max_abs = 0.0f32;
766    let mut max_rel = 0.0f32;
767    let mut worst = 0usize;
768    let mut first_violation = None;
769    for (index, (&reference, &native)) in expected.logits.iter().zip(&actual.logits).enumerate() {
770        if !reference.is_finite() || !native.is_finite() {
771            return Err(format!("non-finite checkpoint logit at token {index}").into());
772        }
773        let absolute = (reference - native).abs();
774        let relative = absolute / reference.abs().max(1e-6);
775        if absolute > max_abs {
776            max_abs = absolute;
777            worst = index;
778        }
779        max_rel = max_rel.max(relative);
780        let allowed = gate.max_abs + gate.max_rel * reference.abs();
781        if absolute > allowed && first_violation.is_none() {
782            first_violation = Some((index, absolute, allowed));
783        }
784    }
785    let reference_argmax = stable_argmax(&expected.logits);
786    let native_argmax = stable_argmax(&actual.logits);
787    if let Some((index, absolute, allowed)) = first_violation {
788        return Err(format!(
789            "checkpoint parity failed at token {index}: abs={absolute} exceeds atol+rtol*abs(reference)={allowed}; observed max_abs={max_abs} at token {worst}, max_rel={max_rel}"
790        )
791        .into());
792    }
793    if gate.require_argmax && reference_argmax != native_argmax {
794        return Err(format!(
795            "checkpoint parity argmax mismatch: reference={reference_argmax} native={native_argmax}"
796        )
797        .into());
798    }
799    Ok(format!(
800        "status\tpassed\nreference_engine\t{}\nnative_engine\t{}\nnumeric_class\t{}\ntokens\t{}\nvocab\t{}\nmax_abs\t{max_abs}\nmax_rel\t{max_rel}\nreference_argmax\t{reference_argmax}\nnative_argmax\t{native_argmax}\n",
801        expected.engine,
802        actual.engine,
803        expected.numeric_class,
804        expected
805            .tokens
806            .iter()
807            .map(u32::to_string)
808            .collect::<Vec<_>>()
809            .join(","),
810        expected.vocab,
811    ))
812}
813
814fn stable_argmax(values: &[f32]) -> usize {
815    values
816        .iter()
817        .enumerate()
818        .max_by(|(left_index, left), (right_index, right)| {
819            left.total_cmp(right)
820                .then_with(|| right_index.cmp(left_index))
821        })
822        .map(|(index, _)| index)
823        .unwrap_or(0)
824}
825
826#[derive(Debug)]
827enum ReferenceVisionError {
828    Reference(memra_reference::ReferenceError),
829    Nondeterministic,
830}
831
832impl std::fmt::Display for ReferenceVisionError {
833    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
834        match self {
835            Self::Reference(error) => error.fmt(f),
836            Self::Nondeterministic => write!(
837                f,
838                "native vision reference fixture is not bit-deterministic"
839            ),
840        }
841    }
842}
843
844impl std::error::Error for ReferenceVisionError {}
845
846impl From<memra_reference::ReferenceError> for ReferenceVisionError {
847    fn from(value: memra_reference::ReferenceError) -> Self {
848        Self::Reference(value)
849    }
850}
851
852pub fn scaffold_model_pack(request: ScaffoldRequest) -> Result<(), Box<dyn std::error::Error>> {
853    validate_family_name(&request.family)?;
854    if request.out_dir.exists() && request.out_dir.read_dir()?.next().is_some() {
855        return Err(format!(
856            "refusing to scaffold into non-empty directory {}",
857            request.out_dir.display()
858        )
859        .into());
860    }
861    std::fs::create_dir_all(&request.out_dir)?;
862    write_atomic(
863        &request.out_dir.join("pack.toml"),
864        format!(
865            "family = {:?}\nconfig_layout = \"pending\"\nsupport = \"pending\"\n\n[checkpoint_parity]\nmax_abs = \"pending\"\nmax_rel = \"pending\"\nrequire_argmax = true\n",
866            request.family
867        )
868        .as_bytes(),
869    )?;
870    write_atomic(
871        &request.out_dir.join("aliases.txt"),
872        format!("{}\n", request.family).as_bytes(),
873    )?;
874    write_atomic(
875        &request.out_dir.join("config-normalization.txt"),
876        b"# source field\tcanonical field\ttransform\n",
877    )?;
878    write_atomic(
879        &request.out_dir.join("tensor-schema.tsv"),
880        b"semantic_id\tcheckpoint_pattern\tshape\townership\ttransform\tquant_layout\n",
881    )?;
882    write_atomic(
883        &request.out_dir.join("tokenizer-template.txt"),
884        b"tokenizer_source=pending\ntemplate=artifact-required\n",
885    )?;
886    write_atomic(
887        &request.out_dir.join("gates.txt"),
888        format_gates(&[
889            Gate::Config,
890            Gate::TokenizerTemplate,
891            Gate::TensorCensus,
892            Gate::TinyParity,
893            Gate::CheckpointParity,
894            Gate::RewriteParity,
895            Gate::Serve,
896        ])
897        .as_bytes(),
898    )?;
899    Ok(())
900}
901
902struct SourceData {
903    label: String,
904    revision: String,
905    dialect: CheckpointDialect,
906    config: ModelConfig,
907    config_bytes: Vec<u8>,
908    tensors: Vec<CensusRow>,
909    shards: Vec<String>,
910    tokenizer: Result<TokenizerEvidence, String>,
911}
912
913struct TokenizerEvidence {
914    source: TokenizerSource,
915    tokenizer_sha256: String,
916    template_sha256: String,
917    template_bytes: usize,
918}
919
920#[derive(Clone)]
921struct CensusRow {
922    physical_name: String,
923    entry: TensorCensusEntry,
924    dtype: String,
925}
926
927pub fn inspect_model(
928    request: InspectRequest,
929) -> Result<InspectSummary, Box<dyn std::error::Error>> {
930    let pack = model_packs::by_alias(&request.against)
931        .ok_or_else(|| format!("unknown model pack {:?}", request.against))?;
932    let source = load_source(&request.source)?;
933    let plan = pack.compile_plan(&source.config)?;
934    let output_head = if source
935        .tensors
936        .iter()
937        .any(|row| row.entry.name == "lm_head.weight" || row.entry.name == "output.weight")
938    {
939        OutputHead::Separate
940    } else {
941        OutputHead::TiedToEmbedding
942    };
943    let entries: Vec<_> = source.tensors.iter().map(|row| row.entry.clone()).collect();
944    std::fs::create_dir_all(&request.out_dir)?;
945    let config_hash = hex_sha256(&source.config_bytes);
946    let census = format_census(&source.tensors);
947    let census_hash = hex_sha256(census.as_bytes());
948    let plan_text = format!("{plan:#?}\n");
949    let plan_hash = hex_sha256(plan_text.as_bytes());
950    let rewrites = memra_gguf::execution_manifest::execution_rewrites(&plan);
951    debug_assert!(
952        rewrites
953            .iter()
954            .all(|rewrite| rewrite.plan_sha256 == plan_hash)
955    );
956    let rewrite_manifest = format_execution_rewrites(&rewrites);
957    let rewrite_hash = hex_sha256(rewrite_manifest.as_bytes());
958    write_atomic(
959        &request.out_dir.join("tensor-census.tsv"),
960        census.as_bytes(),
961    )?;
962    write_atomic(
963        &request.out_dir.join("model-plan.txt"),
964        plan_text.as_bytes(),
965    )?;
966    write_atomic(
967        &request.out_dir.join("execution-rewrites.tsv"),
968        rewrite_manifest.as_bytes(),
969    )?;
970    let binding_error = match pack.compile_tensor_contract(
971        &source.config,
972        &plan,
973        source.dialect,
974        ContractOptions { output_head },
975    ) {
976        Ok(contract) => contract.bind(&entries).err().map(|error| error.to_string()),
977        Err(error) => Some(error.to_string()),
978    };
979    let tokenizer_error = match &source.tokenizer {
980        Ok(evidence) if pack.tokenizer_sources.contains(&evidence.source) => None,
981        Ok(evidence) => Some(format!(
982            "model pack {} does not accept tokenizer source {:?}",
983            pack.family, evidence.source
984        )),
985        Err(error) => Some(error.clone()),
986    };
987    if let Ok(evidence) = &source.tokenizer {
988        write_atomic(
989            &request.out_dir.join("tokenizer-contract.tsv"),
990            format!(
991                "status\tpassed\nsource\t{:?}\ntokenizer_sha256\t{}\ntemplate_sha256\t{}\ntemplate_bytes\t{}\n",
992                evidence.source,
993                evidence.tokenizer_sha256,
994                evidence.template_sha256,
995                evidence.template_bytes,
996            )
997            .as_bytes(),
998        )?;
999    }
1000    write_atomic(
1001        &request.out_dir.join("artifact.lock"),
1002        format_lock(
1003            pack,
1004            &source,
1005            &config_hash,
1006            &census_hash,
1007            &plan_hash,
1008            &rewrite_hash,
1009            if binding_error.is_some() {
1010                "failed"
1011            } else {
1012                "passed"
1013            },
1014        )
1015        .as_bytes(),
1016    )?;
1017    let error_path = request.out_dir.join("contract-error.txt");
1018    let tokenizer_error_path = request.out_dir.join("tokenizer-error.txt");
1019    let mut passed = vec![Gate::Config];
1020    let mut failed = Vec::new();
1021    if tokenizer_error.is_some() {
1022        failed.push(Gate::TokenizerTemplate);
1023    } else {
1024        passed.push(Gate::TokenizerTemplate);
1025    }
1026    if binding_error.is_some() {
1027        failed.push(Gate::TensorCensus);
1028    } else {
1029        passed.push(Gate::TensorCensus);
1030    }
1031    write_atomic(
1032        &request.out_dir.join("gates.txt"),
1033        format_gate_results_with_receipts(pack, &request.out_dir, &passed, &failed).as_bytes(),
1034    )?;
1035    if let Some(error) = binding_error.as_ref() {
1036        write_atomic(&error_path, format!("{error}\n").as_bytes())?;
1037    } else {
1038        match std::fs::remove_file(&error_path) {
1039            Ok(()) => {}
1040            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
1041            Err(error) => return Err(error.into()),
1042        }
1043    }
1044    if let Some(error) = tokenizer_error.as_ref() {
1045        write_atomic(&tokenizer_error_path, format!("{error}\n").as_bytes())?;
1046    } else {
1047        match std::fs::remove_file(&tokenizer_error_path) {
1048            Ok(()) => {}
1049            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
1050            Err(error) => return Err(error.into()),
1051        }
1052    }
1053    match (binding_error, tokenizer_error) {
1054        (Some(binding), Some(tokenizer)) => {
1055            return Err(
1056                format!("tensor contract: {binding}; tokenizer contract: {tokenizer}").into(),
1057            );
1058        }
1059        (Some(error), None) | (None, Some(error)) => return Err(error.into()),
1060        (None, None) => {}
1061    }
1062
1063    Ok(InspectSummary {
1064        family: pack.family,
1065        tensor_count: source.tensors.len(),
1066        out_dir: request.out_dir,
1067    })
1068}
1069
1070fn load_source(source: &str) -> Result<SourceData, Box<dyn std::error::Error>> {
1071    let path = Path::new(source);
1072    if path.exists() {
1073        return load_local(path);
1074    }
1075    let (repo, revision) = parse_pinned_hf_source(source)?;
1076    load_remote(repo, revision)
1077}
1078
1079fn load_config_only(source: &str) -> Result<ModelConfig, Box<dyn std::error::Error>> {
1080    let path = Path::new(source);
1081    if path.is_file() {
1082        return Ok(ModelConfig::from_gguf(&GgufFile::open(path)?));
1083    }
1084    if path.is_dir() {
1085        let bytes = std::fs::read(path.join("config.json"))?;
1086        return Ok(ModelConfig::from_hf(&HfConfig::parse(std::str::from_utf8(
1087            &bytes,
1088        )?)));
1089    }
1090    let (repo, revision) = parse_pinned_hf_source(source)?;
1091    let url = format!("https://huggingface.co/{repo}/resolve/{revision}/config.json");
1092    let config = http_text(&url)?.ok_or("pinned model has no config.json")?;
1093    Ok(ModelConfig::from_hf(&HfConfig::parse(&config)))
1094}
1095
1096fn load_local(path: &Path) -> Result<SourceData, Box<dyn std::error::Error>> {
1097    if path.is_file() {
1098        let gguf = GgufFile::open(path)?;
1099        let tokenizer = inspect_gguf_tokenizer(&gguf);
1100        let config = ModelConfig::from_gguf(&gguf);
1101        let tensors = gguf
1102            .tensors
1103            .iter()
1104            .map(|tensor| CensusRow {
1105                physical_name: tensor.name.clone(),
1106                entry: TensorCensusEntry {
1107                    name: tensor.name.clone(),
1108                    shape: tensor.ne.clone(),
1109                    storage: ggml_storage(tensor.ggml_type),
1110                },
1111                dtype: format!("{:?}", tensor.ggml_type),
1112            })
1113            .collect();
1114        let config_bytes = format!("{config:#?}").into_bytes();
1115        return Ok(SourceData {
1116            label: path.display().to_string(),
1117            revision: "local".to_string(),
1118            dialect: CheckpointDialect::Gguf,
1119            config,
1120            config_bytes,
1121            tensors,
1122            shards: (0..gguf.n_shards())
1123                .map(|index| gguf.shard_path(index).display().to_string())
1124                .collect(),
1125            tokenizer,
1126        });
1127    }
1128
1129    let config_bytes = std::fs::read(path.join("config.json"))?;
1130    let config_text = std::str::from_utf8(&config_bytes)?;
1131    let config = ModelConfig::from_hf(&HfConfig::parse(config_text));
1132    let tokenizer = inspect_hf_tokenizer_dir(path);
1133    let model = StModel::open(path)?;
1134    let shards = local_shards(path)?;
1135    let revision = local_hf_revision(path, &shards).unwrap_or_else(|| "local".to_string());
1136    let headers = model
1137        .names()
1138        .map(|name| {
1139            let (info, _) = model.raw(name).expect("StModel name must resolve");
1140            (name.clone(), info.clone())
1141        })
1142        .collect();
1143    Ok(SourceData {
1144        label: path.display().to_string(),
1145        revision,
1146        dialect: CheckpointDialect::HfSafetensors,
1147        config,
1148        config_bytes,
1149        tensors: census_from_headers(headers)?,
1150        shards,
1151        tokenizer,
1152    })
1153}
1154
1155fn load_remote(repo: &str, revision: &str) -> Result<SourceData, Box<dyn std::error::Error>> {
1156    let base = format!("https://huggingface.co/{repo}/resolve/{revision}");
1157    let config_bytes = http_text(&format!("{base}/config.json"))?
1158        .ok_or("pinned model has no config.json")?
1159        .into_bytes();
1160    let config = ModelConfig::from_hf(&HfConfig::parse(std::str::from_utf8(&config_bytes)?));
1161    let tokenizer = inspect_remote_hf_tokenizer(&base);
1162    let index = http_text(&format!("{base}/model.safetensors.index.json"))?;
1163    let shards: Vec<String> = if let Some(index) = index {
1164        let mut files: Vec<_> = parse_index_json(&index)?.into_values().collect();
1165        files.sort();
1166        files.dedup();
1167        files
1168    } else {
1169        vec!["model.safetensors".to_string()]
1170    };
1171    let mut headers = BTreeMap::new();
1172    for shard in &shards {
1173        validate_remote_filename(shard)?;
1174        let url = format!("{base}/{shard}");
1175        let prefix = http_range(&url, 0, 7)?;
1176        if prefix.len() != 8 {
1177            return Err(format!("{shard}: expected 8-byte safetensors prefix").into());
1178        }
1179        let header_len = u64::from_le_bytes(prefix.try_into().unwrap()) as usize;
1180        if header_len == 0 || header_len > MAX_TEXT_BYTES {
1181            return Err(format!("{shard}: invalid safetensors header length {header_len}").into());
1182        }
1183        let bytes = http_range(&url, 8, 7 + header_len)?;
1184        if bytes.len() != header_len {
1185            return Err(format!(
1186                "{shard}: range returned {} header bytes, expected {header_len}",
1187                bytes.len()
1188            )
1189            .into());
1190        }
1191        let parsed = parse_header(std::str::from_utf8(&bytes)?)?;
1192        for (name, info) in parsed {
1193            if headers.insert(name.clone(), info).is_some() {
1194                return Err(format!("tensor {name} occurs in multiple safetensors shards").into());
1195            }
1196        }
1197    }
1198    Ok(SourceData {
1199        label: repo.to_string(),
1200        revision: revision.to_string(),
1201        dialect: CheckpointDialect::HfSafetensors,
1202        config,
1203        config_bytes,
1204        tensors: census_from_headers(headers)?,
1205        shards,
1206        tokenizer,
1207    })
1208}
1209
1210fn inspect_gguf_tokenizer(gguf: &GgufFile) -> Result<TokenizerEvidence, String> {
1211    let model = gguf
1212        .metadata
1213        .get("tokenizer.ggml.model")
1214        .and_then(|value| value.as_str())
1215        .ok_or_else(|| "GGUF is missing tokenizer.ggml.model".to_string())?;
1216    let tokens = gguf
1217        .metadata
1218        .get("tokenizer.ggml.tokens")
1219        .and_then(|value| value.as_str_array())
1220        .ok_or_else(|| "GGUF is missing tokenizer.ggml.tokens".to_string())?;
1221    if tokens.is_empty() {
1222        return Err("GGUF tokenizer.ggml.tokens is empty".to_string());
1223    }
1224    let template = gguf
1225        .metadata
1226        .get("tokenizer.chat_template")
1227        .and_then(|value| value.as_str())
1228        .filter(|template| !template.trim().is_empty())
1229        .ok_or_else(|| "GGUF is missing tokenizer.chat_template".to_string())?;
1230    let mut hasher = Sha256::new();
1231    hasher.update(model.as_bytes());
1232    if let Some(pre) = gguf
1233        .metadata
1234        .get("tokenizer.ggml.pre")
1235        .and_then(|value| value.as_str())
1236    {
1237        hasher.update([0]);
1238        hasher.update(pre.as_bytes());
1239    }
1240    for token in tokens {
1241        hasher.update([0]);
1242        hasher.update(token.as_bytes());
1243    }
1244    Ok(TokenizerEvidence {
1245        source: TokenizerSource::GgufMetadata,
1246        tokenizer_sha256: hasher
1247            .finalize()
1248            .iter()
1249            .map(|byte| format!("{byte:02x}"))
1250            .collect(),
1251        template_sha256: hex_sha256(template.as_bytes()),
1252        template_bytes: template.len(),
1253    })
1254}
1255
1256fn inspect_hf_tokenizer_dir(path: &Path) -> Result<TokenizerEvidence, String> {
1257    let tokenizer_path = path.join("tokenizer.json");
1258    let tokenizer = std::fs::read(&tokenizer_path)
1259        .map_err(|error| format!("read {}: {error}", tokenizer_path.display()))?;
1260    let template = local_hf_template(path)?;
1261    Ok(TokenizerEvidence {
1262        source: TokenizerSource::TokenizerJson,
1263        tokenizer_sha256: hex_sha256(&tokenizer),
1264        template_sha256: hex_sha256(template.as_bytes()),
1265        template_bytes: template.len(),
1266    })
1267}
1268
1269fn local_hf_template(path: &Path) -> Result<String, String> {
1270    let config_path = path.join("tokenizer_config.json");
1271    if let Ok(config) = std::fs::read_to_string(&config_path)
1272        && let Some(template) = template_from_tokenizer_config(&config)
1273    {
1274        return Ok(template);
1275    }
1276    let template_path = path.join("chat_template.jinja");
1277    std::fs::read_to_string(&template_path)
1278        .map_err(|error| format!("read {}: {error}", template_path.display()))
1279        .and_then(nonempty_template)
1280}
1281
1282fn inspect_remote_hf_tokenizer(base: &str) -> Result<TokenizerEvidence, String> {
1283    let tokenizer = http_text(&format!("{base}/tokenizer.json"))
1284        .map_err(|error| error.to_string())?
1285        .ok_or_else(|| "pinned HF model has no tokenizer.json".to_string())?;
1286    let config =
1287        http_text(&format!("{base}/tokenizer_config.json")).map_err(|error| error.to_string())?;
1288    let template = config
1289        .as_deref()
1290        .and_then(template_from_tokenizer_config)
1291        .or_else(|| {
1292            http_text(&format!("{base}/chat_template.jinja"))
1293                .ok()
1294                .flatten()
1295        })
1296        .ok_or_else(|| {
1297            "pinned HF model has neither tokenizer_config chat_template nor chat_template.jinja"
1298                .to_string()
1299        })
1300        .and_then(nonempty_template)?;
1301    Ok(TokenizerEvidence {
1302        source: TokenizerSource::TokenizerJson,
1303        tokenizer_sha256: hex_sha256(tokenizer.as_bytes()),
1304        template_sha256: hex_sha256(template.as_bytes()),
1305        template_bytes: template.len(),
1306    })
1307}
1308
1309fn template_from_tokenizer_config(config: &str) -> Option<String> {
1310    let config = memra_gguf::config::JsonObj::parse(config);
1311    config
1312        .string("chat_template")
1313        .filter(|value| !value.trim().is_empty())
1314}
1315
1316fn nonempty_template(template: String) -> Result<String, String> {
1317    if template.trim().is_empty() {
1318        Err("chat template is empty".to_string())
1319    } else {
1320        Ok(template)
1321    }
1322}
1323
1324fn census_from_headers(
1325    headers: BTreeMap<String, StInfo>,
1326) -> Result<Vec<CensusRow>, Box<dyn std::error::Error>> {
1327    let mut auxiliary_names = BTreeSet::new();
1328    let mut rows = Vec::new();
1329    for (physical_name, info) in &headers {
1330        if auxiliary_names.contains(physical_name) || is_quant_auxiliary(physical_name, &headers) {
1331            continue;
1332        }
1333        let stem = physical_name.strip_suffix(".weight");
1334        let auxiliaries: Vec<String> = stem
1335            .map(|stem| {
1336                [
1337                    format!("{stem}.weight_scale"),
1338                    format!("{stem}.weight_scale_inv"),
1339                    format!("{stem}.weight_scale_2"),
1340                    format!("{stem}.input_scale"),
1341                    format!("{stem}.scale"),
1342                ]
1343                .into_iter()
1344                .filter(|name| headers.contains_key(name))
1345                .collect()
1346            })
1347            .unwrap_or_default();
1348        auxiliary_names.extend(auxiliaries.iter().cloned());
1349        let (shape, storage) = st_storage(info, &auxiliaries)?;
1350        rows.push(CensusRow {
1351            physical_name: physical_name.clone(),
1352            entry: TensorCensusEntry {
1353                name: canonical_hf_name(physical_name),
1354                shape,
1355                storage: match storage {
1356                    StorageLayout::Quantized(mut layout) => {
1357                        layout.auxiliaries = auxiliaries
1358                            .iter()
1359                            .map(|name| canonical_hf_name(name))
1360                            .collect();
1361                        StorageLayout::Quantized(layout)
1362                    }
1363                    other => other,
1364                },
1365            },
1366            dtype: info.dtype.clone(),
1367        });
1368    }
1369    rows.sort_by(|left, right| left.entry.name.cmp(&right.entry.name));
1370    let mut names = BTreeSet::new();
1371    for row in &rows {
1372        if !names.insert(&row.entry.name) {
1373            return Err(
1374                format!("multiple physical tensors normalize to {}", row.entry.name).into(),
1375            );
1376        }
1377    }
1378    Ok(rows)
1379}
1380
1381fn st_storage(
1382    info: &StInfo,
1383    auxiliaries: &[String],
1384) -> Result<(Vec<u64>, StorageLayout), Box<dyn std::error::Error>> {
1385    let float = match info.dtype.as_str() {
1386        "F32" => Some(FloatType::F32),
1387        "F16" => Some(FloatType::F16),
1388        "BF16" => Some(FloatType::Bf16),
1389        "F8_E4M3" if auxiliaries.is_empty() => Some(FloatType::Fp8E4m3),
1390        _ => None,
1391    };
1392    if let Some(float) = float {
1393        return Ok((info.shape.clone(), StorageLayout::Float(float)));
1394    }
1395    if info.dtype == "I64" && auxiliaries.is_empty() {
1396        return Ok((info.shape.clone(), StorageLayout::Integer(IntegerType::I64)));
1397    }
1398    if auxiliaries.is_empty() {
1399        return Err(format!("unsupported standalone safetensors dtype {}", info.dtype).into());
1400    }
1401    let mut shape = info.shape.clone();
1402    let (format, block_shape) = match info.dtype.as_str() {
1403        "U8" => {
1404            let last = shape
1405                .last_mut()
1406                .ok_or("packed U8 weight has no dimensions")?;
1407            *last *= 2;
1408            ("NVFP4", vec![16])
1409        }
1410        "I8" => {
1411            let last = shape
1412                .last_mut()
1413                .ok_or("packed I8 weight has no dimensions")?;
1414            *last *= 2;
1415            ("MXFP4", vec![32])
1416        }
1417        "F8_E4M3" => ("FP8_E4M3", vec![128, 128]),
1418        other => return Err(format!("unsupported quantized weight dtype {other}").into()),
1419    };
1420    Ok((
1421        shape,
1422        StorageLayout::Quantized(QuantLayout {
1423            format: format.to_string(),
1424            block_shape,
1425            auxiliaries: Vec::new(),
1426        }),
1427    ))
1428}
1429
1430fn is_quant_auxiliary(name: &str, headers: &BTreeMap<String, StInfo>) -> bool {
1431    for suffix in [
1432        ".weight_scale",
1433        ".weight_scale_inv",
1434        ".weight_scale_2",
1435        ".input_scale",
1436        ".scale",
1437    ] {
1438        if let Some(stem) = name.strip_suffix(suffix) {
1439            if headers.contains_key(&format!("{stem}.weight")) {
1440                return true;
1441            }
1442        }
1443    }
1444    false
1445}
1446
1447fn canonical_hf_name(name: &str) -> String {
1448    if let Some(suffix) = name.strip_prefix("model.language_model.") {
1449        return format!("model.{suffix}");
1450    }
1451    if let Some(suffix) = name.strip_prefix("language_model.model.") {
1452        return format!("model.{suffix}");
1453    }
1454    if let Some(suffix) = name.strip_prefix("language_model.lm_head.") {
1455        return format!("lm_head.{suffix}");
1456    }
1457    name.to_string()
1458}
1459
1460fn ggml_storage(kind: GgmlType) -> StorageLayout {
1461    match kind {
1462        GgmlType::F32 => StorageLayout::Float(FloatType::F32),
1463        GgmlType::F16 => StorageLayout::Float(FloatType::F16),
1464        GgmlType::BF16 => StorageLayout::Float(FloatType::Bf16),
1465        GgmlType::I64 => StorageLayout::Integer(IntegerType::I64),
1466        other => {
1467            let (block, _) = other.block_and_type_size();
1468            StorageLayout::Quantized(QuantLayout {
1469                format: format!("{other:?}"),
1470                block_shape: vec![block as u32],
1471                auxiliaries: Vec::new(),
1472            })
1473        }
1474    }
1475}
1476
1477fn parse_pinned_hf_source(source: &str) -> Result<(&str, &str), Box<dyn std::error::Error>> {
1478    let (repo, revision) = source
1479        .rsplit_once('@')
1480        .ok_or("remote sources must be pinned as hf-id@40-char-sha")?;
1481    if repo.split('/').count() != 2
1482        || repo.split('/').any(|part| part.is_empty())
1483        || !repo
1484            .bytes()
1485            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'/' | b'-' | b'_' | b'.'))
1486        || repo.contains("..")
1487    {
1488        return Err("HF model id must be namespace/repository".into());
1489    }
1490    if revision.len() != 40 || !revision.bytes().all(|byte| byte.is_ascii_hexdigit()) {
1491        return Err("HF revision must be a full 40-character commit SHA".into());
1492    }
1493    Ok((repo, revision))
1494}
1495
1496fn validate_family_name(family: &str) -> Result<(), Box<dyn std::error::Error>> {
1497    if family.is_empty()
1498        || !family
1499            .bytes()
1500            .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_')
1501    {
1502        return Err(
1503            "family must contain only lowercase ASCII letters, digits, and underscores".into(),
1504        );
1505    }
1506    Ok(())
1507}
1508
1509fn validate_remote_filename(name: &str) -> Result<(), Box<dyn std::error::Error>> {
1510    if name.is_empty()
1511        || name.starts_with('/')
1512        || name.split('/').any(|part| part.is_empty() || part == "..")
1513        || !name
1514            .bytes()
1515            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'/' | b'-' | b'_' | b'.'))
1516    {
1517        return Err(format!("unsafe shard filename {name:?}").into());
1518    }
1519    Ok(())
1520}
1521
1522fn http_text(url: &str) -> Result<Option<String>, Box<dyn std::error::Error>> {
1523    let mut command = curl_command();
1524    command.args([
1525        "--silent",
1526        "--show-error",
1527        "--location",
1528        "--max-filesize",
1529        &MAX_TEXT_BYTES.to_string(),
1530        "--write-out",
1531        "\n%{http_code}",
1532        url,
1533    ]);
1534    let output = curl_output(command)?;
1535    if !output.status.success() {
1536        return Err(format!(
1537            "curl failed for {url}: {}",
1538            String::from_utf8_lossy(&output.stderr)
1539        )
1540        .into());
1541    }
1542    let split = output
1543        .stdout
1544        .iter()
1545        .rposition(|byte| *byte == b'\n')
1546        .ok_or("curl response omitted HTTP status")?;
1547    let status = std::str::from_utf8(&output.stdout[split + 1..])?.trim();
1548    match status {
1549        "200" => Ok(Some(String::from_utf8(output.stdout[..split].to_vec())?)),
1550        "404" => Ok(None),
1551        other => Err(format!("HTTP {other} for {url}").into()),
1552    }
1553}
1554
1555fn http_range(url: &str, start: usize, end: usize) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
1556    let mut command = curl_command();
1557    command.args([
1558        "--fail",
1559        "--silent",
1560        "--show-error",
1561        "--location",
1562        "--max-filesize",
1563        &MAX_TEXT_BYTES.to_string(),
1564        "--range",
1565        &format!("{start}-{end}"),
1566        url,
1567    ]);
1568    let output = curl_output(command)?;
1569    if !output.status.success() {
1570        return Err(format!(
1571            "range request failed for {url}: {}",
1572            String::from_utf8_lossy(&output.stderr)
1573        )
1574        .into());
1575    }
1576    Ok(output.stdout)
1577}
1578
1579fn curl_command() -> Command {
1580    Command::new("curl")
1581}
1582
1583fn curl_output(mut command: Command) -> std::io::Result<Output> {
1584    let token = std::env::var("HF_TOKEN").ok();
1585    if token.is_none() {
1586        return command.output();
1587    }
1588    command
1589        .args(["--header", "@-"])
1590        .stdin(Stdio::piped())
1591        .stdout(Stdio::piped())
1592        .stderr(Stdio::piped());
1593    let mut child = command.spawn()?;
1594    let mut stdin = child.stdin.take().expect("piped curl stdin");
1595    writeln!(stdin, "Authorization: Bearer {}", token.unwrap())?;
1596    drop(stdin);
1597    child.wait_with_output()
1598}
1599
1600fn local_shards(path: &Path) -> Result<Vec<String>, Box<dyn std::error::Error>> {
1601    let index = path.join("model.safetensors.index.json");
1602    if index.exists() {
1603        let mut shards: Vec<_> = parse_index_json(&std::fs::read_to_string(index)?)?
1604            .into_values()
1605            .collect();
1606        shards.sort();
1607        shards.dedup();
1608        Ok(shards)
1609    } else {
1610        Ok(vec!["model.safetensors".to_string()])
1611    }
1612}
1613
1614fn local_hf_revision(path: &Path, shards: &[String]) -> Option<String> {
1615    let metadata = path.join(".cache/huggingface/download");
1616    let mut files = Vec::with_capacity(shards.len() + 1);
1617    files.push("config.json");
1618    files.extend(shards.iter().map(String::as_str));
1619    let revisions: Option<Vec<_>> = files
1620        .into_iter()
1621        .map(|file| {
1622            let text = std::fs::read_to_string(metadata.join(format!("{file}.metadata"))).ok()?;
1623            let revision = text.lines().next()?;
1624            (revision.len() == 40 && revision.bytes().all(|byte| byte.is_ascii_hexdigit()))
1625                .then(|| revision.to_ascii_lowercase())
1626        })
1627        .collect();
1628    let revisions = revisions?;
1629    let first = revisions.first()?;
1630    revisions
1631        .iter()
1632        .all(|revision| revision == first)
1633        .then(|| first.clone())
1634}
1635
1636fn format_census(rows: &[CensusRow]) -> String {
1637    let mut output = String::from("semantic_name\tphysical_name\tdtype\tshape\tstorage\n");
1638    for row in rows {
1639        writeln!(
1640            output,
1641            "{}\t{}\t{}\t{:?}\t{:?}",
1642            row.entry.name, row.physical_name, row.dtype, row.entry.shape, row.entry.storage
1643        )
1644        .unwrap();
1645    }
1646    output
1647}
1648
1649fn format_execution_rewrites(
1650    rewrites: &[memra_gguf::execution_manifest::ExecutionRewrite],
1651) -> String {
1652    let mut output = String::from(
1653        "rewrite\tsurface\timplementation\tplan_sha256\teligible\tblockers\toperations\treceipt\n",
1654    );
1655    for rewrite in rewrites {
1656        let blockers = rewrite
1657            .blockers
1658            .iter()
1659            .map(|operation| format!("{operation:?}"))
1660            .collect::<Vec<_>>()
1661            .join(",");
1662        let mut unique_operations = Vec::new();
1663        for operation in &rewrite.canonical_operations {
1664            if !unique_operations.contains(operation) {
1665                unique_operations.push(*operation);
1666            }
1667        }
1668        let operations = unique_operations
1669            .iter()
1670            .map(|operation| format!("{operation:?}"))
1671            .collect::<Vec<_>>()
1672            .join(",");
1673        writeln!(
1674            output,
1675            "{}\t{}\t{}\t{}\t{}\t{}\t{}\tpending",
1676            rewrite.id,
1677            rewrite.surface.as_str(),
1678            rewrite.implementation,
1679            rewrite.plan_sha256,
1680            rewrite.eligible(),
1681            blockers,
1682            operations,
1683        )
1684        .unwrap();
1685    }
1686    output
1687}
1688
1689fn format_lock(
1690    pack: &ModelPack,
1691    source: &SourceData,
1692    config: &str,
1693    census: &str,
1694    plan: &str,
1695    rewrites: &str,
1696    binding: &str,
1697) -> String {
1698    let mut output = String::from("format_version=2\n");
1699    writeln!(output, "source={}", lock_value(&source.label)).unwrap();
1700    writeln!(output, "revision={}", lock_value(&source.revision)).unwrap();
1701    writeln!(output, "family={}", pack.family).unwrap();
1702    match pack.support {
1703        Some(support) => writeln!(output, "support={support:?}").unwrap(),
1704        None => writeln!(output, "support=unsupported").unwrap(),
1705    }
1706    if let Some(gate) = pack.checkpoint_parity {
1707        writeln!(output, "checkpoint_atol={}", gate.max_abs).unwrap();
1708        writeln!(output, "checkpoint_rtol={}", gate.max_rel).unwrap();
1709        writeln!(output, "checkpoint_require_argmax={}", gate.require_argmax).unwrap();
1710    }
1711    writeln!(output, "config_sha256={config}").unwrap();
1712    writeln!(output, "census_sha256={census}").unwrap();
1713    writeln!(output, "plan_sha256={plan}").unwrap();
1714    writeln!(output, "rewrite_manifest_sha256={rewrites}").unwrap();
1715    writeln!(output, "binding={binding}").unwrap();
1716    match &source.tokenizer {
1717        Ok(evidence) if pack.tokenizer_sources.contains(&evidence.source) => {
1718            writeln!(output, "tokenizer=passed").unwrap();
1719            writeln!(output, "tokenizer_source={:?}", evidence.source).unwrap();
1720            writeln!(output, "tokenizer_sha256={}", evidence.tokenizer_sha256).unwrap();
1721            writeln!(output, "template_sha256={}", evidence.template_sha256).unwrap();
1722        }
1723        Ok(_) | Err(_) => writeln!(output, "tokenizer=failed").unwrap(),
1724    }
1725    writeln!(output, "tensor_count={}", source.tensors.len()).unwrap();
1726    for shard in &source.shards {
1727        writeln!(output, "shard={}", lock_value(shard)).unwrap();
1728    }
1729    output
1730}
1731
1732fn parse_header(
1733    json: &str,
1734) -> Result<std::collections::HashMap<String, StInfo>, Box<dyn std::error::Error>> {
1735    std::panic::catch_unwind(|| parse_header_json(json))
1736        .map_err(|_| "invalid safetensors header JSON".into())
1737}
1738
1739fn parse_index_json(
1740    json: &str,
1741) -> Result<std::collections::HashMap<String, String>, Box<dyn std::error::Error>> {
1742    std::panic::catch_unwind(|| parse_index_weight_map_json(json))
1743        .map_err(|_| "invalid safetensors index JSON".into())
1744}
1745
1746fn lock_value(value: &str) -> String {
1747    value
1748        .replace('\\', "\\\\")
1749        .replace('\n', "\\n")
1750        .replace('\r', "\\r")
1751}
1752
1753fn format_gates(gates: &[Gate]) -> String {
1754    format_gate_results(gates, &[], &[])
1755}
1756
1757fn format_gate_results(gates: &[Gate], passed: &[Gate], failed: &[Gate]) -> String {
1758    let mut output = String::new();
1759    for gate in gates {
1760        let status = if passed.contains(gate) {
1761            "passed"
1762        } else if failed.contains(gate) {
1763            "failed"
1764        } else {
1765            "pending"
1766        };
1767        writeln!(output, "{gate:?}={status}").unwrap();
1768    }
1769    output
1770}
1771
1772fn all_eligible_rewrites_have_receipts(out_dir: &Path) -> bool {
1773    let Ok(manifest) = std::fs::read_to_string(out_dir.join("execution-rewrites.tsv")) else {
1774        return false;
1775    };
1776    let Ok(index_text) = std::fs::read_to_string(out_dir.join("rewrite-receipts.tsv")) else {
1777        return false;
1778    };
1779    let mut index = BTreeMap::new();
1780    for line in index_text.lines().skip(1) {
1781        let columns: Vec<_> = line.split('\t').collect();
1782        if columns.len() != 4 || columns[3] != "passed" {
1783            return false;
1784        }
1785        index.insert(columns[0], (columns[1], columns[2]));
1786    }
1787    let mut eligible = 0usize;
1788    for line in manifest.lines().skip(1) {
1789        let columns: Vec<_> = line.split('\t').collect();
1790        if columns.len() != 8 {
1791            return false;
1792        }
1793        if columns[4] != "true" {
1794            continue;
1795        }
1796        eligible += 1;
1797        let Some(&(plan, receipt_hash)) = index.get(columns[0]) else {
1798            return false;
1799        };
1800        if plan != columns[3] {
1801            return false;
1802        }
1803        let Ok(receipt) = std::fs::read(
1804            out_dir
1805                .join("rewrite-receipts")
1806                .join(format!("{}.tsv", columns[0])),
1807        ) else {
1808            return false;
1809        };
1810        if hex_sha256(&receipt) != receipt_hash {
1811            return false;
1812        }
1813    }
1814    eligible > 0
1815}
1816
1817fn format_gate_results_with_receipts(
1818    pack: &ModelPack,
1819    out_dir: &Path,
1820    passed: &[Gate],
1821    failed: &[Gate],
1822) -> String {
1823    let mut passed = passed.to_vec();
1824    let artifact_lock = std::fs::read(out_dir.join("artifact.lock")).ok();
1825    let lock_hash = artifact_lock.as_ref().map(|bytes| hex_sha256(bytes));
1826    if let Some(lock) = artifact_lock
1827        .as_deref()
1828        .and_then(|bytes| std::str::from_utf8(bytes).ok())
1829        .filter(|lock| {
1830            lock.lines().any(|line| line == "format_version=2")
1831                && lock
1832                    .lines()
1833                    .any(|line| line == format!("family={}", pack.family))
1834        })
1835    {
1836        for (gate, evidence) in [
1837            (Gate::Config, None),
1838            (Gate::TokenizerTemplate, Some("tokenizer=passed")),
1839            (Gate::TensorCensus, Some("binding=passed")),
1840        ] {
1841            if evidence.is_none_or(|line| lock.lines().any(|candidate| candidate == line))
1842                && !passed.contains(&gate)
1843                && !failed.contains(&gate)
1844            {
1845                passed.push(gate);
1846            }
1847        }
1848    }
1849    let receipt_passes = |name: &str, family_bound: bool, lock_bound: bool| {
1850        let Ok(receipt) = std::fs::read_to_string(out_dir.join(name)) else {
1851            return false;
1852        };
1853        if !receipt.lines().any(|line| line == "status\tpassed") {
1854            return false;
1855        }
1856        if family_bound
1857            && !receipt
1858                .lines()
1859                .any(|line| line == format!("family\t{}", pack.family))
1860        {
1861            return false;
1862        }
1863        if lock_bound
1864            && !lock_hash.as_ref().is_some_and(|hash| {
1865                receipt
1866                    .lines()
1867                    .any(|line| line == format!("artifact_lock_sha256\t{hash}"))
1868            })
1869        {
1870            return false;
1871        }
1872        true
1873    };
1874    for (gate, name, family_bound, lock_bound) in [
1875        (Gate::TinyParity, "tiny-gate.tsv", true, false),
1876        (Gate::CheckpointParity, "checkpoint-parity.tsv", false, true),
1877        (Gate::Serve, "serve-gate.tsv", true, true),
1878    ] {
1879        if receipt_passes(name, family_bound, lock_bound)
1880            && !passed.contains(&gate)
1881            && !failed.contains(&gate)
1882        {
1883            passed.push(gate);
1884        }
1885    }
1886    if all_eligible_rewrites_have_receipts(out_dir)
1887        && !passed.contains(&Gate::RewriteParity)
1888        && !failed.contains(&Gate::RewriteParity)
1889    {
1890        passed.push(Gate::RewriteParity);
1891    }
1892    format_gate_results(pack.gates, &passed, failed)
1893}
1894
1895fn format_tiny_fixture(
1896    plan: &memra_gguf::model_plan::ModelPlan,
1897    fixture: &memra_reference::ReferenceFixture,
1898) -> String {
1899    let mut output = format!("tokens={:?}\nplan={plan:#?}\n", fixture.token_ids);
1900    for (id, tensor) in &fixture.weights {
1901        let mut bytes = Vec::with_capacity(tensor.data.len() * 4);
1902        for value in &tensor.data {
1903            bytes.extend_from_slice(&value.to_bits().to_le_bytes());
1904        }
1905        writeln!(
1906            output,
1907            "tensor={id:?}\tshape={:?}\tsha256={}",
1908            tensor.shape,
1909            hex_sha256(&bytes)
1910        )
1911        .unwrap();
1912    }
1913    if let Some(vision) = fixture.vision.as_ref() {
1914        let mut bytes = Vec::with_capacity(vision.patches.data.len() * 4);
1915        for value in &vision.patches.data {
1916            bytes.extend_from_slice(&value.to_bits().to_le_bytes());
1917        }
1918        writeln!(
1919            output,
1920            "vision_patches={:?}\tsha256={}\tpositions={:?}\toutput_tokens={}",
1921            vision.patches.shape,
1922            hex_sha256(&bytes),
1923            vision.positions,
1924            vision.output_tokens,
1925        )
1926        .unwrap();
1927    }
1928    if let Some(token_ids) = fixture.multimodal_token_ids.as_ref() {
1929        writeln!(output, "multimodal_tokens={token_ids:?}").unwrap();
1930    }
1931    output
1932}
1933
1934fn format_reference_oracle(output: &memra_reference::ReferenceOutput) -> String {
1935    let mut text = String::from("stream\tposition\ttoken\tlogit_f32_bits\n");
1936    append_oracle_rows(
1937        &mut text,
1938        "main",
1939        &output.logits,
1940        output.tokens,
1941        output.vocab,
1942    );
1943    for mtp in &output.mtp {
1944        append_oracle_rows(
1945            &mut text,
1946            &format!("mtp:{}", mtp.depth),
1947            &mtp.logits,
1948            output.tokens,
1949            output.vocab,
1950        );
1951    }
1952    if let Some(draft) = output.draft.as_ref() {
1953        append_oracle_rows(
1954            &mut text,
1955            "dspark",
1956            &draft.logits,
1957            draft.block_size,
1958            output.vocab,
1959        );
1960        for (position, (&token, &confidence)) in draft
1961            .output_ids
1962            .iter()
1963            .skip(1)
1964            .zip(&draft.confidence)
1965            .enumerate()
1966        {
1967            writeln!(
1968                text,
1969                "dspark-confidence\t{position}\t{token}\t{:08x}",
1970                confidence.to_bits()
1971            )
1972            .unwrap();
1973        }
1974    }
1975    text
1976}
1977
1978fn append_oracle_rows(
1979    text: &mut String,
1980    stream: &str,
1981    logits: &[f32],
1982    tokens: usize,
1983    vocab: usize,
1984) {
1985    for position in 0..tokens {
1986        for token in 0..vocab {
1987            writeln!(
1988                text,
1989                "{stream}\t{position}\t{token}\t{:08x}",
1990                logits[position * vocab + token].to_bits()
1991            )
1992            .unwrap();
1993        }
1994    }
1995}
1996
1997fn format_reference_vision_oracle(output: &memra_reference::ReferenceVisionOutput) -> String {
1998    let mut text = String::from("stream\tposition\tchannel\tf32_bits\n");
1999    for (stream, values, rows, width) in [
2000        (
2001            "vision-encoder",
2002            output.encoder_hidden.as_slice(),
2003            output.patch_count,
2004            output.hidden_size,
2005        ),
2006        (
2007            "vision-pooled",
2008            output.pooled_hidden.as_slice(),
2009            output.output_tokens,
2010            output.hidden_size,
2011        ),
2012        (
2013            "vision-projected",
2014            output.projected_hidden.as_slice(),
2015            output.output_tokens,
2016            output.projection_size,
2017        ),
2018    ] {
2019        for position in 0..rows {
2020            for channel in 0..width {
2021                writeln!(
2022                    text,
2023                    "{stream}\t{position}\t{channel}\t{:08x}",
2024                    values[position * width + channel].to_bits()
2025                )
2026                .unwrap();
2027            }
2028        }
2029    }
2030    text
2031}
2032
2033fn hex_sha256(bytes: &[u8]) -> String {
2034    let digest = Sha256::digest(bytes);
2035    digest.iter().map(|byte| format!("{byte:02x}")).collect()
2036}
2037
2038fn write_atomic(path: &Path, bytes: &[u8]) -> std::io::Result<()> {
2039    let temporary = path.with_extension(format!("tmp-{}", std::process::id()));
2040    std::fs::write(&temporary, bytes)?;
2041    std::fs::rename(temporary, path)
2042}
2043
2044#[cfg(test)]
2045mod tests {
2046    use super::*;
2047
2048    #[test]
2049    fn local_glm_fixture_generates_deterministic_onboarding_artifacts() {
2050        let root = std::env::temp_dir().join(format!("memra-cli-inspect-{}", std::process::id()));
2051        let model = root.join("model.gguf");
2052        let output = root.join("out");
2053        std::fs::create_dir_all(&root).unwrap();
2054        memra_gguf::micro_gguf::write_glm_dsa_micro(&model, 0x434c_4901).unwrap();
2055        let verified = verify_model(VerifyRequest {
2056            stage: VerifyStage::Config,
2057            source: model.display().to_string(),
2058            against: "glm_dsa".to_string(),
2059            out_dir: None,
2060            oracle: None,
2061            native_runner: None,
2062        })
2063        .unwrap();
2064        assert_eq!(verified.stage, VerifyStage::Config);
2065        let first = inspect_model(InspectRequest {
2066            source: model.display().to_string(),
2067            against: "glm_dsa".to_string(),
2068            out_dir: output.clone(),
2069        })
2070        .unwrap();
2071        assert_eq!(first.family, "glm_dsa");
2072        assert!(first.tensor_count > 0);
2073        let lock = std::fs::read(output.join("artifact.lock")).unwrap();
2074        inspect_model(InspectRequest {
2075            source: model.display().to_string(),
2076            against: "glm_dsa".to_string(),
2077            out_dir: output.clone(),
2078        })
2079        .unwrap();
2080        assert_eq!(std::fs::read(output.join("artifact.lock")).unwrap(), lock);
2081        for artifact in [
2082            "artifact.lock",
2083            "tensor-census.tsv",
2084            "model-plan.txt",
2085            "execution-rewrites.tsv",
2086            "gates.txt",
2087        ] {
2088            assert!(output.join(artifact).is_file(), "missing {artifact}");
2089        }
2090        std::fs::remove_dir_all(root).unwrap();
2091    }
2092
2093    #[test]
2094    fn pinned_source_and_wrapper_normalization_fail_closed() {
2095        assert!(parse_pinned_hf_source("org/model@main").is_err());
2096        let sha = "a".repeat(40);
2097        assert_eq!(
2098            parse_pinned_hf_source(&format!("org/model@{sha}")).unwrap(),
2099            ("org/model", sha.as_str())
2100        );
2101        assert_eq!(
2102            canonical_hf_name("model.language_model.layers.1.self_attn.q_proj.weight"),
2103            "model.layers.1.self_attn.q_proj.weight"
2104        );
2105    }
2106
2107    #[test]
2108    fn scaffold_is_deterministic_and_refuses_non_empty_targets() {
2109        let root = std::env::temp_dir().join(format!("memra-cli-scaffold-{}", std::process::id()));
2110        scaffold_model_pack(ScaffoldRequest {
2111            family: "new_family".to_string(),
2112            out_dir: root.clone(),
2113        })
2114        .unwrap();
2115        for artifact in [
2116            "pack.toml",
2117            "aliases.txt",
2118            "config-normalization.txt",
2119            "tensor-schema.tsv",
2120            "tokenizer-template.txt",
2121            "gates.txt",
2122        ] {
2123            assert!(root.join(artifact).is_file(), "missing {artifact}");
2124        }
2125        assert!(
2126            scaffold_model_pack(ScaffoldRequest {
2127                family: "new_family".to_string(),
2128                out_dir: root.clone(),
2129            })
2130            .is_err()
2131        );
2132        assert!(validate_family_name("Bad-Family").is_err());
2133        std::fs::remove_dir_all(root).unwrap();
2134    }
2135
2136    #[test]
2137    fn unimplemented_verify_stages_refuse_without_fallback() {
2138        for stage in [VerifyStage::Serve] {
2139            let error = verify_model(VerifyRequest {
2140                stage,
2141                source: "unused".to_string(),
2142                against: "qwen3".to_string(),
2143                out_dir: None,
2144                oracle: None,
2145                native_runner: None,
2146            })
2147            .err()
2148            .unwrap()
2149            .to_string();
2150            assert!(error.contains("no fallback is allowed"));
2151        }
2152    }
2153
2154    #[test]
2155    fn supported_packs_write_deterministic_native_oracles() {
2156        let root = std::env::temp_dir().join(format!("memra-cli-tiny-{}", std::process::id()));
2157        let request = || VerifyRequest {
2158            stage: VerifyStage::Tiny,
2159            source: "unused".to_string(),
2160            against: "qwen3".to_string(),
2161            out_dir: Some(root.clone()),
2162            oracle: None,
2163            native_runner: None,
2164        };
2165        verify_model(request()).unwrap();
2166        let fixture = std::fs::read(root.join("tiny-fixture.txt")).unwrap();
2167        let oracle = std::fs::read(root.join("reference-oracle.tsv")).unwrap();
2168        verify_model(request()).unwrap();
2169        assert_eq!(
2170            std::fs::read(root.join("tiny-fixture.txt")).unwrap(),
2171            fixture
2172        );
2173        assert_eq!(
2174            std::fs::read(root.join("reference-oracle.tsv")).unwrap(),
2175            oracle
2176        );
2177        for pack in model_packs::PACKS {
2178            if pack.family == "qwen3" {
2179                continue;
2180            }
2181            let result = verify_model(VerifyRequest {
2182                stage: VerifyStage::Tiny,
2183                source: "unused".to_string(),
2184                against: pack.family.to_string(),
2185                out_dir: Some(root.join(pack.family)),
2186                oracle: None,
2187                native_runner: None,
2188            });
2189            if pack.support.is_some() {
2190                result.unwrap();
2191                assert!(
2192                    root.join(pack.family)
2193                        .join("reference-oracle.tsv")
2194                        .is_file()
2195                );
2196                if pack.family.starts_with("gemma4") {
2197                    assert!(
2198                        root.join(pack.family)
2199                            .join("reference-vision-oracle.tsv")
2200                            .is_file()
2201                    );
2202                    assert!(
2203                        root.join(pack.family)
2204                            .join("reference-multimodal-oracle.tsv")
2205                            .is_file()
2206                    );
2207                }
2208            } else {
2209                assert!(result.is_err());
2210            }
2211        }
2212        std::fs::remove_dir_all(root).unwrap();
2213    }
2214
2215    #[test]
2216    fn checkpoint_oracle_bundle_is_pinned_and_parity_is_fail_closed() {
2217        let root = std::env::temp_dir().join(format!(
2218            "memra-cli-checkpoint-oracle-{}",
2219            std::process::id()
2220        ));
2221        std::fs::create_dir_all(&root).unwrap();
2222        let sha = "0123456789abcdef0123456789abcdef01234567";
2223        write_hf_oracle_bundle(&format!("org/model@{sha}"), &root).unwrap();
2224        let request = std::fs::read_to_string(root.join("oracle-request.tsv")).unwrap();
2225        let script = std::fs::read_to_string(root.join("capture-hf-oracle.py")).unwrap();
2226        assert!(request.contains(&format!("revision\t{sha}")));
2227        assert!(script.contains(&format!("REVISION = \"{sha}\"")));
2228        assert!(script.contains("trust_remote_code=False"));
2229        assert!(script.contains("dtype=torch.float32"));
2230        assert!(script.contains("source-weights-float32-accumulation"));
2231
2232        let oracle = |engine: &str, values: &[f32]| {
2233            let mut text = format!(
2234                "format\tmemra-checkpoint-oracle-v1\nengine\t{engine}\nnumeric_class\tsource-weights-float32-accumulation\ntokens\t1,2,3,4\nvocab\t{}\n",
2235                values.len()
2236            );
2237            for (index, value) in values.iter().enumerate() {
2238                writeln!(text, "logit\t{index}\t{:08x}", value.to_bits()).unwrap();
2239            }
2240            parse_checkpoint_oracle(&text).unwrap()
2241        };
2242        let reference = oracle("hf-transformers", &[0.0, 1.0, -1.0]);
2243        let native = oracle("memra-native", &[0.0, 1.001, -1.001]);
2244        let gate = model_packs::CheckpointParityGate {
2245            max_abs: 0.01,
2246            max_rel: 2.0,
2247            require_argmax: true,
2248        };
2249        assert!(compare_checkpoint_oracles(&reference, &native, gate).is_ok());
2250        let failing = oracle("memra-native", &[2.0, 1.0, -1.0]);
2251        assert!(compare_checkpoint_oracles(&reference, &failing, gate).is_err());
2252        std::fs::remove_dir_all(root).unwrap();
2253    }
2254
2255    #[test]
2256    fn rewrite_verifier_binds_manifest_plan_and_exact_streams() {
2257        let root =
2258            std::env::temp_dir().join(format!("memra-cli-rewrite-receipt-{}", std::process::id()));
2259        std::fs::create_dir_all(&root).unwrap();
2260        let config = ModelConfig::from_hf(&HfConfig::parse(
2261            r#"{"model_type":"qwen3","num_hidden_layers":2,"hidden_size":64,
2262            "num_attention_heads":2,"num_key_value_heads":1,"head_dim":32,
2263            "intermediate_size":128,"vocab_size":16,"max_position_embeddings":128}"#,
2264        ));
2265        let plan = memra_gguf::model_plan::ModelPlan::compile(&config).unwrap();
2266        let rewrites = memra_gguf::execution_manifest::execution_rewrites(&plan);
2267        let rewrite = rewrites
2268            .iter()
2269            .find(|rewrite| {
2270                rewrite.surface == memra_gguf::execution_manifest::RewriteSurface::DecodeBatch
2271            })
2272            .unwrap();
2273        let artifact_lock = b"format_version=2\nfamily=qwen3\n";
2274        std::fs::write(root.join("artifact.lock"), artifact_lock).unwrap();
2275        std::fs::write(
2276            root.join("execution-rewrites.tsv"),
2277            format_execution_rewrites(&rewrites),
2278        )
2279        .unwrap();
2280        let receipt = rewrite
2281            .verify_logits(
2282                &"00".repeat(32),
2283                &[0.0, 1.0, -1.0],
2284                &[0.0, 1.0, -1.0],
2285                memra_gguf::execution_manifest::RewriteParityPolicy {
2286                    max_abs: 0.0,
2287                    max_rel: 0.0,
2288                    require_argmax: true,
2289                },
2290            )
2291            .unwrap()
2292            .bind_artifact_lock(artifact_lock)
2293            .to_tsv();
2294        let receipt_path = root.join("receipt.tsv");
2295        std::fs::write(&receipt_path, &receipt).unwrap();
2296        verify_rewrite_receipt(
2297            model_packs::by_alias("qwen3").unwrap(),
2298            &receipt_path,
2299            &root,
2300        )
2301        .unwrap();
2302        assert!(
2303            std::fs::read_to_string(root.join("rewrite-receipts.tsv"))
2304                .unwrap()
2305                .contains("decode-batch.v1")
2306        );
2307
2308        let wrong = receipt.replace(&rewrite.plan_sha256, &"11".repeat(32));
2309        std::fs::write(&receipt_path, wrong).unwrap();
2310        assert!(
2311            verify_rewrite_receipt(
2312                model_packs::by_alias("qwen3").unwrap(),
2313                &receipt_path,
2314                &root,
2315            )
2316            .is_err()
2317        );
2318        std::fs::remove_dir_all(root).unwrap();
2319    }
2320
2321    #[cfg(unix)]
2322    #[test]
2323    fn native_serve_gate_launches_readiness_and_completion_on_real_http() {
2324        use std::os::unix::fs::PermissionsExt;
2325
2326        let root =
2327            std::env::temp_dir().join(format!("memra-cli-serve-gate-{}", std::process::id()));
2328        let model = root.join("model");
2329        std::fs::create_dir_all(&model).unwrap();
2330        let artifact_lock = format!(
2331            "source={}\nbinding=passed\ntokenizer=passed\n",
2332            lock_value(model.to_str().unwrap())
2333        );
2334        std::fs::write(root.join("artifact.lock"), &artifact_lock).unwrap();
2335        std::fs::write(
2336            root.join("checkpoint-parity.tsv"),
2337            format!(
2338                "status\tpassed\nartifact_lock_sha256\t{}\n",
2339                hex_sha256(artifact_lock.as_bytes())
2340            ),
2341        )
2342        .unwrap();
2343        let runner = root.join("fake-memra-server.py");
2344        std::fs::write(
2345            &runner,
2346            r#"#!/usr/bin/env python3
2347import json, os
2348from http.server import BaseHTTPRequestHandler, HTTPServer
2349host, port = os.environ["MEMRA_ADDR"].rsplit(":", 1)
2350class Handler(BaseHTTPRequestHandler):
2351    def log_message(self, *args): pass
2352    def do_GET(self):
2353        self.send_response(200 if self.path == "/readyz" else 404)
2354        self.end_headers()
2355        self.wfile.write(b"ready")
2356    def do_POST(self):
2357        length = int(self.headers.get("content-length", "0"))
2358        self.rfile.read(length)
2359        body = json.dumps({"choices":[{"text":"ok"}]}).encode()
2360        self.send_response(200)
2361        self.send_header("content-type", "application/json")
2362        self.send_header("content-length", str(len(body)))
2363        self.end_headers()
2364        self.wfile.write(body)
2365HTTPServer((host, int(port)), Handler).serve_forever()
2366"#,
2367        )
2368        .unwrap();
2369        let mut permissions = std::fs::metadata(&runner).unwrap().permissions();
2370        permissions.set_mode(0o755);
2371        std::fs::set_permissions(&runner, permissions).unwrap();
2372        verify_native_serve(
2373            model_packs::by_alias("qwen3").unwrap(),
2374            model.to_str().unwrap(),
2375            &root,
2376            &runner,
2377        )
2378        .unwrap();
2379        assert!(root.join("serve-response.json").is_file());
2380        assert!(
2381            std::fs::read_to_string(root.join("gates.txt"))
2382                .unwrap()
2383                .contains("Serve=passed")
2384        );
2385        std::fs::remove_dir_all(root).unwrap();
2386    }
2387}