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}