Skip to content

Harden remote scene commit convergence - #539

Merged
Aymericr merged 8 commits into
mainfrom
feat/realtime-collaboration-sfx
Jul 23, 2026
Merged

Harden remote scene commit convergence#539
Aymericr merged 8 commits into
mainfrom
feat/realtime-collaboration-sfx

Conversation

@Aymericr

@Aymericr Aymericr commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

What

  • apply remote scene patches atomically while preserving active local interaction state
  • preserve forward-compatible plugin fields and valid level child identifiers
  • expose the exact host snapshot boundary needed by hosted realtime collaboration
  • scope core test discovery and TypeScript builds to source so stale compiled tests are not run twice

Why

Realtime collaborators need deterministic convergence without remote commits corrupting undo/history state or stripping hosted plugin data. The previous package test command also rediscovered compiled test output, adding duplicate work and misleading failures.

Impact

Hosted collaboration can apply exact remote structural, field, and material changes while keeping local interactions safe. CI retains the source tests but avoids duplicate compiled copies.

Checks

  • bun run test — 11/11 Turbo tasks green from the private monorepo
  • bun run typecheck — 10/10 Turbo tasks green
  • focused remote commit and schema tests included in this PR

Note

High Risk
Large changes to the scene store’s host/collaboration commit path (structural graph, validation, history, dirty tracking) affect data integrity and realtime convergence.

Overview
Adds applySceneOperationPatch and exports SceneOperationPatch / structural patch types so hosted realtime can apply node creates/deletes together with field and material updates in one atomic host commit. applyScenePatch is now a thin wrapper over that path.

Remote/host patch semantics change materially: patches are validated and applied via a single precomputed next state (invalid ops fail without partial writes). Host commits no longer blanket-reject while undo/history is paused—they apply when they don’t touch nodes with live overrides/transforms or structural parents under active live edit; colliding patches still return false. History pause is scoped so external tool pauses aren’t accidentally resumed. Dirty marking/clearing is extended for structural edits (siblings, deleted subtrees, bounded dirty sets on large scenes).

LevelNode.children stops enumerating every core child ID in Zod and accepts any string ID, so persisted levels can reference plugin-minted children; child-kind validation stays in the registry.

Tooling: bun test runs only src, and tsconfig excludes *.test.* from compilation to avoid duplicate/stale compiled tests.

Reviewed by Cursor Bugbot for commit d0afde1. Bugbot is set up for automated code reviews on this repo. Configure here.

@Aymericr
Aymericr merged commit 28ab27f into main Jul 23, 2026
3 checks passed

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d0afde1. Configure here.

!Number.isSafeInteger(change.position) ||
change.position < 0 ||
siblings?.[change.position] !== id ||
!areScenePatchValuesEqual(current, change.node)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strict delete rejects extra fields

High Severity

Remote structural deletes require the delete payload to match the local node with full key-for-key equality. Local nodes that retained forward-compatible or plugin-only fields from earlier host creates/updates often have extra keys the delete payload omits, so valid remote deletes are rejected and the scene cannot converge.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d0afde1. Configure here.

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