Never take a post-click screenshot when a pre-click frame exists
The remaining 'captured slightly after the click' reports came from the fresh-shot fallback, which grabs the screen when the click is processed (after it). The previous lead change made that fallback *more* likely: a frame now had to be >=120ms before the click to qualify, so on machines where the capture stream can't always keep a frame that old buffered, more clicks fell through to the post-click shot. Make the click-lead a two-tier preference instead of a hard gate in selectFrameForClick: 1. newest frame captured at least leadMs before the click (ideal margin), else 2. newest frame captured before the click at all. Only when no pre-click frame exists does the caller fresh-shot. leadMs is threaded through the stream backend to the worker so both selection paths agree. Verified end to end: frames land ~120-170ms before each click, markers stay at 0.00%, and the 8-click burst still saves all 8. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -798,8 +798,8 @@ test('click frames come from the stream backend when it is active', async () =>
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
assert.deepEqual(added, ['stream-frame']);
|
||||
assert.deepEqual(requests, [{ clickPos: { x: 10, y: 10 }, clickAt, strict: true }],
|
||||
'the worker receives the hook-time click timestamp and strictness');
|
||||
assert.deepEqual(requests, [{ clickPos: { x: 10, y: 10 }, clickAt, strict: true, leadMs: 0 }],
|
||||
'the worker receives the hook-time click timestamp, strictness, and lead');
|
||||
});
|
||||
|
||||
test('a stream backend with no qualifying frame falls through to the fresh-shot path', async () => {
|
||||
|
||||
@@ -124,6 +124,39 @@ test('frames of the wrong capture mode are rejected', () => {
|
||||
assert.equal(frameUsableForClick(f, { clickAt, mode: 'window' }), true);
|
||||
});
|
||||
|
||||
test('the click lead prefers a frame captured at least leadMs before the click', () => {
|
||||
const clickAt = 10_000;
|
||||
const frames = [
|
||||
frame('with-margin', { startedAt: 9780, capturedAt: 9800 }), // 200ms before
|
||||
frame('right-at-click', { startedAt: 9970, capturedAt: 9985 }), // 15ms before
|
||||
];
|
||||
|
||||
const chosen = selectFrameForClick(frames, { clickAt, mode: 'fullscreen', strict: true, leadMs: 120 });
|
||||
|
||||
assert.equal(chosen.name, 'with-margin',
|
||||
'with a lead, the frame clear of the click onset wins over the one right at it');
|
||||
});
|
||||
|
||||
test('the click lead falls back to any pre-click frame rather than forcing a post-click shot', () => {
|
||||
// The whole point of the two-tier rule: when nothing satisfies the lead,
|
||||
// we still return a pre-click frame (caller would otherwise fresh-shot
|
||||
// *after* the click). Only "right-before" exists here.
|
||||
const clickAt = 10_000;
|
||||
const frames = [frame('right-before', { startedAt: 9960, capturedAt: 9980 })];
|
||||
|
||||
const chosen = selectFrameForClick(frames, { clickAt, mode: 'fullscreen', strict: true, leadMs: 120 });
|
||||
|
||||
assert.equal(chosen.name, 'right-before');
|
||||
});
|
||||
|
||||
test('the click lead still returns null when no frame precedes the click at all', () => {
|
||||
const clickAt = 10_000;
|
||||
const frames = [frame('after', { startedAt: 10_050, capturedAt: 10_080 })];
|
||||
|
||||
assert.equal(selectFrameForClick(frames, { clickAt, strict: true, leadMs: 120 }), null,
|
||||
'a post-click frame is never selected; the caller takes the fresh-shot fallback');
|
||||
});
|
||||
|
||||
test('a frame without startedAt falls back to capturedAt for the strict check', () => {
|
||||
const clickAt = 10_000;
|
||||
const before = frame('legacy-before', { capturedAt: 9950 });
|
||||
|
||||
Reference in New Issue
Block a user