Three faults found while triaging "I can't launch games via the dedicated game session any more" on a GNOME host.
The pin vetoed game_session=dedicated, silently
PUNKTFUNK_COMPOSITOR is documented as which backend to drive, but it also quietly discarded the dedicated route: resolve_compositor gated it on !overridden and logged nothing either way. A host whose pin was a forgotten validation leftover therefore kept displaying "dedicated" in the console while every launch landed in the desktop instead — for 30 days on the box that surfaced this, the only evidence being the absence of a log line.
The pin still wins, since it is the operator's explicit hand-set knob, but it now says so and names itself.
The same pin left the recovery hook unreachable
A pin puts its backend into available() unconditionally and skips apply_session_env's XDG_CURRENT_DESKTOP scrub, so pick_compositor could never return None — the one place try_recover_session() is called from. A pinned host whose gnome-shell had segfaulted spent every connect on 8 doomed RemoteDesktop.CreateSession: ServiceUnknown retries while the operator's configured PUNKTFUNK_RECOVER_SESSION_CMD sat unreachable behind that arm.
Liveness is now read on both paths, and a pin aimed at a dead session takes the recovery exit with an error naming the pin. Compositor::needs_live_session() exempts gamescope, which stands its own session up — pinning it on a headless box stays supported, and a test guards that.
A mode switch accepted before bring-up finished took down the whole desktop
A switch the control task accepted before the pipeline existed was served the long way round: build at the now-stale mode, then immediately rebuild at the new one in the stream loop. That burns a display create, capture attach and encoder open on every such connect — and because the rebuild is deliberately create-before-drop, it stands up two Mutter RecordVirtual monitors ~400 ms apart, which segfaults mutter 50.4 inside meta_monitor_manager_rebuild:
14:58:30.219 mode switch accepted mode=3200x2400@120 ← queued; NO pipeline exists yet
14:58:32.445 punktfunk/1 virtual display mode=2752x2064 ← built at the STALE mode
14:58:32.464 gnome-shell: Added virtual monitor Meta-0
14:58:33.489 rebuilding pipeline for mode switch new_mode=3200x2400
14:58:33.503 gnome-shell: Added virtual monitor Meta-1
14:58:33.574 gnome-shell SEGFAULT
The blast radius is the whole box: gnome-shell dies, the GDM greeter takes the seat, and GDM auto-login is once-per-boot so the desktop never returns on its own. The game launched moments earlier loses its display and segfaults in libX11 — which makes it look like the game failed and sends triage down the wrong path. Reproduced three times with byte-identical stacks, including on a fresh 0.26.0 canary.
Bring-up now drains the reconfig channel and builds once at the newest queued mode, so the second monitor is never created. Inline path only — a prepared pipeline already exists at the old mode, so adopting there would only desync the variable from the display. The H2/H3 correction ack the replaced rebuild would have sent is carried over.
Note this removes the trigger, not the mutter bug; anything else that adds two virtual monitors in quick succession will still kill it.
Verification
Gated at full CI parity on a real Linux host (x86_64), not the Mac — punktfunk-host does not build on macOS at all, so a Mac check proves nothing here:
punktfunk-host + pf-vdisplay suites — green, including two new tests covering the pin/liveness matrix
The gate was proved non-vacuous against a planted compile_error! first; an earlier run had looked green while never compiling the host crate at all.
Confirmed on glass afterwards: the dedicated route fired for the first time on that box (dedicated game session — routing to a headless gamescope spawn at the client mode, compositor="gamescope"), and it worked with no desktop session live at all — which is the point.
Three faults found while triaging "I can't launch games via the dedicated game session any more" on a GNOME host.
## The pin vetoed `game_session=dedicated`, silently
`PUNKTFUNK_COMPOSITOR` is documented as *which backend to drive*, but it also quietly discarded the dedicated route: `resolve_compositor` gated it on `!overridden` and logged nothing either way. A host whose pin was a forgotten validation leftover therefore kept displaying "dedicated" in the console while every launch landed in the desktop instead — for 30 days on the box that surfaced this, the only evidence being the *absence* of a log line.
The pin still wins, since it is the operator's explicit hand-set knob, but it now says so and names itself.
## The same pin left the recovery hook unreachable
A pin puts its backend into `available()` unconditionally **and** skips `apply_session_env`'s `XDG_CURRENT_DESKTOP` scrub, so `pick_compositor` could never return `None` — the one place `try_recover_session()` is called from. A pinned host whose gnome-shell had segfaulted spent every connect on 8 doomed `RemoteDesktop.CreateSession: ServiceUnknown` retries while the operator's configured `PUNKTFUNK_RECOVER_SESSION_CMD` sat unreachable behind that arm.
Liveness is now read on both paths, and a pin aimed at a dead session takes the recovery exit with an error naming the pin. `Compositor::needs_live_session()` exempts gamescope, which stands its own session up — pinning it on a headless box stays supported, and a test guards that.
## A mode switch accepted before bring-up finished took down the whole desktop
A switch the control task accepted before the pipeline existed was served the long way round: build at the now-stale mode, then immediately rebuild at the new one in the stream loop. That burns a display create, capture attach and encoder open on every such connect — and because the rebuild is deliberately create-before-drop, it stands up two Mutter `RecordVirtual` monitors ~400 ms apart, which segfaults mutter 50.4 inside `meta_monitor_manager_rebuild`:
```
14:58:30.219 mode switch accepted mode=3200x2400@120 ← queued; NO pipeline exists yet
14:58:32.445 punktfunk/1 virtual display mode=2752x2064 ← built at the STALE mode
14:58:32.464 gnome-shell: Added virtual monitor Meta-0
14:58:33.489 rebuilding pipeline for mode switch new_mode=3200x2400
14:58:33.503 gnome-shell: Added virtual monitor Meta-1
14:58:33.574 gnome-shell SEGFAULT
```
The blast radius is the whole box: gnome-shell dies, the GDM greeter takes the seat, and GDM auto-login is once-per-boot so the desktop never returns on its own. The game launched moments earlier loses its display and segfaults in libX11 — which makes it look like the *game* failed and sends triage down the wrong path. Reproduced three times with byte-identical stacks, including on a fresh `0.26.0` canary.
Bring-up now drains the `reconfig` channel and builds **once** at the newest queued mode, so the second monitor is never created. Inline path only — a prepared pipeline already exists at the old mode, so adopting there would only desync the variable from the display. The H2/H3 correction ack the replaced rebuild would have sent is carried over.
Note this removes the *trigger*, not the mutter bug; anything else that adds two virtual monitors in quick succession will still kill it.
## Verification
Gated at full CI parity on a real Linux host (x86_64), not the Mac — `punktfunk-host` does not build on macOS at all, so a Mac check proves nothing here:
- `cargo clippy --workspace --all-targets --locked -- -D warnings` — clean
- `cargo fmt --all --check` — clean
- `punktfunk-host` + `pf-vdisplay` suites — green, including two new tests covering the pin/liveness matrix
The gate was proved non-vacuous against a planted `compile_error!` first; an earlier run had looked green while never compiling the host crate at all.
Confirmed on glass afterwards: the dedicated route fired for the first time on that box (`dedicated game session — routing to a headless gamescope spawn at the client mode`, `compositor="gamescope"`), and it worked with no desktop session live at all — which is the point.
`PUNKTFUNK_COMPOSITOR` is documented as "which backend to drive", but it also
quietly discarded `game_session=dedicated`: `resolve_compositor` gated the
dedicated route on `!overridden` and logged nothing either way. A host whose pin
was a forgotten validation leftover therefore went on displaying "dedicated" in
the console while every launch landed in the desktop instead — for 30 days on the
box that surfaced this, the only evidence being the ABSENCE of a log line.
The pin still wins, since it is the operator's explicit hand-set knob, but it now
says so and names itself.
Two further holes the same triage turned up:
- The pin put its backend into `available()` unconditionally AND skipped
`apply_session_env`'s `XDG_CURRENT_DESKTOP` scrub, so `pick_compositor` could
never return `None` — the one place `try_recover_session()` is called from. A
pinned host whose gnome-shell had segfaulted therefore spent every connect on 8
doomed `RemoteDesktop.CreateSession: ServiceUnknown` retries while the
operator's configured `PUNKTFUNK_RECOVER_SESSION_CMD` sat unreachable behind
that arm. Liveness is now read on both paths, and a pin aimed at a dead session
takes the recovery exit with an error naming the pin. `needs_live_session()`
exempts gamescope, which stands its own session up — pinning it on a headless
box stays supported.
- A mode switch accepted before the pipeline existed was served the long way
round: build at the now-stale mode, then immediately rebuild at the new one in
the stream loop. That burns a display create, capture attach and encoder open
on every such connect, and because the rebuild is deliberately
create-before-drop it stands up two Mutter `RecordVirtual` monitors ~400 ms
apart — which segfaults mutter 50.4 inside `meta_monitor_manager_rebuild` and
takes down the whole desktop session, along with the game just launched into
it (so the GAME looks like what crashed). Bring-up now adopts the newest queued
mode and builds once, carrying over the H2/H3 correction ack that the replaced
rebuild would have sent.
Verified on a real Linux host (192.168.1.21, x86_64): `cargo clippy --workspace
--all-targets --locked -- -D warnings`, `cargo fmt --all --check` and the
punktfunk-host + pf-vdisplay test suites all clean. The gate was proved
non-vacuous against a planted `compile_error!`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Three faults found while triaging "I can't launch games via the dedicated game session any more" on a GNOME host.
The pin vetoed
game_session=dedicated, silentlyPUNKTFUNK_COMPOSITORis documented as which backend to drive, but it also quietly discarded the dedicated route:resolve_compositorgated it on!overriddenand logged nothing either way. A host whose pin was a forgotten validation leftover therefore kept displaying "dedicated" in the console while every launch landed in the desktop instead — for 30 days on the box that surfaced this, the only evidence being the absence of a log line.The pin still wins, since it is the operator's explicit hand-set knob, but it now says so and names itself.
The same pin left the recovery hook unreachable
A pin puts its backend into
available()unconditionally and skipsapply_session_env'sXDG_CURRENT_DESKTOPscrub, sopick_compositorcould never returnNone— the one placetry_recover_session()is called from. A pinned host whose gnome-shell had segfaulted spent every connect on 8 doomedRemoteDesktop.CreateSession: ServiceUnknownretries while the operator's configuredPUNKTFUNK_RECOVER_SESSION_CMDsat unreachable behind that arm.Liveness is now read on both paths, and a pin aimed at a dead session takes the recovery exit with an error naming the pin.
Compositor::needs_live_session()exempts gamescope, which stands its own session up — pinning it on a headless box stays supported, and a test guards that.A mode switch accepted before bring-up finished took down the whole desktop
A switch the control task accepted before the pipeline existed was served the long way round: build at the now-stale mode, then immediately rebuild at the new one in the stream loop. That burns a display create, capture attach and encoder open on every such connect — and because the rebuild is deliberately create-before-drop, it stands up two Mutter
RecordVirtualmonitors ~400 ms apart, which segfaults mutter 50.4 insidemeta_monitor_manager_rebuild:The blast radius is the whole box: gnome-shell dies, the GDM greeter takes the seat, and GDM auto-login is once-per-boot so the desktop never returns on its own. The game launched moments earlier loses its display and segfaults in libX11 — which makes it look like the game failed and sends triage down the wrong path. Reproduced three times with byte-identical stacks, including on a fresh
0.26.0canary.Bring-up now drains the
reconfigchannel and builds once at the newest queued mode, so the second monitor is never created. Inline path only — a prepared pipeline already exists at the old mode, so adopting there would only desync the variable from the display. The H2/H3 correction ack the replaced rebuild would have sent is carried over.Note this removes the trigger, not the mutter bug; anything else that adds two virtual monitors in quick succession will still kill it.
Verification
Gated at full CI parity on a real Linux host (x86_64), not the Mac —
punktfunk-hostdoes not build on macOS at all, so a Mac check proves nothing here:cargo clippy --workspace --all-targets --locked -- -D warnings— cleancargo fmt --all --check— cleanpunktfunk-host+pf-vdisplaysuites — green, including two new tests covering the pin/liveness matrixThe gate was proved non-vacuous against a planted
compile_error!first; an earlier run had looked green while never compiling the host crate at all.Confirmed on glass afterwards: the dedicated route fired for the first time on that box (
dedicated game session — routing to a headless gamescope spawn at the client mode,compositor="gamescope"), and it worked with no desktop session live at all — which is the point.