Luigit
repositories / smith

smith

There are many coding harnesses - but this one is fast

owned by admin

.system/research/SMH-RESEARCH-JTJLLCMH-cargo-and-clippy-lint-scoping/index.md

Raw
Rendered preview

id: SMH-RESEARCH-JTJLLCMH type: research title: "Cargo and Clippy Lint Scoping"

Cargo and Clippy Lint Scoping

Idiomatic ways to scope lint levels by target (production, tests, guests), verified against current docs and this repository.

Mechanisms, verified

mechanism scope unit idiomatic for verified
[workspace.lints] + [lints] workspace = true package (all its targets) stable levels owned in Cargo.toml; cargo-native since 1.74 cargo workspaces
[lints.clippy] per package package per-crate exceptions without attrs clippy configuration
attributes #[deny] / #[expect] item, module, file visible, reasoned, local exceptions clippy docs
rustc args after -- (-A clippy::x) invocation phase splits (--tests, --lib) and one-shot overrides; last level wins over earlier flags rustc lint levels
.cargo/config.toml rustflags every rustc invocation workspace-wide zero-warning policy incl. builds current smith setup
clippy.toml / .clippy.toml whole run VALUES only (thresholds), never levels clippy docs

Nightly-only: cargo's own lint group (unused_dependencies etc.) — not usable on stable.

Facts discovered in this repository

  • CLIPPY_CONF_DIR is real and documented: priority CLIPPY_CONF_DIR → CARGO_MANIFEST_DIR → cwd, then parent walk.
  • Empirically: without the env var, clippy.toml under .config/ is NOT discovered — raw cargo clippy and rust-analyzer silently lose threshold configuration. With the env var (xtask gate), it parses.
  • Clippy levels cannot be scoped by target type (--tests) through any cargo-native table; that gap is what invocation splitting covers.
  • #[expect] on items coexists with command-line -A: expectations stay fulfilled when the lint would fire without the allowance. File-level #![expect] headers on lints the phase allows become redundant but were not observed to error; either way, phase-covered expectations should be deleted.

Idiomatic shape for smith

policy levels      .cargo/config.toml rustflags (unchanged) — the
                   zero-warning law applies to every compilation
thresholds         .config/clippy.toml + CLIPPY_CONF_DIR in xtask
per-crate levels   [lints] tables when a crate needs a standing
                   exception (none today)
local exceptions   #[expect(..., reason)] attributes (status quo)
target phases      xtask clippy split: --lib/--bins strict,
                   --tests with assertion allowances, guests with
                   pedantic+missing_docs allowances

Phase allowances after -- are idiomatic for CI orchestration; they live in one auditable place and cannot leak into source.

Unresolved questions

  • Raw-run configuration loss: developers and rust-analyzer invoke clippy without CLIPPY_CONF_DIR and get default thresholds. Options: symlink .clippy.toml at root into .config/ (root file, law tension), law exception for clippy discovery, or accept gate-only configuration and document it.
  • Precedence between [lints] table levels and config rustflags is undocumented; if both are adopted, test empirically before mixing.
  • Whether test allowances should eventually move into a [lints]-based scheme if cargo grows per-target lint tables.

Sources

---
id: SMH-RESEARCH-JTJLLCMH
type: research
title: "Cargo and Clippy Lint Scoping"
---

# Cargo and Clippy Lint Scoping

Idiomatic ways to scope lint levels by target (production, tests, guests), verified against current docs and this repository.

## Mechanisms, verified

| mechanism | scope unit | idiomatic for | verified |
|---|---|---|---|
| `[workspace.lints]` + `[lints] workspace = true` | package (all its targets) | stable levels owned in Cargo.toml; cargo-native since 1.74 | [cargo workspaces](https://doc.rust-lang.org/cargo/reference/workspaces.html) |
| `[lints.clippy]` per package | package | per-crate exceptions without attrs | [clippy configuration](https://doc.rust-lang.org/clippy/configuration.html) |
| attributes `#[deny]` / `#[expect]` | item, module, file | visible, reasoned, local exceptions | clippy docs |
| rustc args after `--` (`-A clippy::x`) | invocation | phase splits (`--tests`, `--lib`) and one-shot overrides; last level wins over earlier flags | rustc lint levels |
| `.cargo/config.toml` rustflags | every rustc invocation | workspace-wide zero-warning policy incl. builds | current smith setup |
| `clippy.toml` / `.clippy.toml` | whole run | VALUES only (thresholds), never levels | clippy docs |

Nightly-only: `cargo`'s own lint group (`unused_dependencies` etc.) — not usable on stable.

## Facts discovered in this repository

- `CLIPPY_CONF_DIR` is real and documented: priority CLIPPY_CONF_DIR → CARGO_MANIFEST_DIR → cwd, then parent walk.
- Empirically: without the env var, `clippy.toml` under `.config/` is NOT discovered — raw `cargo clippy` and rust-analyzer silently lose threshold configuration. With the env var (xtask gate), it parses.
- Clippy levels cannot be scoped by target type (`--tests`) through any cargo-native table; that gap is what invocation splitting covers.
- `#[expect]` on items coexists with command-line `-A`: expectations stay fulfilled when the lint would fire without the allowance. File-level `#![expect]` headers on lints the phase allows become redundant but were not observed to error; either way, phase-covered expectations should be deleted.

## Idiomatic shape for smith

```text
policy levels      .cargo/config.toml rustflags (unchanged) — the
                   zero-warning law applies to every compilation
thresholds         .config/clippy.toml + CLIPPY_CONF_DIR in xtask
per-crate levels   [lints] tables when a crate needs a standing
                   exception (none today)
local exceptions   #[expect(..., reason)] attributes (status quo)
target phases      xtask clippy split: --lib/--bins strict,
                   --tests with assertion allowances, guests with
                   pedantic+missing_docs allowances
```

Phase allowances after `--` are idiomatic for CI orchestration; they live in one auditable place and cannot leak into source.

## Unresolved questions

- Raw-run configuration loss: developers and rust-analyzer invoke clippy without CLIPPY_CONF_DIR and get default thresholds. Options: symlink `.clippy.toml` at root into `.config/` (root file, law tension), law exception for clippy discovery, or accept gate-only configuration and document it.
- Precedence between `[lints]` table levels and config rustflags is undocumented; if both are adopted, test empirically before mixing.
- Whether test allowances should eventually move into a `[lints]`-based scheme if cargo grows per-target lint tables.

## Sources

- Cargo lints inheritance — <https://doc.rust-lang.org/cargo/reference/workspaces.html>
- Clippy configuration discovery — <https://doc.rust-lang.org/clippy/configuration.html>
- Cargo's own (nightly) lint groups — <https://doc.rust-lang.org/cargo/reference/lints.html>