Skip to content

fix(core): a host inside a scene keeps its own timeline when its file shares a composition id - #7143

Merged
miguel-heygen merged 4 commits into
mainfrom
dslowedit/nested-timeline-keys
Nov 4, 2026
Merged

miguel-heygen merged 4 commits into
mainfrom
dslowedit/nested-timeline-keys

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

What changed

A sub-composition host that sits inside a scene now registers its script's timeline under its own data-composition-id, as a host in index.html already does. Before, the bundler read every host's identity from the map it builds over the root document's hosts; a host inside a scene is not in that map, so it got no runtime id and its script fell back to its file's authored id. Two such hosts whose files share an authored id (two caption layers made from one caption style, say) then registered one timeline key: the first host played the second one's content and the second played none.

inlineSubCompositions now uses the map's entry when there is one and reads a host it lacks from its own attribute, which is what the no-map path already does.

What I measured

Two caption layers of one style (each file's root and timeline id is the style's name), one per take, under hosts caption-…-a-1 and caption-…-b-1; snapshot at 1 s (take A plays) and 8 s (take B plays):

Hosts 1 s 8 s each layer script's __hfTimelineCompId
in index.html take A's words take B's words its host's id
inside a scene take B's words none the style's id, both
  • htmlBundler.nestedTimelines.test.ts before the fix: fails, expected [ 'caption-style', 'caption-style' ] to deeply equal ArrayContaining ["take-a", "take-b"]. After: passes, 3 runs in a row.
  • pageBuild.golden.test.ts: the repeated-scenes project nests a badge scene in each card. Its goldens change in one way only: the nested badge's flattened inner root drops a data-composition-id="badge" that repeated its host's id. That is how a top-level scene's inner root already reads when its id equals its host's; the host still carries data-composition-id="badge". Updated with vitest -u.

fails without the fix: packages/core/src/compiler/htmlBundler.nestedTimelines.test.ts "gives each host inside a scene its own timeline, even when their files share a composition id".

What I did NOT exercise

  • Two hosts inside one scene with the SAME host id (the repeated cards' nested badges all read badge) still share one timeline key, as before this change: nested hosts get no per-instance ids the way top-level duplicates do. Not touched here.
  • The runtime's own mount path (runtime/compositionLoader.ts, used when a page loads compositions live) is not changed; the snapshot above goes through the bundler.

Size

Small on purpose: one decision in the bundler and the test that pins it, a separate fix from any per-instance ids for nested duplicates, so either can be reverted alone.

Size: stands alone, it is the engine half of a reported bug whose app half shipped.

@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 · 1 important · 0 nits · head b27c744e

  • important: packages/core/src/compiler/inlineSubCompositions.ts:476-480: the optional Comments ratchet fails on this head. The file's comment share rose from 20.1% to 20.3% because of 2 added comment lines: the extra docstring line at :228 and the new inline comment at :480. Cutting one of them should turn it green. The check isn't required, so it doesn't block this approval.
What I checked
  • The test fails without the fix. I reverted only inlineSubCompositions.ts to origin/main. The new test then fails with expected [ 'caption-style', 'caption-style' ] to deeply equal ArrayContaining ["take-a","take-b"], and the repeated-scenes goldens fail too. At head, both files pass, 5/5 tests.
  • The new path matches existing ones. A nested host now takes the same branch as a top-level host the map has already met, and as the producer path that passes no map. The producer already read nested hosts from their own attribute, so after this change the bundler and the producer agree.
  • Host id differs from the file's root id. planCompositionAssembly then finds no innerRoot, so the whole body, including the file's own root, is mounted under the host. That is the same as the top-level mismatch case. One consequence: data-width/data-height, data-timeline-locked and data-no-timeline are no longer copied from the inner root onto a nested host. Top-level hosts already behave this way.
  • Host id matches the file's root id. The root is flattened, and its now-redundant data-composition-id is dropped. The host still carries the id, which is the golden diff.
  • No other sites need the change. hostIdentityMap is read only here.
  • CI: at the time of review, PR captures and preview-regression were green and Comments had failed (it isn't required). The required CI/regression/Windows checks were still running.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

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

@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, 1 open, 0 new · b27c744e → 99396333. The only code change is the removed inline comment. The optional Comments ratchet is still red: the file is 20.2% (168/832) against 20.1% at the base, because of the extra docstring line at inlineSubCompositions.ts:228-229. Folding that back to one line turns it green. This does not block.

@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 · 1 resolved, 0 open, 0 new · 99396333 → 186df662. The only change is the docstring, now reworded to its original 3-line length, and it still describes the behavior correctly. That should clear the Comments ratchet; its run on this head was still in progress when I approved.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit 7e71718 Nov 4, 2026
142 checks passed
@miguel-heygen
miguel-heygen deleted the dslowedit/nested-timeline-keys branch November 4, 2026 06:15
SanHsien added a commit to SanHsien/hyperframes that referenced this pull request Nov 4, 2026
…heygen-com#7155; review through 1ff4cef

- heygen-com#7143: inline nested sub-composition timelines (pageBuild goldens
  follow upstream).
- heygen-com#7151: makeOutputFolder skips mkdirSync for existing folders, so
  drive-root outputs like C:\ no longer fail with EPERM.
- heygen-com#7154: a page that never becomes ready reports PAGE_NEVER_READY
  instead of a generic evaluate timeout (adapted by hand).
- heygen-com#7155: cloud upload error handling.
Watermarks: commit 1ff4cef, PR 7157; monitored 88. Ledger in
docs/UPSTREAM_REVIEW_2026-11-04_CONTINUED.md.

Co-authored-by: Miguel Ángel <[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