Skip to content

fix(engine): report a pending setup as a setup timeout, not zero duration - #7211

Merged
jrusso1020 merged 5 commits into
mainfrom
fix/engine-setup-timeout-diagnostic
Nov 5, 2026
Merged

jrusso1020 merged 5 commits into
mainfrom
fix/engine-setup-timeout-diagnostic

Conversation

@jrusso1020

@jrusso1020 jrusso1020 commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

What

When a render gives up waiting for the page to finish setup, the error now says so: Composition setup did not finish within 45000ms. It used to say Composition has zero duration., even for compositions that declare a data-duration. The CLI reports a new code for it, COMPOSITION_SETUP_TIMEOUT.

Why

Before render-ready, the bridge reports __hf.duration as 0. So when pollHfReady timed out because a window.__hf.buildReady promise never settled, the timeout headline said the composition had zero duration. That sends authors looking at their timing attributes when the real problem is setup that never finished. We hit this on a Three.js path-tracing study: its setup waited on an animation frame, which the render clock holds until the first seek.

Related work

Refs the 3D path-tracing follow-up. EF's render-metrics classifier gets a matching row in heygen-com/experiment-framework#65311. We considered letting animation frames run before the first seek (#7213) and closed it, because it made frame-counting loops depend on load time. The render clock stays strict, and this message tells authors how to wait instead.

How

  • buildZeroDurationDiagnostic takes the timeout and picks the headline from renderReady:
    • Not ready: "Composition setup did not finish within Nms."
    • Ready with zero duration: the old "Composition has zero duration."
  • The pending-buildReady hint now also explains the render clock. Date and performance.now stay at 0, and requestAnimationFrame callbacks wait until the first frame, so setup that awaits either never finishes. The hint points authors at the library's own readiness promise (for Three.js, renderer.compileAsync), not a hand-written timer.
  • Not covered here: a scheduler.yield() polling loop. In plain headless Chrome 152 (macOS Metal and Linux), a ten-line page that polls a setTimeout flag with await scheduler.yield() never finishes loading, because yield continuations outrank timers. That starves the page, so the readiness poll never returns and the render ends in a capture stall instead of this message. That guidance goes in the 3D docs and starter recipe.
  • The "no GSAP timeline" hint now shows only once the runtime is ready. Before that, its advice about inferring duration doesn't apply yet.
  • Retry behavior is unchanged: the new message is classified as transient, just like the old zero duration ... Runtime ready: false message.
  • The CLI maps the new message to COMPOSITION_SETUP_TIMEOUT.

Other consumers that match on the old text:

  • EF's render-metrics classifier: gets the follow-up PR mentioned above.
  • HFI's studio-contracts stderrKind: maps Composition has zero duration to composition-empty. Setup timeouts will now land in other there, which is more accurate than "empty".

Test plan

  • Unit tests added/updated:
    • frameCapture.test.ts: three cases. A pending setup gets the setup headline and the clock hint. The timeline hint is skipped while pending. A ready, zero-duration page keeps the old headline.
    • captureFailure.test.ts: the new message is classified as transient.
    • renderDiagnostic.test.ts: the new message maps to COMPOSITION_SETUP_TIMEOUT.
    • The three new frameCapture cases fail on main and pass here.
  • Manual testing performed: rendered 1 s Three.js compositions whose setup waits for performance.now() to advance, or awaits one animation frame,, using the CLI built from this branch (software GL). It fails after 45 s with:
    [FrameCapture] Composition setup did not finish within 45000ms.
      Runtime ready: false, __player: true, __hf.seek: true, GSAP timeline: false, data-duration: 1s
      → window.__hf.buildReady never resolved for: scene. ... During a render, Date and performance.now stay at 0 and requestAnimationFrame callbacks wait until the first frame, so setup that awaits an animation frame or the clock never finishes. Await the library's own readiness promise instead (for Three.js, renderer.compileAsync).
    @hf-diagnostic {"version":1,"operation":"render","code":"COMPOSITION_SETUP_TIMEOUT"}
    
  • Documentation updated (if applicable): no doc names this message.
  • Comments follow CONTRIBUTING.md "Comments".

🤖 Generated with Claude Code

…ration

