| name | fix-rust-lints |
| description | Classify clippy/compiler failures by lint family and apply canonical idiomatic fixes. |
| argument-hint | [lint output | --scan] |
| user-invocable | true |
| allowed-tools | Bash, Read, Edit, Grep |
| truth_contract | {"canonical_sources":["ops/state/config/repo-map.json"],"live_load_required":["cargo clippy --workspace --all-targets -- -D warnings 2>&1","git diff --name-only $(git merge-base HEAD origin/main)..HEAD"],"examples_only":[],"never_hardcode":["toolchain version (read from rust-toolchain.toml)","branch name or changed file list (always live-query)"]} |
Turn recurring Rust lint failures into known remediation classes. Never debug clippy from scratch.
The Problem This Solves
The transcript discovered two lint patterns mid-run and fixed them ad hoc. Those same patterns
will recur. This skill pre-encodes them as named classes with canonical fix shapes so the model
stops relearning under pressure.
Steps
-
Collect failures: If $ARGUMENTS is empty, run:
cargo clippy --workspace --all-targets -- -D warnings 2>&1 | grep "^error"
Or read from provided output.
-
Classify each error by lint name (appears in brackets after error:):
cargo clippy ... 2>&1 | grep -E "^error\[|^\s+-->"
-
Apply canonical fix from the playbook below.
-
Scan for recurrences of the same anti-pattern in nearby code:
grep -rn "<pattern>" crates/ apps/ bins/
-
Verify: Re-run the scoped clippy command to confirm the fix.
Lint Remediation Playbook
field_reassign_with_default
Trigger: let mut x = T::default(); x.field = value;
Canonical fix: Struct update syntax
let mut cfg = FooConfig::default();
cfg.some_field = new_value;
let cfg = FooConfig {
some_field: new_value,
..Default::default()
};
Why: Removes the mut binding, signals intent at construction, eliminates post-init mutation.
Scan for recurrences:
grep -rn "let mut .* = .*::default();" crates/ apps/ bins/ --include="*.rs"
Deprecated item in --all-targets (test code)
Trigger: use of deprecated ... in test modules when compiling with --all-targets -D warnings
Root cause: #[deprecated] is transitive. CI uses --all-targets, which compiles test code.
A deprecated constant marked in a library still fires as an error wherever test code references it,
even if the non-test code is clean.
Canonical fix: Replace deprecated references with the recommended replacement, even in tests.
Do NOT use #[allow(deprecated)] unless the replacement doesn't exist yet.
membership_age_secs: MIN_MEMBERSHIP_AGE_SECS + 1,
membership_age_secs: AttestationThresholds::default().min_membership_age_secs + 1,
Scan for recurrences:
grep -rn "MIN_MEMBERSHIP_AGE_SECS\|MAX_ATTESTATIONS_PER_PERIOD\|MIN_TRUST_TO_ATTEST" \
crates/ apps/ --include="*.rs" | grep -v "pub const\|#\[deprecated"
Re-export workaround: When a module re-exports deprecated items for backward compat,
add #[allow(deprecated)] on the pub use block only, not on callers:
#[allow(deprecated)]
pub use attestation::{LEGACY_CONST, old_function};
clippy::unwrap_used / clippy::expect_used in tests
Trigger: error: used unwrap() on a Result value in test code
Canonical fix: Add workspace-level test allowance or use #![cfg_attr(test, allow(...))]
in the crate root. Do NOT sprinkle #[allow] throughout test functions.
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
clippy::too_many_arguments
Trigger: Function has 8+ parameters.
Canonical fix: Either group related params into a config struct, or accept the lint suppression
if the function is a one-off constructor:
pub fn build_policy(config: PolicyConfig) -> Policy { ... }
#[allow(clippy::too_many_arguments)]
pub fn new_internal(a: T, b: U, ...) -> Self { ... }
ICN note: Prefer the config struct approach for any function that appears in lifecycle.rs,
since those wire multiple values from config objects.
clippy::missing_errors_doc / clippy::missing_panics_doc
Trigger: Public function lacks # Errors / # Panics doc section.
Canonical fix: Add the section, or suppress at crate level with #![allow(missing_docs)]
if the crate already has that allowance:
pub fn do_thing(&self) -> Result<(), String> { ... }
Overflow / underflow in time arithmetic
Trigger: SystemTime subtraction that can underflow, or u64::checked_mul missing.
Canonical fix:
let cutoff = now - duration;
let cutoff = now.checked_sub(duration).unwrap_or(SystemTime::UNIX_EPOCH);
let secs = days.checked_mul(SECONDS_PER_DAY).unwrap_or(u64::MAX);
Guardrails
- Never suppress a lint without understanding its class. Find the canonical fix first.
- Prefer fixing the anti-pattern to suppressing the warning.
- After fixing, scan for the same pattern in nearby code before committing.
- A fix that passes local
cargo clippy -p <crate> may still fail CI --workspace --all-targets.
Always scope-check with --all-targets before declaring victory.