Skip to main content

dsfb_computer_graphics/
cli.rs

1use std::path::PathBuf;
2
3use clap::{Parser, Subcommand};
4
5use crate::config::DemoConfig;
6use crate::datasets::{
7    prepare_davis_dataset, prepare_sintel_dataset, validate_standard_external_package,
8};
9use crate::engine_native::{run_engine_native_import, run_engine_native_replay};
10use crate::error::Result;
11use crate::external_validation::probe_external_gpu_only;
12use crate::mixed_regime::confirm_mixed_regime;
13use crate::pipeline::{
14    export_evaluator_handoff, export_minimal_report, generate_scene_artifacts, run_all,
15    run_all_filtered, run_check_signing, run_demo_a, run_demo_a_filtered, run_demo_b,
16    run_demo_b_efficiency_only, run_demo_b_filtered, run_engine_realistic_bridge,
17    run_external_replay_only, run_fast_path_only, run_gpu_path_only, run_realism_bridge_only,
18    run_resolution_scaling_only, run_sbir_demo, run_sensitivity_only, run_timing_only,
19    validate_artifact_bundle, validate_engine_native_gates, validate_final_bundle,
20};
21use crate::unreal_native::run_unreal_native;
22
23#[derive(Debug, Parser)]
24#[command(
25    author,
26    version,
27    about = "DSFB computer-graphics evaluation and artifact pipeline"
28)]
29pub struct Cli {
30    #[command(subcommand)]
31    pub command: Command,
32}
33
34#[derive(Debug, Subcommand)]
35pub enum Command {
36    PrepareDavis {
37        #[arg(long, default_value = "data/external/davis")]
38        output: PathBuf,
39    },
40    PrepareSintel {
41        #[arg(long, default_value = "data/external/sintel")]
42        output: PathBuf,
43    },
44    GenerateScene {
45        #[arg(long, default_value = "generated")]
46        output: PathBuf,
47        #[arg(long)]
48        scenario: Option<String>,
49    },
50    RunDemoA {
51        #[arg(long, default_value = "generated")]
52        output: PathBuf,
53        #[arg(long)]
54        scenario: Option<String>,
55    },
56    RunDemoB {
57        #[arg(long, default_value = "generated")]
58        output: PathBuf,
59        #[arg(long)]
60        scenario: Option<String>,
61    },
62    RunAblations {
63        #[arg(long, default_value = "generated")]
64        output: PathBuf,
65    },
66    RunScenario {
67        scenario: String,
68        #[arg(long, default_value = "generated")]
69        output: PathBuf,
70    },
71    RunAll {
72        #[arg(long, default_value = "generated")]
73        output: PathBuf,
74        #[arg(long)]
75        scenario: Option<String>,
76    },
77    RunTiming {
78        #[arg(long, default_value = "generated")]
79        output: PathBuf,
80    },
81    RunResolutionScaling {
82        #[arg(long, default_value = "generated")]
83        output: PathBuf,
84    },
85    RunSensitivity {
86        #[arg(long, default_value = "generated")]
87        output: PathBuf,
88    },
89    RunDemoBEfficiency {
90        #[arg(long, default_value = "generated")]
91        output: PathBuf,
92    },
93    RunGpuPath {
94        #[arg(long, default_value = "generated")]
95        output: PathBuf,
96    },
97    #[command(visible_aliases = ["run-external-replay", "replay-external"])]
98    ImportExternal {
99        #[arg(long)]
100        manifest: PathBuf,
101        #[arg(long, default_value = "generated")]
102        output: PathBuf,
103    },
104    #[command(visible_alias = "run-realism-bridge")]
105    RunRealismSuite {
106        #[arg(long, default_value = "generated")]
107        output: PathBuf,
108    },
109    ExportEvaluatorHandoff {
110        #[arg(long, default_value = "generated")]
111        output: PathBuf,
112    },
113    Validate {
114        #[arg(long, default_value = "generated")]
115        output: PathBuf,
116    },
117    ValidateFinal {
118        #[arg(long, default_value = "generated")]
119        output: PathBuf,
120        /// Allow pending engine-native gates (pass even if no real engine capture has been provided).
121        /// Without this flag, validate-final fails if ENGINE_NATIVE_CAPTURE_MISSING=true.
122        #[arg(long)]
123        allow_pending_engine_native: bool,
124    },
125    /// Import and validate an engine-native temporal buffer capture.
126    /// See docs/engine_capture_schema.md and examples/engine_native_capture_manifest.json.
127    ImportEngineNative {
128        #[arg(long)]
129        manifest: PathBuf,
130        #[arg(long, default_value = "generated/engine_native")]
131        output: PathBuf,
132    },
133    /// Run the full DSFB replay pipeline on an engine-native capture.
134    /// Same pipeline as DAVIS/Sintel — no special-case path.
135    RunEngineNativeReplay {
136        #[arg(long)]
137        manifest: PathBuf,
138        #[arg(long, default_value = "generated/engine_native")]
139        output: PathBuf,
140    },
141    /// Run the strict Unreal-native empirical replay path on a real Unreal capture bundle.
142    /// This mode refuses pending, proxy-labeled, or synthetic manifests.
143    RunUnrealNative {
144        #[arg(long)]
145        manifest: PathBuf,
146        #[arg(long, default_value = "generated/unreal_native_runs")]
147        output: PathBuf,
148        #[arg(long)]
149        run_name: Option<String>,
150    },
151    /// Confirm one mixed-regime case (aliasing + variance co-active in same ROI).
152    /// Uses internal synthetic scenario data; engine-native confirmation remains pending.
153    ConfirmMixedRegime {
154        #[arg(long, default_value = "generated")]
155        output: PathBuf,
156    },
157    ValidateArtifacts {
158        #[arg(long, default_value = "generated")]
159        output: PathBuf,
160    },
161    ExportMinimalReport {
162        #[arg(long, default_value = "generated")]
163        output: PathBuf,
164    },
165    /// Internal: run GPU probe in an isolated subprocess (used by run-external-replay)
166    #[command(hide = true)]
167    ProbeExternalGpu {
168        #[arg(long)]
169        manifest: PathBuf,
170        #[arg(long, default_value = "generated")]
171        output: PathBuf,
172        #[arg(long)]
173        capture_label: Option<String>,
174        #[arg(long)]
175        width: Option<usize>,
176        #[arg(long)]
177        height: Option<usize>,
178    },
179    /// Generate the engine-realistic synthetic 1080p bridge and run the full external validation bundle on it.
180    RunEngineRealisticBridge {
181        #[arg(long, default_value = "generated/engine_realistic")]
182        output: PathBuf,
183    },
184    /// Generate the check-signing evidence report answering all panel objections.
185    RunCheckSigning {
186        #[arg(long, default_value = "generated/final_bundle")]
187        output: PathBuf,
188    },
189    /// Run the minimal inline fast-path proxy at 1080p and 4K, measure GPU timings,
190    /// and write artifacts to output/fast_path/.
191    ///
192    /// This is a reduced deployment proxy derived from DSFB residual structure.
193    /// It is NOT the full DSFB supervisory system.
194    RunFastPath {
195        #[arg(long, default_value = "generated/fast_path_runs")]
196        output: PathBuf,
197    },
198    /// Run all tests and pipeline stages, then generate a single PDF engineering
199    /// report suitable for SBIR crate-quality review.
200    ///
201    /// Writes sbir_demo_report.pdf into the output directory alongside all
202    /// intermediate artifacts and a machine-readable test_results.json.
203    SbirDemo {
204        #[arg(long, default_value = "generated/sbir_demo")]
205        output: PathBuf,
206    },
207}
208
209pub fn run(cli: Cli) -> Result<()> {
210    let config = DemoConfig::default();
211    match cli.command {
212        Command::PrepareDavis { output } => {
213            let manifest = prepare_davis_dataset(&output)?;
214            println!("DAVIS manifest: {}", manifest.display());
215        }
216        Command::PrepareSintel { output } => {
217            let manifest = prepare_sintel_dataset(&output)?;
218            println!("Sintel manifest: {}", manifest.display());
219        }
220        Command::GenerateScene { output, .. } => {
221            let manifest = generate_scene_artifacts(&config, &output)?;
222            println!(
223                "generated canonical scene manifest for {} at {}",
224                manifest.scenario_id,
225                output.display()
226            );
227        }
228        Command::RunDemoA { output, scenario } => {
229            let artifacts = if let Some(scenario) = scenario.as_deref() {
230                run_demo_a_filtered(&config, &output, Some(scenario))?
231            } else {
232                run_demo_a(&config, &output)?
233            };
234            print_demo_a_artifacts(&artifacts);
235        }
236        Command::RunDemoB { output, scenario } => {
237            let artifacts = if let Some(scenario) = scenario.as_deref() {
238                run_demo_b_filtered(&config, &output, Some(scenario))?
239            } else {
240                run_demo_b(&config, &output)?
241            };
242            print_demo_b_artifacts(&artifacts);
243        }
244        Command::RunAblations { output } => {
245            let artifacts = run_demo_a_filtered(&config, &output, Some("thin_reveal"))?;
246            print_demo_a_artifacts(&artifacts);
247        }
248        Command::RunScenario { scenario, output } => {
249            let artifacts = run_all_filtered(&config, &output, Some(&scenario))?;
250            println!("scenario output: {}", artifacts.output_dir.display());
251            println!("report: {}", artifacts.demo_a.report_path.display());
252        }
253        Command::RunAll { output, scenario } => {
254            let artifacts = if let Some(scenario) = scenario.as_deref() {
255                run_all_filtered(&config, &output, Some(scenario))?
256            } else {
257                run_all(&config, &output)?
258            };
259            println!("run output: {}", artifacts.output_dir.display());
260            println!("manifest: {}", artifacts.manifest_path.display());
261            println!("report: {}", artifacts.demo_a.report_path.display());
262            println!("demo b report: {}", artifacts.demo_b.report_path.display());
263            println!(
264                "mentor audit: {}",
265                artifacts.five_mentor_audit_path.display()
266            );
267            println!(
268                "blocker report: {}",
269                artifacts.blocker_report_path.display()
270            );
271            println!(
272                "demo b decision report: {}",
273                artifacts.demo_b_decision_report_path.display()
274            );
275        }
276        Command::RunTiming { output } => {
277            let report = run_timing_only(&config, &output)?;
278            println!("timing report: {}", report.display());
279        }
280        Command::RunResolutionScaling { output } => {
281            let report = run_resolution_scaling_only(&config, &output)?;
282            println!("resolution scaling report: {}", report.display());
283        }
284        Command::RunSensitivity { output } => {
285            let report = run_sensitivity_only(&config, &output)?;
286            println!("parameter sensitivity report: {}", report.display());
287        }
288        Command::RunDemoBEfficiency { output } => {
289            let report = run_demo_b_efficiency_only(&config, &output)?;
290            println!("demo b efficiency report: {}", report.display());
291        }
292        Command::RunGpuPath { output } => {
293            let report = run_gpu_path_only(&config, &output)?;
294            println!("gpu execution report: {}", report.display());
295        }
296        Command::ImportExternal { manifest, output } => {
297            let report = run_external_replay_only(&config, &manifest, &output)?;
298            println!("external replay report: {}", report.display());
299        }
300        Command::RunRealismSuite { output } => {
301            let report = run_realism_bridge_only(&config, &output)?;
302            println!("realism bridge report: {}", report.display());
303        }
304        Command::ExportEvaluatorHandoff { output } => {
305            let report = export_evaluator_handoff(&config, &output)?;
306            println!("evaluator handoff: {}", report.display());
307        }
308        Command::Validate { output } => {
309            validate_standard_external_package(&output)?;
310            println!(
311                "validated standard external package at {}",
312                output.display()
313            );
314        }
315        Command::ValidateFinal {
316            output,
317            allow_pending_engine_native,
318        } => {
319            validate_final_bundle(&output)?;
320            // Engine-native gates: check {output}/../engine_native/ (i.e., generated/engine_native/)
321            let engine_native_dir = output
322                .parent()
323                .unwrap_or(std::path::Path::new("."))
324                .join("engine_native");
325            validate_engine_native_gates(&engine_native_dir, allow_pending_engine_native)?;
326            println!("validated final bundle at {}", output.display());
327        }
328        Command::ImportEngineNative { manifest, output } => {
329            let artifacts = run_engine_native_import(&config, &manifest, &output)?;
330            println!("engine-native import report: {}", artifacts.import_report_path.display());
331            println!("resolved manifest: {}", artifacts.resolved_manifest_path.display());
332            println!("ENGINE_NATIVE_CAPTURE_MISSING={}", artifacts.capture_missing);
333        }
334        Command::RunEngineNativeReplay { manifest, output } => {
335            let artifacts = run_engine_native_replay(&config, &manifest, &output)?;
336            println!("engine-native replay report: {}", artifacts.replay_report_path.display());
337            println!("GPU report: {}", artifacts.gpu_report_path.display());
338            println!("Demo A: {}", artifacts.demo_a_report_path.display());
339            println!("Demo B: {}", artifacts.demo_b_report_path.display());
340            println!("validation: {}", artifacts.validation_report_path.display());
341            println!("ENGINE_NATIVE_CAPTURE_MISSING={}", artifacts.capture_missing);
342        }
343        Command::RunUnrealNative {
344            manifest,
345            output,
346            run_name,
347        } => {
348            let cli_args = std::env::args().collect::<Vec<_>>();
349            let artifacts = run_unreal_native(
350                &config,
351                &manifest,
352                &output,
353                run_name.as_deref(),
354                &cli_args,
355            )?;
356            println!("run dir: {}", artifacts.run_dir.display());
357            println!(
358                "materialized manifest: {}",
359                artifacts.materialized_manifest_path.display()
360            );
361            println!("summary: {}", artifacts.summary_path.display());
362            println!("metrics csv: {}", artifacts.metrics_csv_path.display());
363            println!("metrics summary: {}", artifacts.metrics_summary_path.display());
364            println!(
365                "comparison summary: {}",
366                artifacts.comparison_summary_path.display()
367            );
368            println!("failure modes: {}", artifacts.failure_modes_path.display());
369            println!("provenance: {}", artifacts.provenance_path.display());
370            println!(
371                "notebook manifest: {}",
372                artifacts.notebook_manifest_path.display()
373            );
374            println!(
375                "executive sheet: {}",
376                artifacts.executive_sheet_path.display()
377            );
378            println!("pdf: {}", artifacts.pdf_path.display());
379            println!("zip: {}", artifacts.zip_path.display());
380        }
381        Command::ConfirmMixedRegime { output } => {
382            let report = confirm_mixed_regime(&config, &output)?;
383            println!("mixed regime confirmation: {}", report.display());
384        }
385        Command::ValidateArtifacts { output } => {
386            validate_artifact_bundle(&output)?;
387            println!("validated artifact bundle at {}", output.display());
388        }
389        Command::ExportMinimalReport { output } => {
390            let report = export_minimal_report(&config, &output)?;
391            println!("minimal report: {}", report.display());
392        }
393        Command::ProbeExternalGpu {
394            manifest,
395            output,
396            capture_label,
397            width,
398            height,
399        } => {
400            let scaled_resolution = match (width, height) {
401                (Some(width), Some(height)) => Some((width, height)),
402                (None, None) => None,
403                _ => {
404                    return Err(crate::error::Error::Message(
405                        "probe-external-gpu requires both --width and --height when scaling is requested"
406                            .to_string(),
407                    ))
408                }
409            };
410            let metrics_path = probe_external_gpu_only(
411                &config,
412                &manifest,
413                &output,
414                capture_label.as_deref(),
415                scaled_resolution,
416            )?;
417            println!("gpu probe metrics: {}", metrics_path.display());
418        }
419        Command::RunEngineRealisticBridge { output } => {
420            let report = run_engine_realistic_bridge(&config, &output)?;
421            println!("engine-realistic bridge report: {}", report.display());
422        }
423        Command::RunCheckSigning { output } => {
424            let report = run_check_signing(&config, &output)?;
425            println!("check-signing report: {}", report.display());
426        }
427        Command::RunFastPath { output } => {
428            let artifacts = run_fast_path_only(&output)?;
429            println!("fast-path output: {}", artifacts.output_dir.display());
430            println!("timing json: {}", artifacts.timing_json_path.display());
431            println!("summary json: {}", artifacts.summary_json_path.display());
432            println!("trust svg: {}", artifacts.trust_svg_path.display());
433            println!("summary md: {}", artifacts.summary_md_path.display());
434        }
435        Command::SbirDemo { output } => {
436            let artifacts = run_sbir_demo(&config, &output)?;
437            println!("sbir-demo output: {}", artifacts.output_dir.display());
438            println!("pdf: {}", artifacts.pdf_path.display());
439            println!("test results: {}", artifacts.test_results_path.display());
440        }
441    }
442    Ok(())
443}
444
445fn print_demo_a_artifacts(artifacts: &crate::pipeline::DemoAArtifacts) {
446    println!("demo output: {}", artifacts.output_dir.display());
447    println!("metrics: {}", artifacts.metrics_path.display());
448    println!("report: {}", artifacts.report_path.display());
449    println!(
450        "reviewer summary: {}",
451        artifacts.reviewer_summary_path.display()
452    );
453    println!(
454        "ablation report: {}",
455        artifacts.ablation_report_path.display()
456    );
457    println!("cost report: {}", artifacts.cost_report_path.display());
458    println!(
459        "completion note: {}",
460        artifacts.completion_note_path.display()
461    );
462    for figure in &artifacts.figure_paths {
463        println!("figure: {}", figure.display());
464    }
465}
466
467fn print_demo_b_artifacts(artifacts: &crate::pipeline::DemoBArtifacts) {
468    println!("demo output: {}", artifacts.output_dir.display());
469    println!("metrics: {}", artifacts.metrics_path.display());
470    println!("report: {}", artifacts.report_path.display());
471    for figure in &artifacts.figure_paths {
472        println!("figure: {}", figure.display());
473    }
474}