When the runtime never reaches render-ready, __hf.duration reads 0 because
the bridge masks it, so pollHfReady's timeout reported "Composition has zero
duration" even for compositions with a declared data-duration whose
window.__hf.buildReady promise was still pending. Headline that case as
"Composition setup did not finish within <timeout>ms", skip the duration
inference hint that cannot apply yet, and note that the render clock stays
at 0 until the first frame. Keep its transient retry classification and give
it its own CLI diagnostic code.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 113 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 (8)

Unstable (1)

  • seqab-none-center-r0-root-z100: tracking 0.03, pressJump 0, drop 0, reload 0, render 0.02, renderKey -, undo true, teleport true / tracking 0.03, pressJump 0, drop 0, reload 0, render 0.02, renderKey -, undo true, teleport true / tracking 0.03, pressJump 0, drop 0, reload 0, render 0.02, renderKey -, undo true, teleport true

@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 · 0 important · 0 nits
The headline now comes from renderReady, and every in-repo matcher is updated: captureFailure (still transient) and the CLI captureCodeOf. The only out-of-repo consumers are EF's classifier (#65311 in experiment-framework) and HFI's stderrKind (now other), and the PR body names both. CI is green at e353a6d. One note for #7213: this hint tells authors that waiting on the clock never finishes. That stays true after #7213, which keeps Date and performance.now frozen.

— Genesis

Setup that awaits requestAnimationFrame hits the same render-clock rule as
setup that waits on Date or performance.now: frames only fire on a seek, and
the first seek waits for setup. Say so, and point at the waits that work.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

@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 resolved, 0 open, 0 new · e353a6d → 5508ff2. The new hint matches the strict clock: the shim never wraps setTimeout, and scheduler.yield() exists in the pinned Chrome 152 (150 on macOS 12). CI is green.

— Genesis

jrusso1020 and others added 3 commits November 5, 2026 05:10
Chrome runs scheduler.yield() continuations ahead of ordinary tasks, so a
setup loop that polls with it starves the setTimeout-driven work it waits on
(Three's compileAsync polls with setTimeout(10)) and never finishes. Plain
headless Chrome 152 hangs on a ten-line page that does exactly that. Point
authors at setTimeout and say why yield-polling does not work.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
HyperFrames guidance is no system timers, so the hint should not tell authors
to wait with setTimeout. Point them at the library's own readiness promise
(Three.js renderer.compileAsync) and keep the warning about scheduler.yield()
polling loops.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A scheduler.yield() polling loop starves the page, so the readiness poll never
returns and the render reports a capture stall instead of this message. Drop
that sentence; the hint covers animation-frame and clock waits only.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

@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 resolved, 0 open, 0 new · 5508ff2 → 4da6c5e. Supersedes my 5508ff2 note: scheduler.yield() is not safe advice. The hint now only covers animation-frame and clock waits, and its example holds under the strict clock. Three.js compileAsync (r187) checks shader status on its own setTimeout, with no animation frames and no clock. CI is green.

— Genesis

@jrusso1020
jrusso1020 added this pull request to the merge queue Nov 5, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 5, 2026
@jrusso1020
jrusso1020 added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit b98718f Nov 5, 2026
93 of 94 checks passed
@jrusso1020
jrusso1020 deleted the fix/engine-setup-timeout-diagnostic branch November 5, 2026 07:57
SanHsien added a commit to SanHsien/hyperframes that referenced this pull request Nov 6, 2026
…eview

Adopts or partially adopts 8 groups: capture-failure diagnostics and
frame-capture retry in engine, ffprobe fixes, renderOrchestrator
updates, studio-server render/files/source-mutation routes, CLI
screenshot retry and init/snapshot/timeline fixes, and the motion-blur
land-then-undo path (fork seek recovery kept). Left out with ledger
reasons: heygen-com#7211 render diagnostic CLI, heygen-com#7089 reverse start; heygen-com#7220
deferred. Core packed budget grows by the measured 1065 bytes since
upstream heygen-com#7191 changed no budget. Watermark advances to 659ef56.

Co-authored-by: Miguel Ángel <[email protected]>
Co-authored-by: WaterrrForever <[email protected]>
Co-authored-by: Vance Ingalls <[email protected]>
Co-authored-by: James Russo <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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