Skip to content

fix: Harden IPC contracts, empty RPC errors, and Settings async UI - #1778

Merged
hatayama merged 7 commits into
v3-betafrom
feature/design-review-fixes-integration
Jul 14, 2026
Merged

hatayama merged 7 commits into
v3-betafrom
feature/design-review-fixes-integration

Conversation

@hatayama

@hatayama hatayama commented Jul 14, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Freezes shared IPC response/error contracts so Go and C# stay aligned on compile-status, endpoints, and CLI-update-required frames.
  • Makes empty Unity RPC results a typed transport error, hardens JSON-RPC serialization failures, and stops Settings/Setup async void from swallowing UI exceptions.

User Impact

  • Before: contract drift could go unnoticed, empty Unity replies looked like generic failures, JSON serialization faults could escape as uncaught exceptions, and Settings/Setup fire-and-forget handlers could fail silently.
  • After: shared fixtures lock the wire shapes, empty replies become actionable NoResponseErrors, serialization faults return error frames, and Settings/Setup async failures are logged while UI behavior stays the same.

Changes

Child PRs merged into feature/design-review-fixes-integration:

Out of scope by design: protocolVersion / pin / CHANGELOG bumps; deeper Settings View construction split (SettingsWindow still ~860 lines; further cut to <500 is a follow-up).

Verification

  • Per-child PR: uloop compile 0/0 and EditMode suites as recorded on each PR
  • PR-5 (chore: Harden Settings/Setup async UI and shallow presenter split #1777) additional: full EditMode after 5b = 2048 passed / 0 failed / 7 skipped; manual Settings / Setup Wizard / Migration Wizard check = OK (user-confirmed, no bugs)
  • Fable LGTM on each child PR; PR-5 also ran /review with no required fixes

Manual check (already completed for Presentation)

  • Settings window sections, foldouts, CLI actions, skills install, tool toggles
  • Setup Wizard end-to-end
  • Third-party migration wizard open/refresh/actions

Review notes

  • Final review should include Fable manual review and /review (bugbot or security)
  • Do not bump protocolVersion / project-runner-pin / CHANGELOGs in this PR

Review in cubic

hatayama and others added 5 commits July 14, 2026 11:18
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
)

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: df0aa8e5-ff40-4b12-8300-dba71f4228d9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds shared contract validation for IPC endpoints, compile responses, and CLI errors; introduces typed no-response handling; applies ConfigureAwait(false) across first-party workflows; adds a ConfigureAwait analyzer; and moves settings decisions, catalog warmup, and async UI handling into policies and presenters.

Changes

Contracts and protocol behavior

Layer / File(s) Summary
Shared endpoint and response contracts
Assets/Tests/Editor/..., cli/common/project/..., cli/project-runner/..., tests/contracts/*
Unity and Go tests validate endpoint paths and compile-status response shapes against shared JSON contracts.
Error payload and transport classification
Assets/Tests/Editor/CliUpdateRequiredErrorContractTests.cs, Packages/src/Editor/Infrastructure/Api/JsonRpcResponseFactory.cs, cli/common/errors/*, cli/common/unityipc/client.go, tests/contracts/cli_update_required_error_contract.json
CLI update-required payloads are contract-tested, serialization failures produce JSON-RPC errors, and empty RPC results use typed transport errors.
Contract test maintenance
Assets/Tests/Editor/RunTestsTestFrameworkResultTests.cs, Assets/Tests/Editor/StaticFacadeStateGuardTests.cs, cli/*/shared-inputs-stamp.json
Existing assertions and shared-input hashes are updated for current behavior.

Async continuation control

