Files
wz-phone/docs/PRD/PRD-clippy-debt.md
Siavash Sameni 06253fdeeb feat(video+desktop): camera capture, video UI, E2E AEAD wiring, test fixes
Blockers 4 & 5: browser getUserMedia → JPEG IPC → Rust I420 pipeline;
remote video strip renders decoded frames via canvas; EncryptingTransport
wraps QuinnTransport so WZP AEAD is applied to all media (C2 fix).

Test fixes: HandshakeResult.session destructuring across relay/client/crypto
integration tests; video_codecs field added to all CallOffer/CallAnswer
structs; wzp-video pipeline_roundtrip integration tests added.

PRD docs: five Kimi-ready specs for E2E encryption, Android NDK 0.9 migration,
quality upgrade flow, wire-format hardening, and clippy debt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 15:30:26 +04:00

6.8 KiB
Raw Blame History

PRD: Fix wzp-codec Clippy Lint Debt

Status: proposed Resolves: 9 pre-existing clippy lints in crates/wzp-codec/src/ that cause cargo clippy --workspace -D warnings to fail, breaking any strict-CI configuration. Depends on: Nothing — all changes are in crates/wzp-codec/src/.

Problem

cargo clippy -p wzp-codec -- -D warnings fails with 9 lints across 5 files. These are pre-existing code patterns that were never flagged during development because the CI flag was not set. They have no runtime impact today but prevent adding -D warnings to CI without first cleaning them up.

The 3 errors in deps/featherchat are in a submodule — do NOT touch them. warzone_protocol clippy errors are accepted debt (not our code).

Goals

  • cargo clippy -p wzp-codec -- -D warnings exits 0.
  • No behavior changes — every fix is a semantically equivalent rewrite.
  • No changes outside crates/wzp-codec/src/.

Non-goals

  • Fixing clippy lints in any crate other than wzp-codec.
  • Adding new functionality.
  • Touching the deps/featherchat submodule.

Design

Lint inventory

Lint Count File Approx line Fix
implicit_saturating_sub 1 aec.rs 117119 saturating_sub
needless_range_loop 2 aec.rs:164, resample.rs:51 iterate with iter().enumerate() or direct iter
manual_div_ceil 2 codec2_dec.rs:48, codec2_enc.rs:48 div_ceil
manual_clamp 2 denoise.rs:59, opus_enc.rs:250 .clamp(min, max)
manual_ascii_check 1 opus_enc.rs:104 .eq_ignore_ascii_case()
same_item_push 1 resample.rs:184 vec.resize or extend(repeat)

Fix details

1. implicit_saturating_subaec.rs line ~117

Current code:

fn delay_available(&self) -> usize {
    let buffered = self.delay_write - self.delay_read;
    if buffered > self.delay_samples {
        buffered - self.delay_samples
    } else {
        0
    }
}

Clippy wants saturating_sub because the subtraction can underflow if buffered < self.delay_samples:

fn delay_available(&self) -> usize {
    let buffered = self.delay_write - self.delay_read;
    buffered.saturating_sub(self.delay_samples)
}

This is semantically identical (both return 0 when buffered <= delay_samples).

2a. needless_range_loopaec.rs line ~164

Current code:

for i in 0..n {
    let near_f = nearend[i] as f32;
    let base = (self.far_pos + fl * ((n / fl) + 2) + i - n) % fl;
    ...
}

i is used both to index nearend[i] and in arithmetic (+ i - n). Clippy fires because nearend[i] could use .iter().enumerate(). Convert to enumerate:

for (i, &sample) in nearend.iter().enumerate() {
    let near_f = sample as f32;
    let base = (self.far_pos + fl * ((n / fl) + 2) + i - n) % fl;
    ...
}

Make sure to update any references to nearend[i] inside the loop body to use sample (or near_f directly). Also update the NLMS adaptation sub-loop if it references nearend[i].

2b. needless_range_loopresample.rs line ~51

Current code:

