Skip to content

fix(cli): check finishes on long projects with many video clips - #6270

Merged
miguel-heygen merged 2 commits into
mainfrom
checklong/check-defer-media
Oct 25, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
checklong/check-defer-media

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

hyperframes check now finishes on long projects with many video clips. Before, a 500 s project with 137 clips of one 1440p source failed at the 120 s deadline.

Why

check loaded every <video> in the project at once. On that project one renderer reached 6.4 GB (all renderers together 15.75 GB). The second sampling Chrome crashed, and a crashed puppeteer page emits error but never settles the calls pending on it, so the run waited out the idle deadline. The same project pinned to one Chrome passed, which is how the cause was found. Narrowing with --range did not help: --range 0,20 --samples 1 failed the same way, because the page loads the whole project before any range applies.

How

  • check marks its page with Studio's existing capture mode (hyperframes-studio-preview meta, content="capture"), the mode Studio's own screenshot path uses. Only media near the playhead loads, so decoders no longer pile up.
  • The clip-fit audit (auditClipDurations) could no longer read the duration of audio the page never loaded, so it reads it from a detached element on the same source.
  • createPageDriver settles every call with the page's error or close. A dead helper page now hands its samples back to the main page (the existing recovery path, which never ran for a hang), and a dead main page fails at once with "The page crashed".

Not in this PR: splitting a long check into parallel time windows. A 500 s project now checks in about half a minute, so it is not needed yet. Printing the partial report when check is killed by a signal is a separate change.

Test plan

Measured on a 4-core Linux box, check --json, fixtures built for this (a 1440p H.264 source cut into many clips, synthetic audio):

Fixture Before After
500 s, 137 clips of one 1440p source, 41 audio fails at 124 s passes in 31 s
same project, one Chrome 73 s 29 s
same project, --range 0,20 --samples 1 fails at 131 s passes in 4 s
same project, --timeout 15000 not run passes in 17 s
570 s, 957 MB H.264 14 s 9 s
27 s film, one-keyframe 300 s source 11 s 10 s

Peak renderer memory on the first fixture went from 15.75 GB to 1.77 GB. The findings (code, severity, message) are identical before and after on the first three fixtures, compared against a one-Chrome run without the change.

  • Unit tests added: a helper whose page crashes and leaves its seek pending, a main page that crashes, the capture-mode marker, and the audio duration probe.
  • Each fix broken in turn: dead-page guard (2 tests fail), marker (1 fails), duration probe (1 fails); restored, three green runs of the three test files (48, 10 and 21 tests).
  • Manual testing performed (table above).

The previous helper-crash test threw Target closed from the seek, which real puppeteer does not do for a renderer crash. That is why the hang was not covered; the new test models the real behaviour (page emits error, call stays pending).

check loaded every video in the project at once. On a 500 s project with 137
clips of one 1440p source a single renderer reached 6.4 GB, the second sampling
Chrome crashed, and a crashed puppeteer page never settles its calls, so the
run sat until the 120 s deadline.

- Load the check page in Studio's capture mode so only media near the
  playhead loads (peak renderer memory 15.75 GB -> 1.77 GB).
- Read audio durations for the clip-fit audit from a detached element when the
  page has not loaded the one in the composition.
- Settle every driver call with the page's crash or close, so a dead helper
  hands its samples back and a dead main page fails at once.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: APPROVE · 0 blocker · 1 important · 1 nit · head 16043914

  • important — Comments ratchet is red (not a required check): the PR adds 2 comment lines to packages/cli/src/commands/validate.ts and 3 to packages/cli/src/utils/checkBrowser.ts. Cut them, or move the explanation into names.
  • nit — failWhenPageDies only wraps driver calls. If the main page crashes before createPageDriver (auditClipDurations, collectTweenRecords, collectMotionBlurDrafts, checkBrowser.ts:342-350) or in abortedImagesStillBroken, the check still waits out the deadline.
Scope

I read all 4 files end to end and traced the capture-mode path: deferMediaUntilDue keeps src, the holdSeekBarrierUntilVideoLands barrier waits for a deferred clip at each sample, and missing_local_asset lint still catches missing files that are never fetched. I also checked the helper recovery on a rejected call. CI on this head: Test, Typecheck and Build are green. Two Studio edit-accuracy shards were still running when I posted. I could not run the tests locally because the core build was missing.

@github-actions

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 171 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

Unstable (1)

  • seqplainkeys-none-pct-r0-root-z100: tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo false, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit 37f5f27 Oct 25, 2026
67 of 68 checks passed
@miguel-heygen
miguel-heygen deleted the checklong/check-defer-media branch October 25, 2026 03:49
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.

1 participant