Fast-capture: fallback-ratio guard for #3423 x #3429 seam (100%-fallback renders pass artifact validation)
Context
PR #3480 (branch fix/draw-element-canvas-fallback, closes #3423) added a
per-frame screenshot fallback for the drawElement fast-capture path: when
drawElementImage throws a recoverable error (canvas not initialized, or
the native "No cached paint record" InvalidStateError), the affected frame
falls back to Page.captureScreenshot instead of hard-failing the render.
Review feedback on #3480 (from tai) flagged a seam with PR #3429's artifact
validation (ArtifactTransaction.validate() /
packages/producer/src/services/render/artifactTransaction.ts):
If a composition is 100% broken and every frame falls back to screenshot capture, the render passes #3429's artifact validation (correct frame count, correct duration) but ships N wrong-pixel frames as "complete."
To be precise about the actual risk: the screenshot fallback itself produces correct pixels (it's the platform's normal, well-tested capture path) — the real risk is a silent, total loss of the fast-capture speedup (and by extension a masked persistent bug, e.g. a canvas-injection regression) going completely unnoticed because the render still "succeeds" with the right frame count/duration. Today nothing distinguishes "recovered a handful of edge-case frames" from "drawElement never engaged for the whole render" in either telemetry or artifact validation.
What #3480 does today
getCapturePerfSummary() in packages/engine/src/services/frameCapture.ts
now emits a console.warn when deNcprFallbacks / frames exceeds 50%, so
the condition is at least visible in render logs / telemetry ingestion.
This is a diagnostic only — it does not fail or flag the render artifact.
Follow-up needed (pick one, or combine)
- Fallback-ratio circuit breaker (engine or producer-side): if the
realized
deNcprFallbacks / framesratio exceeds some threshold (e.g. 50%), fail the render explicitly instead of shipping it as "complete" — forcing a re-render withforceScreenshot(which the orchestrator already knows how to do forDrawElementVerificationError) rather than silently accepting a render that never got the fast-capture speedup. deNcprFallbacks/framesguard on the #3429 side: thread the ratio (already available viaCapturePerfSummary.deNcprFallbacks/RenderPerfSummary) intoArtifactTransaction.validate()or the orchestrator's post-render checks, so artifact validation can distinguish "correct frame count via drawElement" from "correct frame count via total fallback."- At minimum: promote the current warn-only diagnostic into a structured
CaptureWarning/ render-telemetry field so it's queryable across the fleet, not just visible in ad hoc log scraping.
Pointers
packages/engine/src/services/frameCapture.ts:getCapturePerfSummary(ratio warning),captureFrameCore/captureFrameToBufferPipelined/captureFramesBatchPipelined(the three per-frame/batch fallback sites),CaptureSession.deNcprFallbacks.packages/engine/src/services/drawElementService.ts:DE_CANVAS_NOT_INITIALIZED_CODE,produceDrawElementFrameBatch.packages/producer/src/services/render/artifactTransaction.ts:ArtifactTransaction.validate()(current frame-count/duration-blind validation).
Filed from PR #3480 review discussion (reviewer: tai).
Source: heygen-com/hyperframes