Skip to content

fix: keep live drops atomic across board handoff - #5634

Merged
steve8708 merged 13 commits into
mainfrom
steve8708/live-drop-followup-20260922
Sep 22, 2026
Merged

steve8708 merged 13 commits into
mainfrom
steve8708/live-drop-followup-20260922

Conversation

@steve8708

Copy link
Copy Markdown
Contributor

Problem

Live cross-screen drops into an empty board could unmount the inert board iframe before the asynchronous hit-test posted its runtime insert request. A second live drop could also overwrite the single pending runtime request slots, leaving a destination clone without source removal.

Fix

  • Keep the board surface mounted through the hit-test and runtime insert acknowledgement, with a bounded timeout fallback.
  • Guard cross-screen runtime transactions with a transaction ref and release it only after the insert/delete acknowledgement or rejection.
  • Add a regression test proving a second live transaction is refused while one is pending.

Validation

  • vitest run app/pages/design-editor/commands/cross-screen-element-drop.spec.ts app/components/design/multi-screen/board-surface-rendering.spec.ts
  • 48 tests passed
  • git diff --check

@steve8708
steve8708 force-pushed the steve8708/live-drop-followup-20260922 branch from 27fcf98 to 472a6dd Compare September 22, 2026 16:22
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Visual recap

Open the full interactive recap

builder-io-integration[bot]

This comment was marked as outdated.

@github-actions
github-actions Bot temporarily deployed to pr-5634-design September 22, 2026 17:07 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5634-analytics September 22, 2026 17:07 Destroyed
builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

@github-actions
github-actions Bot temporarily deployed to pr-5634-analytics September 22, 2026 17:54 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5634-design September 22, 2026 17:54 Destroyed
builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

@builder-io-integration builder-io-integration 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.

Builder reviewed your changes and found 3 potential issues 🟡

Review Details

Incremental Code Review Summary

The latest update substantially addresses the prior transaction-lifecycle findings. The shared insert setter now rejects competing transaction ids, board transaction identity is retained through rollback, and the timeout path attempts to reconcile a possibly-applied DOM mutation. I verified and resolved the four previously open comments covered by these fixes. Targeted regression tests pass locally: 49/49.

New findings

  • 🟡 MEDIUM — The retained board transaction id is not reset when a new board handoff begins, allowing a late acknowledgement from the previous drop to settle the new drop and cancel its timeout.
  • 🟡 MEDIUM — The admission wrapper silently drops unrelated paste/create/duplicate/redo runtime inserts while a cross-screen transaction is pending, leaving callers believing their operation succeeded.
  • 🟡 MEDIUM — A timeout-triggered rollback clears the insert request before ensuring the empty board iframe remains mounted, so the rollback executor can unmount before it runs and leave the transaction lock stuck.

The dev server was healthy. Full browser verification was attempted with seeded live-edit designs, but all 14 cases were blocked because Chrome automation tools were unavailable in the browser-test executor session.

🧪 Browser testing: Attempted full visual verification, but blocked by missing Chrome automation tools in the executor.

Comment on lines +10881 to +10884
onRuntimeStructureInsertApplied={(details) => {
const expectedTransactionId =
boardCrossScreenDropTransactionRef.current;
if (

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.

🟡 Prevent a stale acknowledgement from settling the next board drop

After a successful insert, finishBoardCrossScreenDrop({ preserveTransaction: true }) intentionally retains boardCrossScreenDropTransactionRef, but starting the next board handoff does not reset it. A late acknowledgement for the previous transaction can therefore match expectedTransactionId here, call finishBoardCrossScreenDrop(), and cancel the new drop's timeout before the new insert is admitted. Reset or sequence the expected transaction when each new board handoff begins so only the current drop can settle it.

Additional Info
New finding confirmed by one review agent; distinct from the resolved rollback cleanup comment.

Fix in Builder

Comment on lines +1686 to +1699
const pendingTransactionId =
runtimeStructurePendingTransactionRef.current;
if (
resolved &&
pendingTransactionId &&
resolved.transactionId !== pendingTransactionId
) {
if (DESIGN_EDITOR_DEBUG_LOGS) {
console.warn("[design] runtime structure insert admission refused", {
pendingTransactionId,
requestTransactionId: resolved.transactionId ?? null,
});
}
return current;

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.

🟡 Do not silently discard unrelated runtime inserts

While a cross-screen transaction is pending, this setter returns the old state for every request with a different transaction id, including untagged inserts from paste, primitive creation, duplicate, redo, and layer-move commands. Those callers receive no admission result and can update local state or report success even though no iframe request is sent. Expose an explicit rejection/queue path or preflight the admission in each caller so user inserts are not silently lost.

Additional Info
Found by two independent review agents; this is a new user-facing consequence of the admission wrapper, not a repost of the prior serialization comment.

Fix in Builder

transactionId &&
boardCrossScreenDropTransactionRef.current === transactionId
) {
onBoardRuntimeStructureInsertRejectedRef.current?.(

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.

🟡 Keep the board mounted while timeout rollback executes

When the timeout callback invokes the parent rejection handler, the handler schedules boardRuntimeStructureRollbackRequest and clears runtimeStructureInsertRequest. For an empty board with no acknowledged runtime content, shouldMountBoardSurface can then become false before the rollback request executes, unmounting the only iframe that can perform the rollback and release the transaction lock. Keep the board surface active until rollback settlement, or explicitly settle and release the transaction when unmounting.

Additional Info
New finding confirmed by one review agent; distinct from the resolved early-timeout-cancellation comment.

Fix in Builder

@github-actions
github-actions Bot temporarily deployed to pr-5634-analytics September 22, 2026 19:26 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5634-design September 22, 2026 19:26 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5634-analytics September 22, 2026 19:46 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5634-design September 22, 2026 19:47 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5634-design September 22, 2026 20:10 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5634-design September 22, 2026 20:36 Destroyed
@steve8708
steve8708 merged commit 4ddff31 into main Sep 22, 2026
48 checks passed
@steve8708
steve8708 deleted the steve8708/live-drop-followup-20260922 branch September 22, 2026 20:48

This branch was successfully deployed

No deployments
pr-5634-design — 6d855303 Deployed Sep 22, 2026 by github-actions[bot]
pr-5634-analytics — 434a3ed8 Deployed Sep 22, 2026 by github-actions[bot]
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