fix: rojo died on SSH exit - launch via Task Scheduler, not Start-Process
CI / quality (push) Failing after 47s

Root cause: Windows OpenSSH kills the whole process tree when the SSH
session exits, so rojo started over SSH died seconds later. Proven:
1 proc inside the session, 0 from a fresh session.

Guard now calls 'schtasks /Run /TN RojoTWR' instead of Start-Process.
Verified unattended: killed rojo, scheduler restored it (Last Result: 0).
This commit is contained in:
2026-08-06 22:05:36 -04:00
parent 25d1e37750
commit ae5b26b3eb
2 changed files with 59 additions and 7 deletions
+21 -7
View File
@@ -144,16 +144,30 @@ A scheduled task `RojoTWR` does exactly this — `schtasks /Run /TN "RojoTWR"`.
(Launching via `start` over SSH does **not** work: the process dies when the SSH
session exits. Use the task.)
**Rojo does not stay up on its own.** It was observed dying repeatedly (Studio
restarts, machine sleep, the one-shot task simply ending). A watchdog handles
this now:
**Rojo does not stay up on its own.** The root cause was found on 2026-08-06:
**Windows OpenSSH kills the entire process tree when the SSH session exits.**
Anything started over SSH with `Start-Process` — including Rojo — dies seconds
later. This presents as "Rojo was running a minute ago and now the plugin won't
connect," and it is *not* a plugin fault.
Proof: `rojo procs: 1` inside the SSH session, `rojo procs: 0` from a new
session moments later.
The fix is to hand ownership to **Task Scheduler**, which is not part of the SSH
process tree:
```
%USERPROFILE%\rojo-guard.ps1 idempotent restart script
schtasks /Query /TN "RojoTWR-Guard" runs it every 3 minutes
schtasks /Run /TN "RojoTWR" start rojo detached (survives SSH exit)
%USERPROFILE%\rojo-guard.ps1 idempotent watchdog
schtasks /Query /TN "RojoTWR-Guard" runs the watchdog every 3 minutes
%USERPROFILE%\rojo-guard.log only logs real events, silent when healthy
```
Repo copy of the watchdog: `tools/win/rojo-guard.ps1`.
> **Never start Rojo with `Start-Process`/`start` over SSH.** Always go through
> `schtasks /Run /TN "RojoTWR"`. The guard itself follows this rule internally.
The guard is deliberately conservative:
- if `rojo` already owns 34872 it exits 0 and does nothing (safe mid-session —
it will not disturb a live Studio connection)
@@ -162,8 +176,8 @@ The guard is deliberately conservative:
- if `ServerPackages` is missing it logs that instead of letting Rojo silently
exit on startup
Verified by killing `rojo` and confirming the guard restored it with the port
owned by `rojo`.
Verified end-to-end: killed `rojo`, waited, and the scheduler restored it
unattended (`Last Result: 0`, port owned by `rojo`).
**Clicking Rojo → Connect in Studio is still manual and always will be.** The
guard keeps the *server* alive; it cannot press the button. `Rojo_autoReconnect`