fix(ci): green main again — clock_sync callers, two clippy denials, an unused import
ci / web (push) Successful in 56s
ci / docs-site (push) Successful in 1m11s
apple / swift (push) Successful in 1m20s
decky / build-publish (push) Successful in 36s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 9s
ci / bench (push) Successful in 7m0s
flatpak / build-publish (push) Successful in 6m25s
deb / build-publish (push) Successful in 9m53s
docker / deploy-docs (push) Successful in 28s
release / apple (push) Successful in 9m25s
deb / build-publish-host (push) Successful in 10m0s
windows-host / package (push) Successful in 15m34s
apple / screenshots (push) Successful in 6m30s
arch / build-publish (push) Successful in 18m15s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m6s
android / android (push) Successful in 19m13s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 3m14s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m6s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m3s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m37s
ci / rust (push) Successful in 26m59s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m31s

`ci.yml`'s clippy gate has been failing on main since the pre-0.16.0 sweep landed, and
because clippy stops at the first crate it can't compile, the visible error was only
ever the first of four. `ci.yml` is not tag-triggered, so v0.16.0 cut and shipped over
a red main; none of this reaches the release artifacts (the two E0308s are in a test
binary and a dev tool, and the rest are lints) but the gate has been blind since.

Fixed, in the order clippy surfaced them:

- clients/probe failed to COMPILE (E0308, x2). `810d918d` moved `clock_sync` onto the
  resumable `io::MsgReader` but only updated the client pump, leaving the probe passing
  a bare `&mut RecvStream`. The probe now wraps the control stream in a `MsgReader` at
  `open_bi` and threads that everywhere — Welcome, the --remode and --bitrate watchers,
  and the speed-test result read — which is also what the refactor was for: those reads
  sit behind timeouts and `select!`, exactly where a straddling frame would desync the
  stream for the rest of the run.

- pf-capture: `SPA_META_Cursor as u32` is a `u32 -> u32` no-op
  (`clippy::unnecessary_cast`). Line 1274 already passes the same constant uncast, so
  the type is not in question.

- pf-inject: `noop as usize` on the SIGUSR1 wake handler added in `986402f7` trips
  `clippy::function_casts_as_integer`; goes via `*const ()` as the lint asks. Same value
  in the `usize`-typed `sa_sigaction` slot.

- punktfunk-core: the `ctrl_framing` test module's `use super::*` is unused, which
  `-D warnings` promotes to an error.

