Files
punktfunk/Cargo.toml
enricobuehler 0870f81148
apple / swift (pull_request) Successful in 2m0s
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 3m6s
android / android (pull_request) Successful in 5m48s
ci / bun-nix (pull_request) Successful in 58s
ci / web (pull_request) Successful in 6m9s
ci / docs-site (pull_request) Successful in 6m22s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 6m39s
ci / rust-arm64 (pull_request) Successful in 9m42s
ci / rust (pull_request) Successful in 14m57s
nix / flake (pull_request) Successful in 15m55s
release: 0.28.1 — version bump, notes, CHANGELOG, Play notes
50 commits since v0.28.0 (32 non-merge). Cut from origin/main f8361f3e.

THE NUMBER: 0.28.1 is defensible but not free. Three `feat(...)` commits landed
since the tag — the "unpair all" button and its two endpoints, the Apple
gamepad-UI host menu, and the tvOS present-floor levers. That is not the shape
of v0.28.0's cut (17 feats, a packager-visible default flip, an MSRV rise and a
deletion that empties the library grid), and none of the three changes a
contract: every one is additive, and the version table is unchanged on every row
an embedder, packager or driver author reads. `scripts/ci/pf-version.sh` derives
the canary base as latest-stable + one minor, so 0.28.1 and 0.29.0 both leave
canary on 0.29.x and neither collides.

NOTHING BREAKS, and this was measured rather than assumed, twice — before and
after the four late PRs. `include/` is byte-identical to the v0.28.0 tag, so the
C ABI stays 19; `crates/pf-driver-proto`, `plugin-kit/package.json` and `sdk/`
show no diff against the tag at all. The one Rust-visible change is an addition:
`punktfunk_core::client::FLUSH_COOLDOWN` went `pub(crate)` -> `pub`, so the host
can compare against the constant instead of a copy of the number.

ONE DEFECT FOUND AND FIXED WHILE PREPARING:

`docs-site/public/openapi.json` had drifted for the THIRD time in two release
cycles. It was still stamped 0.27.0 and missing both new collection deletes,
while `api/openapi.json` sits at 0.28.0. v0.28.0 fixed this once (it was five
releases stale at 0.21.0) and it drifted again inside that same cycle. Re-synced;
the two files are byte-identical again, and re-checked after the rebase. The copy
is a documented manual step (CONTRIBUTING.md) that nothing in CI enforces — three
drifts is the argument for gating it, and that gate is not in this commit.

CHANGELOG: the in-development section carried four topics and the late PRs
brought four more of their own; the remaining twenty-one commits had none. Added
the version table (every row measured, not copied forward), an explicit empty
breaking-changes verdict, and sections for the management API's two collection
deletes, the Hyprland/Sway cursor-mode negotiation, the gamescope WSI layer we
now ship ourselves, the 203-nit SDR anchor, the Apple stats/colour faults, the
Skia loader-version regression, the AV1 level sentinel, the stats stage-line
partition, the two host warnings that named the wrong subsystem, and the
docs-site openapi drift.

NOTES: `docs/releases/v0.28.1.md` follows the post-v0.25.0 split — user-facing
only, TL;DR first, internals left to the CHANGELOG link, which points at the
v0.28.1 TAG rather than main. The two Windows headliners lead it: the Steam
add-on publishing nothing (a 0.28.0 regression that emptied the grid) and an idle
host wrecking a locally played game. `Before you update` carries the two
Sound-settings changes an operator will see and could read as defects, plus the
0.27-and-older pointer at v0.28.0's action items.

luxus is credited three times: in the lead-in the Discord embed shows, inline on
the fix itself, and in a new `## Thanks` section — the linger crash was his find,
his patch and his on-glass proof, and it ships as he wrote it. The CHANGELOG
keeps its own credit with the overlay#9 link.

Play notes are 436 characters against the 500 cap and cover only what changed in
the Android app, which this release is still one commit of.

GATES, all green on this tree after the rebase: `cargo fmt --all --check` clean;
`cargo metadata --locked` consistent; Cargo.lock diff is versions-only, 36/36
lines, zero non-version lines against the new base; `cargo test -p punktfunk-core`
210 passed; the C ABI harness passes printing abi_version=19 (needs
`LIBRARY_PATH=/opt/homebrew/opt/opus/lib` on macOS — a link path, not a defect);
the repo pre-push hook exits 0.
2026-08-14 11:22:08 +02:00

128 lines
6.2 KiB
TOML