Layer / File(s) Summary
ConfigureAwait coverage across workflows
Packages/src/Editor/FirstPartyTools/...
Compilation, dynamic execution, testing, input, replay, and watch workflows use ConfigureAwait(false).
Command execution thread boundaries
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/CommandRunner.cs
Command execution switches to Unity’s main thread for Unity-bound work and returns to it after context-free internal execution.
ConfigureAwait guard and validation
tools/UnityCliLoop.CodeComplexity/ConfigureAwaitGuard.cs, tests/UnityCliLoop.CodeComplexity.Tests/*
A Roslyn-based guard detects missing ConfigureAwait(false) usage and tests validate both violations and repository compliance.

Settings and setup orchestration

Layer / File(s) Summary
Settings decision policies
Packages/src/Editor/Domain/*Policy.cs, Assets/Tests/Editor/SettingsPresentationDecisionPolicyTests.cs, Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs
CLI path checks and skills-installed dialog decisions are centralized in policy classes and tested directly.
Setup presenter mediation
Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs, Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs, Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs
CLI actions, compatibility decisions, path setup, and skill dialog decisions are delegated to presenters and policies.
Tool settings catalog warmup
Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs
Catalog invalidation, view readiness, registry warmup retries, and refresh decisions are managed by the presenter.
Settings window integration
Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs
Window lifecycle, session state, async handlers, catalog updates, and installation flows use presenter-owned state and Task-based callbacks.
Setup and migration async flow
Packages/src/Editor/Presentation/Setup/SetupWizardStartupFlow.cs, Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardWindow.cs
Startup evaluation and migration handlers return Tasks and use explicit fire-and-forget wiring with awaited refreshes.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main changes: IPC contract hardening, typed empty RPC errors, and async UI fixes.
Description check ✅ Passed The description matches the changeset and summarizes the contract, error-handling, and async UI updates accurately.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/design-review-fixes-integration

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

🧹 Nitpick comments (2)
Packages/src/Editor/Infrastructure/Api/JsonRpcResponseFactory.cs (1)

37-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Catch JsonException to align with the Fail Fast policy.

Based on learnings, avoid broad defensive catch (Exception) blocks and only catch expected, domain-specific exceptions. Since this block is intended to recover from serialization failures gracefully, consider catching JsonException (the base class for Newtonsoft.Json exceptions) so that severe runtime errors (like OutOfMemoryException) continue to fail fast instead of being swallowed into an RPC error frame.

♻️ Proposed refactor
-            catch (Exception ex)
+            catch (JsonException ex)
             {
                 // Why error frame instead of success+error object: clients treat jsonrpc success as
                 // completed tool results; a fake success would hide serialization failure from agents.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Packages/src/Editor/Infrastructure/Api/JsonRpcResponseFactory.cs` around
lines 37 - 40, Update the exception handler in JsonRpcResponseFactory to catch
only JsonException for expected serialization failures, replacing the broad
catch (Exception) while preserving the existing error-frame handling for that
exception. Allow severe runtime exceptions to propagate fail fast.

Source: Learnings

Packages/src/Editor/FirstPartyTools/RunTests/RunTestsUseCase.cs (1)

117-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Update the stale ConfigureAwait rationale.

The comment at Lines 103-107 says these awaits intentionally avoid ConfigureAwait(false), but all three awaits now use it. Update the rationale—or revert the awaits if Unity-context preservation is still required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Packages/src/Editor/FirstPartyTools/RunTests/RunTestsUseCase.cs` around lines
117 - 127, Update the stale ConfigureAwait rationale near
_waitForTestRunnerCleanupAsync to accurately reflect that the test execution and
cleanup awaits use ConfigureAwait(false), preserving the current await behavior
unless Unity-context preservation is explicitly required by the surrounding
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Packages/src/Editor/FirstPartyTools/Compile/CompileLifecycleWatchdog.cs`:
- Line 105: Keep the awaits on the Unity thread by removing
ConfigureAwait(false) or otherwise preserving Unity-context continuation at
Packages/src/Editor/FirstPartyTools/Compile/CompileLifecycleWatchdog.cs:105 for
_waitForPollAsync,
Packages/src/Editor/FirstPartyTools/Compile/CompileUseCase.cs:106 and :174 for
the play-mode polling loops, and
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/AutoUsingResolver.cs:43
and :106 for retry paths invoking buildFunc.

In
`@Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/CommandRunner.cs`:
- Around line 69-71: Update ExecuteAsync around the initial
MainThreadSwitcher.SwitchToMainThread call so OperationCanceledException from a
pre-cancelled token or queued cancellation is handled by the existing
cancellation path and returns CreateCancelledResult(). Keep the main-thread
switch and normal execution behavior unchanged for non-cancellation failures and
successful calls.

In
`@Packages/src/Editor/FirstPartyTools/RunTests/TestFramework/PlayModeTestExecuter.cs`:
- Around line 126-128: Keep the async continuation after
taskCompletionSource.Task on the Unity Editor thread by removing
ConfigureAwait(false) or explicitly dispatching to the Editor synchronization
context. Ensure UnifiedTestCallback.Dispose(), the cancellation recovery calls
to RunTestsCancelStopRestore.StopAndRestoreAsync(), and the polling at
Packages/src/Editor/FirstPartyTools/RunTests/RunTestsCancelStopRestore.cs:224
execute on that thread; update the affected sites in
Packages/src/Editor/FirstPartyTools/RunTests/TestFramework/PlayModeTestExecuter.cs:126-128,
:55-67, and :83-92, while preserving cancellation behavior.

In `@Packages/src/Editor/FirstPartyTools/Watch/WatchTools.cs`:
- Around line 191-192: Update the await in the watch compilation flow around
WatchExpressionServices.Compiler.CompileAsync so continuation resumes on the
captured Editor context before any subsequent Registry.Register or
EnsureMonitorStarted mutations; remove ConfigureAwait(false) for this
Editor-scoped operation while preserving cancellation and result handling.

In `@Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs`:
- Line 76: Update the isCliInstalled assignment in
UnityCliLoopSettingsCliSetupPresenter to treat both null and empty cached CLI
versions from GetCachedCliVersion() as not installed, ensuring the setup flow
selects Install/Update rather than Uninstall.

---

Nitpick comments:
In `@Packages/src/Editor/FirstPartyTools/RunTests/RunTestsUseCase.cs`:
- Around line 117-127: Update the stale ConfigureAwait rationale near
_waitForTestRunnerCleanupAsync to accurately reflect that the test execution and
cleanup awaits use ConfigureAwait(false), preserving the current await behavior
unless Unity-context preservation is explicitly required by the surrounding
implementation.

In `@Packages/src/Editor/Infrastructure/Api/JsonRpcResponseFactory.cs`:
- Around line 37-40: Update the exception handler in JsonRpcResponseFactory to
catch only JsonException for expected serialization failures, replacing the
broad catch (Exception) while preserving the existing error-frame handling for
that exception. Allow severe runtime exceptions to propagate fail fast.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 071ad40f-c1d3-4125-88cf-3bb2f942f2c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d67dae and a9e2798.

⛔ Files ignored due to path filters (6)
  • Assets/Tests/Editor/CliUpdateRequiredErrorContractTests.cs.meta is excluded by none and included by none
  • Assets/Tests/Editor/GetCompileStatusResponseContractTests.cs.meta is excluded by none and included by none
  • Assets/Tests/Editor/JsonRpcResponseFactorySerializationFallbackTests.cs.meta is excluded by none and included by none
  • Assets/Tests/Editor/SettingsPresentationDecisionPolicyTests.cs.meta is excluded by none and included by none
  • Packages/src/Editor/Domain/CliPathSetupCheckPolicy.cs.meta is excluded by none and included by none
  • Packages/src/Editor/Domain/SkillInstallDialogPolicy.cs.meta is excluded by none and included by none
📒 Files selected for processing (52)
  • Assets/Tests/Editor/BridgeTransportEndpointTests.cs
  • Assets/Tests/Editor/CliUpdateRequiredErrorContractTests.cs
  • Assets/Tests/Editor/GetCompileStatusResponseContractTests.cs
  • Assets/Tests/Editor/JsonRpcResponseFactorySerializationFallbackTests.cs
  • Assets/Tests/Editor/RunTestsTestFrameworkResultTests.cs
  • Assets/Tests/Editor/SettingsPresentationDecisionPolicyTests.cs
  • Assets/Tests/Editor/StaticFacadeStateGuardTests.cs
  • Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs
  • Packages/src/Editor/Domain/CliPathSetupCheckPolicy.cs
  • Packages/src/Editor/Domain/SkillInstallDialogPolicy.cs
  • Packages/src/Editor/FirstPartyTools/Compile/CompilationExecutionService.cs
  • Packages/src/Editor/FirstPartyTools/Compile/CompileController.cs
  • Packages/src/Editor/FirstPartyTools/Compile/CompileLifecycleWatchdog.cs
  • Packages/src/Editor/FirstPartyTools/Compile/CompileUseCase.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCodeServices.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/AutoUsingResolver.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/CompiledAssemblyBuilder.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeCompiler.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/CommandRunner.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/DynamicCodeExecutionFacade.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/DynamicCodeExecutionScheduler.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/DynamicCodeExecutionSchedulerHooks.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/DynamicCodeExecutor.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/DynamicCodeForegroundWarmupRunner.cs
  • Packages/src/Editor/FirstPartyTools/ReplayInput/ReplayInputUseCase.cs
  • Packages/src/Editor/FirstPartyTools/RunTests/RunTestsCancelStopRestore.cs
  • Packages/src/Editor/FirstPartyTools/RunTests/RunTestsUseCase.cs
  • Packages/src/Editor/FirstPartyTools/RunTests/TestFramework/PlayModeTestExecuter.cs
  • Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs
  • Packages/src/Editor/FirstPartyTools/SimulateMouseInput/SimulateMouseInputUseCase.cs
  • Packages/src/Editor/FirstPartyTools/Watch/WatchTools.cs
  • Packages/src/Editor/Infrastructure/Api/JsonRpcRequestProcessor.cs
  • Packages/src/Editor/Infrastructure/Api/JsonRpcResponseFactory.cs
  • Packages/src/Editor/Presentation/Setup/SetupWizardStartupFlow.cs
  • Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs
  • Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardWindow.cs
  • Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs
  • Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs
  • Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs
  • cli/common/errors/cli_update_required_error_contract_test.go
  • cli/common/errors/transport_errors.go
  • cli/common/errors/transport_errors_test.go
  • cli/common/project/endpoint_contract_test.go
  • cli/common/unityipc/client.go
  • cli/dispatcher/shared-inputs-stamp.json
  • cli/project-runner/internal/projectrunner/compile_status_response_contract_test.go
  • cli/project-runner/shared-inputs-stamp.json
  • tests/UnityCliLoop.CodeComplexity.Tests/ConfigureAwaitGuardTests.cs
  • tests/contracts/cli_update_required_error_contract.json
  • tests/contracts/compile_status_response_contract.json
  • tests/contracts/endpoint_contract.json
  • tools/UnityCliLoop.CodeComplexity/ConfigureAwaitGuard.cs
💤 Files with no reviewable changes (1)
  • Packages/src/Editor/Infrastructure/Api/JsonRpcRequestProcessor.cs

Comment thread Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/CommandRunner.cs Outdated
Comment thread Packages/src/Editor/FirstPartyTools/Watch/WatchTools.cs
Comment thread Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs Outdated
hatayama and others added 2 commits July 14, 2026 16:38
PR-4's bulk ConfigureAwait(false) left Unity API continuations on worker
threads. Switch back before Editor callbacks (watch, compile watchdog,
run-tests), keep AssemblyBuilder/play-mode polls on the Editor context,
map pre-cancelled CommandRunner switches to CreateCancelledResult, and
treat empty cached CLI versions as not installed.

Co-authored-by: Cursor <cursoragent@cursor.com>
Restore ConfigureAwait(false) with SwitchToMainThread for CompileUseCase
and AutoUsingResolver so the FirstPartyTools guard stays green, and use
CancellationToken.None on the watchdog main-thread switch so cancelled
polls still reach the loop-head AbortCompile path.

Co-authored-by: Cursor <cursoragent@cursor.com>
@hatayama

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@hatayama
hatayama merged commit 0dffc75 into v3-beta Jul 14, 2026
10 checks passed
@hatayama
hatayama deleted the feature/design-review-fixes-integration branch July 14, 2026 07:49
@github-actions github-actions Bot mentioned this pull request Jul 14, 2026
hatayama added a commit that referenced this pull request Jul 17, 2026
simulate-mouse-input and simulate-keyboard always failed with
"set_runInBackground can only be called from the main thread"
(UNITY_RPC_ERROR) even though the simulation itself succeeded, and the
thrown exception additionally left PlayMode in Error Pause.

The executor awaits in both use cases were given .ConfigureAwait(false)
by the ConfigureAwait guard (#1778). Their completions come from a TCS
created with RunContinuationsAsynchronously, so the method always
resumed on a thread-pool thread, and the `using` scope's Dispose then
set Application.runInBackground (a main-thread-only API) off the main
thread, discarding the successful response.

Follow the existing PlayModeTestExecuter pattern: replace `using` with
an explicit scope + try-finally that switches back to the main thread
via InputSystemUpdateHelper.SwitchToMainThreadIfNeeded before Dispose.
Also assert the main-thread precondition inside
InputSimulationRunInBackgroundScope.Dispose so future regressions fail
fast (requires the ToolContracts asmdef reference).
RyanXie123 pushed a commit to RyanXie123/unity-cli-loop that referenced this pull request Sep 22, 2026
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