Skip to content

fix: Busy responses now show as temporary status messages#1227

Merged
hatayama merged 1 commit into
v3-betafrom
feature/hatayama/update-busy-status-message
May 27, 2026
Merged

fix: Busy responses now show as temporary status messages#1227
hatayama merged 1 commit into
v3-betafrom
feature/hatayama/update-busy-status-message

Conversation

@hatayama

Copy link
Copy Markdown
Owner

Summary

  • Busy command responses now return a lightweight status JSON instead of a full error envelope.
  • The message now says the requested command was not executed because Unity is busy running another command.

User Impact

  • Before this change, busy responses showed fields such as UNITY_SERVER_BUSY, errorCode, and retry details, which made a temporary busy state look like a severe Unity failure.
  • After this change, users see Status: "Busy" and a clear message explaining that they can retry after the running command completes.

Changes

  • Emit a compact busy status response for server_busy RPC failures.
  • Keep internal retryable classification so CLI handling can still recognize busy responses.
  • Update Go CLI tests and rebuild checked-in native CLI binaries.

Verification

  • go test ./internal/cli -run ServerBusy
  • go test ./internal/cli
  • scripts/check-go-cli-source.sh
  • scripts/check-go-cli.sh

Busy states are temporary command rejections, not severe Unity failures. Emit a lightweight Status/Message JSON for server_busy RPC responses while keeping the internal retryable classification for CLI handling.
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a "Unity is busy" status envelope with RPC-informed messaging for server_busy errors. New busy_status.go module defines the envelope type and message construction from running/requested tool names. Error classification and output paths are updated to route busy errors through this envelope instead of generic error responses. String utility is extracted to a new helper module.

Changes

Busy Status Error Handling

Layer / File(s) Summary
Busy status envelope and message construction
Packages/src/Cli~/internal/cli/string_helpers.go, Packages/src/Cli~/internal/cli/busy_status.go
firstNonEmpty utility extracts the first non-empty string from variadic inputs. cliStatusEnvelope defines JSON output with Status and Message. writeBusyStatusEnvelope encodes it as indented JSON. unityServerBusyMessage constructs user-facing retry guidance by extracting runningToolName and requestedToolName from RPC data, falling back to command context when fields are missing. rpcStringData safely retrieves string values from RPC map payloads.
Error envelope routing and output dispatch
Packages/src/Cli~/internal/cli/error_envelope.go
classifyError routes server_busy RPC errors to unityServerBusyError with decoded RPC payload and context. unityServerBusyError signature updated to accept RPC data and generates message via unityServerBusyMessage instead of using raw RPC message. writeErrorEnvelope special-cases UNITY_SERVER_BUSY errors to dispatch to writeBusyStatusEnvelope and return early. firstNonEmpty removed from this file after relocation.
Busy status error classification and output tests
Packages/src/Cli~/internal/cli/error_envelope_test.go
TestClassifyServerBusyRPCError validates exact retry-guidance message format. TestWriteClassifiedServerBusyRPCErrorWritesBusyStatus verifies writeClassifiedError outputs cliStatusEnvelope with Status="Busy" and correct message, excluding error-envelope fields like Success or errorCode.

Sequence Diagram

sequenceDiagram
    participant ErrorHandler as classifyError
    participant ServerBusyErr as unityServerBusyError
    participant MessageBuild as unityServerBusyMessage
    participant ErrorWriter as writeErrorEnvelope
    participant BusyWriter as writeBusyStatusEnvelope
    participant Output as JSON Output
    
    ErrorHandler->>ServerBusyErr: route server_busy RPC error + decodedData
    ServerBusyErr->>MessageBuild: build message from RPC data + context
    MessageBuild->>ServerBusyErr: return formatted retry message
    ServerBusyErr->>ErrorHandler: return classified error
    ErrorHandler->>ErrorWriter: pass error with message
    ErrorWriter->>BusyWriter: dispatch UNITY_SERVER_BUSY error
    BusyWriter->>Output: write cliStatusEnvelope as JSON
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • hatayama/unity-cli-loop#1215: Updates Unity-side JsonRpcProcessor CLI version gate tests to assert that server_busy error messages include running and requested tool names, matching the Go-side busy message construction in this PR.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 accurately summarizes the main change: introducing lightweight status messages for busy responses instead of full error envelopes.
Description check ✅ Passed The description clearly explains the changeset purpose, user impact, specific changes made, and verification steps, all directly related to the busy status messaging improvements.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feature/hatayama/update-busy-status-message

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 and usage tips.

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

