Skip to content

Commit f5d0e1e

Browse files
authored
fix(ruvnet#894): actionable diagnostic when --model gets a non-RVF file (ruvnet#919)
Users who downloaded ruvnet/wifi-densepose-pretrained and passed model.safetensors / model-q4.bin / model.rvf.jsonl to --model hit a bare "Progressive loader init failed: invalid magic at offset 0: expected 0x52564653, got 0x77455735" and were stuck — the server then silently fell back to signal heuristics (which over-count, feeding "is it fake" reports). The HF files are a different *format* and encoder architecture than the RVF binary container the progressive loader expects, so they can't load directly. Now the load-failure path detects the common cases (safetensors header, JSONL manifest, quantized .bin blob) and emits a plain explanation naming the format, what --model actually expects (RVF `RVFS` container from wifi-densepose-train), and that it's continuing with heuristics — with a pointer to ruvnet#894. Pure, testable `diagnose_model_load_error()` + 4 unit tests (run under the default `--no-default-features` CI). Full crate unit suite: 429 + 114 passed, 0 failed.
1 parent b12662a commit f5d0e1e

1 file changed

Lines changed: 95 additions & 1 deletion

File tree

  • v2/crates/wifi-densepose-sensing-server/src

v2/crates/wifi-densepose-sensing-server/src/main.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5570,6 +5570,55 @@ fn vitals_snapshots_from_sensing_json(
55705570
}
55715571
}
55725572

5573+
/// Turn a `ProgressiveLoader::new` failure into an actionable diagnostic (#894).
5574+
///
5575+
/// The published HuggingFace `ruvnet/wifi-densepose-pretrained` files
5576+
/// (`model.safetensors`, `model-q{2,4,8}.bin`, `model.rvf.jsonl`) are a
5577+
/// different *format* — and a different encoder architecture — than the RVF
5578+
/// binary container the `--model` progressive loader expects (`RVFS` magic
5579+
/// `0x52564653`). Feeding one to `--model` produced a bare
5580+
/// "invalid magic at offset 0 …" that left users stuck. Detect the common
5581+
/// cases and explain plainly what's loadable instead.
5582+
fn diagnose_model_load_error(path: &std::path::Path, data: &[u8], err: &str) -> String {
5583+
let name = path
5584+
.file_name()
5585+
.and_then(|n| n.to_str())
5586+
.unwrap_or("")
5587+
.to_ascii_lowercase();
5588+
let ext = path
5589+
.extension()
5590+
.and_then(|e| e.to_str())
5591+
.unwrap_or("")
5592+
.to_ascii_lowercase();
5593+
5594+
// safetensors: 8-byte LE header length, then a JSON object starting with '{'.
5595+
let looks_safetensors = ext == "safetensors" || (data.len() > 9 && data[8] == b'{');
5596+
// JSONL manifest: starts with '{' (or the well-known suffix).
5597+
let looks_jsonl =
5598+
ext == "jsonl" || name.ends_with(".rvf.jsonl") || data.first() == Some(&b'{');
5599+
// Quantized weight blob shipped on HF (model-q2/q4/q8.bin).
5600+
let looks_quant_bin = ext == "bin" || name.contains("-q");
5601+
5602+
let kind = if looks_safetensors {
5603+
"a safetensors weight file"
5604+
} else if looks_jsonl {
5605+
"a JSONL manifest, not the binary container"
5606+
} else if looks_quant_bin {
5607+
"a quantized weight blob (e.g. HuggingFace model-q4.bin)"
5608+
} else {
5609+
"not an RVF binary container"
5610+
};
5611+
5612+
format!(
5613+
"model `{}` could not be loaded: it is {kind}. The --model flag expects an \
5614+
RVF binary container (`RVFS` magic 0x52564653) produced by the \
5615+
wifi-densepose-train pipeline. The HuggingFace ruvnet/wifi-densepose-pretrained \
5616+
files are a different format and encoder architecture, so they do not load \
5617+
here directly (issue #894). Continuing with signal heuristics. (loader: {err})",
5618+
path.display()
5619+
)
5620+
}
5621+
55735622
// ── Main ─────────────────────────────────────────────────────────────────────
55745623

55755624
/// If `--ui-path` points nowhere (wrong cwd), try common repo layouts relative to cwd.
@@ -6207,7 +6256,9 @@ async fn main() {
62076256
model_loaded = true;
62086257
progressive_loader = Some(loader);
62096258
}
6210-
Err(e) => error!("Progressive loader init failed: {e}"),
6259+
Err(e) => {
6260+
error!("{}", diagnose_model_load_error(mp, &data, &e.to_string()))
6261+
}
62116262
},
62126263
Err(e) => error!("Failed to read model file: {e}"),
62136264
}
@@ -7216,3 +7267,46 @@ mod mqtt_bridge_tests {
72167267
assert!(!snaps[0].presence);
72177268
}
72187269
}
7270+
7271+
#[cfg(test)]
7272+
mod model_load_diagnostic_tests {
7273+
use super::diagnose_model_load_error;
7274+
use std::path::Path;
7275+
7276+
#[test]
7277+
fn safetensors_is_named_and_points_at_894() {
7278+
// 8-byte LE header length then '{' — the safetensors signature.
7279+
let data = [0x10, 0, 0, 0, 0, 0, 0, 0, b'{', b'"'];
7280+
let msg = diagnose_model_load_error(
7281+
Path::new("models/wifi-densepose-pretrained/model.safetensors"),
7282+
&data,
7283+
"invalid magic at offset 0",
7284+
);
7285+
assert!(msg.contains("safetensors"), "{msg}");
7286+
assert!(msg.contains("#894"), "{msg}");
7287+
assert!(msg.contains("signal heuristics"), "{msg}");
7288+
}
7289+
7290+
#[test]
7291+
fn quantized_bin_is_identified() {
7292+
let data = [0x35, 0x57, 0x45, 0x77]; // the 0x77455735 the loader reports
7293+
let msg = diagnose_model_load_error(Path::new("model-q4.bin"), &data, "bad magic");
7294+
assert!(msg.contains("quantized weight blob"), "{msg}");
7295+
assert!(msg.contains("RVFS") || msg.contains("0x52564653"), "{msg}");
7296+
}
7297+
7298+
#[test]
7299+
fn jsonl_manifest_is_identified() {
7300+
let data = *b"{\"seg\":0}";
7301+
let msg = diagnose_model_load_error(Path::new("model.rvf.jsonl"), &data, "x");
7302+
assert!(msg.contains("JSONL manifest"), "{msg}");
7303+
}
7304+
7305+
#[test]
7306+
fn unknown_format_still_gives_guidance() {
7307+
let data = [0u8, 1, 2, 3];
7308+
let msg = diagnose_model_load_error(Path::new("weird.dat"), &data, "x");
7309+
assert!(msg.contains("RVF binary container"), "{msg}");
7310+
assert!(msg.contains("wifi-densepose-train"), "{msg}");
7311+
}
7312+
}

0 commit comments

Comments
 (0)