Skip to content

feat: a local host that fails to start is shown in the window - #695

Draft
Tryanks wants to merge 1 commit into
mainfrom
feat/startup-failure-in-window
Draft

Tryanks wants to merge 1 commit into
mainfrom
feat/startup-failure-in-window

Conversation

@Tryanks

@Tryanks Tryanks commented Oct 11, 2026

Copy link
Copy Markdown
Owner

Summary

A local host that fails to start is now one more attachment failure. The window opens as usual on Machines, where This machine gives the reason and offers Retry and Quit. Saved machines and pairing stay available.

 main (crates/app/src/main.rs)
-  SessionStore::open_host / needs_migration / LocalKernel::start
-    Err → exit_with_startup_failure   # empty window + Critical system prompt, exit 1
+  start_local_host()                  # same function at launch and on Retry
+    Ok(Started) → launch(Ok(kernel))
+    Ok(Migrate) → migration window (unchanged)
+    Err(reason) → launch(Err(reason))  # normal window, no local host
+  exit_with_startup_failure           # only when no data dir can be named at all
 AppShell::attach(Local)                      (crates/ui/src/shell.rs)
+  setup.local(cx) -> Result<Transport, String>   # LocalTransport is now fallible
+    Err(reason) → RemotePanel.set_local_failure(reason); current attachment kept
   Attachment::open(target, transport, …)
 <RemotePanel> local_row                      (crates/ui/src/remote/mod.rs)
+  "Could not start: <reason>"  [Retry] [Quit]   # Retry = switch(Local) again

What each failure now shows (on the This machine row):

  • Data dir in use by another Tcode (acquire_ownership): "Could not start: another Tcode host is already using the data directory …". Retry takes ownership once the other instance quits.
  • Data dir cannot be opened (open_host): the error, then "Its settings could not be read, so the default language and theme are in use."
  • Migration check fails / blocked relocation surfaced by it: the error text from needs_migration.
  • Kernel does not start: the error text from spawn_host.
  • Retry finds that a migration is now needed: "Its data has to be upgraded first. Quit Tcode and open it again."

Things that follow from having no local host:

  • Settings → Remote and the Machines invitation need the RemoteController that the process's own host installs, so they are offered only while that host runs. Without this, a window attached to a remote machine could reach update_global::<RemoteController> with no controller installed.
  • Disconnect now detaches first (deferred until the panel's listener returns), then falls back to the local host. If that host does not start, the window is left on nothing instead of on the machine you disconnected.

Failures in the migration window are unchanged. They were already drawn in-window.

Evidence

  • Before: two instances on one TCODE_DATA_DIR. The second shows a system alert and exits.
    before
    After: same setup. The window opens with This machine unavailable, Retry and Quit (desktop, light, English, HOSTNAME="Demo Mac", throwaway profile).
    after

Live checks, run by hand against the debug build:

  • With instance A running, Retry in B failed again (logged a second time). After A was stopped, Retry in B attached the local workspace, and Machines showed the invitation section.
  • Quit on the failed window exited that process only.
  • TCODE_DATA_DIR pointed at a regular file: "Could not start: File exists (os error 17). Its settings could not be read, so the default language and theme are in use."
  • Narrow width: the row wraps and the buttons stay beside it.

Seam test, shell::tests::a_local_host_that_does_not_start_is_shown_and_retried. It drives AppShell through the same ShellSetup.local that run_shell feeds:

local answers: Err(busy), Err(busy), Ok(transport)
mount → 1 attempt, no store, hosts-local-failure shown
click Retry → 2 attempts, still unavailable
click Retry → 3 attempts, local store attached, failure line gone

Mutation check: when attach does not hand the reason to the panel, the test fails (shell.rs:4587).

Tests touched:

  • attachment::tests::closing_an_attachment_finishes_its_pump_without_shutting_down_the_host: setup only. It now passes the Transport directly, because Attachment::open takes a resolved transport. Its contract is unchanged.
  • shell::tests::mount_initial: the helper's local factory now returns Ok(transport).
  • No test was deleted.

Checks:

cargo fmt --all --check                                        ok
cargo clippy --workspace --all-targets --locked -- -D warnings ok
cargo nextest run --workspace --locked                         1126 tests run: 1126 passed, 13 skipped
cargo machete                                                  didn't find any unused dependencies
cargo clippy -p tcode-ui --no-default-features --lib -- -D warnings  ok

Gaps:

  • No phone screenshot. The phone shell shares the Machines surface, but a phone has no local host (local: None), so this state cannot occur there.
  • Dark theme not looked at live, because the theme follows the system appearance.
  • Two failure cases were not reproduced live: a kernel that does not start, and a migration-check failure.

Merge Danger

Door: two-way

Blast Radius: startup

The desktop startup path changed:

  • The data dir is now resolved with store::data_dir(), and the store is opened inside start_local_host. --pair opens its own store handle.
  • LocalTransport's signature changed for every caller (desktop, phone example, tests).
  • A Retry runs the ownership attempt on the UI thread, as the launch did before the event loop. If a relaunch marker is pending, that attempt can wait up to RELAUNCH_WAIT.

Closes #682

A data directory in use by another Tcode, one that cannot be opened, a
failed migration check or a kernel that does not start no longer end in a
system alert and exit. The window opens on Machines, where This machine
says why and offers Retry and Quit; saved machines and pairing stay
available. Retry takes ownership of the data directory again.

The local transport bootstrap gives the shell is now fallible, and the
shell resolves it before replacing the current attachment. Settings →
Remote and the invitation need the process's own host, so they apply only
while it runs.
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.

Startup: a local host that fails to start is shown in the window, not as a system alert

1 participant