🧹 Nitpick comments (1)
Packages/src/Cli~/internal/cli/error_envelope_test.go (1)

240-266: ⚡ Quick win

Add a fallback-path test for missing tool names in server_busy data.

This block covers the fully populated payload path, but not the branch that falls back to rpcErr.Message when runningToolName/requestedToolName are absent.

Proposed test addition
 func TestWriteClassifiedServerBusyRPCErrorWritesBusyStatus(t *testing.T) {
@@
 	if bytes.Contains(stderr.Bytes(), []byte("Success")) || bytes.Contains(stderr.Bytes(), []byte("errorCode")) {
 		t.Fatalf("busy output should not include error envelope fields: %s", stderr.String())
 	}
 }
+
+func TestWriteClassifiedServerBusyRPCErrorFallsBackToRPCMessage(t *testing.T) {
+	rpcErr := &unityipc.RPCError{
+		Code:    -32603,
+		Message: "Unity is busy. Retry after the running tool completes.",
+		Data:    json.RawMessage(`{"type":"server_busy"}`),
+	}
+	var stderr bytes.Buffer
+
+	writeClassifiedError(&stderr, rpcErr, errorContext{projectRoot: "/tmp/MyProject", command: "get-logs"})
+
+	var envelope cliStatusEnvelope
+	if err := json.Unmarshal(stderr.Bytes(), &envelope); err != nil {
+		t.Fatalf("stderr is not valid JSON: %v\n%s", err, stderr.String())
+	}
+	if envelope.Status != cliStatusBusy {
+		t.Fatalf("status mismatch: %#v", envelope)
+	}
+	if envelope.Message != rpcErr.Message {
+		t.Fatalf("fallback message mismatch: %#v", envelope)
+	}
+}
🤖 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/Cli`~/internal/cli/error_envelope_test.go around lines 240 -
266, Add a new unit test that exercises the fallback branch when server_busy
data omits tool names: create an RPCError (unityipc.RPCError) whose Data either
lacks runningToolName/requestedToolName or is empty but whose Message contains
the fallback text, call writeClassifiedError with the same errorContext used in
TestWriteClassifiedServerBusyRPCErrorWritesBusyStatus, unmarshal stderr into
cliStatusEnvelope and assert envelope.Status == cliStatusBusy and
envelope.Message == rpcErr.Message (the fallback), and finally assert the output
does not contain full envelope fields like "Success" or "errorCode"; mirror
naming and structure of TestWriteClassifiedServerBusyRPCErrorWritesBusyStatus
for consistency.
🤖 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.

Nitpick comments:
In `@Packages/src/Cli`~/internal/cli/error_envelope_test.go:
- Around line 240-266: Add a new unit test that exercises the fallback branch
when server_busy data omits tool names: create an RPCError (unityipc.RPCError)
whose Data either lacks runningToolName/requestedToolName or is empty but whose
Message contains the fallback text, call writeClassifiedError with the same
errorContext used in TestWriteClassifiedServerBusyRPCErrorWritesBusyStatus,
unmarshal stderr into cliStatusEnvelope and assert envelope.Status ==
cliStatusBusy and envelope.Message == rpcErr.Message (the fallback), and finally
assert the output does not contain full envelope fields like "Success" or
"errorCode"; mirror naming and structure of
TestWriteClassifiedServerBusyRPCErrorWritesBusyStatus for consistency.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d46ba688-da46-470d-a95f-674b507a90a2

📥 Commits

Reviewing files that changed from the base of the PR and between a90ca87 and 5b18993.

⛔ Files ignored due to path filters (3)
  • Packages/src/Cli~/dist/darwin-amd64/uloop is excluded by !**/dist/** and included by none
  • Packages/src/Cli~/dist/darwin-arm64/uloop is excluded by !**/dist/** and included by none
  • Packages/src/Cli~/dist/windows-amd64/uloop.exe is excluded by !**/dist/**, !**/*.exe and included by none
📒 Files selected for processing (4)
  • Packages/src/Cli~/internal/cli/busy_status.go
  • Packages/src/Cli~/internal/cli/error_envelope.go
  • Packages/src/Cli~/internal/cli/error_envelope_test.go
  • Packages/src/Cli~/internal/cli/string_helpers.go

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 7 files

Re-trigger cubic

@hatayama
hatayama merged commit fdd6b98 into v3-beta May 27, 2026
8 checks passed
@hatayama
hatayama deleted the feature/hatayama/update-busy-status-message branch May 27, 2026 14:52
@github-actions github-actions Bot mentioned this pull request May 27, 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