From c5af482bcecc972f141c4c8c24048e8a5c24539f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 12:53:09 +0000 Subject: [PATCH] QA: frame scores refuse NaN samples and mismatched buffers (#427 follow-up) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f --- crates/effects/src/fidelity.rs | 12 +++++++++++- crates/effects/src/lib.rs | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/effects/src/fidelity.rs b/crates/effects/src/fidelity.rs index 31243bd0..e18803ee 100644 --- a/crates/effects/src/fidelity.rs +++ b/crates/effects/src/fidelity.rs @@ -2,17 +2,21 @@ use effectcraft_raster::Image; +/// How far a rendered frame is from its reference. #[derive(Clone, Copy, Debug, PartialEq)] pub struct FrameScore { + /// Pixels compared (the frames' width × height). pub compared_pixels: usize, + /// Mean absolute difference over every channel sample. pub mean_absolute_error: f64, + /// Largest absolute difference of any channel sample. pub max_error: f32, } /// Compare two premultiplied rendered frames. A size mismatch is reported as an error instead of /// silently producing a misleading score. pub fn compare_frames(actual: &Image, reference: &Image) -> Result { - if actual.width != reference.width || actual.height != reference.height { + if actual.width != reference.width || actual.height != reference.height || actual.data.len() != reference.data.len() { return Err(format!("frame size mismatch: {}x{} vs {}x{}", actual.width, actual.height, reference.width, reference.height)); } let mut sum = 0.0f64; @@ -20,6 +24,10 @@ pub fn compare_frames(actual: &Image, reference: &Image) -> Result tolerance` check reads as a pass. + if !error.is_finite() { + return Err("frame has a non-finite sample".into()); + } sum += f64::from(error); max = max.max(error); } @@ -43,5 +51,7 @@ mod tests { assert!((score.mean_absolute_error - 0.0625).abs() < f64::EPSILON); assert_eq!(score.max_error, 0.5); assert!(compare_frames(&actual, &Image::new(1, 1)).is_err()); + actual.data[0][1] = f32::NAN; + assert!(compare_frames(&actual, &reference).is_err(), "NaN is an error, not a pass"); } } diff --git a/crates/effects/src/lib.rs b/crates/effects/src/lib.rs index ad3c0a9e..4bce0636 100644 --- a/crates/effects/src/lib.rs +++ b/crates/effects/src/lib.rs @@ -21,12 +21,12 @@ mod color2; mod color3; mod color_fx; pub mod controls; -pub mod fidelity; mod distort; mod distort2; mod distort3; pub mod distort4; pub mod face_track; +pub mod fidelity; mod generate; mod generate2; mod generate3;