0.31.2 — the address the host used, from three directions #369

Merged
enricobuehler merged 1 commits from worktree-release-0312-prep into main 2026-08-21 20:50:26 +00:00
Owner

Release prep for v0.31.2: version bump, release notes, CHANGELOG section, Play "What's new", and one docs-freshness fix. Cut from main at 48eeae75 (#368 merged).

10 commits since v0.31.1 (6 non-merge).

The number

A patch, and this time the version table does not have to argue for it. Nothing versioned moved:

  • WIRE_VERSION 2, C ABI 25include/punktfunk_core.h has no diff at all against the v0.31.1 tag, not even a #define (unlike the last two releases)
  • driver protocol 6 / min 3, pf-driver-proto unchanged
  • gamepad channel 3, plugin index schema 1, host event schema 1
  • gamescope +pfhdr8, no new patch files
  • SDK 0.1.5 and plugin-kit 0.4.4 both untouched

No ! commit, no feat, no route added or removed, no breaking change of any kind. Every non-merge commit is fix/refactor/test.

The shape of the cycle

Three of the six non-merge commits are the same class of fault — the host using the wrong local address — reached from three directions:

#367 the data socket bound 0.0.0.0:0 and let routing pick the video source, which the client's connected socket then dropped in-kernel
#366 Host::detect() froze the advertised address at process start, so a cold boot that beat the network pinned 127.0.0.1 for the life of the process — breaking both mDNS adverts, the Moonlight session URL, the WoL mac record and HostInfo together
#368 the firewall rules guarding the ports those addresses point at admitted any program on the machine

The fourth is an Android regression from v0.31.1 (#365); the remaining two are the refactor and test supporting #366.

Two behaviour changes (no build breaks)

  • Windows service install scopes all five fixed-port rules to the listening executable, keeping their localport=. Externally visible: 5353 is punktfunk's alone now, so anything else on the machine that was reachable on mDNS through our any-program rule needs its own. Fallbacks are asymmetric on purpose — a fixed-port rule that cannot resolve its exe falls back to the old wide form (a looser rule still streams), while the data-plane rule skips (no port to fall back to, so a program-less version would not be looser, it would be open).
  • HostInfo.local_ip is no longer static for the process. It was a field snapshotted at detect(); it is now a method that re-reads per request. A consumer that cached it at startup was caching a value that could be 127.0.0.1 forever. This is the only api/openapi.json content change — two description strings, no route/schema/field/type.

Also here

docs-site/content/docs/ports.mdx. Its "Video needs nothing opened" bullet has been wrong for Windows since v0.31.1 added the data-plane rule — it now says so and names why (no fixed rule can cover a per-session ephemeral port). The Windows line gains a Callout for the 5353 change, since that is the one thing on the page a reader may have to act on.

Play notes are Android-only per whatsnew/TEMPLATE.txt, which this cycle means the #365 regression alone. The three host-side fixes are deliberately not listed: updating the app fixes none of them, so putting them on the store page would promise something the download does not deliver.

Gates

gate result
cargo fmt --all --check clean
cargo metadata --offline ok, Cargo.lock diff versions-only (36/36)
cargo test -p punktfunk-core --lib 273 passed
C ABI harness passed, abi_version=25
cbindgen regen of punktfunk_core.h byte-identical to checked-in and to the v0.31.1 tag
scripts/ci/check-docs-drift.sh clean
scripts/ci/check-docs-links.sh clean
android.yml Play notes gate (run verbatim) 357/500 chars, unique
both openapi copies cmp identical, stamped 0.31.2
notes voice scan clean — one backticked term in the file

Not run here: clippy and any punktfunk-host build (does not compile on macOS — CI covers it), and the Android unit tests (:kit: and :app: ran on #365 itself; nothing here touches Kotlin).

One call left for the tagger

SECURITY.md promises to credit a reporter in the release notes when the fix is public. The #368 commit records only "a user on 2026-08-21" with no name, so the notes credit them unnamed. If they want their name on it, that is a one-line edit to docs/releases/v0.31.2.md before the tag is pushed.


Merge, then tag per docs/releases/README.md: git tag -a v0.31.2 … && git push origin v0.31.2, wait for every platform green, then dispatch announce.yml.

Release prep for **v0.31.2**: version bump, release notes, CHANGELOG section, Play "What's new", and one docs-freshness fix. Cut from `main` at 48eeae75 (#368 merged). 10 commits since v0.31.1 (6 non-merge). ## The number A patch, and this time the version table does not have to argue for it. **Nothing versioned moved:** - `WIRE_VERSION` **2**, C ABI **25** — `include/punktfunk_core.h` has **no diff at all** against the v0.31.1 tag, not even a `#define` (unlike the last two releases) - driver protocol **6** / min **3**, `pf-driver-proto` unchanged - gamepad channel **3**, plugin index schema **1**, host event schema **1** - gamescope **+pfhdr8**, no new patch files - SDK **0.1.5** and plugin-kit **0.4.4** both untouched No `!` commit, no `feat`, no route added or removed, no breaking change of any kind. Every non-merge commit is `fix`/`refactor`/`test`. ## The shape of the cycle Three of the six non-merge commits are the same class of fault — **the host using the wrong local address** — reached from three directions: | | | |---|---| | #367 | the data socket bound `0.0.0.0:0` and let routing pick the video source, which the client's connected socket then dropped in-kernel | | #366 | `Host::detect()` froze the advertised address at process start, so a cold boot that beat the network pinned `127.0.0.1` for the life of the process — breaking both mDNS adverts, the Moonlight session URL, the WoL `mac` record and `HostInfo` together | | #368 | the firewall rules guarding the ports those addresses point at admitted **any program on the machine** | The fourth is an Android regression from v0.31.1 (#365); the remaining two are the refactor and test supporting #366. ## Two behaviour changes (no build breaks) - **Windows `service install` scopes all five fixed-port rules to the listening executable**, keeping their `localport=`. Externally visible: **5353 is punktfunk's alone now**, so anything else on the machine that was reachable on mDNS through our any-program rule needs its own. Fallbacks are asymmetric on purpose — a fixed-port rule that cannot resolve its exe falls back to the old wide form (a looser rule still streams), while the data-plane rule *skips* (no port to fall back to, so a program-less version would not be looser, it would be open). - **`HostInfo.local_ip` is no longer static for the process.** It was a field snapshotted at `detect()`; it is now a method that re-reads per request. A consumer that cached it at startup was caching a value that could be `127.0.0.1` forever. This is the only `api/openapi.json` content change — two `description` strings, no route/schema/field/type. ## Also here `docs-site/content/docs/ports.mdx`. Its **"Video needs nothing opened"** bullet has been wrong for Windows since v0.31.1 added the data-plane rule — it now says so and names why (no fixed rule can cover a per-session ephemeral port). The Windows line gains a `Callout` for the 5353 change, since that is the one thing on the page a reader may have to act on. Play notes are Android-only per `whatsnew/TEMPLATE.txt`, which this cycle means the #365 regression alone. The three host-side fixes are deliberately **not** listed: updating the app fixes none of them, so putting them on the store page would promise something the download does not deliver. ## Gates | gate | result | |---|---| | `cargo fmt --all --check` | clean | | `cargo metadata --offline` | ok, `Cargo.lock` diff versions-only (36/36) | | `cargo test -p punktfunk-core --lib` | 273 passed | | C ABI harness | **passed**, `abi_version=25` | | cbindgen regen of `punktfunk_core.h` | byte-identical to checked-in **and** to the v0.31.1 tag | | `scripts/ci/check-docs-drift.sh` | clean | | `scripts/ci/check-docs-links.sh` | clean | | android.yml Play notes gate (run verbatim) | 357/500 chars, unique | | both openapi copies | `cmp` identical, stamped 0.31.2 | | notes voice scan | clean — one backticked term in the file | **Not run here:** clippy and any `punktfunk-host` build (does not compile on macOS — CI covers it), and the Android unit tests (`:kit:` and `:app:` ran on #365 itself; nothing here touches Kotlin). ## One call left for the tagger `SECURITY.md` promises to credit a reporter in the release notes when the fix is public. The #368 commit records only "a user on 2026-08-21" with no name, so the notes credit them unnamed. If they want their name on it, that is a one-line edit to `docs/releases/v0.31.2.md` **before** the tag is pushed. --- Merge, then tag per `docs/releases/README.md`: `git tag -a v0.31.2 … && git push origin v0.31.2`, wait for every platform green, then dispatch `announce.yml`.
enricobuehler added 1 commit 2026-08-21 18:05:02 +00:00
release: 0.31.2 — version bump, notes, CHANGELOG, Play notes
apple / swift (pull_request) Successful in 2m17s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 4m59s
android / android (pull_request) Successful in 6m30s
nix / flake (pull_request) Successful in 6m38s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 8m5s
ci / docs-drift (pull_request) Successful in 29s
ci / bun-nix (pull_request) Successful in 32s
ci / web (pull_request) Successful in 1m6s
ci / docs-site (pull_request) Successful in 1m9s
ci / rust-arm64 (pull_request) Successful in 1m25s
ci / rust (pull_request) Successful in 16m10s
a2dc011200
10 commits since v0.31.1 (6 non-merge). Cut from origin/main 48eeae75 (#368
merged).

THE NUMBER: a patch, and unlike the last cut the version table does not even
have to argue for it. Nothing versioned moved — WIRE_VERSION 2, C ABI 25 with
include/punktfunk_core.h showing NO diff at all against the v0.31.1 tag (not
even a #define, unlike the last two releases), driver protocol 6 / min 3 with
pf-driver-proto unchanged, gamepad channel 3, plugin index schema 1, host event
schema 1, gamescope +pfhdr8 with no new patch files, SDK 0.1.5 and plugin-kit
0.4.4 both untouched. No `!` commit, no feat, no route added or removed, no
breaking change of any kind. Every non-merge commit is fix/refactor/test.

The cycle has a shape: three of the six non-merge commits are the same class of
fault — the host using the wrong local address — reached from three directions.
The data socket bound 0.0.0.0:0 and let routing pick the video source, which the
client's connected socket then dropped in-kernel (#367). Host::detect() froze the
advertised address at process start, so a cold boot that beat the network pinned
127.0.0.1 for the life of the process and broke both mDNS adverts, the Moonlight
session URL, the WoL mac record and HostInfo together (#366). And the firewall
rules guarding the ports those addresses point at admitted any program on the
machine (#368). The fourth is an Android regression from v0.31.1 (#365); the
remaining two are the refactor and test supporting #366.

api/openapi.json changes in DOCUMENTATION ONLY this time — two description
strings on HostInfo, no route, schema, required field or type — plus the stamp.
Re-stamped here, not regenerated: punktfunk-host does not build on macOS, and
#366 regenerated the document itself on a runner where
openapi_document_is_complete_and_checked_in actually executes. "0.31.1" appears
nowhere in either copy afterwards, and the two copies are byte-identical.

That description change is load-bearing rather than cosmetic, so it is called out
as a behaviour change in the CHANGELOG beside the firewall one: HostInfo.local_ip
was a field snapshotted at detect() and is now a method that re-reads per
request, so a consumer that cached it at startup was caching a value that could
be 127.0.0.1 forever.

The other behaviour change is the externally visible one: Windows service install
now scopes all five fixed-port rules to the listening executable while keeping
their localport=, so 5353 is punktfunk's alone and anything else on the machine
that was reachable on mDNS through our any-program rule needs its own. Fallbacks
are asymmetric on purpose — a fixed-port rule that cannot resolve its exe falls
back to the old wide form (a looser rule still streams), while the data-plane
rule skips (it has no port to fall back to, so a program-less version would not
be looser, it would be open).

Also in this commit, because a cut is when docs freshness bites:
docs-site/content/docs/ports.mdx. Its "Video needs nothing opened" bullet has
been wrong for Windows since v0.31.1 added the data-plane rule — it now says so
and names why (no fixed rule can cover a per-session ephemeral port). And the
Windows line gains a Callout for the 5353 change above, since that is the one
thing on this page a reader may have to act on. Callout shape copied from the
proven usage in plugins.mdx (no `title` prop — node_modules is not installed here
and fumadocs' prop surface could not be verified offline).

Play notes are Android-only per whatsnew/TEMPLATE.txt, which this cycle means the
#365 regression alone. The three host-side fixes are deliberately NOT in there:
updating the app does not fix any of them, so listing them on the store page
would promise something the download does not deliver.

Gates: cargo fmt --all --check clean; cargo metadata --offline ok with the
Cargo.lock diff versions-only (36/36); cargo test -p punktfunk-core --lib 273
passed; the C ABI harness PASSED reporting abi_version=25 (needed `brew install
opus` on this Mac to link — the first run failed on the missing library, not on
the code); cbindgen regenerated include/punktfunk_core.h during that build and it
came out byte-identical to the checked-in file AND to the v0.31.1 tag, which is a
stronger check on the ABI row than diffing it; scripts/ci/check-docs-drift.sh
clean; scripts/ci/check-docs-links.sh clean; the android.yml Play notes gate run
verbatim, 357/500 characters and unique; both openapi copies cmp identical and
stamped 0.31.2; notes voice scan clean (one backticked term in the whole file,
the `punktfunk-host service install` command, and the only technical vocabulary
sits inside `## For developers`).

Not run here, and why: clippy and any punktfunk-host build (does not compile on
macOS — CI covers it), and the Android unit tests (:kit: and :app: were run on
#365 itself; nothing in this commit touches Kotlin).

One judgement call left for the tag: SECURITY.md promises to credit a reporter in
the release notes when the fix is public, and the #368 commit records only "a
user on 2026-08-21" with no name. The notes credit them unnamed. If they want
their name on it, that is a one-line edit to docs/releases/v0.31.2.md before the
tag is pushed.
enricobuehler merged commit ca2ff7093a into main 2026-08-21 20:50:26 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#369