jouleclaw-loader-gguf: 161 clippy warnings -> 0, and -D warnings now gates it #414

Merged
dcharlot merged 5 commits from fix/loader-gguf-lints into main 2026-10-22 04:30:57 -04:00
Owner

#373 gated jouleclaw-omni --features metal with -D warnings but left the crate omni loads its weights through linted by nothing at all. This closes it: 161 → 0, in both the default and rayon fabric-meter configurations, and loader-gguf joins the lint step in standards-build.yml.

How

clippy --fix (MachineApplicable only) 161 → 161, 7 files
policy allows, same three as omni's lib.rs → 81
clippy's own MaybeIncorrect suggestions, applied from the JSON → 12
the last dozen, by hand → 0

Most of this crate's lints carry MaybeIncorrect suggestions, which --fix skips. Those are still exact byte spans with exact replacement text — "maybe incorrect" means clippy will not promise the semantics, not that the text is wrong. So a small script applied them and the crate's 343 tests decided. That covered ~140 spans across 26 files.

The policy allows are the same three decisions omni already records, for the same reasons, this being quantisation and tokeniser code with the same shapes: needless_range_loop, too_many_arguments, and the two doc-indentation lints.

The last dozen, which needed judgement

  • two from_str methods that are not FromStr-shaped (one returns Option, one is infallible) renamed to parse
  • assert!(FLASH_KV_CHUNK.is_power_of_two()) and >= 64 moved from a #[test] into const _: () = assert!(..) beside the constant — they are properties of a constant, and a test only holds them if someone runs it
  • kv_quant_tests moved to the end of kv_cache_inplace.rs, which had 300 lines of real items after it
  • an example discarded the Result from matmul_bf16_threaded, so a failure would have been timed as a success
  • needless_range_loop allowed per-file in three benches and one test, since those are separate crates and src/lib.rs's decision does not reach them

