Part of #123. File: crates/rustmotion/src/encode/video/formats.rs
The PNG sequence writer permutes frames
formats.rs:45:
let frame_num = counter.fetch_add(1, Ordering::Relaxed);
The index comes from a shared atomic in rayon's scheduling order, not the task's position, so frames are permuted within each batch by ±(2·ncores−1).
Verified: two runs of the same input differ on 114 frames (max mean-abs 12.4/255); --threads 1 output is byte-identical to the --frame N path; multi-threaded output is a strict permutation of it (identical multiset, 436/486 misplaced, displacement −19..+18). It raises the measured noise floor 9.4× and manufactures fake spikes around transitions — it corrupted an earlier analysis before being caught.
mp4 and gif are unaffected: those paths use the counter only for progress, and rayon's collect preserves order.
Fix: derive the frame index from the task's position (enumerate over the batch plus the batch base) rather than the atomic.
Acceptance
- Two multi-threaded runs of the same input produce byte-identical sequences.
- Multi-threaded output is byte-identical to
--threads 1.
- Prove both by hashing the sequences, not by inspection.
Part of #123. File:
crates/rustmotion/src/encode/video/formats.rsThe PNG sequence writer permutes frames
formats.rs:45:The index comes from a shared atomic in rayon's scheduling order, not the task's position, so frames are permuted within each batch by ±(2·ncores−1).
Verified: two runs of the same input differ on 114 frames (max mean-abs 12.4/255);
--threads 1output is byte-identical to the--frame Npath; multi-threaded output is a strict permutation of it (identical multiset, 436/486 misplaced, displacement −19..+18). It raises the measured noise floor 9.4× and manufactures fake spikes around transitions — it corrupted an earlier analysis before being caught.mp4andgifare unaffected: those paths use the counter only for progress, and rayon'scollectpreserves order.Fix: derive the frame index from the task's position (enumerate over the batch plus the batch base) rather than the atomic.
Acceptance
--threads 1.