Skip to content

feat: configurable compile wait timeout and working timeout recovery - #2036

Merged
hatayama merged 7 commits into
v3-betafrom
feature/issue-2032-compile-wait
Jul 28, 2026
Merged

feat: configurable compile wait timeout and working timeout recovery#2036
hatayama merged 7 commits into
v3-betafrom
feature/issue-2032-compile-wait

Conversation

@hatayama

@hatayama hatayama commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • uloop compile can wait longer than the previous hard-coded 10 minutes via --compile-wait-timeout-seconds.
  • After a wait timeout, retrying uloop compile reattaches to the in-flight compile instead of starting a new one that hits UNITY_SERVER_BUSY.
  • Timeout errors now include the last observed compile state and clearer NextActions that match real recovery behavior.

Fixes #2032

User Impact

  • Before: Long compiles always timed out at 10 minutes with no way to extend the wait. Retrying after timeout issued a new compile request and was rejected as busy while Unity was still compiling; the NextActions text incorrectly suggested retry would recover the original result.
  • After: Agents can set a longer wait for large projects. A timed-out compile leaves a local pending record so the next uloop compile attaches to the same RequestId and returns that result. Timeout and busy messages guide agents toward reattach rather than a useless new request.

Changes

  • Add CompileWaitTimeoutSeconds to the compile schema/skill catalog and wire it through the project-runner wait loop (default 600s).
  • Persist .uloop/pending-compile-request.json on wait timeout; on the next compile, attach via get-compile-status when the record is still valid.
  • Put last observed IsCompiling / IsUpdating / IsDomainReloadInProgress and WaitedMs into COMPILE_WAIT_TIMEOUT Details; extend compile-path UNITY_SERVER_BUSY NextActions with reattach guidance.

Verification

Review in cubic

hatayama and others added 3 commits July 28, 2026 16:10
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

Next review available in: 22 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 Plus

Run ID: cb1149ae-34f0-4987-a742-e59065a9d5ab

📥 Commits

Reviewing files that changed from the base of the PR and between 68d74e8 and 6bc1fac.

📒 Files selected for processing (7)
  • cli/dispatcher/shared-inputs-stamp.json
  • cli/project-runner/internal/projectrunner/compile_attach.go
  • cli/project-runner/internal/projectrunner/compile_attach_test.go
  • cli/project-runner/internal/projectrunner/compile_wait_test.go
  • cli/project-runner/internal/projectrunner/execution_errors.go
  • cli/project-runner/internal/projectrunner/run.go
  • cli/project-runner/shared-inputs-stamp.json
📝 Walkthrough

Walkthrough

Changes

Compile timeout and reattach

