diff --git a/packages/cli/src/commands/snapshot.test.ts b/packages/cli/src/commands/snapshot.test.ts index 4cb0d394c7..1e0b9ac7d7 100644 --- a/packages/cli/src/commands/snapshot.test.ts +++ b/packages/cli/src/commands/snapshot.test.ts @@ -62,6 +62,16 @@ describe("computeSnapshotTimes (FINDING [7]: tail is always captured)", () => { expect(times).toEqual([1, 2]); expect(appendedTail).toBe(false); }); + + it("preserves exact explicit transition timestamps", () => { + const exactTransition = 3.3666666666666667; + const { times } = computeSnapshotTimes(8, { + frames: 5, + at: [exactTransition], + includeEnd: false, + }); + expect(times).toEqual([exactTransition]); + }); }); describe("parseZoomScale (--zoom-scale)", () => { diff --git a/packages/cli/src/commands/snapshot.ts b/packages/cli/src/commands/snapshot.ts index ae8e8297b0..00bc03cfe5 100644 --- a/packages/cli/src/commands/snapshot.ts +++ b/packages/cli/src/commands/snapshot.ts @@ -159,7 +159,11 @@ export function computeSnapshotTimes( const round = (t: number) => Math.round(t * 1000) / 1000; if (opts.at?.length) { - const times = opts.at.map(round); + // `--at` is an evidence contract: callers may pass exact fractional-frame + // boundaries (for example 101 / 30). Do not normalize their requested + // positions; rounding to milliseconds can move a transition sample to the + // other side of the boundary. + const times = [...opts.at]; // Only append if the user didn't already sample at/near the readable tail. const hasTail = times.some((t) => Math.abs(t - tail) < 0.05 || t >= duration); if (includeEnd && duration > 0 && !hasTail) {