Skip to content

Fix "Always" confirmation behavior setting which currently works like "Initial"#1216

Open
warsam wants to merge 3 commits into
rojo-rbx:masterfrom
warsam:master
Open

Fix "Always" confirmation behavior setting which currently works like "Initial"#1216
warsam wants to merge 3 commits into
rojo-rbx:masterfrom
warsam:master

Conversation

@warsam

@warsam warsam commented Jan 24, 2026

Copy link
Copy Markdown

Summary
Implements the "Always" confirmation behavior setting, which prompts for confirmation on every sync patch (not just the initial sync). Changes that arrive during confirmation are merged into the pending patch and the UI updates in real-time.

Implementation

  • Add "Always" option to confirmationBehavior setting
  • Route WebSocket patches through the confirmation callback when "Always" is enabled
  • Refactor ServeSession to connect WebSocket before showing confirmation, allowing patches to merge during confirmation
  • Add PatchSet.merge() function that properly reconciles conflicts:
    • Cancels additions when they're subsequently removed
    • Combines updates for the same instance
    • Removes changes that revert to current instance state
  • Auto-dismiss confirmation dialog when all changes have been reverted (patch becomes empty)
  • Fix UI not transitioning back to Connected after confirming ongoing patches
  • Fix DomLabel Flipper motor cleanup on unmount to prevent Roact errors
  • Add unit tests for PatchSet.merge() and related functions

Test Plan

  • Set confirmationBehavior to "Always" in plugin settings
  • Connect to a Rojo server and verify the initial sync prompts for confirmation
  • Accept the initial sync and verify the UI transitions to "Connected"
  • Make a file change and verify a new confirmation dialog appears
  • While confirmation is showing, make additional file changes and verify they merge into the pending patch (UI updates in real-time)
  • Revert a file change during confirmation and verify it's removed from the pending patch
  • Revert all changes during confirmation and verify the dialog auto-dismisses
  • Test "Abort" option disconnects from the server
  • Verify no Roact errors appear when rapidly opening/closing the confirmation dialog

@kennethloeffler

kennethloeffler commented Jan 25, 2026

Copy link
Copy Markdown
Member

The purpose of this setting is mostly to prevent users from unknowingly syncing the wrong project on initial sync. If I'm understanding correctly, the new "Always" option in this PR requires the user to accept any and all incoming changes from the Rojo server, even those that occur after the initial sync. I don't think I've ever seen anyone request this, and I'm unsure about its utility. Can you elaborate further on the purpose?

@warsam

warsam commented Jan 25, 2026

Copy link
Copy Markdown
Author

The purpose of this setting is mostly to prevent users from unknowingly syncing the wrong project on initial sync. If I'm understanding correctly, the new "Always" option in this PR requires the user to accept any and all incoming changes from the Rojo server, even those that occur after the initial sync. I don't think I've ever seen anyone request this, and I'm unsure about its utility. Can you elaborate further on the purpose?

The default option in that setting is "Initial" which works as you are describing. The "Always" option already existed in the confirmation behavior setting and I noticed that it works like "Initial" rather than actually prompting confirmation always as described. This PR just fixes it so it actually works. Previously, selecting "Always" had no effect on ongoing sync patches; they would still be applied automatically without confirmation. This PR routes WebSocket patches through the confirmation callback so the setting is respected as users would expect.

If the "Always" option shouldn't apply to ongoing patches (only initial sync), that's a separate design decision, but currently the UI presents it as an option without it functioning.

Comment thread plugin/src/App/init.lua Outdated
if serverInfo.expectedPlaceIds then
local isListed = table.find(serverInfo.expectedPlaceIds, game.PlaceId) ~= nil
if isListed then
if confirmationBehavior ~= "Always" then

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This is to make this confirmation behavior setting explicit rather than implicitly falling through this block so there's no actual behavior change here.

Comment thread plugin/src/Settings.lua Outdated
checkForPrereleases = false,
autoConnectPlaytestServer = false,
confirmationBehavior = "Initial" :: "Never" | "Initial" | "Large Changes" | "Unlisted PlaceId",
confirmationBehavior = "Initial" :: "Never" | "Initial" | "Always" | "Large Changes" | "Unlisted PlaceId",

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This is adding handling for the "Always" setting which already exists in UI drop down in the plugin:
https://github.com/warsam/rojo/blob/master/plugin/src/Settings.lua#L23

@kennethloeffler

Copy link
Copy Markdown
Member

My understanding is that the confirmation behavior setting is only meant to guard the initial sync. I don't believe that Rojo users want manually confirm every change they make, and if we shipped this change, I'd worry that some users would forget/not realize they turned it on and be confused about the behavior.

I agree that the current behavior of the "Always" option doesn't really make sense, but I don't think this PR captures the original intent, and does significantly change the mental model of live sync: Rojo has never made users confirm every change. Maybe @boatbomber can weigh in here since he is the original implementer.

@warsam

