Skip to content

fix(render): reject incomplete captured frames#2293

Merged
miguel-heygen merged 1 commit into
mainfrom
fix/verify-encoded-frame-count
Jul 13, 2026
Merged

fix(render): reject incomplete captured frames#2293
miguel-heygen merged 1 commit into
mainfrom
fix/verify-encoded-frame-count

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

Treat tiny capture-worker frame placeholders as missing frames before encoding.

Why

A Windows multi-worker render reported success even though its video stopped at frame 2,855 while audio continued to the full 229.5 seconds. Locally, an image sequence containing a one-byte worker placeholder reproduced the integrity failure: FFmpeg stopped at the placeholder, emitted only the prefix, and still exited with status 0. The existing capture continuity check only tested file existence, so it accepted the placeholder as a completed frame.

How

  • Require captured JPEG/PNG frame files to be larger than the 8-byte image-signature floor when scanning continuity.
  • Let the existing adaptive missing-frame path retry or fail the affected range instead of encoding a truncated prefix.
  • Add a regression test for a one-byte placeholder inside an otherwise contiguous sequence.

Test plan

  • Reproduced FFmpeg exit-0 truncation locally with a one-byte frame placeholder.
  • bunx vitest run src/services/renderOrchestrator.test.ts (140 passed)
  • bun run test:unit
  • bun run typecheck
  • bunx oxfmt --check src/services/renderOrchestrator.ts src/services/renderOrchestrator.test.ts
  • bunx oxlint src/services/renderOrchestrator.ts src/services/renderOrchestrator.test.ts

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 3bda0b9c.

Correct root-cause fix. Verified findMissingFrameRanges is the single canonical "which frames need retry" gate — callers at renderOrchestrator.ts:844,881,943 all pipe through this one function. No sibling existsSync-only checks elsewhere in the producer that would still accept placeholder frames.

The 8-byte threshold correctly catches the reported failure mode: PNG's full magic signature is exactly 8 bytes, and any legitimate JPEG is far larger than its 3-byte SOI marker. <= 8 cleanly separates "worker exited between open() and write()" from "real captured frame." Short-circuit !existsSync(framePath) || statSync(...) avoids the ENOENT case on the fast path.

Test coverage matches the fix's shape: the new test proves a 1-byte placeholder mid-sequence gets reported as a retry range, and the earlier tests were rewritten from "x" (1 byte) to "captured-frame" (14 bytes) so the existing "contiguous missing" test still exercises the presence path rather than accidentally tripping the new guard. Ratchet.

Not addressed here (and probably not this PR's job): JPEG/PNG files that survive the size threshold but are still structurally truncated (e.g., a worker that crashed after writing headers but before end-of-image markers). If that recurs on Windows post-fix, a follow-up could tighten to a decoder-level integrity check — but decoding N frames on the retry path would be a real perf hit for the tail case. The 8-byte pragmatic minimum is the right first cut.

LGTM.

Review by Rames D Jusso

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving on Rames-D's go (R2 delta clean, nit round addressed) + Magi's CI-green confirmation. Verified at final head 3bda0b9c: CI green, no changes-requested, mergeable.

@miguel-heygen miguel-heygen merged commit 9958854 into main Jul 13, 2026
48 checks passed
@miguel-heygen miguel-heygen deleted the fix/verify-encoded-frame-count branch July 13, 2026 02:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants