Second and final batch from the 2026-07-20 core-sweep lows:
client:
- connect() timeout now sets `quit` before shutdown, so a handshake that
completes after the deadline closes with QUIT_CLOSE_CODE instead of
leaving the host lingering (virtual display up) for a reconnect that
never comes.
- probe_result: saturating_add on the wire-supplied wire_packets +
send_dropped counters (debug-build overflow panic / release wrap).
- the standing-latency bleed no longer sets flush_in_window: that flag
is the ABR's SEVERE (×0.7) verdict, and the bleed fires only on
provably loss-free windows the controller itself scores as fine.
clipboard:
- fetch_cancels pruned on every new fetch (was: one dead oneshot per
paste for the session).
- serve chunks gated on a parked waiter + capped at CLIP_FETCH_CAP with
an Error event (was: unbounded silent accumulation under any req_id).
- serve_inbound park bounded by FETCH_STALL_SECS + send.stopped() (was:
an unanswered FetchRequest parked the task, waiter, and bi-stream
forever; ~100 of them exhaust the connection's bidi budget).
C ABI (ABI_VERSION 9 → 10, header regenerated, additive only):
- new punktfunk_connection_clock_offset_now_ns — the LIVE re-synced
offset (Swift/Kotlin latency math read the frozen connect-time value
~40ms wrong after a wall-clock step).
- to_config: checked u64→usize narrowing of max_frame_bytes (32-bit
armeabi truncated >4GiB to a plausible residue).
- host_poll_input: no &mut held across the embedder callback (re-entry
aliased it — UB under noalias); mid-drain callback clears now stick.
- next_audio_pcm: DTX (empty) payloads skipped — decode synthesized
120ms of concealment per 5ms slot and grew the playout ring forever.
- next_clipboard releases the parked payload on an empty poll (a one-off
50MiB paste stayed resident all session).
- frames_dropped / wants_decode_latency write their documented 0/false
defaults before the NULL-handle check.
- gamepad constant docs match pick_gamepad() reality (DualSenseEdge/
SwitchPro landed; DualSense/DS4 honored on Windows UMDF too).
FEC:
- gf8 reconstruct/reconstruct_into reuse the (k,m) codec cache like
encode_into (was: fresh 230×200 generator + decode inversion per
lossy block on the pump thread).
- vendored fec-rs: the 8 safe wrap_mul_slice shims assert equal lengths
(x86 SIMD callees bound stores on input.len() — safe-code OOB write);
ReconstructShard's safety contract gains the len()==get().len()
clause and reconstruct_internal sizes raw slices from the slice.
transport/GTK:
- Linux GSO super-buffer capped at the real UDP payload ceiling (65487)
not 65535 — seg sizes ≥1024 could EMSGSIZE and latch GSO off
process-wide, blamed on the network.
- GTK settings dialog no longer rewrites an unlisted-but-valid stored
gamepad preference to "auto" on close.
Already fixed on main (verified stale, skipped): the reassembler FEC
ceiling, wants_decode_latency's third term, request_probe rollback +
the generalized probe watchdog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Full project rename, decided 2026-06-10:
- Crates/binaries: punktfunk-core / punktfunk-host / punktfunk-client-rs.
- C ABI: punktfunk_* symbols, Punktfunk* types, include/punktfunk_core.h,
PUNKTFUNK_FEATURE_QUIC guard (header regenerated; cbindgen renames updated, incl.
PUNKTFUNK_BTN_*/PUNKTFUNK_AXIS_* wire constants).
- Protocol: punktfunk/1 — control-plane magic LMN1 → PKF1, nonce salt lmn1 → pkf1.
WIRE BREAK: clients must be rebuilt from this revision.
- Env knobs: PUNKTFUNK_VIDEO_SOURCE / PUNKTFUNK_COMPOSITOR / PUNKTFUNK_ZEROCOPY / ….
- Host config dir: ~/.config/punktfunk (the box's dir was migrated in place — the
persistent identity is unchanged, pinned fingerprints stay valid).
- Swift package: PunktfunkKit + PunktfunkCore.xcframework + PunktfunkConnection
(Sources/PunktfunkClient app + tests renamed with it); build-xcframework.sh updated.
- scripts/: 60-punktfunk.rules, punktfunk-host.service; OpenAPI doc regenerated.
Also: scripts/headless/run-headless-kde.sh — full headless Plasma bringup. Root cause of
"desktop but no apps/settings" over the stream: plasmashell launched without
XDG_MENU_PREFIX=plasma-, so the launcher resolved a nonexistent applications.menu and
rendered an empty menu. The script sets the complete KDE session env (menu prefix,
KDE_FULL_SESSION, session version) and rebuilds ksycoca before starting plasmashell.
Gate: 97/97 tests, clippy -D warnings (both feature sets), fmt, C-ABI harness PASS,
zero lumen references left outside .git.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>