diff --git a/crates/skate-game/src/camera/publication.rs b/crates/skate-game/src/camera/publication.rs index 40944c2f..083d5f8e 100644 --- a/crates/skate-game/src/camera/publication.rs +++ b/crates/skate-game/src/camera/publication.rs @@ -168,8 +168,11 @@ pub(crate) fn snapshot( //The source getter396 is bound to Motion64, despite its camera name //"acceleration". Motion64 is the published deck angular velocity. let acceleration = p.skateboard.vector_64.map(f32::from_bits); - let finite = |name: &str, values: &[f32]| -> Result<(), String> { - if values.iter().all(|value| value.is_finite()) { + // Native vector storage retains four lanes, but camera positions, + // directions and magnitudes use only XYZ. W is not a homogeneous + // coordinate here and can be non-finite without corrupting the pose. + let finite = |name: &str, values: &[f32; 4]| -> Result<(), String> { + if values[..3].iter().all(|value| value.is_finite()) { Ok(()) } else { Err(format!( @@ -183,11 +186,13 @@ pub(crate) fn snapshot( finite("reckoning_up", &up)?; finite("damped_centre_of_mass", &input.damped_com_80)?; finite("ground_up", &input.ground_up_80)?; - finite("skeleton_root", skeleton_root.iter().flatten().copied().collect::>().as_slice())?; + for column in &skeleton_root { + finite("skeleton_root", column)?; + } for (index, pose) in [1usize, 15, 19, 23].into_iter().map(|index| (index, record.pose[index][3])) { finite(match index { 1 => "head", 15 => "left_foot", 19 => "right_foot", _ => "hips" }, &pose)?; } - if velocity.iter().chain(acceleration.iter()).any(|v| !v.is_finite()) { + if velocity[..3].iter().chain(acceleration[..3].iter()).any(|v| !v.is_finite()) { return Err(format!( "Camera received non-finite board motion publication: velocity={velocity:?}; acceleration={acceleration:?}; raw_velocity={:?}; raw_acceleration={:?}", p.skateboard.vector_80, diff --git a/docs/camera-vector-validation-crash.md b/docs/camera-vector-validation-crash.md new file mode 100644 index 00000000..1906267c --- /dev/null +++ b/docs/camera-vector-validation-crash.md @@ -0,0 +1,19 @@ +# Camera validation crash after the archive merge + +`game-20260907-225258.stderr.log` exited at tick1016 in state/category500. +The imported camera publication check rejected the skeleton root translation +`[5.0928864, -1.535, -4.822083, -inf]`. All position and basis XYZ components +were finite; only the translation's fourth stored lane was non-finite. + +The native-shaped camera vectors retain all four lanes, but camera distances, +dot products, direction tests and final rendered positions use XYZ. See +`skate-core/src/camera/vector_tracker.rs`, `compass.rs` and `subject_pose.rs`. +The merge introduced validation of every stored lane, incorrectly making the +unused lane fatal even though the existing camera accepts this representation. + +Publication validation now checks XYZ independently for each root column and +each position/direction/motion vector. Invalid XYZ remains an error. No source +vector is sanitized, and no offboard simulation or camera tracking is changed. +The root check also no longer allocates a temporary flattened vector each tick. + +Validation: source inspection and compilation; no automated gameplay/tests run.