fix(engine,producer): fix quadratic dedup rescan, correct race justification

Address two max-effort code-review findings on PR #2056 not covered by
the earlier review-gap commit:

- captureFrameToBufferPipelined's static-dedup reuse branch never
  advanced session.lastEncodeResultFrame, unlike its sibling real-capture
  branches. The gap-check window is computed from that watermark, so
  every consecutive reuse in a static run rescanned an ever-widening
  window instead of just the newest frame — O(n^2) total work over a
  long static stretch instead of O(n).

- The "single-threaded, no race" justification on the shared
  parallelGuard closure was wrong: the guard has real internal await
  points (recapture, PSNR) between reading and writing its
  sizes/absFloor/acceptedSmall state, so concurrent workers' calls do
  interleave there (confirmed). Replaced with the actual reason it's
  safe: absFloor only ratchets down, sizes is append-only and
  order-independent for the median, and acceptedSmall's fast path
  re-validates by exact byte-equality regardless of which worker wrote
  the reference buffer.
This commit is contained in:
Vance Ingalls
2026-07-08 16:11:46 -07:00
parent 2dbe958a49
commit 381887541f
2 changed files with 17 additions and 5 deletions
@@ -2677,6 +2677,11 @@ export async function captureFrameToBufferPipelined(
if (gapStatic) {
session.staticDedupCount = (session.staticDedupCount ?? 0) + 1;
session.capturePerf.frames += 1;
// Advance the watermark on reuse too, not just on real captures — the
// gap-check above starts from lastEncodeResultFrame, so leaving it
// pinned to the last REAL capture makes every consecutive reuse rescan
// an ever-widening window instead of just the one new frame (review).
session.lastEncodeResultFrame = frameIndex;
return { encodeResult: session.lastEncodeResult, captureTimeMs: Date.now() - startTime };
}
}