Skip to content

chore: Harden Settings/Setup async UI and shallow presenter split#1777

Merged
hatayama merged 2 commits into
feature/design-review-fixes-integrationfrom
feat/presentation-async-void-and-shallow-split
Jul 14, 2026
Merged

chore: Harden Settings/Setup async UI and shallow presenter split#1777
hatayama merged 2 commits into
feature/design-review-fixes-integrationfrom
feat/presentation-async-void-and-shallow-split

Conversation

@hatayama

@hatayama hatayama commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • Settings, Setup Wizard, and Migration Wizard async UI work now surfaces failures through Forget() instead of silent async void handlers.
  • Settings responsibilities for session restore, tool catalog cache/warmup, and CLI primary-action decisions move into existing presenters / Domain policies without changing intended UI behavior.

User Impact

  • Before: fire-and-forget Settings/Setup handlers used async void, so exceptions could disappear and window code kept growing harder to review.
  • After: the same UI flows keep working, but failures are logged and Settings orchestration is thinner for safer manual verification.

Changes

  • Commit 5a: convert remaining Presentation async void methods to async Task and bridge Action/delegate call sites with Forget().
  • Commit 5b: Move Method for catalog cache/warmup into UnityCliLoopSettingsToolSettingsPresenter, CLI primary-action mediation into UnityCliLoopSettingsCliSetupPresenter, session restore/save inlined onto the model, and extract SkillInstallDialogPolicy / CliPathSetupCheckPolicy (Domain, no UnityEditor dependency) with focused tests.
  • Scope stop (agreed with design review): no CreateGUI / View construction surgery.
  • Presentation does not add ConfigureAwait(false) (UI must continue on the main thread).

Verification

  • uloop compile: Success, 0 errors / 0 warnings
  • EditMode full suite after 5a: 2043 passed, 0 failed, 7 skipped
  • EditMode related policies after 5b: 81 passed
  • EditMode full suite after 5b: 2048 passed, 0 failed, 7 skipped

Manual check required (do not merge until confirmed)

Please verify once in a running Editor:

  1. Unity CLI Loop Settings window
    • Open Window → Unity CLI Loop Settings
    • All sections render (Configuration, CLI setup, Tool Settings)
    • Toggle foldouts; reopen window and confirm section visibility restores
    • Refresh CLI version; Install/Update/Fix PATH/Uninstall primary button still does the expected action
    • Install skills for the selected target
    • Toggle a built-in tool on/off and confirm UI + skill side effects remain responsive
  2. Setup Wizard
    • Run through the wizard to completion (CLI step + skills step)
    • Confirm success/error dialogs still match previous behavior
  3. Third-party migration wizard
    • Open the migration wizard
    • Refresh UI loads
    • Migrate / toggle migration skill buttons remain usable

Review notes

  • Target base: feature/design-review-fixes-integration (not v3-beta directly)
  • Final review should include Fable manual review and /review (bugbot or security)

Review in cubic

hatayama and others added 2 commits July 14, 2026 15:29
async void swallows exceptions and complicates UI lifecycle ownership.
Convert Settings, migration wizard, and setup startup handlers to async Task,
and bridge Action/delegate call sites with Forget() so failures stay logged.

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

Keep the EditorWindow as a thin orchestrator for one manual UI check.
Move catalog cache/warmup into ToolSettingsPresenter, CLI primary-action
mediation into CliSetupPresenter, and extract UnityEditor-independent
dialog/PATH policies to Domain with focused tests.

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

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The changes extract settings decision policies, move CLI action and tool-settings state management into presenters, and convert editor async handlers from async void to Task with explicit awaiting or fire-and-forget handling.

Changes

Settings presentation refactor

