From 874b323e6c0e76008a594141d0edf16cfbe146f5 Mon Sep 17 00:00:00 2001 From: Val Date: Wed, 26 Aug 2026 15:46:52 -0700 Subject: [PATCH] fix(core,producer): stamp render ids on empty-src media and pair the snapshot by them Residual of #3340: runtime-assigned src is skipped by the static parse, so the browser snapshot was still keying clips by author id. Colliding scenes collapsed onto one window. --- .../core/src/compiler/mediaRenderIds.test.ts | 23 +++++++++--- packages/core/src/compiler/mediaRenderIds.ts | 22 ++++-------- .../src/services/htmlCompiler.test.ts | 35 +++++++++++++++++++ .../producer/src/services/htmlCompiler.ts | 24 ++++++++++--- 4 files changed, 79 insertions(+), 25 deletions(-) diff --git a/packages/core/src/compiler/mediaRenderIds.test.ts b/packages/core/src/compiler/mediaRenderIds.test.ts index 7552ca062f..4e6bfab329 100644 --- a/packages/core/src/compiler/mediaRenderIds.test.ts +++ b/packages/core/src/compiler/mediaRenderIds.test.ts @@ -75,10 +75,25 @@ describe("assignMediaRenderIds", () => { expect(ids[1]).toBe("clip__hf2"); }); - it("leaves media with no source at all alone", () => { + it("stamps empty-src media with colliding author ids", () => { + // `src=""` used to skip the stamp. The snapshot then keyed by raw id and + // colliding scenes collapsed. Runtime assignment is why the src is empty, + // not a second path this function sees. + const { document } = parseHTML( + '', + ); + assignMediaRenderIds(document as unknown as Parameters[0]); + expect( + Array.from(document.querySelectorAll("video")).map((el) => + el.getAttribute(MEDIA_RENDER_ID_ATTR), + ), + ).toEqual(["clip", "clip__hf2"]); + }); + + it("stamps a video with no source attribute at all", () => { const { document } = parseHTML(''); assignMediaRenderIds(document as unknown as Parameters[0]); - expect(document.querySelector("video")?.hasAttribute(MEDIA_RENDER_ID_ATTR)).toBe(false); + expect(document.querySelector("video")?.getAttribute(MEDIA_RENDER_ID_ATTR)).toBe("no-src"); }); it("stamps media whose source is a child rather than a src attribute", () => { @@ -103,10 +118,10 @@ describe("assignMediaRenderIds", () => { expect(document.querySelector("audio")?.getAttribute(MEDIA_RENDER_ID_ATTR)).toBe("bed"); }); - it("ignores a child that carries no src", () => { + it("stamps a video whose child carries no src", () => { const { document } = parseHTML(''); assignMediaRenderIds(document as unknown as Parameters[0]); - expect(document.querySelector("video")?.hasAttribute(MEDIA_RENDER_ID_ATTR)).toBe(false); + expect(document.querySelector("video")?.getAttribute(MEDIA_RENDER_ID_ATTR)).toBe("empty"); }); }); diff --git a/packages/core/src/compiler/mediaRenderIds.ts b/packages/core/src/compiler/mediaRenderIds.ts index 4c1f306b3a..9e2a545e7a 100644 --- a/packages/core/src/compiler/mediaRenderIds.ts +++ b/packages/core/src/compiler/mediaRenderIds.ts @@ -43,11 +43,12 @@ export const AUDIO_GROUP_RENDER_ID_ATTR = "data-hf-group-render-id"; /** * Elements the render pipeline addresses by id. * - * `