fix: On Windows, uloop status reports a dialog as soon as it opens

Merged
HA
14h ago
+473-54

Summary

  • On Windows, uloop status (and the check before every command) reports BlockedByDialog within about a third of a second after a dialog opens, even in Editors older than 6000.7 that cannot report their dialogs.
  • uloop status with no dialog open is no slower, because the Editor now tells the CLI its own process ID instead of the CLI searching for it.

User Impact

  • Before: an Editor older than 6000.7 was reported Ready for about a second after a dialog opened, because uloop looked at Unity's windows only after the main thread had been still for a second and a second answer confirmed it. A command sent in that time went to an Editor that could not run it.
  • After: on Windows, an answer that would let the reader send a command (Ready, Compiling, ImportingAssets) gets one look at Unity's windows right away once the main thread has been still for 0.3 seconds. A dialog found makes it BlockedByDialog; no dialog, or a look that fails, keeps the usual report with no extra hint.
  • A main thread that keeps running gets no look, so a window that only looks like a dialog (a message box with no owner that another thread opened) cannot make status, or the check before every command, refuse commands while the Editor can run them.
  • uloop status while a dialog is open also returns faster on Windows (about 1.1 s instead of 2.1–2.4 s), because the five-second path no longer searches the process list either.
  • macOS and Linux keep the look after a short stall.

Changes

  • The Editor reads its process ID once when the server starts and reports it as ProcessId in get-editor-status. No protocol version change: the field is additive, and an old package simply reports nothing.
  • unitydialog.Inspector.InspectEditor takes that process ID and skips the process search (which starts PowerShell on Windows, about 360 ms). Inspect keeps its behavior by passing zero.
  • The project runner passes the reported process ID to every look. On Windows it looks once right after the first answer when the main thread has been still for 0.3 seconds or more, instead of asking the Editor again after a one-second stall. Why 0.3 seconds: the Editor loop is ticked at 6 Hz or more, so a running main thread is never still for much over 0.17 seconds.
  • The status skill says when each operating system looks.
  • Shared release input stamps are refreshed for the cli/common change.

Known cost

With the new project runner and a package that predates ProcessId, each Windows command whose main thread has paused pays the process search on its pre-send check (status and get-logs both measured at about 410–440 ms instead of 35–75 ms). The project runner is pinned by the package, so this pairing should be rare.

Verification

  • scripts/check-go-cli.sh (format, vet, lint, tests, build) on macOS; go test ./..., go vet ./..., golangci-lint fmt --diff and golangci-lint run in cli/common, cli/project-runner and cli/dispatcher on Windows; GOOS=windows go vet ./... on macOS.
  • go test ./internal/architecture/, go run ./cmd/check-release-triggers --base origin/feat/modal-dialog-detection-integration --head HEAD, go run ./cmd/check-skill-size, and go run ./cmd/sync-tool-docs --check in cli/release-automation.
  • uloop compile, and uloop run-tests --filter-type regex --filter-value "EditorStatusBridgeCommandTests|UnityCliLoopExecutionRouterActivityTests|JsonRpcRequestProcessorTests" (30 passed).
  • New Go tests run on any OS by replacing the operating system: Windows looks right after the first answer once the main thread has been still for exactly 0.3 seconds or longer (Ready / short stall / Compiling / ImportingAssets) and passes the reported process ID; a main thread still for 0.1 or 0.29 seconds gets no look even when a dialog-like window is there; no dialog keeps Ready with one look and no recheck; a failed look prints the same JSON as before; Busy and an Editor-reported dialog get no look; macOS keeps no look for a running main thread; the inspector skips the process search when given a process ID and searches when not.
  • The 0.3-second condition was added after the Windows measurements below, from review. It has not run on a Windows Editor yet; the first run after a dialog opened in those measurements had a main thread still for 0.34 seconds, so it would still be caught.

Measurements on Windows, with no dialog open, 10 runs each (median / max, ms):

CommandBefore (Unity 6000.3)After (Unity 6000.3)After (Unity 6000.7)
uloop status33 / 24935 / 4038 / 42
uloop get-logs72 / 9476 / 9591 / 108
uloop get-dialogs (for reference)406 / 424407 / 412—
Get-CimInstance in a new PowerShell (for reference)363 / 421——

Dialog opened from the Editor loop with no command running, then uloop status every ~0.6 s:

  • Unity 6000.3: Ready until the dialog opened, then BlockedByDialog from the first run after it opened (main thread still for 0.34 s at that run); before this change, runs in the first second after a dialog opened were Ready.
  • Unity 6000.7 (reports its dialogs itself): BlockedByDialog from the first run after the dialog opened, with every run under 0.1 s.
  • With the dialog open on 6000.3, uloop status took 1.08–1.09 s in 5 runs (2.1–2.4 s before), and uloop get-logs was refused with BLOCKED_BY_DIALOG.