Layer / File(s) Summary
Decision policies and integrations
Packages/src/Editor/Domain/*Policy.cs, Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs, Assets/Tests/Editor/SettingsPresentationDecisionPolicyTests.cs, Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs
CLI PATH checks and skills-install dialog eligibility use dedicated policies with focused tests.
CLI action mediation
Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs, Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs, Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs
Primary-action resolution, update evaluation, uninstall routing, PATH repair, and executable-action transitions are handled through the CLI setup presenter.
Tool-settings catalog and warmup ownership
Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs, Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs
Catalog invalidation, view readiness, header updates, and registry warmup scheduling are owned by the tool-settings presenter.
Task-based editor flows
Packages/src/Editor/Presentation/Setup/SetupWizardStartupFlow.cs, Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardWindow.cs, Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs
Async editor handlers return Task; callers use await or .Forget() for scheduled operations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the async UI hardening and presenter refactor described by the changeset.
Description check ✅ Passed The description directly matches the async UI hardening and presenter/domain split work in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/presentation-async-void-and-shallow-split

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: 1

🧹 Nitpick comments (4)
Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs (1)

100-111: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant warmup-cancel calls before SetViewReady(false).

SetViewReady(false) already calls CancelRegistryWarmup() internally when not ready, so the preceding explicit _toolSettingsPresenter?.CancelRegistryWarmup() is a no-op duplicate in both OnDestroy and OnDisable. ResetRegistryWarmupAttemptCount() right before nulling _toolSettingsPresenter also has no observable effect.

♻️ Simplify cleanup
 private void OnDestroy()
 {
     CancelDeferredInitialRefresh();
-    _toolSettingsPresenter?.CancelRegistryWarmup();
-    _toolSettingsPresenter?.ResetRegistryWarmupAttemptCount();
     CancelSkillInstallStateRefresh();
     _toolSettingsPresenter?.SetViewReady(false);
     _view?.Dispose();

Also applies to: 216-229

🤖 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/Presentation/UnityCliLoopSettingsWindow.cs` around lines
100 - 111, Remove the explicit _toolSettingsPresenter?.CancelRegistryWarmup()
and _toolSettingsPresenter?.ResetRegistryWarmupAttemptCount() calls from both
OnDestroy and OnDisable. Keep _toolSettingsPresenter?.SetViewReady(false) in the
cleanup sequence so it performs the required warmup cancellation before the
presenter is cleared.
Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs (2)

53-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated cached-CLI-state retrieval within the same class.

ResolveCurrentPrimaryButtonAction re-fetches cliVersion, cliIsDispatcher, cliExecutablePath, canUninstallCli, and requiredCliVersion from _cliSetupApplicationService — the same set already computed in CreateCliSetupData (Line 147-155). Consider extracting a small private helper to avoid the two call sites drifting apart.

🤖 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/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs`
around lines 53 - 68, The cached CLI state is assembled twice in the presenter,
allowing ResolveCurrentPrimaryButtonAction and CreateCliSetupData to diverge.
Extract the shared retrieval and canUninstallCli calculation into a private
helper, then reuse it from both methods while preserving the existing
ResolveCliPrimaryButtonAction behavior.

116-123: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate CliPathSetupCheckPolicy.ShouldCheck wrapper across two presenters. Both files define an internal static method with the identical body — mapping platform == RuntimePlatform.WindowsEditor to isWindowsEditor and forwarding to CliPathSetupCheckPolicy.ShouldCheck — under different names. One of these should be the single source of truth, reused by the other call site (and by UnityCliLoopSettingsWindow.ShouldCheckCliPathSetup, which already calls the presenter's copy).

  • Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs#L116-L123: keep this as the canonical wrapper (or move the mapping directly into CliPathSetupCheckPolicy itself).
  • Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs#L575-L582: delegate ShouldCheckCliPathSetupForSetupWizard to UnityCliLoopSettingsCliSetupPresenter.ShouldCheckCliPathSetupForPlatform instead of re-wrapping the policy.
🤖 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/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs`
around lines 116 - 123, The duplicate policy wrapper should have one source of
truth. Keep
UnityCliLoopSettingsCliSetupPresenter.ShouldCheckCliPathSetupForPlatform as the
canonical mapping to CliPathSetupCheckPolicy.ShouldCheck; in
Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs lines 575-582,
update ShouldCheckCliPathSetupForSetupWizard to delegate to that presenter
method instead of re-wrapping the policy. No direct change is needed at the
presenter site.
Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs (1)

541-545: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse the dialog helper here

HandleInstallSkillsAsync duplicates the ShouldShowSkillsInstalledDialog check. Calling the helper keeps the decision in one place; otherwise the wrapper should be removed and its tests updated.

🤖 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/Presentation/Setup/SetupWizardWindow.cs` around lines 541
- 545, Update HandleInstallSkillsAsync to call the existing
ShouldShowSkillsInstalledDialog helper instead of duplicating its decision
logic. Preserve the helper’s behavior and, if the wrapper is no longer needed,
remove ShouldShowSkillsInstalledDialog and update its tests accordingly.
🤖 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/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs`:
- Around line 50-53: Update InvalidateCatalog in
UnityCliLoopSettingsToolSettingsPresenter to reset the registry warmup/retry
budget whenever the catalog is invalidated, in addition to setting
_isCatalogDirty. Ensure invalidation through
UnityCliLoopSettingsWindow.InvalidateToolSettingsCatalog can restart warmup even
after the retry cap was exhausted.

---

Nitpick comments:
In `@Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs`:
- Around line 541-545: Update HandleInstallSkillsAsync to call the existing
ShouldShowSkillsInstalledDialog helper instead of duplicating its decision
logic. Preserve the helper’s behavior and, if the wrapper is no longer needed,
remove ShouldShowSkillsInstalledDialog and update its tests accordingly.

In `@Packages/src/Editor/Presentation/UnityCliLoopSettingsCliSetupPresenter.cs`:
- Around line 53-68: The cached CLI state is assembled twice in the presenter,
allowing ResolveCurrentPrimaryButtonAction and CreateCliSetupData to diverge.
Extract the shared retrieval and canUninstallCli calculation into a private
helper, then reuse it from both methods while preserving the existing
ResolveCliPrimaryButtonAction behavior.
- Around line 116-123: The duplicate policy wrapper should have one source of
truth. Keep
UnityCliLoopSettingsCliSetupPresenter.ShouldCheckCliPathSetupForPlatform as the
canonical mapping to CliPathSetupCheckPolicy.ShouldCheck; in
Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs lines 575-582,
update ShouldCheckCliPathSetupForSetupWizard to delegate to that presenter
method instead of re-wrapping the policy. No direct change is needed at the
presenter site.

In `@Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs`:
- Around line 100-111: Remove the explicit
_toolSettingsPresenter?.CancelRegistryWarmup() and
_toolSettingsPresenter?.ResetRegistryWarmupAttemptCount() calls from both
OnDestroy and OnDisable. Keep _toolSettingsPresenter?.SetViewReady(false) in the
cleanup sequence so it performs the required warmup cancellation before the
presenter is cleared.
🪄 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: 102bd7cf-f52d-4a58-88e0-1305560e16e0

📥 Commits

Reviewing files that changed from the base of the PR and between 920da27 and 2758256.

⛔ Files ignored due to path filters (3)
  • 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 (10)
  • Assets/Tests/Editor/SettingsPresentationDecisionPolicyTests.cs
  • Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs
  • Packages/src/Editor/Domain/CliPathSetupCheckPolicy.cs
  • Packages/src/Editor/Domain/SkillInstallDialogPolicy.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

Comment on lines +50 to +53
internal void InvalidateCatalog()
{
_isCatalogDirty = true;
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -e
file='Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs'
echo "== outline =="
ast-grep outline "$file" --view expanded || true
echo "== references =="
rg -n "_registryWarmupAttemptCount|InvalidateCatalog|ScheduleRegistryWarmup|ResetRegistryWarmupAttemptCount" "$file"
echo "== file excerpt =="
nl -ba "$file" | sed -n '1,260p'

Repository: hatayama/unity-cli-loop

Length of output: 2407


🏁 Script executed:

rg -n "_registryWarmupAttemptCount|InvalidateCatalog|ScheduleRegistryWarmup|ResetRegistryWarmupAttemptCount" Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs

Repository: hatayama/unity-cli-loop

Length of output: 821


🏁 Script executed:

set -e
file='Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs'
echo "== relevant excerpt =="
sed -n '40,175p' "$file" | cat -n

Repository: hatayama/unity-cli-loop

Length of output: 5353


🏁 Script executed:

set -e
file='Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs'
sed -n '50,175p' "$file" | cat -n

Repository: hatayama/unity-cli-loop

Length of output: 5047


🏁 Script executed:

set -e
rg -n "InvalidateCatalog\(" .

Repository: hatayama/unity-cli-loop

Length of output: 529


🏁 Script executed:

set -e
file='Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs'
sed -n '360,420p' "$file" | cat -n

Repository: hatayama/unity-cli-loop

Length of output: 2515


Reset the warmup budget when invalidating the catalog. Packages/src/Editor/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs:50 only marks the catalog dirty; if the retry cap is already exhausted, a later invalidation (including UnityCliLoopSettingsWindow.InvalidateToolSettingsCatalog()) can’t restart registry warmup until another reset path runs.

🤖 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/Presentation/UnityCliLoopSettingsToolSettingsPresenter.cs`
around lines 50 - 53, Update InvalidateCatalog in
UnityCliLoopSettingsToolSettingsPresenter to reset the registry warmup/retry
budget whenever the catalog is invalidated, in addition to setting
_isCatalogDirty. Ensure invalidation through
UnityCliLoopSettingsWindow.InvalidateToolSettingsCatalog can restart warmup even
after the retry cap was exhausted.

@hatayama
hatayama merged commit a9e2798 into feature/design-review-fixes-integration Jul 14, 2026
2 checks passed
@hatayama
hatayama deleted the feat/presentation-async-void-and-shallow-split branch July 14, 2026 07:05
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