Four things the work corrected about itself

  • needless_range_loop suggestions are templates, not replacements. Clippy emits for (i, <item>) in w.iter_mut().enumerate(), leaving both the binding name and the body's w[i] uses for a human. Applied literally it writes <item> into the source; four files stopped compiling. The applier now refuses any replacement containing a bare bracketed word — but the first version of that guard rejected all 28 as_chunks::<2>() suggestions too, because a turbofish also has angle brackets.
  • chunks_exact_mut suggests as_chunks_mut::<N>().0.iter() — a non-mutable iterator over a mutable chunk, which does not compile. Only the fabric-meter configuration contained one, so the default build stayed green while that example was broken. Checking both configurations caught it.
  • Renaming wants a grep for the method, not the type. My caller check missed mlx.rs, which reaches SafetensorsDtype through a type alias, so SafetensorsDtype::from_str( never matched.
  • A duplicate that is not a bug. fabric_dispatch.rs calls ledger_record twice with identical arguments; the comment three lines above says attention is "recorded as two GEMM-equivalents" so the measured µJ/GFLOP table prices it. Deliberate, left alone.

Scope of the gate

Default features only. Under rayon fabric-meter this crate is also clean, but clippy reports jouleclaw-backend-apple through the path dependency (--no-deps does not exclude workspace members), and that crate has 43 warnings — 27 unused_unsafe and 15 unused_imports that are unused in that configuration and needed in others. Those want cfg work rather than deletion, which is the trap #373 already paid for once, so they are left as their own change.

Verified

All four lint specs in the step pass, 343 loader-gguf tests, 77 omni tests, both configurations build clean.

🤖 Generated with Claude Code

#373 gated `jouleclaw-omni --features metal` with `-D warnings` but left the crate omni loads its weights through linted by nothing at all. This closes it: **161 → 0**, in both the default and `rayon fabric-meter` configurations, and loader-gguf joins the lint step in `standards-build.yml`. ## How | | | |---|---| | `clippy --fix` (MachineApplicable only) | 161 → 161, 7 files | | policy allows, same three as omni's `lib.rs` | → 81 | | clippy's own MaybeIncorrect suggestions, applied from the JSON | → 12 | | the last dozen, by hand | → **0** | Most of this crate's lints carry *MaybeIncorrect* suggestions, which `--fix` skips. Those are still exact byte spans with exact replacement text — "maybe incorrect" means clippy will not promise the semantics, not that the text is wrong. So a small script applied them and the crate's **343 tests** decided. That covered ~140 spans across 26 files. The policy allows are the same three decisions omni already records, for the same reasons, this being quantisation and tokeniser code with the same shapes: `needless_range_loop`, `too_many_arguments`, and the two doc-indentation lints. ## The last dozen, which needed judgement - two `from_str` methods that are not `FromStr`-shaped (one returns `Option`, one is infallible) renamed to `parse` - `assert!(FLASH_KV_CHUNK.is_power_of_two())` and `>= 64` moved from a `#[test]` into `const _: () = assert!(..)` beside the constant — they are properties of a constant, and a test only holds them if someone runs it - `kv_quant_tests` moved to the end of `kv_cache_inplace.rs`, which had 300 lines of real items after it - an example discarded the `Result` from `matmul_bf16_threaded`, so a failure would have been **timed as a success** - `needless_range_loop` allowed per-file in three benches and one test, since those are separate crates and `src/lib.rs`'s decision does not reach them ## Four things the work corrected about itself - **`needless_range_loop` suggestions are templates, not replacements.** Clippy emits `for (i, <item>) in w.iter_mut().enumerate()`, leaving both the binding name and the body's `w[i]` uses for a human. Applied literally it writes `<item>` into the source; four files stopped compiling. The applier now refuses any replacement containing a bare bracketed word — but the *first* version of that guard rejected all 28 `as_chunks::<2>()` suggestions too, because a turbofish also has angle brackets. - **`chunks_exact_mut` suggests `as_chunks_mut::<N>().0.iter()`** — a non-mutable iterator over a mutable chunk, which does not compile. Only the `fabric-meter` configuration contained one, so the default build stayed green while that example was broken. Checking both configurations caught it. - **Renaming wants a grep for the method, not the type.** My caller check missed `mlx.rs`, which reaches `SafetensorsDtype` through a type alias, so `SafetensorsDtype::from_str(` never matched. - **A duplicate that is not a bug.** `fabric_dispatch.rs` calls `ledger_record` twice with identical arguments; the comment three lines above says attention is "recorded as two GEMM-equivalents" so the measured µJ/GFLOP table prices it. Deliberate, left alone. ## Scope of the gate Default features only. Under `rayon fabric-meter` this crate is also clean, but clippy reports **jouleclaw-backend-apple** through the path dependency (`--no-deps` does not exclude workspace members), and that crate has 43 warnings — 27 `unused_unsafe` and 15 `unused_imports` that are unused in *that* configuration and needed in others. Those want cfg work rather than deletion, which is the trap #373 already paid for once, so they are left as their own change. ## Verified All four lint specs in the step pass, 343 loader-gguf tests, 77 omni tests, both configurations build clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jouleclaw-loader-gguf: 161 -> 81 clippy warnings, and what the gate still needs
Some checks failed
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
standards workspaces build + test / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
8f4d5b49b1
#373 left this crate as the remaining half of the per-configuration lint
hole: `jouleclaw-omni --features metal` is gated with `-D warnings`, but
loader-gguf, which omni depends on, is not linted at all on its own.

Two steps here, neither of them risky:

- `cargo clippy --fix` applied the machine-applicable suggestions. Only
  seven files; most of this crate's lints are not auto-fixable.
- the same three policy decisions omni's lib.rs already records, for the
  same reasons, since this is quantisation and tokeniser code with the
  same shapes: `needless_range_loop` (kernels walk several arrays at one
  index, often at an offset), `too_many_arguments` (a dequantiser's
  signature is its block format), and the two doc-indentation lints.

161 -> 81 on the default feature set.

It still cannot join the `-D warnings` list, and the measurement says
precisely why. Counting distinct sites, deduplicated, by crate:

                              default   + rayon fabric-meter
    loader-gguf src              75              76
    loader-gguf tests/examples   10              14
    jouleclaw-backend-apple       -              43

Three things that measurement settles, all of which I had wrong at some
point while taking it:

- `--no-deps` does NOT exclude workspace path-dependencies. Running
  `clippy -p jouleclaw-loader-gguf` reports jouleclaw-backend-apple's
  warnings too, so gating this crate means gating that one as well.
  That is also why 27 `unused_unsafe` and 15 `unused_imports` appear
  under fabric-meter and not on default: they are backend-apple's, in
  mps_matmul.rs, not this crate's.
- the remainder is in `src`, not tests. I guessed "largely tests and
  examples" from the first number and it is 75 against 10.
- what is left is mechanical rather than policy: 16
  `chunks_exact_to_as_chunks`, 9 `unnecessary_cast`, 9 `redundant_guards`,
  6 `collapsible_if`, 6 `manual_repeat_n`, 5 `manual_is_multiple_of`,
  5 `unnecessary_sort_by`, and a tail of ones and twos.

So closing it is ~80 edits here plus ~43 in a second crate, each needing
care because `chunks_exact` -> `as_chunks` changes remainder handling in
quantisation code. That is a decision about appetite, not a blocker, and
it is left as one.

Verified: 343 loader-gguf tests, the fabric-meter `process_calibration`
build that caught a deleted label yesterday, and omni's own
`-D warnings` gate and 77 tests all still pass.

Co-Authored-By: Claude Opus 5 <[email protected]>
`cargo clippy --fix` only applies MachineApplicable suggestions, and most
of this crate's remaining lints carry MaybeIncorrect ones. Those are still
exact byte spans with exact replacement text; "maybe incorrect" means
clippy will not promise the semantics, not that the text is wrong. So
scripts/../apply-suggestions.py reads the JSON and applies them, and the
crate's 343 tests decide.

96 spans across 26 files: collapsible_if, redundant_guards,
needless_late_init, unnecessary_cast, manual_is_multiple_of,
manual_repeat_n, unnecessary_sort_by, manual_slice_size_calculation,
unused_mut, needless_lifetimes, needless_borrows_for_generic_args,
double_parens.

One suggestion class must never be applied this way, and it cost a
revert to learn: `needless_range_loop` emits a *template*, not a
replacement --

    for (i, <item>) in w.iter_mut().enumerate().take(total)

-- leaving both the binding name and the body's `w[i]` uses for a human.
Applied literally it writes `<item>` into the source, which does not
parse; four files failed to compile. They were reverted to HEAD and the
applier now refuses any replacement containing `<` and `>`.

The lesson that actually matters is the ordering: the first batch of 69
was verified green and then left uncommitted while a riskier batch ran on
top, so reverting the breakage could not be done without also losing
verified work. Commit verified progress before the next batch.

Verified: 0 errors, 343 tests pass.

Co-Authored-By: Claude Opus 5 <[email protected]>
26 more of clippy's own suggestions: unused_parens (18 of them introduced
by the previous batch's rewrites), collapsible_match, derivable_impls,
manual_range_contains, unnecessary_mut_passed. 0 errors, 343 tests pass.

Co-Authored-By: Claude Opus 5 <[email protected]>
16 `chunks_exact(N)` -> `as_chunks::<N>().0` across 8 files, which is the
batch that needed the tests rather than the compiler: the two forms differ
in how they expose the trailing remainder, and these walk quantised block
layouts.

The first guard against template suggestions was too crude and rejected
all 28 of these, because `as_chunks::<2>()` legitimately contains angle
brackets. It now rejects only a bare lowercase word in brackets that no
`::` precedes, which is what a placeholder looks like.

One follow-on the suggestion cannot express: `as_chunks` yields
`&[u8; N]`, so the `c.try_into().unwrap()` that `chunks_exact(8)` needed
in onnx.rs became ill-typed. Dropped to `*c`.

Verified: 0 errors, 343 tests pass.

Co-Authored-By: Claude Opus 5 <[email protected]>
jouleclaw-loader-gguf: 0 warnings, and -D warnings now gates it
All checks were successful
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m2s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 46s
standards workspaces build + test / arl-rs (arl/arl-rs, arl-rs, linux) (pull_request) Successful in 1m16s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m53s
standards workspaces build + test / eoc-rs (eoc/eoc-rs, -p eoc-meter --features cuda, eoc-rs, linux) (pull_request) Successful in 2m9s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m14s
standards workspaces build + test / joulehook-rs (joulehook/joulehook-rs, joulehook-rs, linux) (pull_request) Successful in 1m11s
standards workspaces build + test / pool-rs (pool/pool-rs, pool-rs, linux) (pull_request) Successful in 1m8s
standards workspaces build + test / proof-rs (proof-conformance, proof/proof-rs, proof-rs, linux, true) (pull_request) Successful in 1m28s
standards workspaces build + test / sense-rs (sense/sense-rs, sense-rs, linux) (pull_request) Successful in 1m16s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, sandbox-rs, linux) (pull_request) Successful in 2m27s
standards workspaces build + test / smart-byte-rs (smart-byte/smart-byte-rs, smart-byte-rs, linux) (pull_request) Successful in 4m10s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 6m50s
standards workspaces build + test / joulecontract-rs (joulecontract/joulecontract-rs, joulecontract-rs, linux-arm64, true) (pull_request) Successful in 1m30s
standards workspaces build + test / map-rs (map-conformance, map/map-rs, map-rs, linux-arm64) (pull_request) Successful in 1m28s
standards workspaces build + test / aac-rs (aac-conformance, aac/aac-rs, aac-rs, linux-arm64) (pull_request) Successful in 5m17s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 5m10s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 2m24s
standards workspaces build + test / openpay (openpay, openpay, linux-arm64) (pull_request) Successful in 6m16s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 8m16s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 2m52s
f5760cc22d
12 -> 0, in both the default and `rayon fabric-meter` configurations, and
the crate joins the `-D warnings` clippy step in standards-build.yml.

