You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #673, which is closed by the per-game button. This is the other half: the strip.
Why this exists as its own issue
#673's decision of 2026-08-04 scoped it to the button and assigned the strip to #794 ("leave the strip alone"). The Codex-found second route recorded on 2026-08-18 then added an acceptance criterion that widened it: "restores the strip and the Close Apps affordance without a relaunch."
Those two cannot both be satisfied by one PR, so the button shipped and the strip is tracked here rather than being quietly dropped. The affordance now returns on both routes (restart and the process-tracking toggle cycle), because the closable set is rebuilt from the store. The dots do not: they come from getTrackedRunningApps, which is gated on adoptedOrLaunchedGameKeys, and nothing puts the key back into that set.
Why the obvious fix is still ruled out
Adopting a game key because a configured companion is running remains unsafe for the reason in #673's Fix section: the adopted key feeds the aggregate running status that drives row highlight, sorting and canRelaunch, so every profile with SimHub enabled would read as "running" whenever SimHub is up. It is also intent-blind, which is the objection #794 settled: it cannot tell "left over from our session" from "autostarts with Windows".
The direction that is not intent-blind
Remember ownership instead of inferring it. SimLauncher knows it launched SimHub under the AC profile; it just forgets at exit.
Pruned: on verified exit, on successful kill, on a startup re-check miss, and when the path leaves the profile's trackable set on a config change.
The trap that decides whether this is correct
A reboot ends our processes by definition. User reboots, SimHub autostarts, SimLauncher starts, finds a record, path-verifies it and re-adopts a process it never launched this boot. Path verification proves "something runs at this path", never "the thing we launched still runs". So drop any record whose launchedAt predates the current boot, derived from os.uptime(). A rare false drop fails safe, back to today's behaviour for one session.
Second trap: #591. Tracking-off must HIDE the surfaced state at read time and must not delete the record, or toggling back on cannot restore it and the acceptance above fails again. Same one-way-door lesson already paid for on the elevated handoffs.
Acceptance
After a tray Quit and reopen with companions still running, the strip shows them and Close Apps is primary, with no relaunch.
Turning process tracking off hides them within one publish and turning it back on restores them, with no relaunch.
A record whose launchedAt predates the current boot is dropped without adopting, even when something is running at that path.
A record with nothing at its path is dropped on the first succeeded scan.
Follow-up to #673, which is closed by the per-game button. This is the other half: the strip.
Why this exists as its own issue
#673's decision of 2026-08-04 scoped it to the button and assigned the strip to #794 ("leave the strip alone"). The Codex-found second route recorded on 2026-08-18 then added an acceptance criterion that widened it: "restores the strip and the Close Apps affordance without a relaunch."
Those two cannot both be satisfied by one PR, so the button shipped and the strip is tracked here rather than being quietly dropped. The affordance now returns on both routes (restart and the process-tracking toggle cycle), because the closable set is rebuilt from the store. The dots do not: they come from
getTrackedRunningApps, which is gated onadoptedOrLaunchedGameKeys, and nothing puts the key back into that set.Why the obvious fix is still ruled out
Adopting a game key because a configured companion is running remains unsafe for the reason in #673's Fix section: the adopted key feeds the aggregate running status that drives row highlight, sorting and
canRelaunch, so every profile with SimHub enabled would read as "running" whenever SimHub is up. It is also intent-blind, which is the objection #794 settled: it cannot tell "left over from our session" from "autostarts with Windows".The direction that is not intent-blind
Remember ownership instead of inferring it. SimLauncher knows it launched SimHub under the AC profile; it just forgets at exit.
{ [gameKey]: Array<{ path: string; launchedAt: number }> }. Paths and timestamps only. Never PIDs (Poll path cache: a PID reused within one tick keeps the old executable path #847), never name-scoped entries (they have no path to verify and would reintroduce the Exe-name collision: same-named exe from another path fakes already-running, then kill reports bogus running-as-administrator #674 collision class), never the game exe.runningProcessesis written. Transition-driven, never per scan tick.adoptedOrLaunchedGameKeysas a fourth membership source. Do NOT re-seedrunningProcesses: itsprocess: ChildProcessis required and the kill paths assume a live handle a restarted app does not have.The trap that decides whether this is correct
A reboot ends our processes by definition. User reboots, SimHub autostarts, SimLauncher starts, finds a record, path-verifies it and re-adopts a process it never launched this boot. Path verification proves "something runs at this path", never "the thing we launched still runs". So drop any record whose
launchedAtpredates the current boot, derived fromos.uptime(). A rare false drop fails safe, back to today's behaviour for one session.Second trap: #591. Tracking-off must HIDE the surfaced state at read time and must not delete the record, or toggling back on cannot restore it and the acceptance above fails again. Same one-way-door lesson already paid for on the elevated handoffs.
Acceptance
launchedAtpredates the current boot is dropped without adopting, even when something is running at that path.