warsam commented Jan 25, 2026

Copy link
Copy Markdown
Author

My understanding is that the confirmation behavior setting is only meant to guard the initial sync. I don't believe that Rojo users want manually confirm every change they make, and if we shipped this change, I'd worry that some users would forget/not realize they turned it on and be confused about the behavior.

I agree that the current behavior of the "Always" option doesn't really make sense, but I don't think this PR captures the original intent, and does significantly change the mental model of live sync: Rojo has never made users confirm every change. Maybe @boatbomber can weigh in here since he is the original implementer.

I understand the concern, but this doesn't change the default behavior as "Initial" remains the default. Users would have to deliberately go into settings and select "Always" to enable this behavior.

I'm a user who wanted this functionality, found the setting, switched to it, and discovered it didn't work. The option exists in the UI with a clear label. If it's not supposed to do what the label says, it's misleading to have it there.

If the concern is users accidentally enabling it, that's a UX/discoverability issue with having the option at all, not with making it function as labeled.

@boatbomber

Copy link
Copy Markdown
Member

The Initial setting has some cases where it doesn't prompt, so Always was added as a stricter Initial. I've never head of someone wanting Rojo to halt and popup after every single change. Why would you need that?

@warsam

warsam commented Feb 3, 2026

Copy link
Copy Markdown
Author

I've never heard of someone wanting Rojo to halt and popup after every single change.

To clarify - it doesn't pop up for every individual change. Changes are batched and the confirmation dialog updates in real-time. You approve once when you're ready.

The Initial setting has some cases where it doesn't prompt, so Always was added as a stricter Initial.

What are those cases? If they both only apply to initial sync, why have two options instead of just fixing "Initial"?

@boatbomber

Copy link
Copy Markdown
Member

What are those cases? If they both only apply to initial sync, why have two options instead of just fixing "Initial"?

It's actually the other way around, Initial was added because Always was annoying people. Initial only prompts you on the first time you sync a particular project per Studio session.

See #773 and #774 for more context.

@warsam

warsam commented Feb 13, 2026

Copy link
Copy Markdown
Author

Thanks for the context @boatbomber! Looking at #773 and #774, the goal was making confirmation less annoying by default, not removing it. I see that Dekkonot noted it's worth having "for new games" and you said disabling it entirely "is just avoiding addressing the root issue." That's why "Always" was kept as an option. I can confirm that by my own desire for it as a new rojo user.

This PR just makes that option work as labeled when someone deliberately enables it. Right now selecting "Always" silently behaves like "Initial", which I found confusing.

It also addresses the "hot workflows of constant connect/disconnect" you mentioned in #774. Patches now merge while the confirmation dialog is open, so you see the final merged state when you hit "accept". So you now only need to accept once at the end of multiple changes. The dialog auto-dismisses if all changes revert (as I didn't think it was useful to accept a change that does nothing), so it shouldn't be as noisy as the old "Always" behavior was.

If "Always" shouldn't exist at all, I think the right fix is removing it from the UI rather than keeping a broken option. Happy to do that instead if preferred?

@Dekkonot

Copy link
Copy Markdown
Member

If "Always" shouldn't exist at all, I think the right fix is removing it from the UI rather than keeping a broken option. Happy to do that instead if preferred?

As a point of clarity, the setting isn't broken, it's just misleading. It's behaving exactly as it was implemented to do, which is prompting the user for the initial sync every time. In hindsight though, we probably could have named the setting something better.

I don't really see the use case of a setting for prompting on every sync. I'd much rather we just rename the setting to make it more obvious what it does.

@boatbomber

Copy link
Copy Markdown
Member

I agree, it's behaving exactly as intended. We just need a better name for it.

If we changed its behavior that would be broken since people who had Always selected would suddenly have confirmation popups unexpectedly.

@warsam

warsam commented Feb 14, 2026

Copy link
Copy Markdown
Author

Gotcha, makes sense. I'll leave "Always" as-is. I've reworked this to add "Every Change" as a new option instead. No existing behavior is changed.

warsam and others added 3 commits May 13, 2026 19:06
…ngoing sync patches

- Add "Always" option to confirmationBehavior setting
- Route WebSocket patches through the confirmation callback
- Fix UI not transitioning back to Connected after confirming ongoing patches
- Fix DomLabel Flipper motor cleanup on unmount to prevent errors
Corrected the description of the 'Always' confirmation behavior setting to clarify its functionality.
@warsam

warsam commented May 14, 2026

Copy link
Copy Markdown
Author

Rebased on master and updated the CHANGELOG. To recap after the discussion above: Always is left untouched, and I added Every Change as a new opt-in option that prompts on every sync patch. Patches merge into the pending confirmation dialog while it's open, so it stays usable for hot edit workflows rather than popping repeatedly.

Happy to also rename Always to something clearer (per @Dekkonot's point that it's misleading) and bundle it here, if that'd help land this.

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.

4 participants