Release prep for v0.24.0. Version is forced: scripts/ci/pf-version.sh reports PF_BASE=0.24.0 (one minor ahead of the latest stable tag), which is what canary has been publishing against.
This is the last piece of the 0.24.0 cut — everything else is already on main. Merging this puts the version bump and the notes on main; the tag goes on top of it.
What this release is
Mostly a fix-up of 0.23.0, on two fronts:
The slice wire (97b2c01a) — the reassembler sized every sentinel-opened access unit at max_frame_bytes and lost 9 of 12 in-flight frames on any reordering link. That is the freeze in the Android and session-client field reports, and the fix is client-side, so a 0.23.0 client keeps the bug against any host.
Automatic bitrate (#28) — eleven defects, headlined by an escalation latch that pinned sessions at the 20 Mbps default indefinitely. The long-running "my bitrate is stuck at 20". Measured escape: 150 Mbps in ~16 s against ~17 minutes.
Plus the desktop presenter rebuild (#20), the Decky settings tab growing from nine rows to the whole store (#24), a "Forward controllers" off switch (#22), plugin output reaching the console's log page (#27), and the two controller fixes (#25 rumble after reconnect, #26 an unplugged pad actually disappearing).
The branch is bump → merge → notes → merge, rather than a clean rebase, because this session cannot force-push. Net diff against main is the four files above, and main is an ancestor, so it is a clean merge.
Verified locally (re-run after each merge of main, most recently at 7db83445)
cargo metadata --locked resolves; 35 workspace members, ours all at 0.24.0.
Lock diff is versions-only (verified by filtering the diff for non-version = lines: none). The 33rd 0.23.0 line in the lock is the third-party wasapi crate, itself at 0.23.0 — the same trap as the last cut. Neither #28 nor #25/#26 touched a manifest, so the bump survived every merge untouched.
cargo fmt --all --check clean in the main workspace andpackaging/windows/drivers.
android.yml's Play-notes gate run locally against its real logic, GITHUB_REF_NAME=v0.24.0: file exists, not byte-identical to any other release's, 497/500 chars. Hard failure at step 1 of the android job if it were wrong.
scripts/ci/gitea-release.sh resolves notes as docs/releases/<tag>.md from repo root — the file is exactly there, so ensure_release seeds the body at creation.
Doc lazy-continuation scanner clean (0 hits). That is the specific defect that made the first v0.23.0 tag go red on Windows clippy, and it is worth re-checking every cut because no Windows leg runs on a main push — main being green proves nothing about the tag fan-out.
Notes voice checked programmatically: 0 internal-vocabulary hits above ## Under the hood.
The #25/#26 notes entries were checked against the code rather than the commit messages: SWEEP_GRACE is 300 ms ("about a third of a second"), and "up to 128 sends" is right — seq_newer has a forward window of 127, so a client sitting at 127 drops seq 0–127 before the host counts past it.
Nothing else in the tree hardcodes the version. api/openapi.json is deliberately left at 0.23.0 (it tracks API edits and lags a release, as in every prior cut).
Unchanged versions
Wire protocol 2, C ABI 14, virtual-display driver protocol 6, Windows virtual-gamepad channel 3 — all identical to 0.23.0. No new capability bits: VIDEO_CAP_MULTI_SLICE (0x80) took the video-caps byte's last free bit in 0.23.0, so the next one needs a second byte and an ABI bump.
⚠ Known-red on main, not caused by this PR
The bazzite RPM leg of rpm.yml failed on 1feeff3c with NoSpaceLeft during bun install inside the RPM %build — the runner ran out of disk. The fedora-44 leg of the same run passed. Re-run requested. This leg also builds the HDR gamescope and the sysext image, so while it is red those artifacts do not attach to a release.
After merging
Tag v0.24.0 on the resulting main commit. Note that this now publishes to Google Play production at 100% (09b9ee8f, production access granted 2026-08-01) with no further click.
Separately: v0.23.0 was never announced, so the stable update manifest was never published — every 0.23.0 host's Updates card still reads "none published yet". 0.22.0–0.22.3 were never announced either.
Suggested tag annotation
punktfunk 0.24.0 — 0.23.0, made right
The slice-by-slice video delivery introduced in 0.23.0 could throw most of a
frame away on any link that reorders packets, freezing the picture on Android
and on the Linux and Windows desktop app; the fix is in the client. Automatic
bitrate could decide early in a session that your connection was worth 20 Mb/s
and hold you there for the rest of it — a sweep of that path fixed eleven
faults, and the case that used to take seventeen minutes to climb out now takes
sixteen seconds. Alongside them, the desktop app gains the frame scheduler the
phone and Apple apps already had, the Steam Deck plugin reaches every setting
instead of nine of them, controllers can be told not to be forwarded, rumble
comes back after a reconnect, and plugin output reaches the web console's log
page.
Release prep for **v0.24.0**. Version is forced: `scripts/ci/pf-version.sh` reports `PF_BASE=0.24.0` (one minor ahead of the latest stable tag), which is what canary has been publishing against.
**This is the last piece of the 0.24.0 cut — everything else is already on `main`.** Merging this puts the version bump and the notes on main; the tag goes on top of it.
## What this release is
Mostly a fix-up of 0.23.0, on two fronts:
- **The slice wire** (`97b2c01a`) — the reassembler sized every sentinel-opened access unit at `max_frame_bytes` and lost 9 of 12 in-flight frames on any reordering link. That is the freeze in the Android and session-client field reports, and the fix is client-side, so a 0.23.0 client keeps the bug against any host.
- **Automatic bitrate** (#28) — eleven defects, headlined by an escalation latch that pinned sessions at the 20 Mbps default indefinitely. The long-running "my bitrate is stuck at 20". Measured escape: 150 Mbps in ~16 s against ~17 minutes.
Plus the desktop presenter rebuild (#20), the Decky settings tab growing from nine rows to the whole store (#24), a "Forward controllers" off switch (#22), plugin output reaching the console's log page (#27), and the two controller fixes (#25 rumble after reconnect, #26 an unplugged pad actually disappearing).
## What's in the diff
| File | |
|---|---|
| `Cargo.toml` | `[workspace.package] version` 0.23.0 → 0.24.0 |
| `Cargo.lock` | `cargo update --workspace`, versions-only, 32 insertions / 32 deletions |
| `docs/releases/v0.24.0.md` | the release body CI seeds at tag creation |
| `docs/releases/whatsnew/v0.24.0.txt` | Play "What's new", 497/500 chars |
The branch is bump → merge → notes → merge, rather than a clean rebase, because this session cannot force-push. Net diff against `main` is the four files above, and `main` is an ancestor, so it is a clean merge.
## Verified locally (re-run after each merge of main, most recently at `7db83445`)
- `cargo metadata --locked` resolves; 35 workspace members, ours all at 0.24.0.
- Lock diff is **versions-only** (verified by filtering the diff for non-`version =` lines: none). The 33rd `0.23.0` line in the lock is the third-party `wasapi` crate, itself at 0.23.0 — the same trap as the last cut. **Neither #28 nor #25/#26 touched a manifest**, so the bump survived every merge untouched.
- `cargo fmt --all --check` clean in the main workspace **and** `packaging/windows/drivers`.
- **android.yml's Play-notes gate run locally against its real logic**, `GITHUB_REF_NAME=v0.24.0`: file exists, not byte-identical to any other release's, 497/500 chars. Hard failure at step 1 of the android job if it were wrong.
- `scripts/ci/gitea-release.sh` resolves notes as `docs/releases/<tag>.md` from repo root — the file is exactly there, so `ensure_release` seeds the body at creation.
- **Doc lazy-continuation scanner clean (0 hits).** That is the specific defect that made the first v0.23.0 tag go red on Windows clippy, and it is worth re-checking every cut because **no Windows leg runs on a main push** — main being green proves nothing about the tag fan-out.
- Notes voice checked programmatically: **0 internal-vocabulary hits** above `## Under the hood`.
- The #25/#26 notes entries were checked against the code rather than the commit messages: `SWEEP_GRACE` is 300 ms ("about a third of a second"), and "up to 128 sends" is right — `seq_newer` has a forward window of 127, so a client sitting at 127 drops seq 0–127 before the host counts past it.
- Nothing else in the tree hardcodes the version. `api/openapi.json` is deliberately left at 0.23.0 (it tracks API edits and lags a release, as in every prior cut).
## Unchanged versions
Wire protocol 2, C ABI 14, virtual-display driver protocol 6, Windows virtual-gamepad channel 3 — all identical to 0.23.0. No new capability bits: `VIDEO_CAP_MULTI_SLICE` (`0x80`) took the video-caps byte's last free bit in 0.23.0, so the next one needs a second byte *and* an ABI bump.
## ⚠ Known-red on main, not caused by this PR
The **bazzite RPM leg** of `rpm.yml` failed on `1feeff3c` with `NoSpaceLeft` during `bun install` inside the RPM `%build` — the runner ran out of disk. The fedora-44 leg of the same run passed. Re-run requested. This leg also builds the HDR gamescope and the sysext image, so while it is red those artifacts do not attach to a release.
## After merging
Tag `v0.24.0` on the resulting main commit. Note that this now **publishes to Google Play production at 100%** (`09b9ee8f`, production access granted 2026-08-01) with no further click.
Separately: **v0.23.0 was never announced**, so the stable update manifest was never published — every 0.23.0 host's Updates card still reads "none published yet". 0.22.0–0.22.3 were never announced either.
## Suggested tag annotation
```
punktfunk 0.24.0 — 0.23.0, made right
The slice-by-slice video delivery introduced in 0.23.0 could throw most of a
frame away on any link that reorders packets, freezing the picture on Android
and on the Linux and Windows desktop app; the fix is in the client. Automatic
bitrate could decide early in a session that your connection was worth 20 Mb/s
and hold you there for the rest of it — a sweep of that path fixed eleven
faults, and the case that used to take seventeen minutes to climb out now takes
sixteen seconds. Alongside them, the desktop app gains the frame scheduler the
phone and Apple apps already had, the Steam Deck plugin reaches every setting
instead of nine of them, controllers can be told not to be forwarded, rumble
comes back after a reconnect, and plugin output reaches the web console's log
page.
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
A minor bump: 39 commits since v0.23.0 across 121 files. Mostly a fix-up of
0.23.0 — the slice wire's reassembler sized every sentinel-opened AU at
max_frame_bytes and lost 9 of 12 in-flight frames on any link that reorders,
which is the freeze field reports were seeing on Android and the session client
— plus the desktop presenter rebuild (intent model, V-Sync/VRR as real settings,
the driver's queue-free vblank mode where it exists), the Decky settings tab
growing from nine rows to the whole store, a "Forward controllers" off switch
for passthrough couches, and plugin output finally reaching the console's log
page. The canary base is already 0.24 — scripts/ci/pf-version.sh derives it as
one minor ahead of the latest stable tag — so this is the version canary has
been publishing against all along.
No wire, ABI or driver-protocol change: wire protocol 2, C ABI 14, virtual-display
driver protocol 6 and the Windows virtual-gamepad channel 3 are all identical to
0.23.0. No new capability bits either — VIDEO_CAP_MULTI_SLICE took the video-caps
byte's last free bit in 0.23.0 and nothing here needed the next one. The only
generated-header change since the tag is documentation (probe elapsed_ms
semantics), already committed and verified by ci.yml's staleness gate on main.
Lock touched for the 32 workspace members only, via `cargo update --workspace`:
diff against origin/main is versions-only, 32 insertions and 32 deletions (the
33rd 0.23.0 line in the lock is the third-party `wasapi` crate, which sits at
0.23.0 itself — same trap as the last cut). `cargo metadata --locked` resolves;
`cargo fmt --all --check` clean in both the main and the packaging/windows/drivers
workspaces.
api/openapi.json is deliberately left at 0.23.0: it tracks API edits and lags a
release, as in every prior cut.
Notes at docs/releases/v0.24.0.md, per docs/releases/README.md — authored with the
bump so CI's ensure_release seeds the release body at tag creation. Play's "What's
new" at docs/releases/whatsnew/v0.24.0.txt (409/500 chars), which android.yml now
gates as a hard failure at step 1; the gate's own logic was run locally against
this file, including the byte-identical-to-another-release check.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR #28 merged after the bump commit was written, so the notes described a
release that no longer matched the tree. Merged origin/main and added what it
brings: 45 commits since v0.23.0 now, not 39.
Four user-facing entries, because eleven defects in one path is not one bullet
and the pinning is the headline the field reports have been describing for
months ("my bitrate is stuck at 20"):
- the 20 Mbps pin itself, with the measured escape (150 Mbps in ~16 s against
~17 minutes) — the number is the point, since the old behaviour was not "slow
to climb" but "never arrives"
- the five single-window lessons the controller treated as permanent
- throughput counted with FEC parity, which rose with the loss it was meant to
detect
- the silent host re-target, which made a client's first climb a request to go
DOWN
The Under the hood section gets the whole sweep in one bullet rather than
scattering it, and PUNKTFUNK_ABR_MAX_MBPS moves from the probe bullet into it
(it now binds at construction, not only on probe-learned ceilings, so it no
longer belongs to the probe).
Play notes gain an ABR line and now run 459/500 chars; the gate's real logic was
re-run against the file, including the byte-identical check. Voice check over
everything above "Under the hood" is clean of internal vocabulary.
Re-verified after the merge: cargo metadata --locked resolves, cargo fmt --all
--check clean, doc lazy-continuation scanner 0 hits. #28 touched no manifest, so
the version bump and the versions-only lock diff are untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PRs #25 and #26 are going into this release, and neither was in the notes.
Both are user-visible and easy to have lived with without knowing why:
force-feedback stopping for good after a controller reconnect (roughly half of
reconnects, every platform), and an unplugged pad staying visible to the game
for the rest of the session (every time, if it was your only controller).
The whatsnew line for the rumble fix is Play listing copy and that file has a
500-character ceiling, so "A decoder hiccup no longer snowballs into a burst of
broken frames" loses "snowballs into" for "causes" — same meaning, and the new
line is kept short. 498 of 500 used.
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.
Release prep for v0.24.0. Version is forced:
scripts/ci/pf-version.shreportsPF_BASE=0.24.0(one minor ahead of the latest stable tag), which is what canary has been publishing against.This is the last piece of the 0.24.0 cut — everything else is already on
main. Merging this puts the version bump and the notes on main; the tag goes on top of it.What this release is
Mostly a fix-up of 0.23.0, on two fronts:
97b2c01a) — the reassembler sized every sentinel-opened access unit atmax_frame_bytesand lost 9 of 12 in-flight frames on any reordering link. That is the freeze in the Android and session-client field reports, and the fix is client-side, so a 0.23.0 client keeps the bug against any host.Plus the desktop presenter rebuild (#20), the Decky settings tab growing from nine rows to the whole store (#24), a "Forward controllers" off switch (#22), plugin output reaching the console's log page (#27), and the two controller fixes (#25 rumble after reconnect, #26 an unplugged pad actually disappearing).
What's in the diff
Cargo.toml[workspace.package] version0.23.0 → 0.24.0Cargo.lockcargo update --workspace, versions-only, 32 insertions / 32 deletionsdocs/releases/v0.24.0.mddocs/releases/whatsnew/v0.24.0.txtThe branch is bump → merge → notes → merge, rather than a clean rebase, because this session cannot force-push. Net diff against
mainis the four files above, andmainis an ancestor, so it is a clean merge.Verified locally (re-run after each merge of main, most recently at
7db83445)cargo metadata --lockedresolves; 35 workspace members, ours all at 0.24.0.version =lines: none). The 33rd0.23.0line in the lock is the third-partywasapicrate, itself at 0.23.0 — the same trap as the last cut. Neither #28 nor #25/#26 touched a manifest, so the bump survived every merge untouched.cargo fmt --all --checkclean in the main workspace andpackaging/windows/drivers.GITHUB_REF_NAME=v0.24.0: file exists, not byte-identical to any other release's, 497/500 chars. Hard failure at step 1 of the android job if it were wrong.scripts/ci/gitea-release.shresolves notes asdocs/releases/<tag>.mdfrom repo root — the file is exactly there, soensure_releaseseeds the body at creation.## Under the hood.SWEEP_GRACEis 300 ms ("about a third of a second"), and "up to 128 sends" is right —seq_newerhas a forward window of 127, so a client sitting at 127 drops seq 0–127 before the host counts past it.api/openapi.jsonis deliberately left at 0.23.0 (it tracks API edits and lags a release, as in every prior cut).Unchanged versions
Wire protocol 2, C ABI 14, virtual-display driver protocol 6, Windows virtual-gamepad channel 3 — all identical to 0.23.0. No new capability bits:
VIDEO_CAP_MULTI_SLICE(0x80) took the video-caps byte's last free bit in 0.23.0, so the next one needs a second byte and an ABI bump.⚠ Known-red on main, not caused by this PR
The bazzite RPM leg of
rpm.ymlfailed on1feeff3cwithNoSpaceLeftduringbun installinside the RPM%build— the runner ran out of disk. The fedora-44 leg of the same run passed. Re-run requested. This leg also builds the HDR gamescope and the sysext image, so while it is red those artifacts do not attach to a release.After merging
Tag
v0.24.0on the resulting main commit. Note that this now publishes to Google Play production at 100% (09b9ee8f, production access granted 2026-08-01) with no further click.Separately: v0.23.0 was never announced, so the stable update manifest was never published — every 0.23.0 host's Updates card still reads "none published yet". 0.22.0–0.22.3 were never announced either.
Suggested tag annotation
🤖 Generated with Claude Code