From 65349a3ccfccadcceb0d78a0c415f38ba37ed684 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Tue, 7 Jul 2026 21:12:34 -0700 Subject: [PATCH] fix(engine): fail-fast the sub-composition timeline wait when a script 404s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pollSubCompositionTimelines waits for every [data-composition-id] host to register window.__timelines[id]. When the script carrying that registration fails to load (404 / request failure), the registration can never arrive — but the poll still burned the full playerReadyTimeout (45s), then warned and shipped a silently animation-less render. Wild scale: the capture-setup histogram over 30 days of local renders decays smoothly (402/503/364/282/191 per 5s bucket) then spikes to 705 at the 45s bucket — ~1,000 renders/month across 402 distinct users, ~15 user-hours of pure waiting. - Sessions now record failed SCRIPT resources (requestfailed + HTTP>=400 response, listeners that already existed for diagnostics) in session.scriptLoadFailures. - pollSubCompositionTimelines takes a failure getter and cuts the wait to a 2s grace once any script failed, with a loud warning naming the URL(s). Late-registering fetch-async comps are unaffected: no script failure means the full timeout still applies, and a registration landing inside the grace window still wins (tested). - Outcome telemetry: session.subTimelineWaitOutcome ("ready" | "timeout" | "script_failure") -> CapturePerfSummary -> RenderPerfSummary.subTimelineWait (worst across sessions) -> render_complete sub_timeline_wait, so the wild rate becomes directly trackable instead of setup-histogram forensics. Validation: the discovery comp (0768f038, its animations.js unreachable) drops from ~72s to 23.1s total — poll cut at 2.1s with the script named; healthy comp reports "ready". Canary suite 7/7 (PSNRs identical). 4 new poll unit tests; engine suite 907 passed (14 failures are PRE-EXISTING on main at v0.7.42 — 18 fail on a clean checkout, stash A/B verified). tsc/oxlint/oxfmt clean. Corpus note: 258/1,762 corpus comps (14%) reference local scripts missing from the corpus fetch — their historical eval INIT timings measured this timeout, not the engine. Capture-stage ratios remain valid (both paths paid it equally). Co-Authored-By: Claude Fable 5 --- packages/cli/src/commands/render.ts | 1 + packages/cli/src/telemetry/events.ts | 2 + .../frameCapture-subTimelinePoll.test.ts | 66 ++++++++++++++ packages/engine/src/services/frameCapture.ts | 90 ++++++++++++++----- packages/engine/src/types.ts | 2 + .../src/services/render/perfSummary.ts | 10 +++ .../src/services/renderOrchestrator.ts | 2 + 7 files changed, 150 insertions(+), 23 deletions(-) create mode 100644 packages/engine/src/services/frameCapture-subTimelinePoll.test.ts diff --git a/packages/cli/src/commands/render.ts b/packages/cli/src/commands/render.ts index a07e1c988..08904c67c 100644 --- a/packages/cli/src/commands/render.ts +++ b/packages/cli/src/commands/render.ts @@ -1700,6 +1700,7 @@ function trackRenderMetrics( speedRatio, captureAvgMs: perf?.captureAvgMs, captureP50Ms: perf?.captureP50Ms, + subTimelineWait: perf?.subTimelineWait, videoCount: perf?.videoCount, capturePeakMs: perf?.capturePeakMs, tmpPeakBytes: perf?.tmpPeakBytes, diff --git a/packages/cli/src/telemetry/events.ts b/packages/cli/src/telemetry/events.ts index a6d017676..db4f30feb 100644 --- a/packages/cli/src/telemetry/events.ts +++ b/packages/cli/src/telemetry/events.ts @@ -148,6 +148,7 @@ export function trackRenderComplete( captureAvgMs?: number; /** Warmup-robust per-frame capture median (basis for speedup estimates). */ captureP50Ms?: number; + subTimelineWait?: string; /**