diff --git a/docs/user-guide.md b/docs/user-guide.md index 5bf2e0cb..1e149d24 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -1048,7 +1048,7 @@ The Rust sensing server binary accepts the following flags: | `--dataset` | (none) | Path to dataset directory (MM-Fi or Wi-Pose) | | `--dataset-type` | `mmfi` | Dataset format: `mmfi` or `wipose` | | `--epochs` | `100` | Training epochs | -| `--export-rvf` | (none) | Export RVF model container and exit | +| `--export-rvf` | (none) | Export a **placeholder** RVF container-format demo and exit — **not a trained model**. For a real model use `--train` (+ `--save-rvf`) or download a pretrained encoder. | | `--save-rvf` | (none) | Save model state to RVF on shutdown | | `--model` | (none) | Load a trained `.rvf` model for inference | | `--load-rvf` | (none) | Load model config from RVF container | @@ -1359,7 +1359,7 @@ docker run --rm \ -v $(pwd)/output:/output \ --entrypoint /app/sensing-server \ ruvnet/wifi-densepose:latest \ - --train --dataset /data --epochs 100 --export-rvf /output/model.rvf + --train --dataset /data --epochs 100 --save-rvf /output/model.rvf ``` The pipeline runs 10 phases: diff --git a/v2/crates/wifi-densepose-sensing-server/src/main.rs b/v2/crates/wifi-densepose-sensing-server/src/main.rs index eaebdbdf..cec524c5 100644 --- a/v2/crates/wifi-densepose-sensing-server/src/main.rs +++ b/v2/crates/wifi-densepose-sensing-server/src/main.rs @@ -5619,6 +5619,16 @@ fn diagnose_model_load_error(path: &std::path::Path, data: &[u8], err: &str) -> ) } +/// Whether `--export-rvf` should emit the placeholder container-format demo. +/// +/// It must only do so **standalone**. Combined with `--train`/`--pretrain` the +/// real model is produced by the training pipeline, so short-circuiting here +/// would silently skip training and write placeholder weights — the #894 bug +/// where the documented `--train … --export-rvf` workflow produced a fake model. +fn export_emits_placeholder_demo(export_set: bool, train: bool, pretrain: bool) -> bool { + export_set && !train && !pretrain +} + // ── Main ───────────────────────────────────────────────────────────────────── /// If `--ui-path` points nowhere (wrong cwd), try common repo layouts relative to cwd. @@ -5662,9 +5672,24 @@ async fn main() { return; } - // Handle --export-rvf mode: build an RVF container package and exit - if let Some(ref rvf_path) = args.export_rvf { - eprintln!("Exporting RVF container package..."); + // Handle --export-rvf: writes a CONTAINER-FORMAT DEMO with placeholder + // weights — it is NOT a trained model. Only short-circuit when standalone: + // combined with --train/--pretrain the real model is exported by the + // training pipeline, and short-circuiting here would silently skip training + // and write placeholder weights (#894 — the documented `--train … + // --export-rvf` workflow produced a placeholder and never trained). + if export_emits_placeholder_demo(args.export_rvf.is_some(), args.train, args.pretrain) { + let rvf_path = args + .export_rvf + .as_ref() + .expect("export_emits_placeholder_demo implies export_rvf is set"); + eprintln!( + "WARNING: --export-rvf writes a CONTAINER-FORMAT DEMO with placeholder \ + weights — it is NOT a trained model. Train one with \ + `--train --dataset