Both MSIX matrix jobs failed at the v0.15.0 tag, for two unrelated reasons, both introduced by this release. 0.13.0 and 0.14.0 shipped both packages; 0.15.0 shipped neither. ARM64 failed to BUILD. The PyroWave Windows un-gating (1ef0229b) moved `pyrowave-sys` in pf-client-core out of `cfg(target_os = "linux")` into a general optional dependency that pf-client-core's own `default = ["pyrowave"]` turns on. The ARM64 leg builds `--no-default-features` precisely to skip it, but that only disables defaults for the two packages named with `-p` — every internal edge kept inheriting them: clients/windows -> pf-client-core, clients/session -> pf-client-core, clients/session -> pf-presenter, and pf-presenter's own `default = ["pyrowave"]` -> pf-client-core. So the vendored Granite C++ compiled on ARM64 and stopped where it always does: muglm.cpp reaching for _MM_TRANSPOSE4_PS/_mm_storeu_ps, then `simd.hpp:103 #error "Implement me."`. Those three internal edges now pass `default-features = false`; the feature is enabled only through an explicit chain (clients/session's `pyrowave` -> pf-client-core/pyrowave + pf-presenter/pyrowave, and pf-presenter's `pyrowave` -> pf-client-core/pyrowave), so `--no-default-features` finally means what it says. Verified by feature resolution rather than assertion — `cargo tree -i pyrowave-sys`: aarch64-pc-windows-msvc, --no-default-features -> not in the graph (was: present) x86_64-pc-windows-msvc, default features -> present x86_64-unknown-linux-gnu, default features -> present PyroWave is NOT dropped from the Windows client. Decode has always run in the spawned punktfunk-session binary, whose own default keeps the feature on, and unification turns it back on for the shared pf-client-core wherever that binary is in the build (x64, Linux). The shell only ever offered "pyrowave" as a codec preference string — it holds no decoder and never called one, so linking the C++ into it was dead weight even on x64. x64 built fine and failed at PACKAGING: `makepri new` rejected the manifest with PRI191 "Appx manifest not found or is invalid" / malformed comment syntax. The console tile added in2508b720documented its flag inside an XML comment, and XML forbids `--` anywhere in a comment body, so the literal flag spelling made the whole manifest unparseable. Reworded, with a note to keep the next person from reintroducing it. Confirmed by parsing both revisions after template substitution: the tagged manifest fails at line 63 col 9, this one parses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
punktfunk-session
The Vulkan session binary: one stream per invocation in an SDL3 window — no UI toolkit,
no widgets, terminal stats. The power-user / gamescope stream client, and the stage-2
presenter of the Linux client re-architecture (punktfunk-planning:
linux-client-rearchitecture.md).
punktfunk-session --connect host[:port] [--fp HEX] [--launch id] [--fullscreen] [--stats]
punktfunk-session --browse host[:port] [--mgmt PORT] [--fullscreen]
--browse opens the console game library (the Skia coverflow over the animated aurora)
instead of connecting: A launches the focused title as a stream in the same window,
session end returns to the library, B quits (Gaming Mode returns). Paired hosts only —
pairing is the desktop client / Decky plugin's job. PUNKTFUNK_FAKE_LIBRARY=<file.json>
feeds canned entries with no host (portrait paths starting with / load from disk).
Reads the same identity / known-hosts / settings stores as the desktop client
(punktfunk-client) — pair there (or via its headless --pair) first; this binary never
connects to a host it has no pinned fingerprint for (--fp HEX overrides the store).
Stdout is the machine interface: {"ready":true} after the first presented frame,
stats: … once per second while the overlay tier isn't Off (always the full detailed
text, whatever the OSD shows; --stats forces the overlay on), one
{"error"|"ended": …} JSON line on the way out. Logs go to stderr. Exit codes: 0
clean end, 2 connect failed, 3 trust rejected / pairing required, 4 presenter
init failed.
In-stream keys match the desktop client: click captures input (Ctrl+Alt+Shift+Q releases), Ctrl+Alt+Shift+D disconnects, F11 toggles fullscreen; the controller escape chord (L1+R1+Start+Select, hold to disconnect) works the same.
The default build carries the Skia console UI (ui feature): the stats OSD and capture
hint render in-window. Ctrl+Alt+Shift+S cycles the OSD tier live — Off → Compact (one
line: fps · latency · Mb/s) → Normal (mode + end-to-end percentiles) → Detailed (decoder
path + per-stage latency equation); any tier but Off also emits the stdout mirror.
--no-default-features is the ~5 MB power-user build — same streaming, stats on stdout
only, no Skia anywhere in the dependency tree.
Decode follows the Settings preference (auto: Vulkan Video → VAAPI → software on Linux,
Vulkan Video → D3D11VA → software on Windows): FFmpeg's Vulkan Video decoder runs on the
presenter's own device where the stack supports it (every vendor, zero copy); VAAPI
dmabufs import per-plane elsewhere (D3D11VA textures on Windows); software is the
universal fallback. 10-bit Main10 and HDR10 are advertised
(VIDEO_CAP_10BIT|HDR): P010 decodes through all three paths, and PQ streams present
on an HDR10/ST.2084 swapchain when the desktop offers one (KDE HDR, gamescope) or
tone-map in-shader to SDR when it doesn't (PUNKTFUNK_TONEMAP_PEAK tunes the rolloff,
default ≈1000 nits). The host still gates the upgrade behind its PUNKTFUNK_10BIT
policy.
Debug/bisect knobs: PUNKTFUNK_DECODER=vulkan|vaapi|d3d11va|software, PUNKTFUNK_PRESENT_MODE= mailbox|immediate (default FIFO), PUNKTFUNK_VK_DEVICE=<index> (multi-GPU), and
PUNKTFUNK_HW_FAULT=import (fault every VAAPI dmabuf import — proves the three-strike
demotion to software on healthy hardware).