for i in 0..FIR_TAPS {
    let n = i as f64 - m / 2.0;
    let sinc = ...;
    let t = 2.0 * i as f64 / m - 1.0;
    let kaiser = ...;
    kernel[i] = sinc * kaiser;
}

i is used both as an index (kernel[i]) and in arithmetic. Use iter_mut().enumerate():

for (i, slot) in kernel.iter_mut().enumerate() {
    let n = i as f64 - m / 2.0;
    let sinc = ...;
    let t = 2.0 * i as f64 / m - 1.0;
    let kaiser = ...;
    *slot = sinc * kaiser;
}

3a. manual_div_ceilcodec2_dec.rs line ~48

Current code:

fn bytes_per_frame(&self) -> usize {
    (self.inner.bits_per_frame() + 7) / 8
}

Replace with:

fn bytes_per_frame(&self) -> usize {
    self.inner.bits_per_frame().div_ceil(8)
}

div_ceil is stable as of Rust 1.73. The builder uses a recent enough toolchain. If bits_per_frame() returns usize, the method is available. If it returns a different integer type, cast accordingly.

3b. manual_div_ceilcodec2_enc.rs line ~48

Same pattern, same fix:

fn bytes_per_frame(&self) -> usize {
    self.inner.bits_per_frame().div_ceil(8)
}

4a. manual_clampdenoise.rs line ~59

Current code:

let clamped = val.max(-32768.0).min(32767.0);

Replace with:

let clamped = val.clamp(-32768.0_f32, 32767.0_f32);

Note: .clamp() on f32 requires both bounds to be the same type. If val is already f32, no extra cast is needed. Verify the type of val in context (it is f32 per the output array type [f32; 480]).

4b. manual_clampopus_enc.rs line ~252

Read the surrounding code for the exact pattern. It will be something like:

let v = if x < min_val { min_val } else if x > max_val { max_val } else { x };

or the .max().min() chain. Replace with x.clamp(min_val, max_val).

5. manual_ascii_checkopus_enc.rs line ~104

Current code:

Ok(v) => !v.is_empty() && v != "0" && v.to_ascii_lowercase() != "false",

Clippy wants .eq_ignore_ascii_case() instead of lowercasing the whole string:

Ok(v) => !v.is_empty() && v != "0" && !v.eq_ignore_ascii_case("false"),

6. same_item_pushresample.rs line ~183

Current code:

for _ in 1..RATIO {
    work.push(0.0);
}

This pushes the same 0.0 value (RATIO - 1) times. Replace with:

work.resize(work.len() + (RATIO - 1), 0.0f64);

Or equivalently:

work.extend(std::iter::repeat(0.0f64).take(RATIO - 1));

Note: RATIO is a const usize. Verify work is Vec<f64> in context (it is — work.push(s as f64) immediately before).

Implementation steps

  1. Read each file at the line numbers listed above to confirm the exact current code before editing (line numbers may shift slightly due to prior edits).
  2. Apply all 9 fixes. They are independent — no ordering requirement.
  3. Run cargo clippy -p wzp-codec -- -D warnings locally or via the CI command.
  4. If any lint persists, re-read that file section and adjust.

Files to read before implementing

  • crates/wzp-codec/src/aec.rs lines 114200
  • crates/wzp-codec/src/resample.rs lines 4570 and 178190
  • crates/wzp-codec/src/codec2_dec.rs lines 4055
  • crates/wzp-codec/src/codec2_enc.rs lines 4055
  • crates/wzp-codec/src/denoise.rs lines 4565
  • crates/wzp-codec/src/opus_enc.rs lines 96110 and 244260

Verify

cargo clippy -p wzp-codec -- -D warnings

Expected: exits 0 with no warnings.

Also run to confirm no regressions:

cargo test -p wzp-codec

Done when

cargo clippy -p wzp-codec -- -D warnings exits 0. All 9 lints are gone. cargo test -p wzp-codec passes. No changes outside crates/wzp-codec/src/.