From 6e07d063c3cb680d712d1aa629d294a42f73a2dd Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sun, 26 Jul 2026 20:30:18 +0200 Subject: [PATCH] fix(session/gamelease): Windows had no launch reference, so it adopted old games MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On glass (.173), with a copy of Buckshot Roulette already running: a session launched the same title, Steam focused the existing instance rather than starting one, the lease adopted THAT process — and a deliberate stop closed the player's pre-existing game. That is the one thing the design says must never happen. The rule was written and the matcher implements it; the reference instant it filters against just never arrived. `procscan::launch_stamp` supports Windows, but the wrapper every launch site calls was gated `#[cfg(target_os = "linux")]` and answered `None` everywhere else — and `None` doesn't fail, it turns the filter OFF (`find` skips it), so every process under the install dir became adoptable. Windows is where this matters most: the host runs as SYSTEM and can see every process on the box, which is why `procscan/windows.rs` calls rule 1 load-bearing rather than a nicety. Both planes were affected. No unit test could have caught it — the Linux fixtures pass an explicit `min_start`, and the Windows live test passes `None` deliberately. So the guard added here asserts the reference EXISTS wherever processes can be matched, which is the shape of the failure: silent, and invisible from downstream. .133: 282 passed (+1), same 4 environmental native::tests failures. --- crates/punktfunk-host/src/gamelease.rs | 29 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/crates/punktfunk-host/src/gamelease.rs b/crates/punktfunk-host/src/gamelease.rs index 899cdff8..79863062 100644 --- a/crates/punktfunk-host/src/gamelease.rs +++ b/crates/punktfunk-host/src/gamelease.rs @@ -260,14 +260,13 @@ pub struct LeaseRequest { /// The reference instant for adopting this launch's processes, in seconds since boot. Call it /// **before** anything spawns; see [`LeaseRequest::launch_stamp`]. pub fn launch_clock() -> Option { - #[cfg(target_os = "linux")] - { - crate::procscan::launch_stamp() - } - #[cfg(not(target_os = "linux"))] - { - None - } + // Delegate unconditionally: `procscan::launch_stamp` already answers `None` on a platform with + // no matcher. Gating this on Linux here silently disabled the start-time floor on Windows — + // `find(spec, None)` skips the filter entirely — so a copy of the game the player already had + // open was adopted and then ended with the session (caught on glass, .173: Steam focused a + // running instance instead of starting one, and the lease took it). The Windows matcher is + // exactly where that rule matters most, since the host is SYSTEM and can see every process. + crate::procscan::launch_stamp() } /// What the watcher does when it concludes the game has exited. @@ -1207,6 +1206,20 @@ mod tests { ); } + /// Wherever the host can match processes at all, a launch MUST have a reference instant to + /// match them against — it is the only thing standing between this feature and ending a copy of + /// the game the player already had open. `None` here doesn't fail loudly; it silently turns the + /// filter off ([`crate::procscan::Scanner::find`] skips it), so nothing downstream can notice. + #[cfg(any(target_os = "linux", windows))] + #[test] + fn a_launch_always_gets_a_reference_instant_to_adopt_against() { + assert!( + launch_clock().is_some(), + "no launch reference on a platform that matches processes — every pre-existing \ + instance of a title would be adoptable, and endable" + ); + } + #[test] fn state_strings_are_stable() { // These reach the API and the console; renaming one is a wire change.