[workspace]
resolver = "2"
members = [
"crates/punktfunk-core",
"crates/punktfunk-host",
"crates/punktfunk-host/vendor/usbip-sim",
# The capability-carrying PyroWave encode worker. A SEPARATE binary by design — never a
# hardlink of, or a subcommand of, punktfunk-host (design/gpu-priority-capability-worker.md).
"crates/punktfunk-encode-worker",
"crates/punktfunk-tray",
"crates/pf-bitstream",
"crates/pf-bitstream/vendor/cros-codecs",
"crates/pf-client-core",
"crates/pf-clipboard",
"crates/pf-presenter",
"crates/pf-console-ui",
"crates/pf-driver-proto",
"crates/pf-paths",
"crates/pf-update",
"crates/pf-update-check",
"crates/pf-host-config",
"crates/pf-gpu",
"crates/pf-zerocopy",
"crates/pf-frame",
"crates/pf-win-display",
"crates/pf-encode",
"crates/pf-capture",
"crates/pf-inject",
"crates/pf-vdisplay",
"crates/pf-vkdecode",
"crates/pf-dxvadec",
"crates/pf-vaadec",
"crates/pyrowave-sys",
"crates/libvpl-sys",
"clients/probe",
"clients/cli",
"clients/linux",
"clients/session",
"clients/windows",
"clients/android/native",
"tools/cursor-probe",
"tools/display-disturb",
"tools/latency-probe",
"tools/loss-harness",
]
# Standalone PoC (built on its own; pulls usbip/tokio/libusb we don't want in the workspace).
# The vendored `ndk` is a [patch.crates-io] source, not a member: it only compiles for the
# `*-linux-android` targets, so workspace membership would break host `cargo build --workspace`.
exclude = [
"packaging/linux/steam-deck-gadget/usbip-poc",
"clients/android/native/vendor/ndk",
# Bring-your-own-hardware measurement tools. `hid-descriptor-dump` pulls `hidapi`, a C library
# wanting libudev on Linux; `win-input-matrix` is Windows-only and asks the live input stacks
# what they can see. Neither belongs in `cargo build --workspace` or on a CI leg with no pad.
"tools/hid-descriptor-dump",
"tools/win-input-matrix",
]
# ndk 0.9.0 verbatim from crates.io plus ONE visibility change (and two warning fixes — an
# unnecessary `std::` qualification and a feature-gated `Result` import): `MediaCodec::as_ptr` made public
# (upstream keeps it private and exposes no frame-rendered binding), so the Android client can
# call `AMediaCodec_setOnFrameRenderedCallback` via ndk-sys for the HUD's `display` stage
# (design/stats-unification.md). Drop the patch when upstream exposes the pointer or the callback.
[patch.crates-io]
ndk = { path = "clients/android/native/vendor/ndk" }
[workspace.package]
version = "0.28.1"
edition = "2024"
rust-version = "1.85"
license = "MIT OR Apache-2.0"
authors = ["unom"]
repository = "https://git.unom.io/unom/punktfunk"
# The `unsafe` discipline the `packaging/windows/drivers/*` crates already run, extended to the
# workspace. `unsafe fn` marks a CONTRACT the caller must uphold; it is not a licence for the whole
# body to skip checking. Without this lint an `unsafe fn` body is unchecked end to end, so a 600-line
# function hides which handful of lines are actually the unsafe ones — exactly the reviewer-hostile
# shape we are working down. (This is the Rust 2024 default; adopting it early also pays off the
# edition migration.)
#
# `deny`, not `warn`. `warn` was never actually a softer setting: CI runs `cargo clippy … -D
# warnings`, which promotes it to a hard error anyway — that is how adopting this lint turned main
# red on every platform for a day without the level in this file ever saying `deny`. A level that
# lies about its own severity is worse than a strict one, so this now states what CI already does,
# and the exemptions are written down per file instead of hiding in a 689-warning wall nobody reads.
#
# THE EXEMPTIONS. Fourteen GPU/FFI backend files carry `#![allow(unsafe_op_in_unsafe_fn)]` with a
# one-line reason each. They are not "not done yet" — they are where this lint stops paying:
# their bodies are ash/CUDA/AMF/libav calls almost line for line (measured: 64% of the sites are a
# single third-party FFI call, and of the 44 `unsafe fn`s in them only 4 have a body containing no
# unsafe operation at all). Narrowing them means one `unsafe {}` per line plus, since pf-encode also
# denies `clippy::undocumented_unsafe_blocks`, one hand-written SAFETY comment per line that could
# only ever restate "an ash call on a live device" — the precise noise that made `unsafe` stop
# meaning anything here before (see the header of `pf-win-display/src/win_display.rs`).
#
# Everything else in the workspace is at zero and enforced. Removing one of those allows, file by
# file, is real work with a real payoff; blanket-narrowing all fourteen is not. Prefer DELETING an
# `unsafe fn` marker over wrapping its body: keep the marker only where a caller can actually break
# something (a raw pointer, a borrowed HANDLE, a GPU object that must not be in flight).
[workspace.lints.rust]
unsafe_op_in_unsafe_fn = "deny"
# The companion lint: every `unsafe {}` / `unsafe impl` carries a `// SAFETY:` proof. Hoisted here
# from ~85 per-file `#![deny(...)]` attributes so a NEW crate (or a new module in an old one) is
# covered on creation rather than on remembering — the per-file form left pf-vkhdr-layer,
# wdk-probe, and half of pf-clipboard uncovered for months. NOTE: this table reaches only crates
# with `[lints] workspace = true`; `packaging/windows/drivers` and `packaging/windows/pf-vkhdr-layer`
# are SEPARATE workspaces and restate it (any "workspace-wide" claim must be made three times or it
# is false). Of the members, only the two vendored snapshots (pf-bitstream/vendor/cros-codecs,
# punktfunk-host/vendor/usbip-sim) stay out, deliberately — upstream code stays pristine.
[workspace.lints.clippy]
undocumented_unsafe_blocks = "deny"
[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 1
# NOTE: deliberately NOT `panic = "abort"`. punktfunk-core ships as a cdylib/staticlib into
# third-party apps (Swift/Kotlin/C) and its C ABI catches panics at the boundary
# (`catch_unwind` → `PunktfunkStatus::Panic`). `panic = "abort"` would make that guard a
# no-op and let a stray panic abort the embedding application. Unwinding keeps the
# documented isolation guarantee real.
# The per-frame hot path must stay fast even in dev builds.
[profile.dev.package."*"]
opt-level = 2