Skip to content

fix(core): avoid live volume probe during render - #2816

Merged
jrusso1020 merged 1 commit into
mainfrom
fix/2809-static-volume-live-seek
Jul 27, 2026
Merged

fix(core): avoid live volume probe during render#2816
jrusso1020 merged 1 commit into
mainfrom
fix/2809-static-volume-live-seek

Conversation

@jrusso1020

Copy link
Copy Markdown
Collaborator

Summary

  • mark producer-served pages before the Hyperframes runtime loads
  • prevent preview-only volume-envelope discovery from seeking the live visual timeline in render/probe pages
  • preserve Studio preview behavior and producer-side isolated audio automation discovery/baking
  • add the reported 12s/24fps/120-frame nested future-tl.set distributed golden

Fixes #2809.

Root cause

Runtime media initialization called probeAndCacheElementVolume() for every
audio/video element, including static data-volume media. The helper sampled
the captured GSAP timeline at 60 Hz across the media window and restored only
the numeric playhead. On a non-zero distributed cold start, future nested
zero-duration state could remain materialized before its authored time.

Producer pages do not need this live runtime probe: scripted volume automation
is already discovered in an isolated producer probe page and baked into audio
before frame capture.

Validation

  • core runtime typecheck
  • producer typecheck
  • core runtime: 42 files / 811 tests
  • producer file server: 49 tests
  • in-process fixture golden: 288/288 frames
  • distributed-simulated: 100/100 visual checkpoints, audio correlation 1.0
  • oxfmt, oxlint, fallow, large-file and tracked-artifact hooks
  • independent review: no findings

Real GCP (hyperframes-dev/us-east1)

Owner-isolated smoke using 120-frame chunks:

  • v1: success, 120,050 ms
  • Plan v2: success, 17,748 ms
  • encoded outputs byte-identical: 82,249 bytes, SHA-256
    f6d639c79226dd7ef93369c5f8b1e296895e8049ca8234d887615c6ff1965b31
  • decoded video, decoded audio, and normalized metadata exactly equal
  • direct Plan v2 frame extraction at master 7s shows the complete
    MUST BE VISIBLE panel in the non-zero-start chunk
  • all nine Terraform resources and owned image/staging/repository resources
    destroyed and verified absent

The cross-Chrome PSNR against the local Chrome 152 baseline was 34.78 dB. The
smoke was intentionally invoked with an over-strict 40 dB wrapper threshold;
both workflows and all exact parity/visibility checks succeeded.

<head>
<meta charset="utf-8" />
<title>Static volume with future nested set</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>

@miguel-heygen miguel-heygen 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.

Reviewed exact head 477defc7e7397684c2def4459b3981f62a06816d. No blocking findings.

The render/probe marker is injected before the runtime on every producer-served HTML page, the runtime-side guard disables only the live timeline sampling, and the helper defaults preserve Studio/preview discovery. Producer-side automation discovery remains in its separate probe pass and continues to bake keyframes before capture. The nested future-tl.set golden exercises the reported non-zero distributed cold-start failure shape. All CI, including the full regression matrix and Windows render/tests, is green.

The CodeQL CDN observation is confined to the deterministic regression fixture and the repository security checks are green; it does not alter the production path.

— Magi

Verdict: APPROVE
Reasoning: The change removes the render-time timeline mutation at the correct boundary while preserving preview and producer-side audio automation behavior.

@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 477defc7e7397684c2def4459b3981f62a06816d.

Clean small fix. The root cause reads correctly — probeAndCacheElementVolume() sampled the captured GSAP timeline at 60Hz across the media window and restored only the numeric playhead. That's fine for preview (single-composition, main timeline), but distributed cold-start chunks that begin at non-zero times were vulnerable: seeking the captured timeline forward materializes nested-composition scripted state (like a future tl.set(".future-state", { visibility: "hidden" }) at 9.65s), and restoring the playhead numerically doesn't reverse the state mutation the seek triggered.

The gate

Three files, one contract:

  • fileServer.ts:685 — new RENDER_CAPTURE_MODE_SHIM = "globalThis.__HF_RENDER_CAPTURE_MODE = true;" injected via preHeadScripts at line 721-725, so it lands BEFORE the HF runtime script. The createFileServer test at fileServer.test.ts:319-345 locks in the ordering: expect(html.indexOf(RENDER_CAPTURE_MODE_SHIM)).toBeLessThan(html.indexOf(runtimeScript)). Correct — a global mutated after runtime execution wouldn't gate initialization.

  • init.ts:1837-1840initSandboxRuntimeModular() reads the global and passes allowLiveTimelineSeek: !window.__HF_RENDER_CAPTURE_MODE. Preview pages don't inject the shim → __HF_RENDER_CAPTURE_MODE is undefined!undefined = true → probe runs as before. Render pages inject → true!true = false → probe short-circuits. Backward-compatible.

  • mediaVolumeEnvelope.ts:135-158VolumeProbeOptions.allowLiveTimelineSeek?: boolean. Early return at line 156 uses strict === false, so undefined (default when called without options) falls through to the original probe path. Existing callers unchanged.

The unit test does not seek or cache when live timeline probing is disabled at mediaVolumeEnvelope.test.ts:6-28 covers the exact contract: no seeks recorded, no cache entries added, media volume unchanged from author-declared value.

Regression fixture

static-volume-future-set/src/compositions/child.html sets up the reproducer: nested composition with timeline.set(".future-state", { visibility: "hidden" }, 9.65). Static-volume audio (data-volume="1") on the parent triggers probeAndCacheElementVolume on the child's captured timeline; the probe seeks to sample volume automation, materializing the future visibility: hidden prematurely. With chunkSize: 120 at 24fps = 5-second chunks, a chunk starting at t=5 (second chunk) would seek forward through 9.65 during the probe and lose the "MUST BE VISIBLE" panel.

maxAudioLagWindows: 120 (fixture-wide) is unusually permissive — this fixture uses silence.wav where correlation is meaningless, so widening the window past strict audio parity is the right call. maxFrameFailures: 0 keeps the visual assertion strict, which is what actually tests the fix.

The producer-side isolated discovery is untouched

Per your PR body: "producer-side isolated audio automation discovery/baking" still works. That's the isolated producer probe page (separate flow) — not touched by this PR, so scripted volume-automation coverage for baked audio is preserved. Verified by grep: probeAndCacheElementVolume is only called at init.ts:1837, and the producer's audio discovery uses its own separate probe path in packages/producer/src/services/audioExtractor.ts (unrelated code).

Small note

  • GitHub Advanced Security flagged the CDN-loaded GSAP <script> in static-volume-future-set/src/index.html — expected for the test fixture. Not a security concern for test infrastructure. Every other distributed fixture that needs GSAP does the same.

Nothing blocking. LGTM.

Review by Rames D Jusso

@jrusso1020
jrusso1020 merged commit 6c98e54 into main Jul 27, 2026
53 checks passed
@jrusso1020
jrusso1020 deleted the fix/2809-static-volume-live-seek branch July 27, 2026 01:11
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.

Runtime audio-volume probe seeks live GSAP timeline and applies future tl.set state to earlier chunks

4 participants