The last dozen needed judgement rather than a script:

- two `from_str` methods that are not FromStr-shaped (one returns Option,
  the other is infallible) renamed to `parse`. Both are file-local, so
  there is no caller churn -- except that my check for callers missed
  mlx.rs, which reaches SafetensorsDtype through a type ALIAS, so
  `SafetensorsDtype::from_str(` never matched. Renaming wants a grep for
  the method name across the workspace, not for the type names you happen
  to know.
- `assert!(FLASH_KV_CHUNK.is_power_of_two())` and `>= 64` moved out of a
  `#[test]` into `const _: () = assert!(..)` beside the constant. These
  are properties of a constant; a test only holds them if someone runs it.
- the `kv_quant_tests` module moved to the end of kv_cache_inplace.rs,
  because 300 lines of real items sat after it.
- an example discarded the `Result` from `matmul_bf16_threaded`, so a
  failure would have been timed as a success.
- `needless_range_loop` allowed per-file in three benches and one test:
  those are separate crates, so src/lib.rs's decision does not reach them.
- checked_div for two guarded divisions, and one unused `mut`.

Two near-misses worth recording:

- `fabric_dispatch.rs` calls `ledger_record` twice with identical
  arguments, which reads exactly like a copy-paste bug. The comment three
  lines above says attention is "recorded as two GEMM-equivalents" so the
  measured µJ/GFLOP table prices it. Deliberate. Left alone.
- clippy's `chunks_exact_mut` suggestion is `as_chunks_mut::<N>().0.iter()`
  -- a non-mutable iterator over a mutable chunk. It does not compile, and
  only the fabric-meter configuration contained one, so the default build
  stayed green while that example was broken. Checking both configurations
  is what caught it.

The gate covers default features only. Under `rayon fabric-meter` this
crate is also clean, but clippy reports jouleclaw-backend-apple through
the path dependency, and that crate has 43 warnings -- 27 `unused_unsafe`
and 15 `unused_imports` that are unused in THAT configuration and needed
in others. Those want cfg work, not deletion, which is the trap #373
already paid for once.

Verified: four lint specs pass, 343 loader-gguf tests, 77 omni tests.

Co-Authored-By: Claude Opus 5 <[email protected]>
dcharlot changed title from jouleclaw-loader-gguf: 161 -> 81 clippy warnings, and what the -D warnings gate still needs to jouleclaw-loader-gguf: 161 clippy warnings -> 0, and -D warnings now gates it 2026-10-21 20:40:54 -04:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!414
No description provided.