Skip to content

fix: Fail control-play-mode fast when unsaved changes cannot be quietly saved#1941

Merged
hatayama merged 1 commit into
feature/round8-pause-point-improvementsfrom
fix/control-play-mode-unsaved-changes-fast-fail
Jul 22, 2026
Merged

fix: Fail control-play-mode fast when unsaved changes cannot be quietly saved#1941
hatayama merged 1 commit into
feature/round8-pause-point-improvementsfrom
fix/control-play-mode-unsaved-changes-fast-fail

Conversation

@hatayama

@hatayama hatayama commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • control-play-mode --action Play no longer waits the full timeout (up to 180s) when Play mode cannot start because unsaved editor changes could not be quietly saved (for example, an Untitled scene).

User Impact

  • Before: if the active scene had no path (an Untitled scene) or otherwise could not be saved, Unity's synchronous handler gave up in milliseconds, but the response looked identical on the wire to "no state change yet." The CLI then polled Unity's status for the full wait timeout before finally reporting a generic "did not complete" error, hiding the real cause.
  • After: the CLI recognizes this failure immediately and returns an actionable error listing exactly which scene/prefab changes could not be saved, with guidance to save or discard them (or give an Untitled scene a path) before retrying.

Changes

  • Packages/src/Editor/FirstPartyTools/ControlPlayMode: added a BlockedByUnsavedChanges response field, set when SaveDirtyEditorChangesBeforePlayStart fails, mirroring the existing BlockedByCompileErrors field.
  • cli/project-runner: runControlPlayModeWithStateWait now checks BlockedByUnsavedChanges on the initial response and fails fast with a new CONTROL_PLAY_MODE_UNSAVED_CHANGES error instead of entering the state-wait poll loop.

Verification

  • Root-caused via a live reproduction in this checkout: created an Untitled dirty scene with execute-dynamic-code, then ran control-play-mode --action Play, which hung for the full timeout before this fix (EditorApplication.isPlaying stayed false throughout, confirming Unity had already given up).
  • TDD: added a failing Go test (TestRunControlPlayModeWithStateWaitFailsImmediatelyWhenUnsavedChangesBlockPlay) reproducing the fall-through-to-polling bug against the pre-fix code, confirmed it failed with a generic timeout, then implemented the fix. Added assertions to the existing C# unit tests (ExecuteAsync_WhenPlayStartSaveFails_DoesNotEnterPlayMode, ExecuteAsync_WhenPlayStartLeavesUnsavedChanges_DoesNotEnterPlayMode) confirming BlockedByUnsavedChanges is set; confirmed both failed (Expected: True / But was: False) before the fix.
  • Re-ran the live repro after the fix: control-play-mode --action Play against the same Untitled dirty scene now returns the new error in well under a second instead of hanging.
  • sh scripts/check-go-cli.sh: format/vet/lint 0 issues, all Go packages pass (including the new test).
  • go test -run TestProductionGoFilesStayFocused ./... (release-automation): pass.
  • sh scripts/stamp-release-inputs.sh: re-run and committed, since cli/common changed.
  • dist/darwin-arm64/uloop compile: 0 errors / 0 warnings.
  • uloop run-tests (EditMode, ControlPlayModeUseCaseTests): 18/18 passed after the fix.

Review in cubic

Root cause: SaveDirtyEditorChangesBeforePlayStart returns synchronously
when a scene/prefab cannot be saved (e.g. an Untitled scene with no
path), but the response was numerically identical to "no state change
yet" on the wire (IsPlaying=false, Changed=false,
BlockedByCompileErrors=false). The Go CLI's initial-response check only
special-cased BlockedByCompileErrors, so this terminal failure fell
through into the 180s state-wait poll loop and surfaced as a generic
timeout, even though Unity had already given up in milliseconds.

Adds a BlockedByUnsavedChanges response field (mirroring the existing
BlockedByCompileErrors pattern) and an early-return check in
runControlPlayModeWithStateWait so this failure mode returns
immediately with an actionable error instead of waiting.
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@hatayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 20 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 69a8f70c-5cbb-4ddb-9cf5-f156998c65cb

📥 Commits

Reviewing files that changed from the base of the PR and between ac70353 and d19a254.

📒 Files selected for processing (8)
  • Assets/Tests/Editor/ControlPlayModeUseCaseTests.cs
  • Packages/src/Editor/FirstPartyTools/ControlPlayMode/ControlPlayModeResponse.cs
  • Packages/src/Editor/FirstPartyTools/ControlPlayMode/ControlPlayModeUseCase.cs
  • cli/common/errors/error_envelope.go
  • cli/dispatcher/shared-inputs-stamp.json
  • cli/project-runner/internal/projectrunner/control_play_mode_wait.go
  • cli/project-runner/internal/projectrunner/control_play_mode_wait_test.go
  • cli/project-runner/shared-inputs-stamp.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/control-play-mode-unsaved-changes-fast-fail

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hatayama
hatayama merged commit 5fbc2c3 into feature/round8-pause-point-improvements Jul 22, 2026
2 checks passed
@hatayama
hatayama deleted the fix/control-play-mode-unsaved-changes-fast-fail branch July 22, 2026 08:39
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