Skip to content

Ensure tower-runtime setup failures surface a terminal status#253

Open
socksy wants to merge 1 commit intodevelopfrom
fix/tower-runtime-silent-setup-errors
Open

Ensure tower-runtime setup failures surface a terminal status#253
socksy wants to merge 1 commit intodevelopfrom
fix/tower-runtime-silent-setup-errors

Conversation

@socksy
Copy link
Copy Markdown
Contributor

@socksy socksy commented Apr 17, 2026

Several setup error paths in execute_local_app (uv spawn, venv, PYTHONPATH construction, etc.) returned without notifying the status channel, so the app got stuck reporting an unusable state and runs crashed with exit 1. Wrap the sender in a drop guard that always sends a -2 sentinel on failure, distinct from -1 (cancelled).

Summary by CodeRabbit

  • Bug Fixes

    • Improved application reliability by ensuring status is consistently reported in all failure scenarios, preventing potential hangs or unresponsive states during initialization.
  • Tests

    • Added test coverage for setup failure scenarios to verify proper status reporting behavior.

Several setup error paths in execute_local_app (uv spawn, venv,
PYTHONPATH construction, etc.) returned without notifying the status
channel, so the app got stuck reporting an unusable state and runs
crashed with exit 1. Wrap the sender in a drop guard that always sends
a -2 sentinel on failure, distinct from -1 (cancelled).
@github-actions
Copy link
Copy Markdown
Contributor

⚠️ WARNING: This PR targets main instead of develop

This PR is targeting main which will trigger a production deployment when merged.

If this is a regular feature/fix PR, please change the base branch to develop.
If this is intentional (e.g., hotfix), you can ignore this warning.

Current base: main
Recommended base: develop

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

📝 Walkthrough

Walkthrough

The changes introduce a StatusReporter drop-guard in the local runtime to guarantee the oneshot sender is always signaled with a status code, even when execute_local_app returns errors before process execution. A new constant SETUP_FAILURE_EXIT_CODE = -2 distinguishes setup failures from cancellation (-1). A test validates this behavior with invalid manifest entries.

Changes

Cohort / File(s) Summary
Status Reporter Drop-Guard
crates/tower-runtime/src/local.rs
Added StatusReporter wrapper to ensure oneshot Sender<i32> is always signaled, even on early error paths. Introduced SETUP_FAILURE_EXIT_CODE = -2 constant to distinguish setup failures from cancellation sentinel (-1). Replaced direct sx.send(...) calls with reporter.send(...) across multiple branches.
Setup Failure Test
crates/tower-runtime/tests/local_test.rs
Added Unix-gated async test validating that setup failures (via invalid manifest import_paths) result in Status::Crashed { code } rather than a waiter error. Test polls app.status() until terminal state and verifies negative exit code is reported.

Poem

🐰 A guard upon the drop, so neat,
Ensures the sender code's complete,
No error left without a say,
Setup failures now report the way!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: ensuring setup failures in tower-runtime surface a terminal status.

✏️ 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 fix/tower-runtime-silent-setup-errors

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

⚠️ WARNING: This PR targets main instead of develop

This PR is targeting main which will trigger a production deployment when merged.

If this is a regular feature/fix PR, please change the base branch to develop.
If this is intentional (e.g., hotfix), you can ignore this warning.

Current base: main
Recommended base: develop

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/tower-runtime/src/local.rs`:
- Around line 52-55: The comment points out that -1 is overloaded between
cancellation and child.wait() I/O failures; change the contract so
SETUP_FAILURE_EXIT_CODE remains -2 and -1 is reserved exclusively for
cancellation, and introduce a new sentinel or typed status for wait failures
(for example WAIT_FAILURE_EXIT_CODE) used by wait_for_process() instead of
returning -1 on child.wait() I/O errors; update wait_for_process(), its callers,
and any documentation/comments that reference the old -1 behavior (identify uses
in wait_for_process(), child.wait() error handling, and callers of
execute_local_app()) so callers can reliably distinguish cancellation vs. wait
failures.

In `@crates/tower-runtime/tests/local_test.rs`:
- Around line 383-385: Replace the loose check that Status::Crashed { code }
asserts code < 0 with an exact equality assertion for the setup-failure sentinel
introduced by the PR (i.e., assert_eq!(code, -2) or reference the exported
constant if available), so update the assertion in the Status::Crashed match arm
to pin the specific setup-failure code rather than any negative value; if the
constant (e.g., SETUP_FAILURE_SENTINEL) is not exported to tests, duplicate the
-2 literal in the test to make the expectation explicit.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 49ee58df-251b-42f8-85be-da3fe4396056

📥 Commits

Reviewing files that changed from the base of the PR and between 500bd96 and 196a706.

📒 Files selected for processing (2)
  • crates/tower-runtime/src/local.rs
  • crates/tower-runtime/tests/local_test.rs

Comment on lines +52 to +55
// Sent when execute_local_app returns Err before producing a real exit code
// (uv not found, venv spawn failed, PYTHONPATH construction failed, etc).
// Distinct from the cancellation sentinel -1.
pub(crate) const SETUP_FAILURE_EXIT_CODE: i32 = -2;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

-1 is still overloaded.

These comments make -1 part of the cancellation contract, but wait_for_process() in this file also returns -1 for child.wait() I/O failures at Lines 578-581. That means callers still can't reliably distinguish cancellation from a runtime wait failure. If these negative codes are now semantic, reserve -1 for cancellation only and give wait errors their own sentinel or a typed status.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/tower-runtime/src/local.rs` around lines 52 - 55, The comment points
out that -1 is overloaded between cancellation and child.wait() I/O failures;
change the contract so SETUP_FAILURE_EXIT_CODE remains -2 and -1 is reserved
exclusively for cancellation, and introduce a new sentinel or typed status for
wait failures (for example WAIT_FAILURE_EXIT_CODE) used by wait_for_process()
instead of returning -1 on child.wait() I/O errors; update wait_for_process(),
its callers, and any documentation/comments that reference the old -1 behavior
(identify uses in wait_for_process(), child.wait() error handling, and callers
of execute_local_app()) so callers can reliably distinguish cancellation vs.
wait failures.

Comment on lines +383 to +385
Status::Crashed { code } => {
assert!(code < 0, "expected negative sentinel, got {}", code);
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Assert the exact setup-failure code.

code < 0 is too loose for this regression: it would also pass if setup failures accidentally started reporting the cancellation sentinel (-1). This test should pin the specific setup-failure code introduced by the PR, even if that means exposing the constant to integration tests or duplicating -2 here.

Suggested assertion
-                    assert!(code < 0, "expected negative sentinel, got {}", code);
+                    assert_eq!(code, -2, "expected setup failure sentinel, got {}", code);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Status::Crashed { code } => {
assert!(code < 0, "expected negative sentinel, got {}", code);
return;
Status::Crashed { code } => {
assert_eq!(code, -2, "expected setup failure sentinel, got {}", code);
return;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/tower-runtime/tests/local_test.rs` around lines 383 - 385, Replace the
loose check that Status::Crashed { code } asserts code < 0 with an exact
equality assertion for the setup-failure sentinel introduced by the PR (i.e.,
assert_eq!(code, -2) or reference the exported constant if available), so update
the assertion in the Status::Crashed match arm to pin the specific setup-failure
code rather than any negative value; if the constant (e.g.,
SETUP_FAILURE_SENTINEL) is not exported to tests, duplicate the -2 literal in
the test to make the expectation explicit.

@socksy socksy changed the base branch from main to develop April 23, 2026 10:47
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