test(studio): add T11 history coalescing and cross-prop separation suite#1242
Conversation
0b25203 to
f6031a6
Compare
2f91440 to
0e5c2d5
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
T11 — two substantive tests are good:
- Same
coalesceKey→ coalesces correctly (before from first entry, after from second, id from second ✅) - Different
coalesceKey→ no coalesce ✅
The prop:title.color / prop:body.color key format isn't defined anywhere yet — fine for now, but R5/R6 should canonicalize this format and these tests should be updated to match.
The two .todos are placed between the new tests and an existing test ("does not coalesce source editor edits outside the coalesce window"), which breaks the visual flow a bit. Minor, but consider moving todos to the bottom of their describe block.
✅ Approve.
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Hey Vance — T11 lands a clean cross-prop separation test plus two .todo stubs blocked on R5/R6 infrastructure. The cross-prop test is the load-bearing one and pins exactly the coalescer's key-discrimination logic the refactor will need to preserve. No blockers. Two notes on coverage shape + a PR-body count nit.
What I verified
Walked each test against "what could R5/R6 break that this catches":
- Same-coalesceKey within window (test 1) — coalesces to one entry, file-state runs
before: "a", after: "c"end-to-end. Locks that the coalescer accumulates file deltas correctly across coalesced entries, not just the latest. Load-bearing for any refactor that touches the merge path. - Cross-prop separation (test 2) — two entries with different
coalesceKeyvalues within the same coalesce window → two separate undo entries. The most load-bearing test in this PR. If R5 introduces a gesture lifecycle that auto-generates coalesceKeys, this test catches "two distinct prop edits got bucketed into one undo because the new keying scheme collided." Hard to over-praise this one. .todos — both are correctly punted to where the API exists. Gesture lifecycle needs R5; SDK session needs the SDK runtime bridge (R6). Honest scope.
Concerns
- PR body says "New passing test (1)" but the diff adds two passing tests (same-key + cross-prop) plus two
.todos. Worth tightening the PR body so the reader's mental model matches the diff. The same-key test is a complementaryprop:-keyed re-assertion that the existing same-key coalescing pattern still works under the newprop:keying convention — that's a useful safety net, just under-described. - Window-edge coverage is missing. Tests 1 and 2 both use
now: 100andnow: 200withcoalesceMs: 1000— comfortably inside the window. There's no test that exercises the boundary, e.g.now: 100andnow: 1100withcoalesceMs: 1000(exactly-at-window — coalesce? separate?). The contract at the edge is the kind of thing a refactor can flip silently. The existing test file (per the diff context at line 209) has "outside the coalesce window" — assuming that coversnow: 1101+, but pinning exactly-at-window would close the boundary gap. Cheap one-line test. (See nit.) - The
.todofororigin:applyPatchesis the highest-value future test in this PR. "SDK patches don't push to undo stack to prevent undo loops" is the kind of contract that, if it regresses, surfaces as user-visible weirdness (undo button does nothing, or worse, infinite undo loop). Worth flagging in the R6 PR description as a hard precondition for merge.
Nits
- Add a boundary test:
now: 100+now: 100 + coalesceMs— is exactly-at-window a coalesce or a split? Both behaviors are defensible; the codebase's current answer should be locked. One test, three lines. (nit) - Both
.todostubs reference future APIs (session.on("patch", ...),session.dispatch(...)) only in the text. Worth a// blocked by: R5 gesture lifecycle / R6 SDK session — see plan doccomment so they don't sit forever as "todo without context." If there's a Linear ticket per R-number, the cross-link is even better. (nit) - Coalesce-key format
prop:title.coloris implied but not documented in the test file. A one-line comment at the top of the describe block — "coalesceKeyshape:prop:<elementId>.<propName>for studio prop edits" — would make the test self-explanatory for someone reading the file cold. The next reader will be the R5 author trying to honor this contract; cheap to help them. (nit) - Both new tests use
kind: "source". Ifkindparticipates in coalescing decisions (e.g. onlysourcekinds coalesce, orsourcevssdkkinds never coalesce), there's no test pinning that. Out of scope for this PR but worth a future ticket. (nit)
Questions
- The
.todofor gesture-start/commit drag steps — what's the planned API shape?gesture.start(coalesceKey) ... gesture.commit()with a single undo entry on commit, or something else? Asking because the answer affects whether the existingcoalesceKey+ window approach gets replaced or extended. - Is
coalesceKey: undefinedvalid today (legacy edit shape), and if so, what's the coalesce behavior? No test covers the undefined-key path; if it matters for the migration, worth one assertion. - The
prop:format prefix — is the plan to namespace coalesce keys by source (prop:,gesture:,sdk:) or by intent (reversible:,final:)? The choice will shape every test name from R5 onward.
What I didn't verify
- The HeyGenverse plan doc (HTTP 403 unauthenticated). Trusted the PR body's T11 framing.
- The existing same-coalesceKey tests at lines 176-243 (the PR body references them but I only saw the line-209 context in the diff). Trusted the framing that the new same-key test complements rather than duplicates them.
- Behavior of
pushEditHistoryEntrywith the redo stack pre-populated — coalescing might interact with redo invalidation, and there's no test for that interaction here. - Whether
coalesceMsdefaults to a reasonable value when omitted frompushEditHistoryEntryoptions (both new tests pass{ coalesceMs: 1000 }explicitly).
— Review by Rames D Jusso
f6031a6 to
5caae48
Compare
0e5c2d5 to
28d2349
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Building on Rames's review.
The window-boundary test is the one I'd prioritize: now: 100 + coalesceMs (exactly at the boundary) — coalesce or split? The current tests at +100ms and +200ms are both comfortably inside the window. Fencepost bugs are the class of error a refactor is most likely to introduce, and the existing "outside the window" test from the pre-PR file presumably covers now: 1101+, leaving exactly the now: 1100 case uncovered.
Rames's note about the .todo placement (they're between test 2 and an existing test) — the does not coalesce source editor edits outside the coalesce window test appears right after the new todos. Move the todos to the end of their describe block before this merges; it's a one-move change and will save any future git blame reader from puzzling over the ordering.
The origin:applyPatches undo-exclusion todo pairing with T4's matching todo: both should reference a shared Linear ticket so they don't drift. If there's no ticket yet, create one now.
5caae48 to
fdc3073
Compare
28d2349 to
830cd8d
Compare
|
Addressed in latest push:
|
miguel-heygen
left a comment
There was a problem hiding this comment.
Follow-up: both concerns addressed.
- ✅ Boundary test added:
now: 1100withcoalesceMs: 1000— boundary is<=(inclusive), comment documents it explicitly - ✅
.todos moved to end of describe block
One remaining nit from Rames: the applyPatches undo-exclusion todo should ideally share a Linear ticket with T4's matching stub, but not a blocker.
✅ Re-approve.
…1240) ## What Adds `htmlParser.roundtrip.test.ts` — T1 from the SDK migration test plan. Tests that `parseHtml → generateHyperframesHtml → parseHtml` is lossless for element structure and timing. Scope is DOM/timing only; GSAP script round-trip is T6 territory. ## Tests **Inline fixtures (5):** - element count + ids preserved - `startTime` / `duration` preserved - element types preserved (`text`, `video`, `img`, `audio`) - double-serialize stability (`serialize(parse(serialize(parse(html)))) === serialize(parse(html))`) - empty stage doesn't throw **Registry block sampling (10):** first 10 blocks in `registry/blocks/` — each asserts element count survives a round-trip. ## Finding Stability test surfaced a real bug: `generateHyperframesHtml` defaults `compositionId` to `` `comp-${Date.now()}` ``. Since `ParsedHtml` doesn't capture this, every re-serialize emits a different id. The test works around it by passing a fixed `compositionId: "test-comp"` so structural instability is still detectable. The root cause is tracked as **R1 (stable hf- ids)**. ## Stack Prerequisite for: T8 (#1241), T11 (#1242), T4 (#1243)
62d30dc to
5630509
Compare
fdc3073 to
c74cfde
Compare
#1241) ## What Extends `getVariables.test.ts` with T8 from the SDK migration test plan: override-set merge semantics. ## Tests (4 new) - **last-write-wins** — calling `setOverrides` twice; second value wins - **sparse override** — override one key, unmentioned declared defaults survive intact - **batch override (brand kit)** — setting all keys at once via a single override object - **manual override after batch** — replacing one key from a kit batch; others untouched ## Scope note Tests are labeled **"flat-merge, current behaviour"** — `getVariables` does `{...defaults, ...overrides}`. Dotted-key path resolution (`"headline.color"` as `id.prop`) is a future SDK concern; these tests validate the flat-merge contract that exists today, not the future path-resolution semantics. ## Stack Stacked on T1 (#1240). Prerequisite for T11 (#1242), T4 (#1243).
c74cfde to
8d9db68
Compare
5630509 to
37d02f2
Compare
The base branch was changed.
8d9db68 to
b474f12
Compare
Merge activity
|

What
Extends
editHistory.test.tswith T11 from the SDK migration test plan: history coalescing gaps and origin guard stubs.Tests
New passing test (1):
coalesceKeyvalues produce two separate undo entries, not one coalesced entry. Fills the gap left by the existing same-file coalescing tests (lines 176–243)..todostubs (2):gesture-start/commit collapses intermediate drag steps into one undo entry— requires gesture lifecycle API not yet builtorigin:applyPatches edits excluded from undo stack— requires SDK session object (session.on("patch", ...),session.dispatch(...)) which doesn't exist yet; needed to prevent undo loops when SDK patches are appliedStack
Stacked on T8 (#1241). Prerequisite for T4 (#1243).