Skip to main content

dsfb_gpu_debug_demo/cli/
run_cpu.rs

1//! `dsfb-gpu-debug run-cpu` — run the CPU reference pipeline.
2//!
3//! Required flags:
4//!
5//! * `--fixture PATH` — canonical fixture JSON written by
6//!   `generate-fixture`.
7//! * `--out PATH` — destination for the case-file JSON.
8//!
9//! Optional flags:
10//!
11//! * `--contract PATH` — contract.toml to apply. v0 ignores the file
12//!   contents and uses `Contract::canonical()` with the bank and
13//!   detector-registry hashes pinned to the in-repo values; the flag is
14//!   accepted so the CLI matches the spec interface. Future sections
15//!   will load and validate the file.
16
17use std::fs;
18use std::path::Path;
19use std::process::ExitCode;
20
21use dsfb_gpu_debug_core::bank::bank_hash;
22use dsfb_gpu_debug_core::casefile::{build_cpu, emit};
23use dsfb_gpu_debug_core::contract::Contract;
24use dsfb_gpu_debug_core::motif::registry_hash;
25use dsfb_gpu_debug_core::serialize::read_fixture;
26
27use super::{parse_flags, require_flag, usage_error};
28
29pub fn parse_and_run(args: &[String]) -> ExitCode {
30    let flags = match parse_flags(args) {
31        Ok(f) => f,
32        Err(message) => return usage_error(&message),
33    };
34    let fixture_path = match require_flag(&flags, "fixture") {
35        Ok(s) => s.to_string(),
36        Err(message) => return usage_error(&message),
37    };
38    let out_path = match require_flag(&flags, "out") {
39        Ok(s) => s.to_string(),
40        Err(message) => return usage_error(&message),
41    };
42    let _contract_path = flags.get("contract").cloned();
43
44    let raw = match fs::read(&fixture_path) {
45        Ok(bytes) => bytes,
46        Err(error) => {
47            eprintln!("dsfb-gpu-debug: failed to read {fixture_path}: {error}");
48            return ExitCode::from(5);
49        }
50    };
51    let events = match read_fixture(&raw) {
52        Ok(events) => events,
53        Err(error) => {
54            eprintln!("dsfb-gpu-debug: fixture parse error: {error:?}");
55            return ExitCode::from(5);
56        }
57    };
58
59    let mut contract = Contract::canonical();
60    contract.pin_bank_hash(bank_hash());
61    contract.pin_detector_registry_hash(registry_hash());
62    let case = build_cpu(&events, &contract);
63    let bytes = emit(&case);
64
65    if let Some(parent) = Path::new(&out_path).parent() {
66        if !parent.as_os_str().is_empty() {
67            if let Err(error) = fs::create_dir_all(parent) {
68                eprintln!(
69                    "dsfb-gpu-debug: could not create {}: {error}",
70                    parent.display()
71                );
72                return ExitCode::from(5);
73            }
74        }
75    }
76    if let Err(error) = fs::write(&out_path, &bytes) {
77        eprintln!("dsfb-gpu-debug: failed to write {out_path}: {error}");
78        return ExitCode::from(5);
79    }
80
81    eprintln!(
82        "dsfb-gpu-debug: wrote case file ({} bytes, {} episodes, verdict={}) to {out_path}",
83        bytes.len(),
84        case.episodes.len(),
85        case.final_verdict.name(),
86    );
87    ExitCode::from(case.final_verdict.exit_code())
88}