Verified with CI's own commands on a Linux box (this is all Linux-gated code, so a Mac
cannot check it): `cargo clippy --workspace --all-targets --locked -- -D warnings`
finishes clean, `cargo build --workspace --locked` succeeds, and
`cargo test --workspace --locked` exits 0 with no failures — including punktfunk-core's
196-test suite, which covers the control-stream framing the probe change touches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 11:49:31 +02:00
parent 3213c1b61c
commit a53369bf21
4 changed files with 16 additions and 16 deletions
+10 -12
View File
@@ -458,7 +458,11 @@ async fn session(args: Args) -> Result<()> {
), ),
(None, None) => tracing::info!(%remote, "punktfunk/1 connected"), (None, None) => tracing::info!(%remote, "punktfunk/1 connected"),
} }
let (mut send, mut recv) = conn.open_bi().await.context("open control stream")?; let (mut send, recv) = conn.open_bi().await.context("open control stream")?;
// Frame every read on the control stream through the resumable reader, exactly as the client
// pump does: `clock_sync` bounds each read with a timeout, and a frame straddling two wakeups
// would otherwise leave the stream permanently misaligned for the rest of the run.
let mut recv = io::MsgReader::new(recv);
io::write_msg( io::write_msg(
&mut send, &mut send,
@@ -513,8 +517,8 @@ async fn session(args: Args) -> Result<()> {
.encode(), .encode(),
) )
.await?; .await?;
let welcome = Welcome::decode(&io::read_msg(&mut recv).await?) let welcome =
.map_err(|e| anyhow!("Welcome decode: {e:?}"))?; Welcome::decode(&recv.read_msg().await?).map_err(|e| anyhow!("Welcome decode: {e:?}"))?;
tracing::info!( tracing::info!(
mode = ?welcome.mode, mode = ?welcome.mode,
fec = ?welcome.fec, fec = ?welcome.fec,
@@ -629,10 +633,7 @@ async fn session(args: Args) -> Result<()> {
tracing::error!("Reconfigure write failed"); tracing::error!("Reconfigure write failed");
return; return;
} }
match io::read_msg(&mut rr) match rr.read_msg().await.map(|b| Reconfigured::decode(&b)) {
.await
.map(|b| Reconfigured::decode(&b))
{
Ok(Ok(ack)) if ack.accepted => { Ok(Ok(ack)) if ack.accepted => {
tracing::info!(mode = ?ack.mode, "mode switch ACCEPTED") tracing::info!(mode = ?ack.mode, "mode switch ACCEPTED")
} }
@@ -685,10 +686,7 @@ async fn session(args: Args) -> Result<()> {
tracing::error!("SetBitrate write failed"); tracing::error!("SetBitrate write failed");
return; return;
} }
match io::read_msg(&mut rr) match rr.read_msg().await.map(|b| BitrateChanged::decode(&b)) {
.await
.map(|b| BitrateChanged::decode(&b))
{
Ok(Ok(ack)) => tracing::info!( Ok(Ok(ack)) => tracing::info!(
applied_kbps = ack.bitrate_kbps, applied_kbps = ack.bitrate_kbps,
"BITRATE CHANGE acked by host" "BITRATE CHANGE acked by host"
@@ -750,7 +748,7 @@ async fn session(args: Args) -> Result<()> {
tracing::error!("ProbeRequest write failed"); tracing::error!("ProbeRequest write failed");
return; return;
} }
let res = match io::read_msg(&mut sr).await.map(|b| ProbeResult::decode(&b)) { let res = match sr.read_msg().await.map(|b| ProbeResult::decode(&b)) {
Ok(Ok(r)) => r, Ok(Ok(r)) => r,
other => { other => {
tracing::error!(?other, "bad ProbeResult"); tracing::error!(?other, "bad ProbeResult");
+1 -2
View File
@@ -1318,8 +1318,7 @@ mod pipewire {
// that SIGSEGVs inside the PipeWire `.process` callback (a segfault `catch_unwind` cannot // that SIGSEGVs inside the PipeWire `.process` callback (a segfault `catch_unwind` cannot
// catch). Every offset below is validated against `region_size` with checked arithmetic, // catch). Every offset below is validated against `region_size` with checked arithmetic,
// mirroring the fd-length guard the main frame path already applies to xdg-desktop-portal-wlr. // mirroring the fd-length guard the main frame path already applies to xdg-desktop-portal-wlr.
let meta = let meta = unsafe { spa::sys::spa_buffer_find_meta(spa_buf, spa::sys::SPA_META_Cursor) };
unsafe { spa::sys::spa_buffer_find_meta(spa_buf, spa::sys::SPA_META_Cursor as u32) };
if meta.is_null() { if meta.is_null() {
return; return;
} }
@@ -215,7 +215,11 @@ fn install_wake_handler() {
// for a single signal; touches only this process's disposition for `WAKE_SIGNAL`. // for a single signal; touches only this process's disposition for `WAKE_SIGNAL`.
unsafe { unsafe {
let mut sa: libc::sigaction = std::mem::zeroed(); let mut sa: libc::sigaction = std::mem::zeroed();
sa.sa_sigaction = noop as usize; // Via `*const ()`: casting a function item straight to an integer is what
// `clippy::function_casts_as_integer` rejects, and the pointer hop is the documented
// way to spell it. `sa_sigaction` is a `usize`-typed handler slot, so the value is
// unchanged.
sa.sa_sigaction = noop as *const () as usize;
libc::sigemptyset(&mut sa.sa_mask); libc::sigemptyset(&mut sa.sa_mask);
sa.sa_flags = 0; sa.sa_flags = 0;
libc::sigaction(WAKE_SIGNAL, &sa, std::ptr::null_mut()); libc::sigaction(WAKE_SIGNAL, &sa, std::ptr::null_mut());
-1
View File
@@ -1737,7 +1737,6 @@ mod clip_loopback {
/// [`io::MsgReader`] must survive that: the partial frame lives in the reader, not the future. /// [`io::MsgReader`] must survive that: the partial frame lives in the reader, not the future.
mod ctrl_framing { mod ctrl_framing {
use super::clip_loopback::connect_pair; use super::clip_loopback::connect_pair;
use super::*;
use crate::quic::io; use crate::quic::io;
/// A frame whose halves land in different wakeups, with the read cancelled in between, must /// A frame whose halves land in different wakeups, with the read cancelled in between, must