Layer / File(s) Summary
Command contracts and guidance
Packages/src/Editor/FirstPartyTools/Compile/CompileSchema.cs, cli/common/tools/default-tools.json, */skills/uloop-compile/*, cli/common/errors/*
Adds CompileWaitTimeoutSeconds with a default of 600 seconds and documents reattachment guidance for timed-out compiles.
Timeout parsing and reporting
cli/project-runner/internal/projectrunner/compile_wait.go, compile_wait_log.go, execution_errors.go, run.go, compile_wait_test.go
Validates configured timeout values, applies them to polling, records status details, emits structured logs, and returns richer timeout envelopes.
Pending compile persistence
cli/project-runner/internal/projectrunner/compile_pending_record*
Persists pending request identifiers after timeout, validates and expires records, and clears them when consumed or invalid.
Compile reattachment and recovery
cli/project-runner/internal/projectrunner/compile_attach*
Probes and resumes timed-out compiles, returns stored results, handles completion, disappearance, cancellation, and repeated timeout outcomes, and covers these flows with tests.

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

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant ProjectRunner
  participant Unity
  participant PendingRecord
  CLI->>ProjectRunner: Run compile with timeout
  ProjectRunner->>Unity: Poll compile status
  Unity-->>ProjectRunner: In-progress status
  ProjectRunner->>PendingRecord: Persist timed-out request
  CLI->>ProjectRunner: Retry compile
  ProjectRunner->>PendingRecord: Read pending request
  ProjectRunner->>Unity: Probe original request status
  Unity-->>ProjectRunner: Return stored or completed result
  ProjectRunner-->>CLI: Return compile result or timeout envelope
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.35% 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 summarizes the main change: configurable compile wait timeout plus improved timeout recovery.
Description check ✅ Passed The description is directly related to the implemented compile timeout and reattach recovery changes.
Linked Issues check ✅ Passed The PR satisfies #2032 by making the timeout configurable, preserving the default, and adding reattach-aware recovery and status details.
Out of Scope Changes check ✅ Passed The changes stay focused on compile timeout configuration, recovery, docs, tests, and supporting workflow updates.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-2032-compile-wait

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 and others added 2 commits July 28, 2026 17:20
compile_wait.go grew past the 500-line production-file limit after the
timeout/attach work. The VibeLog write and formatting helpers are a
separate concern from the wait loop, so relocate them without behavior
change.

Co-authored-by: Cursor <cursoragent@cursor.com>
The new CLI-only schema property is unreferenced in C# by design (same
pattern as other schema fields) and lifts PublicCandidate from 22 to 23.
Bump the gate to the measured count so the ceiling stays a no-slack
monitor.

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

Copy link
Copy Markdown
Owner Author

CI fixes pushed

TestProductionGoFilesStayFocused

Moved VibeLog helpers (writeCompileVibeLogcompileStatusLogContext) from compile_wait.go into compile_wait_log.go.

  • compile_wait.go: 273 lines
  • compile_wait_log.go: 317 lines

② Dead Code Gate

Compared against origin/v3-beta with the same CI flags:

  • v3-beta: Total 178 / PublicCandidate 22 (gate passes)
  • this branch: Total 179 / PublicCandidate 23

The sole new PublicCandidate is CompileSchema.CompileWaitTimeoutSeconds (CLI-consumed schema property; Unity ignores it). Raised --max-public-candidates 22 → 23 in .github/workflows/dead-code.yml.

Local verification: TestProductionGoFilesStayFocused, scripts/check-go-cli.sh, and CI-equivalent dead-code scan with max 23 all pass.

Please re-review.

@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)
cli/project-runner/internal/projectrunner/run.go (1)

239-249: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider also persisting the pending record when the wait is cancelled.

persistCompilePendingRecordOrWarn only runs on the !completed timeout path. If the wait ends via context cancellation (line 231-238), Unity is still compiling with the same requestID, but no pending record exists, so the next uloop compile cannot reattach and hits UNITY_SERVER_BUSY — the exact recovery gap this PR targets. requestID is in scope in that branch, so persisting there too is cheap.

🤖 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 `@cli/project-runner/internal/projectrunner/run.go` around lines 239 - 249,
Persist the compile-pending record in the context-cancellation branch as well as
the existing !completed timeout path. Update the cancellation handling around
the wait logic to call persistCompilePendingRecordOrWarn with
connection.ProjectRoot, requestID, and stderr before returning, preserving the
existing cancellation error behavior.
🤖 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 `@cli/project-runner/internal/projectrunner/run.go`:
- Around line 239-249: Persist the compile-pending record in the
context-cancellation branch as well as the existing !completed timeout path.
Update the cancellation handling around the wait logic to call
persistCompilePendingRecordOrWarn with connection.ProjectRoot, requestID, and
stderr before returning, preserving the existing cancellation error behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: be719c09-e5e3-4271-89f2-39278006e144

📥 Commits

Reviewing files that changed from the base of the PR and between 5aa4ac7 and 68d74e8.

📒 Files selected for processing (20)
  • .agents/skills/uloop-compile/SKILL.md
  • .claude/skills/uloop-compile/SKILL.md
  • .github/workflows/dead-code.yml
  • Packages/src/Editor/FirstPartyTools/Compile/CompileSchema.cs
  • Packages/src/Editor/FirstPartyTools/Compile/Skill/SKILL.md
  • cli/common/errors/busy_editor_state.go
  • cli/common/errors/busy_editor_state_test.go
  • cli/common/tools/default-tools.json
  • cli/dispatcher/shared-inputs-stamp.json
  • cli/project-runner/internal/projectrunner/compile_attach.go
  • cli/project-runner/internal/projectrunner/compile_attach_test.go
  • cli/project-runner/internal/projectrunner/compile_pending_record.go
  • cli/project-runner/internal/projectrunner/compile_pending_record_test.go
  • cli/project-runner/internal/projectrunner/compile_wait.go
  • cli/project-runner/internal/projectrunner/compile_wait_deps.go
  • cli/project-runner/internal/projectrunner/compile_wait_log.go
  • cli/project-runner/internal/projectrunner/compile_wait_test.go
  • cli/project-runner/internal/projectrunner/execution_errors.go
  • cli/project-runner/internal/projectrunner/run.go
  • cli/project-runner/shared-inputs-stamp.json

Bring in the grpc v1.82.1 bump so Go CLI Security Analysis can pass.

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

# Conflicts:
#	cli/dispatcher/shared-inputs-stamp.json
#	cli/project-runner/shared-inputs-stamp.json
@hatayama

Copy link
Copy Markdown
Owner Author

Follow-up: synced with v3-beta after #2040

  • Merged origin/v3-beta (includes grpc v1.82.1 from chore: bump google.golang.org/grpc to v1.82.1 for GO-2026-6061 #2040).
  • Resolved expected conflicts in cli/dispatcher/shared-inputs-stamp.json and cli/project-runner/shared-inputs-stamp.json by re-running scripts/stamp-release-inputs.sh (did not pick either side's hash).
  • Local scripts/check-go-cli.sh and govulncheck ./... (all four modules) pass.

Merge commit: 3cd75d50

Attach keeps the first TimedOutAtUtc, so remaining retrieval time is
wall-clock until that anchor plus the pending-record TTL. Computing
remaining as TTL minus the current wait overstated the window on every
reattach timeout and revived the misleading guidance from issue #2032.

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

Copy link
Copy Markdown
Owner Author

To-Do 18: attach re-timeout retention overstatement

Fixed in this PR per plan audit:

  • compileWaitTimeoutError now takes caller-supplied retentionRemaining.
  • New compile path (run.go): compilePendingRecordLifetime - waitTimeout (unchanged value).
  • Attach re-timeout (compile_attach.go): time.Until(record.TimedOutAtUtc.Add(compilePendingRecordLifetime)).
  • Tests: unit coverage for caller-supplied remaining; attach re-timeout asserts it does not report `roughly 19 more minutes` for a 1s wait when the first timeout was 15 minutes ago.

scripts/check-go-cli.sh completed with exit 0 (full four-module run, including architecture file-size test).

@hatayama
hatayama merged commit fc867c3 into v3-beta Jul 28, 2026
13 checks passed
@hatayama
hatayama deleted the feature/issue-2032-compile-wait branch July 28, 2026 09:03
@github-actions github-actions Bot mentioned this pull request Jul 28, 2026
hatayama added a commit that referenced this pull request Jul 28, 2026
Reviewing #2036 raised the question of why a runner-only change released
the dispatcher too, and answering it took several wrong guesses about the
mechanism before the facts were checked. The rule was documented but the
decision behind its granularity was not, so the settled question had no
reversal condition to consult and was relitigated from scratch.

Add ADR 0003 with the decision, why the coarse rule stays, and the two
finer alternatives (call-graph reachability, reproducible-build
comparison) with their reversal conditions. Record the facts that were
guessed wrong during the discussion: sharedInputsHash is a change marker
no consumer compares across commits, the gap is a cost trade rather than
a limit of static analysis, whitelist alignment with go list -deps is
already test-enforced rather than manual, and no-op releases already
carry a cli-release approval click today. Keep shared-release-inputs.md
operational with the observable behaviour and a pointer to the ADR.
hatayama added a commit that referenced this pull request Jul 28, 2026
Reviewing #2036 raised the question of why a runner-only change released
the dispatcher too, and answering it took several wrong guesses about the
mechanism before the facts were checked. The rule was documented but the
decision behind its granularity was not, so the settled question had no
reversal condition to consult and was relitigated from scratch.

Add ADR 0003 with the decision, why the coarse rule stays, and the two
finer alternatives (call-graph reachability, reproducible-build
comparison) with their reversal conditions. Record the facts that were
guessed wrong during the discussion: sharedInputsHash is a change marker
no consumer compares across commits, the gap is a cost trade rather than
a limit of static analysis, whitelist alignment with go list -deps is
already test-enforced rather than manual, and no-op releases already
carry a cli-release approval click today. Keep shared-release-inputs.md
operational with the observable behaviour and a pointer to the ADR.
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